// pgh-sidecar registration — makes the daemon a first-class pgh app. Registering our UDS
// with the sidecar lets `app-lookup` resolve us (so `pgh app status atproto-bridge` and the
// readiness probe work) and survives the boot race (sidecar socket may appear after us).
// Mirrors pear-git-v3/lib/sidecar-wait.js + server.js registerWithSidecar.
// ⚠ BARE-NATIVE IMPORTS. Copied from atproto-bridge, which resolves `#node:*` through an "imports" map
// in its package.json — favela-web has none, so those specifiers throw PACKAGE_IMPORT_NOT_DEFINED. The
// failure is INVISIBLE because the caller treats a missing control surface as non-fatal, so the daemon
// boots normally and simply never registers. Exactly the same trap was hit in hyper-proto-peer 0.3.102.
import fs from 'bare-fs'
import path from 'bare-path'
import os from 'bare-os'
import process from 'bare-process'
export function sidecarSockPath () {
return process.env.PGH_SIDECAR_SOCK || path.join(os.homedir(), '.pgh', 'svc.sock')
}
// Poll for the sidecar socket (it may be created after this daemon boots — the boot race).
export async function waitForSidecarSock ({ timeoutMs = 120000, intervalMs = 1000, shouldStop = () => false } = {}) {
const sock = sidecarSockPath()
const deadline = Date.now() + timeoutMs
while (!fs.existsSync(sock)) {
if (shouldStop()) return false
if (Date.now() >= deadline) return false
await new Promise((r) => setTimeout(r, intervalMs))
}
return true
}
// app-register (last-writer-wins, idempotent) our live UDS + pid with the sidecar.
export async function registerWithSidecar ({ udsPath, name, runtime = 'bare', version = null }) {
const sidecarSock = sidecarSockPath()
if (!fs.existsSync(sidecarSock)) return { registered: false, reason: 'sidecar not running' }
const installName = name || process.env.PGH_APP_NAME || 'atproto-bridge'
try {
const { Client } = await import('hyper-svc')
const c = await Client.connectUds(sidecarSock)
await c.call('app-register', { name: installName, udsPath, pid: process.pid, runtime, version })
await c.close()
return { registered: true, name: installName }
} catch (err) {
return { registered: false, reason: err.message }
}
}
// Register once the sidecar is up, then re-register on an interval (the sidecar keeps its
// registry in memory, so a sidecar restart silently drops us). Returns a stop() fn.
export function maintainSidecarRegistration ({ udsPath, name, runtime, version, intervalMs = 30000 } = {}) {
let timer = null
let stopped = false
;(async () => {
const ready = await waitForSidecarSock({ shouldStop: () => stopped })
if (stopped) return
if (ready) await registerWithSidecar({ udsPath, name, runtime, version })
timer = setInterval(() => { registerWithSidecar({ udsPath, name, runtime, version }) }, intervalMs)
if (timer.unref) timer.unref()
})()
return () => { stopped = true; if (timer) clearInterval(timer) }
}