@hediet/linkrpc-hub 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +101 -0
  2. package/dist/chunks/config-BCvkg7jv.d.ts +566 -0
  3. package/dist/chunks/configFile-y6Phntqu.d.ts +9 -0
  4. package/dist/chunks/connectionTokenBinder.interfaces-B-beCg06.js +40 -0
  5. package/dist/chunks/connectionTokenBinder.interfaces-B-beCg06.js.map +1 -0
  6. package/dist/chunks/connectionTokenBinder.interfaces-BhzQ1DTS.d.ts +36 -0
  7. package/dist/chunks/hubConnectionAcceptor-B5-8JsFY.js +2768 -0
  8. package/dist/chunks/hubConnectionAcceptor-B5-8JsFY.js.map +1 -0
  9. package/dist/chunks/hubConnectionAcceptor-BwydvFa4.d.ts +1560 -0
  10. package/dist/chunks/index-CLIUrV88.d.ts +481 -0
  11. package/dist/chunks/node-CTXsQ6oa.js +460 -0
  12. package/dist/chunks/node-CTXsQ6oa.js.map +1 -0
  13. package/dist/chunks/nodeTransit-CWeFnbwt.js +444 -0
  14. package/dist/chunks/nodeTransit-CWeFnbwt.js.map +1 -0
  15. package/dist/chunks/nodeTransit-cmtZgdpW.d.ts +226 -0
  16. package/dist/chunks/runHub-P3YUwwdv.js +1797 -0
  17. package/dist/chunks/runHub-P3YUwwdv.js.map +1 -0
  18. package/dist/chunks/server-BAxchQhy.js +1368 -0
  19. package/dist/chunks/server-BAxchQhy.js.map +1 -0
  20. package/dist/cli.d.ts +1 -0
  21. package/dist/cli.js +38 -0
  22. package/dist/cli.js.map +1 -0
  23. package/dist/config.d.ts +2 -0
  24. package/dist/config.js +305 -0
  25. package/dist/config.js.map +1 -0
  26. package/dist/configFile.d.ts +2 -0
  27. package/dist/configFile.js +27 -0
  28. package/dist/configFile.js.map +1 -0
  29. package/dist/engine/runHub.d.ts +42 -0
  30. package/dist/engine/runHub.js +2 -0
  31. package/dist/hub/server/client.d.ts +2 -0
  32. package/dist/hub/server/client.js +2 -0
  33. package/dist/hub/server/connectionTokenBinder.d.ts +2 -0
  34. package/dist/hub/server/connectionTokenBinder.js +2 -0
  35. package/dist/hub/server/index.d.ts +5 -0
  36. package/dist/hub/server/index.js +5 -0
  37. package/dist/hub/server/node/index.d.ts +218 -0
  38. package/dist/hub/server/node/index.js +2 -0
  39. package/dist/hub/server/transit.d.ts +2 -0
  40. package/dist/hub/server/transit.js +2 -0
  41. package/dist/index.d.ts +512 -0
  42. package/dist/index.js +309 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/serve.d.ts +14 -0
  45. package/dist/serve.js +31 -0
  46. package/dist/serve.js.map +1 -0
  47. package/dist/spawn.d.ts +12 -0
  48. package/dist/spawn.js +25 -0
  49. package/dist/spawn.js.map +1 -0
  50. package/package.json +83 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runHub-P3YUwwdv.js","names":[],"sources":["../../src/engine/consent.ts","../../src/engine/hubAccessConfig.ts","../../src/engine/hubAccessManifest.ts","../../src/engine/approveClient.ts","../../src/engine/manifestApprover.ts","../../src/engine/cmdEndpoint.ts","../../src/engine/routeTable.ts","../../src/engine/configuredParticipants.ts","../../src/engine/runHub.ts"],"sourcesContent":["/**\n * Approver-side consent utilities for the `hubAccessManifest` flow.\n *\n * This module is consumed by *approvers* — {@link runManifestApprover} (the CLI)\n * and any other manifest consumer. It provides:\n *\n * - the prompt contract ({@link ConsentPrompt} / {@link ConsentPromptRequest} /\n * {@link ConsentDecision}) an approver uses to ask a human, plus the default\n * terminal y/N prompt ({@link createTerminalConsentPrompt});\n * - capability-shaping helpers an approver uses when it mints\n * ({@link toSignedPermissions} / {@link computeCallBindHash}, which honor\n * \"Allow once\" `callBind` byte-binding); and\n * - {@link describePermissions} for rendering a request.\n *\n * The hub-side translation of `hubAccess` requests into parked manifest entries\n * lives on {@link HubAccessManifestHost} (`hubAccessConfig`), not here.\n */\nimport {\n HUBRPC_META_KEY,\n type CallMeta,\n type JsonValue,\n type PrincipalId,\n type Pattern,\n type Permission,\n requireObjectParams,\n signedHash,\n type SignedCapability,\n} from '@hediet/linkrpc';\nimport {\n type AccessCallIntent,\n type AccessDirectPermission,\n} from '../hub/server';\nimport * as readline from 'node:readline';\n\n/**\n * The outcome of a single consent prompt.\n *\n * - `{ grant: false }` — deny (optionally with a reason).\n * - `{ grant: true, capabilities }` — approve. The approver minted the\n * capabilities itself (with its own accepted-root identity); the keyless\n * {@link HubAccessManifestHost} relays them verbatim. On a grant the\n * capabilities are **required** — the host has no signing identity of its\n * own.\n */\nexport type ConsentDecision =\n | { readonly grant: false; readonly reason?: string; }\n | { readonly grant: true; readonly capabilities?: readonly SignedCapability[]; };\n\n/**\n * Asks an approver to decide a single access request. Injected so different\n * approvers (the terminal prompt, the hub-served manifest, tests) can supply the\n * decision. May be aborted via {@link ConsentPromptRequest.signal} when another\n * racing prompt settles first — implementations should stop waiting and clean up.\n */\nexport type ConsentPrompt = (request: ConsentPromptRequest) => Promise<ConsentDecision>;\n\nexport interface ConsentPromptRequest {\n /** Correlates the prompt with the blocked `hubAccess` call. */\n readonly requestId: string;\n /** Which `hubAccess` method is blocked on this request. */\n readonly kind: 'request' | 'extend' | 'requestAccess';\n /** Human-friendly description of who is asking. */\n readonly consumer: { readonly name: string; readonly origin?: string; readonly purpose?: string; };\n /** Verified PrincipalId of the calling consumer (the capability audience). */\n readonly consumerPrincipalId: PrincipalId;\n /**\n * The exact authority requested. Each permission may carry the consent-only\n * `callIntent` preview, so an approver can mint a byte-bound one-shot\n * (\"Allow once\") capability.\n */\n readonly permissions: readonly AccessDirectPermission[];\n /** One line per authority being requested (`serviceId::interfaceId member`). */\n readonly grants: readonly string[];\n /** `once` / `session` / `persistent`, when the consumer expressed one. */\n readonly duration: string | undefined;\n /** Aborts when another racing prompt has already settled this request. */\n readonly signal: AbortSignal;\n}\n\n/** One-line, human-readable summary of a permission for the consent prompt. */\nfunction describePermission(perm: Permission): string {\n const svc = patternText(perm.target.serviceId);\n const iface = patternText(perm.target.interfaceId);\n const members = perm.target.members.map(patternText).join(',');\n return `${svc}::${iface} {${members}}`;\n}\n\n/** One human-readable line per permission, for an approver's UI / prompt. */\nexport function describePermissions(permissions: readonly Permission[]): string[] {\n return permissions.map(describePermission);\n}\n\nfunction patternText(p: Pattern | undefined): string {\n if (p === undefined) return '*';\n if ('exact' in p) return p.exact;\n if ('prefix' in p) return p.prefix === '' ? '*' : `${p.prefix}*`;\n return '*';\n}\n\n/**\n * Strip the consent-only `callIntent` from each requested permission and, for a\n * one-shot (`duration: 'once'`) grant whose intent declares a concrete call,\n * pin the permission to that exact call via `callBind.payloadHash`. The result\n * is the `Permission[]` to sign into the capability. Shared by the hub-issuer\n * mint path and any inbox approver that wants to honor \"Allow once\".\n *\n * `callIntent` is never itself signed — only the derived `callBind` is.\n */\nexport async function toSignedPermissions(\n permissions: readonly AccessDirectPermission[],\n consumerPrincipalId: PrincipalId,\n duration: string | undefined,\n): Promise<Permission[]> {\n return Promise.all(\n permissions.map(async ({ callIntent, ...perm }) => {\n const signed: Permission = { ...perm };\n if (\n duration === 'once'\n && callIntent !== undefined\n && callIntent.params !== undefined\n && callIntent.nonce\n && callIntent.signedAtMs !== undefined\n ) {\n signed.callBind = {\n alg: 'sha256',\n payloadHash: await computeCallBindHash(callIntent, consumerPrincipalId),\n };\n }\n return signed;\n }),\n );\n}\n\n/**\n * Compute `callBind.payloadHash` for a grant bound to one consumer-declared\n * call. Builds the SAME signed params the consumer commits to at sign time\n * (`signedHash('call', { ...params, $hubrpc: meta })`); the forwarded-call gate\n * re-derives this on the inbound call and checks the hash matches. The consumer\n * owns `nonce`/`signedAtMs`, supplied via `callIntent`.\n */\nexport async function computeCallBindHash(\n intent: AccessCallIntent,\n consumerPrincipalId: PrincipalId,\n): Promise<string> {\n const callMeta: CallMeta = {\n method: intent.method,\n nonce: intent.nonce,\n signedAtMs: intent.signedAtMs,\n principal: consumerPrincipalId,\n ...(intent.interfaceHash !== undefined ? { interfaceHash: intent.interfaceHash } : {}),\n };\n const userParams = requireObjectParams(intent.params as JsonValue | undefined);\n const signedParams = { ...userParams, [HUBRPC_META_KEY]: callMeta };\n return signedHash('call', signedParams);\n}\n\n/**\n * A terminal yes/no consent prompt on stdin.\n *\n * When stdin is not a TTY (no operator to answer) it **abstains** — it never\n * settles, parking until {@link ConsentPromptRequest.signal} aborts. This keeps\n * it safe inside {@link raceConsent}: a non-interactive terminal must not win\n * the race with an instant deny, or a hub-served inbox approval could never\n * land. A headless hub should simply not install this prompt at all (or pair it\n * with an inbox); on its own it grants nothing.\n *\n * When interactive, it resolves on the operator's answer, and abandons the\n * readline prompt if the request is aborted (another prompt decided first).\n */\nexport function createTerminalConsentPrompt(): ConsentPrompt {\n return (request) =>\n new Promise<ConsentDecision>((resolve) => {\n if (request.signal.aborted) {\n resolve({ grant: false });\n return;\n }\n if (!process.stdin.isTTY) {\n process.stderr.write(\n 'hubAccess: stdin is not a TTY; the terminal prompt is abstaining '\n + '(waiting for an out-of-band approval or cancellation).\\n',\n );\n request.signal.addEventListener('abort', () => resolve({ grant: false }), { once: true });\n return;\n }\n const rl = readline.createInterface({ input: process.stdin, output: process.stderr });\n const onAbort = () => {\n rl.close();\n resolve({ grant: false });\n };\n request.signal.addEventListener('abort', onAbort, { once: true });\n const lines = [\n '',\n `Access request from \"${request.consumer.name}\"`,\n ...(request.consumer.purpose ? [` purpose: ${request.consumer.purpose}`] : []),\n ` node: ${request.consumerPrincipalId}`,\n ...request.grants.map((g) => ` grant: ${g}`),\n ...(request.duration ? [` duration: ${request.duration}`] : []),\n '',\n ];\n process.stderr.write(lines.join('\\n'));\n rl.question('Allow? [y/N] ', (answer) => {\n request.signal.removeEventListener('abort', onAbort);\n rl.close();\n resolve(/^y(es)?$/i.test(answer.trim()) ? { grant: true } : { grant: false });\n });\n });\n}\n\n/**\n * Compose several {@link ConsentPrompt}s into one that presents each request to\n * **all** of them and takes the **first** to settle (first responder wins,\n * including a deny). Once one settles, the rest are aborted via a shared signal\n * so they can tear down (close the readline, drop the inbox entry). The\n * incoming request's own signal is honored too: if the consumer cancels, every\n * child prompt is aborted.\n *\n * This is what lets a single `hubAccess` request reach the hub operator's\n * terminal prompt and a hub-served inbox at the same time.\n */\nexport function raceConsent(prompts: readonly ConsentPrompt[]): ConsentPrompt {\n return (request) =>\n new Promise<ConsentDecision>((resolve, reject) => {\n if (prompts.length === 0) {\n resolve({ grant: false, reason: 'no consent surface configured' });\n return;\n }\n const child = new AbortController();\n const onOuterAbort = () => child.abort();\n if (request.signal.aborted) {\n child.abort();\n } else {\n request.signal.addEventListener('abort', onOuterAbort, { once: true });\n }\n let settled = false;\n const finish = (run: () => void) => {\n if (settled) return;\n settled = true;\n request.signal.removeEventListener('abort', onOuterAbort);\n child.abort();\n run();\n };\n const childRequest: ConsentPromptRequest = { ...request, signal: child.signal };\n for (const prompt of prompts) {\n Promise.resolve()\n .then(() => prompt(childRequest))\n .then(\n (decision) => finish(() => resolve(decision)),\n (err) => finish(() => reject(err)),\n );\n }\n });\n}\n","/**\n * `createHubAccessConfig` — the adapter from the imperative `hubAccess` front\n * door to a single {@link AccessDecider} callback.\n *\n * The `hubAccess::{request,extend,requestAccess}` interface has three shapes;\n * this adapter normalizes all of them into one {@link AccessRequestContext}\n * (resolving discovery candidates for `request`, building permissions for\n * `extend`) and hands them to `decide`. The decider supplies the\n * approver-signed capabilities to relay (it never mints here). Two deciders\n * exist:\n *\n * - {@link HubAccessManifestHost.park} — parks the request as a manifest entry\n * and awaits a remote approver.\n * - {@link HubAccessGrantSigner.decide} — decides + mints in-process with a\n * held signing identity (the simple \"hub grants locally\" case).\n *\n * `fetchDirectory` is the candidate-resolution source for `request`; it is a\n * property of *this* front-door registration, not of any decider. Defaults to\n * an empty directory (every `request` slot then resolves to `noCandidates`).\n */\nimport { type Pattern, type Permission } from '@hediet/linkrpc';\nimport {\n type AccessConsumer,\n type AccessDirectPermission,\n type AccessDuration,\n type AccessSlotBinding,\n type DirectoryEntry,\n type HubAccessConfig,\n type HubAccessHandlers,\n} from '../hub/server';\nimport { type ConsentDecision, describePermissions } from './consent';\nimport type { SignedCapability } from '@hediet/linkrpc';\n\n/** The normalized request every `hubAccess` shape collapses to before deciding. */\nexport interface AccessRequestContext {\n readonly kind: 'request' | 'extend' | 'requestAccess';\n readonly consumer: AccessConsumer;\n /** Capability audience — the consumer's own PrincipalId. */\n readonly consumerPrincipalId: string;\n /** The requested authority; permissions may carry a consent-only `callIntent`. */\n readonly permissions: readonly AccessDirectPermission[];\n readonly duration: AccessDuration | undefined;\n}\n\n/** Decides one normalized request, returning the approver-signed capabilities to relay. */\nexport type AccessDecider = (ctx: AccessRequestContext) => Promise<ConsentDecision>;\n\n/**\n * Build the `hubAccess` front-door config from a single {@link AccessDecider}.\n * The returned {@link HubAccessConfig} is what `registerHubAccessService`\n * installs at a participant's overlay root.\n */\nexport function createHubAccessConfig(\n decide: AccessDecider,\n fetchDirectory: () => Promise<readonly DirectoryEntry[]> = async () => [],\n): HubAccessConfig {\n const handlers: HubAccessHandlers = {\n onAccessRequest: async (args) => {\n const slotIds = Object.keys(args.dependencies);\n if (slotIds.length === 0) {\n return { granted: false, reason: 'no slots requested' };\n }\n const resolvedSlots: Record<string, AccessSlotBinding> = {};\n const permissions: Permission[] = [];\n for (const [slotId, slot] of Object.entries(args.dependencies)) {\n const candidate = slot.candidates[0];\n if (!candidate) {\n return { granted: false, reason: `no candidate for slot '${slotId}'` };\n }\n const present = new Set(candidate.satisfiedInterfaces.map((i) => i.id));\n resolvedSlots[slotId] = {\n serviceId: candidate.serviceId,\n interfaces: candidate.satisfiedInterfaces.map((i) => i.id),\n };\n permissions.push(\n ...buildSlotPermissions(candidate.serviceId, slot.request.interfaces, slot.request.members, present),\n );\n }\n const decision = await decide({\n kind: 'request',\n consumer: args.consumer,\n consumerPrincipalId: args.consumerPrincipalId,\n permissions,\n duration: args.duration,\n });\n if (!decision.grant) {\n return { granted: false, reason: decision.reason ?? 'user denied' };\n }\n return { granted: true, resolvedSlots, capabilities: capsFromDecision(decision) };\n },\n\n onAccessExtend: async (args) => {\n const byIface = new Map<string, Pattern[]>();\n for (const a of args.added) {\n const members = byIface.get(a.interfaceId) ?? [];\n members.push(a.member);\n byIface.set(a.interfaceId, members);\n }\n const permissions: Permission[] = [...byIface.entries()].map(([interfaceId, members]) => ({\n target: { serviceId: { exact: args.serviceId }, interfaceId: { exact: interfaceId }, members },\n canInvoke: true,\n }));\n if (permissions.length === 0) {\n return { granted: false, reason: 'no members requested' };\n }\n const decision = await decide({\n kind: 'extend',\n consumer: args.consumer,\n consumerPrincipalId: args.consumerPrincipalId,\n permissions,\n duration: args.duration,\n });\n if (!decision.grant) {\n return { granted: false, reason: decision.reason ?? 'user denied' };\n }\n return {\n granted: true,\n serviceId: args.serviceId,\n grantedMembers: args.added.map((a) => ({ interfaceId: a.interfaceId, member: a.member })),\n capabilities: capsFromDecision(decision),\n };\n },\n\n onAccessRequestDirect: async (args) => {\n if (args.permissions.length === 0) {\n return { granted: false, reason: 'no permissions requested' };\n }\n const decision = await decide({\n kind: 'requestAccess',\n consumer: args.consumer,\n consumerPrincipalId: args.consumerPrincipalId,\n permissions: args.permissions,\n duration: args.duration,\n });\n if (!decision.grant) {\n return { granted: false, reason: decision.reason ?? 'user denied' };\n }\n return { granted: true, capabilities: capsFromDecision(decision) };\n },\n };\n\n return {\n handlers,\n fetchDirectory: async () => [...(await fetchDirectory())],\n };\n}\n\n/** A one-line human summary of a request, for a decider's log. */\nexport function describeRequest(ctx: AccessRequestContext): string {\n return `\"${ctx.consumer.name}\" (node=${ctx.consumerPrincipalId}) requests `\n + `[${describePermissions(ctx.permissions).join(', ')}]${ctx.duration ? ` for '${ctx.duration}'` : ''}`;\n}\n\n/**\n * Extract the approver-supplied capabilities from an approved decision. The\n * adapter never mints — an approval that carries no capabilities is a contract\n * violation by the decider.\n */\nfunction capsFromDecision(\n decision: { readonly grant: true; readonly capabilities?: readonly SignedCapability[]; },\n): SignedCapability[] {\n if (decision.capabilities === undefined || decision.capabilities.length === 0) {\n throw new Error(\n 'hubAccess: a grant decision carried no capabilities to relay — the '\n + 'decider must supply approver-signed capabilities (the adapter never mints).',\n );\n }\n return [...decision.capabilities];\n}\n\n/** Build one permission per requested interface, scoped to `serviceId`. */\nexport function buildSlotPermissions(\n serviceId: string,\n interfaces: readonly { id: string; hash?: string; }[],\n members: readonly { interfaceId: string; member: Pattern; }[],\n present: ReadonlySet<string>,\n): Permission[] {\n const hashByIface = new Map(interfaces.map((i) => [i.id, i.hash]));\n const buckets = new Map<string, { interfaceId: string; hash: string | undefined; members: Pattern[]; }>();\n for (const m of members) {\n if (!present.has(m.interfaceId)) continue;\n const hash = hashByIface.get(m.interfaceId);\n const key = `${m.interfaceId}\\u0000${hash ?? ''}`;\n let bucket = buckets.get(key);\n if (!bucket) {\n bucket = { interfaceId: m.interfaceId, hash, members: [] };\n buckets.set(key, bucket);\n }\n bucket.members.push(m.member);\n }\n // No member-level requests: grant the whole interface (any member).\n if (buckets.size === 0) {\n return [...present].map((interfaceId) => {\n const hash = hashByIface.get(interfaceId);\n const target: Permission['target'] = {\n serviceId: { exact: serviceId },\n interfaceId: { exact: interfaceId },\n members: [{ prefix: '' }],\n };\n if (hash !== undefined) (target as { interfaceHash?: string }).interfaceHash = hash;\n return { target, canInvoke: true };\n });\n }\n return [...buckets.values()].map((b) => {\n const target: Permission['target'] = {\n serviceId: { exact: serviceId },\n interfaceId: { exact: b.interfaceId },\n members: b.members,\n };\n if (b.hash !== undefined) (target as { interfaceHash?: string }).interfaceHash = b.hash;\n return { target, canInvoke: true };\n });\n}\n","/**\n * `HubAccessManifestHost` — the hub's keyless consent **rendezvous**. It is the\n * inverse-of-control twin of the imperative `hubAccess` front door: it serves\n * the discoverable `hubAccessManifest`, and it registers `hubAccess` **directly**\n * ({@link registerHubAccessAtRoot}) rather than through the imperative\n * `registerHubAccessService` (which resolves discovery candidates hub-side and\n * mints hub-side). Mapping:\n *\n * - `hubAccess::requestAccess` → a **direct** desired entry (verbatim perms).\n * - `hubAccess::extend` → a **direct** desired entry (widen on a service).\n * - `hubAccess::request` → one **discover** desired entry per dependency\n * slot; the *approver* resolves candidates against the directory (over its\n * own connection) and returns the chosen service. The blocked call unblocks\n * when every slot is decided. **No hub-side directory** is consulted here.\n *\n * The host is **keyless**. A decision is a pure relay: the approver mints a\n * capability with its own accepted-root identity (audience = the entry's\n * consumer) and writes it into `current` via `setCurrent`; the host forwards it\n * verbatim as the blocked `hubAccess` call's result. The authority is the\n * signature, not the `setCurrent` call — reachable only behind the\n * forwarded-call gate. Each desired entry advertises `acceptableRootIds` (the\n * hub's accepted roots) so an approver can skip entries it cannot satisfy.\n */\nimport {\n type LinkRpcConnection,\n type Pattern,\n type Permission,\n type SignedCapability,\n} from '@hediet/linkrpc';\nimport { hubAccessInterface, hubAccessManifestInterface } from '@hediet/linkrpc/hub/common';\nimport { type AccessDirectPermission } from '../hub/server';\nimport { randomUUID } from 'node:crypto';\nimport { describePermissions } from './consent';\n\n/** One interface a discover slot's chosen service must implement. */\nexport interface ManifestInterfaceReq {\n readonly id: string;\n readonly hash?: string;\n readonly required?: boolean;\n}\n\n/** One member a discover slot's consumer intends to call. */\nexport interface ManifestMemberReq {\n readonly interfaceId: string;\n readonly member: Pattern;\n readonly required?: boolean;\n}\n\ninterface PendingBase {\n readonly requestId: string;\n readonly consumer: { readonly name: string; readonly origin?: string; readonly purpose?: string; };\n readonly consumerPrincipalId: string;\n readonly duration: string | undefined;\n /**\n * Host-authored provenance bag, bound per transport at\n * {@link HubAccessManifestHost.registerHubAccessAtRoot} — never read from the\n * request params. Relayed verbatim in `getDesired`; the host does not\n * interpret it.\n */\n readonly origin?: Record<string, unknown>;\n}\n\n/** A parked, undecided request — the host's view of one desired entry. */\nexport type PendingManifestEntry =\n | (PendingBase & {\n readonly kind: 'direct';\n /** Verbatim requested authority; permissions may carry a `callIntent`. */\n readonly permissions: readonly AccessDirectPermission[];\n })\n | (PendingBase & {\n readonly kind: 'discover';\n /** The interfaces the chosen service must implement (unresolved). */\n readonly interfaces: readonly ManifestInterfaceReq[];\n /** The members the consumer intends to call. */\n readonly members: readonly ManifestMemberReq[];\n });\n\n/**\n * The approver's decision for one parked entry, delivered via `setCurrent`.\n * A `discover` grant additionally names the chosen service (`resolvedSlot`).\n */\nexport type ManifestEntryDecision =\n | { readonly grant: false; readonly reason?: string; }\n | {\n readonly grant: true;\n readonly capabilities: readonly SignedCapability[];\n /** Present for a `discover` grant: which service the approver picked. */\n readonly resolvedSlot?: { readonly serviceId: string; readonly satisfiedInterfaces: readonly string[]; };\n };\n\ninterface InternalEntry {\n readonly entry: PendingManifestEntry;\n readonly resolve: (decision: ManifestEntryDecision) => void;\n}\n\n/** Distributive `Omit` — preserves each union member (unlike the built-in `Omit`). */\ntype DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;\n\nexport interface HubAccessManifestHostOptions {\n /**\n * Root issuer principals the hub's forwarded-call gate accepts. Published as\n * each desired entry's `acceptableRootIds`, so an approver only acts on\n * entries it can satisfy (it is — or chains to — one of these). Omit/empty to\n * leave the roots unspecified (approver decides).\n */\n readonly acceptableRootIds?: readonly string[];\n /** Human log sink for incoming requests. Defaults to stderr. */\n readonly log?: (line: string) => void;\n}\n\nexport class HubAccessManifestHost {\n private readonly _pending = new Map<string, InternalEntry>();\n private readonly _listeners = new Set<() => void>();\n private readonly _acceptableRootIds: readonly string[];\n private readonly _log: (line: string) => void;\n private _revision = 0;\n\n constructor(options: HubAccessManifestHostOptions = {}) {\n this._acceptableRootIds = options.acceptableRootIds ?? [];\n this._log = options.log ?? ((line: string) => process.stderr.write(line + '\\n'));\n }\n\n // ---- hubAccess in: registered DIRECTLY at the overlay root ------------\n\n /**\n * Register `hubAccess::{request,extend,requestAccess}` directly at a\n * participant's overlay root (root form, never forwarded → never gated).\n * Unlike `registerHubAccessService` this consults **no** hub-side directory:\n * `request` forwards raw slots as `discover` entries for the approver to\n * resolve.\n *\n * `options.origin` is a host-authored provenance bag bound to THIS\n * connection and stamped onto every entry parked here. It is bound\n * server-side (not read from the consumer's request params) so a consumer\n * cannot spoof another transport's origin. The host relays it verbatim; it\n * does not interpret it.\n */\n public registerHubAccessAtRoot(\n connection: LinkRpcConnection<unknown>,\n options?: { readonly origin?: Record<string, unknown>; },\n ): void {\n const origin = options?.origin;\n connection.register(hubAccessInterface, {\n request: async (params, _ctx, stream) => {\n const consumerPrincipalId = params.consumer.principal;\n const consumer = plainConsumer(params.consumer);\n const slotIds = Object.keys(params.dependencies);\n if (slotIds.length === 0) {\n return { status: 'denied', reason: 'no slots requested' };\n }\n this._log(\n `hubAccess::request \"${consumer.name}\" (node=${consumerPrincipalId}) `\n + `slots=[${slotIds.join(', ')}]${params.duration ? ` for '${params.duration}'` : ''}`,\n );\n const results = await Promise.all(slotIds.map((slotId) => {\n const slot = params.dependencies[slotId]!;\n return this._park({\n kind: 'discover',\n consumer,\n consumerPrincipalId,\n duration: params.duration,\n interfaces: slot.interfaces,\n members: slot.members ?? [],\n origin,\n }, stream.signal);\n }));\n\n const denied = results.find((r) => !r.grant);\n if (denied && !denied.grant) {\n return denied.reason !== undefined\n ? { status: 'denied', reason: denied.reason }\n : { status: 'denied' };\n }\n const slots: Record<string, { serviceId: string; satisfiedInterfaces: string[]; }> = {};\n const capabilities: SignedCapability[] = [];\n slotIds.forEach((slotId, i) => {\n const r = results[i]!;\n if (!r.grant) return; // unreachable (denied handled above)\n if (r.resolvedSlot) {\n slots[slotId] = {\n serviceId: r.resolvedSlot.serviceId,\n satisfiedInterfaces: [...r.resolvedSlot.satisfiedInterfaces],\n };\n }\n capabilities.push(...r.capabilities);\n });\n return { status: 'granted', slots, capabilities };\n },\n\n extend: async (params, _ctx, stream) => {\n const consumerPrincipalId = params.consumer.principal;\n const permissions = extendPermissions(params.serviceId, params.added);\n this._log(\n `hubAccess::extend \"${params.consumer.name}\" (node=${consumerPrincipalId}) `\n + `service=${params.serviceId}`,\n );\n const decision = await this._park({\n kind: 'direct',\n consumer: plainConsumer(params.consumer),\n consumerPrincipalId,\n duration: params.duration,\n permissions,\n origin,\n }, stream.signal);\n if (!decision.grant) {\n return decision.reason !== undefined\n ? { status: 'denied', reason: decision.reason }\n : { status: 'denied' };\n }\n return {\n status: 'granted',\n serviceId: params.serviceId,\n granted: params.added.map((a) => ({ interfaceId: a.interfaceId, member: a.member })),\n capabilities: [...decision.capabilities],\n };\n },\n\n requestAccess: async (params, _ctx, stream) => {\n const consumerPrincipalId = params.consumer.principal;\n const permissions = params.permissions as AccessDirectPermission[];\n if (permissions.length === 0) {\n return { status: 'denied', reason: 'no permissions requested' };\n }\n this._log(\n `hubAccess::requestAccess \"${params.consumer.name}\" (node=${consumerPrincipalId}) `\n + `[${describePermissions(permissions).join(', ')}]`\n + `${params.duration ? ` for '${params.duration}'` : ''}`,\n );\n const decision = await this._park({\n kind: 'direct',\n consumer: plainConsumer(params.consumer),\n consumerPrincipalId,\n duration: params.duration,\n permissions,\n origin,\n }, stream.signal);\n if (!decision.grant) {\n return decision.reason !== undefined\n ? { status: 'denied', reason: decision.reason }\n : { status: 'denied' };\n }\n return { status: 'granted', capabilities: [...decision.capabilities] };\n },\n });\n }\n\n /** Park a desired entry and await the approver's decision (via `setCurrent`). */\n private _park(\n entry: DistributiveOmit<PendingManifestEntry, 'requestId'>,\n signal?: AbortSignal,\n ): Promise<ManifestEntryDecision> {\n signal?.throwIfAborted();\n return new Promise<ManifestEntryDecision>((resolve, reject) => {\n const requestId = randomUUID();\n const full = { ...entry, requestId } as PendingManifestEntry;\n let done = false;\n const settle = (decision: ManifestEntryDecision) => {\n if (done) return;\n done = true;\n signal?.removeEventListener('abort', abort);\n this._pending.delete(requestId);\n this._bump();\n resolve(decision);\n };\n const abort = () => {\n if (done) return;\n done = true;\n this._pending.delete(requestId);\n this._bump();\n reject(signal?.reason ?? new Error('hubAccess request cancelled'));\n };\n this._pending.set(requestId, { entry: full, resolve: settle });\n this._bump();\n signal?.addEventListener('abort', abort, { once: true });\n if (signal?.aborted) abort();\n });\n }\n\n // ---- manifest out: the served desired/current state -------------------\n\n /** Snapshot of the desired document (entryId → desired entry) + revision. */\n public getDesired(): { entries: PendingManifestEntry[]; acceptableRootIds: readonly string[]; revision: number; } {\n return {\n entries: [...this._pending.values()].map((e) => e.entry),\n acceptableRootIds: this._acceptableRootIds,\n revision: this._revision,\n };\n }\n\n /**\n * Resolve a parked entry from a `setCurrent` decision. Returns `false` when\n * no entry with that id is pending (already decided / cancelled).\n */\n public resolve(requestId: string, decision: ManifestEntryDecision): boolean {\n const found = this._pending.get(requestId);\n if (!found) return false;\n found.resolve(decision);\n return true;\n }\n\n /** Subscribe to coarse \"desired set may have changed\" notifications. */\n public onDidChange(listener: () => void): () => void {\n this._listeners.add(listener);\n return () => this._listeners.delete(listener);\n }\n\n private _bump(): void {\n this._revision += 1;\n for (const l of [...this._listeners]) {\n l();\n }\n }\n}\n\ntype ManifestDuration = 'once' | 'shortLived' | 'longLived' | 'persistent';\n\nfunction plainConsumer(c: { name: string; origin?: string; purpose?: string; }): { name: string; origin?: string; purpose?: string; } {\n return {\n name: c.name,\n ...(c.origin !== undefined ? { origin: c.origin } : {}),\n ...(c.purpose !== undefined ? { purpose: c.purpose } : {}),\n };\n}\n\n/** Group extend `added` members by interface into permissions scoped to `serviceId`. */\nfunction extendPermissions(\n serviceId: string,\n added: readonly { interfaceId: string; member: Pattern; }[],\n): AccessDirectPermission[] {\n const byIface = new Map<string, Pattern[]>();\n for (const a of added) {\n const members = byIface.get(a.interfaceId) ?? [];\n members.push(a.member);\n byIface.set(a.interfaceId, members);\n }\n return [...byIface.entries()].map(([interfaceId, members]) => ({\n target: { serviceId: { exact: serviceId }, interfaceId: { exact: interfaceId }, members },\n canInvoke: true,\n }));\n}\n\n/**\n * Serve `hubAccessManifest::*` on `connection`, mounted under `serviceId` (the\n * hub's own service prefix). Reachable only through the forwarded-call gate, so\n * authorization (an accepted-root capability) is enforced upstream — no gate is\n * applied here.\n *\n * `getCurrent`/`watchCurrent` are vestigial for the hub broker: granted caps are\n * delivered as the blocked `hubAccess` call's result, not read back through\n * `current`. They are served (empty) to satisfy the interface.\n */\nexport function registerHubAccessManifest(\n connection: LinkRpcConnection<unknown>,\n host: HubAccessManifestHost,\n options: { readonly serviceId: string; },\n): void {\n connection.register(hubAccessManifestInterface, {\n getDesired: () => {\n const { entries, acceptableRootIds, revision } = host.getDesired();\n const requested: Record<string, ManifestRequestWire> = {};\n const roots = acceptableRootIds.length > 0 ? [...acceptableRootIds] : undefined;\n for (const e of entries) {\n const consumer = { ...e.consumer, principal: e.consumerPrincipalId };\n const duration = e.duration as ManifestDuration | undefined;\n const originFields = e.origin !== undefined ? { origin: e.origin } : {};\n if (e.kind === 'direct') {\n requested[e.requestId] = {\n kind: 'direct',\n consumer,\n permissions: e.permissions as Permission[],\n ...(duration !== undefined ? { duration } : {}),\n ...(roots !== undefined ? { acceptableRootIds: roots } : {}),\n ...originFields,\n };\n } else {\n requested[e.requestId] = {\n kind: 'discover',\n consumer,\n interfaces: e.interfaces.map((i) => ({ id: i.id, ...(i.hash !== undefined ? { hash: i.hash } : {}), ...(i.required !== undefined ? { required: i.required } : {}) })),\n members: e.members.map((m) => ({ interfaceId: m.interfaceId, member: m.member, ...(m.required !== undefined ? { required: m.required } : {}) })),\n ...(duration !== undefined ? { duration } : {}),\n ...(roots !== undefined ? { acceptableRootIds: roots } : {}),\n ...originFields,\n };\n }\n }\n return { requested, revision };\n },\n\n watchDesired: (_params, _ctx, stream) =>\n new Promise<Record<string, never>>((resolve) => {\n if (stream.signal.aborted) {\n resolve({});\n return;\n }\n const unsubscribe = host.onDidChange(() => {\n if (stream.signal.aborted) return;\n stream.send({});\n });\n stream.signal.addEventListener(\n 'abort',\n () => {\n unsubscribe();\n resolve({});\n },\n { once: true },\n );\n }),\n\n getCurrent: () => ({ current: {}, revision: 0 }),\n\n setCurrent: (params) => {\n const unknown: string[] = [];\n for (const patch of params.patches) {\n if (patch.op !== 'set') continue;\n for (const [requestId, value] of currentEntriesOfPatch(patch.path, patch.value)) {\n if (!host.resolve(requestId, currentEntryToDecision(value))) unknown.push(requestId);\n }\n }\n if (unknown.length > 0) {\n throw new Error(`manifest entries are no longer pending: ${unknown.join(', ')}`);\n }\n return { revision: 0 };\n },\n\n watchCurrent: (_params, _ctx, stream) =>\n new Promise<Record<string, never>>((resolve) => {\n stream.signal.addEventListener('abort', () => resolve({}), { once: true });\n }),\n }, { serviceId: options.serviceId });\n}\n\ninterface ManifestConsumerWire { name: string; principal: string; origin?: string; purpose?: string; }\ntype ManifestRequestWire =\n | {\n kind: 'direct';\n consumer: ManifestConsumerWire;\n permissions: Permission[];\n duration?: ManifestDuration;\n acceptableRootIds?: string[];\n origin?: Record<string, unknown>;\n }\n | {\n kind: 'discover';\n consumer: ManifestConsumerWire;\n interfaces: { id: string; hash?: string; required?: boolean; }[];\n members: { interfaceId: string; member: Pattern; required?: boolean; }[];\n duration?: ManifestDuration;\n acceptableRootIds?: string[];\n origin?: Record<string, unknown>;\n };\n\n/** A `zCurrentEntry` wire value. */\ntype CurrentEntryValue =\n | {\n status: 'granted';\n granted:\n | { kind: 'direct'; capabilities: SignedCapability[]; }\n | { kind: 'discover'; serviceId: string; satisfiedInterfaces: string[]; capabilities: SignedCapability[]; };\n }\n | { status: 'denied'; reason?: string; };\n\nfunction currentEntryToDecision(value: CurrentEntryValue): ManifestEntryDecision {\n if (value.status !== 'granted') {\n return value.reason !== undefined ? { grant: false, reason: value.reason } : { grant: false };\n }\n if (value.granted.kind === 'discover') {\n return {\n grant: true,\n capabilities: value.granted.capabilities,\n resolvedSlot: { serviceId: value.granted.serviceId, satisfiedInterfaces: value.granted.satisfiedInterfaces },\n };\n }\n return { grant: true, capabilities: value.granted.capabilities };\n}\n\n/**\n * Yield `[entryId, currentEntry]` pairs a `setCurrent` patch targets. Supports\n * whole-document (`''` → `{ current: {...} }`), the `current` map\n * (`/current` → `{...}`), and a single entry (`/current/<id>`).\n */\nfunction* currentEntriesOfPatch(path: string, value: unknown): Iterable<[string, CurrentEntryValue]> {\n const segments = path === '' ? [] : path.split('/').slice(1).map(unescapePointer);\n if (segments.length === 0) {\n const current = (value as { current?: Record<string, CurrentEntryValue>; }).current ?? {};\n yield* Object.entries(current);\n return;\n }\n if (segments[0] !== 'current') return;\n if (segments.length === 1) {\n yield* Object.entries((value as Record<string, CurrentEntryValue>) ?? {});\n return;\n }\n if (segments.length === 2) {\n yield [segments[1], value as CurrentEntryValue];\n }\n}\n\nfunction unescapePointer(segment: string): string {\n return segment.replace(/~1/g, '/').replace(/~0/g, '~');\n}\n","import type {\n HubAccessManifestDecision,\n HubAccessManifestRequest,\n IHubAccessManifest,\n} from '@hediet/linkrpc/hub/common';\nimport { DEFAULT_RPC_TIMEOUT_MS, withRpcTimeout } from '@hediet/linkrpc';\nimport {\n observableValue,\n type IObservable,\n type ISettableObservable,\n} from '@vscode/observables';\n\nexport interface CapRequest {\n readonly id: string;\n readonly request: HubAccessManifestRequest;\n readonly revision: number;\n}\n\nexport type ApproveClientState = 'connecting' | 'live' | 'stale';\n\nexport interface ApproveClientOptions {\n readonly manifest: IHubAccessManifest;\n /** Only expose requests this root can satisfy. Omit to expose every request. */\n readonly ownPrincipalId?: string;\n readonly log?: (line: string) => void;\n readonly reconnectDelayMs?: number;\n readonly timeoutMs?: number;\n}\n\n/**\n * Authoritative, typed frontend for a `hubAccessManifest`.\n *\n * Consumers render {@link requests}; coarse watch ticks are reconciled through\n * one serialized full-snapshot loop, so older reads cannot overwrite newer\n * state. A completed watch is re-opened and a failed read keeps the last known\n * snapshot while {@link state} reports `stale`.\n */\nexport class ApproveClient {\n private readonly _requests: ISettableObservable<readonly CapRequest[]>;\n public readonly requests: IObservable<readonly CapRequest[]>;\n private readonly _state: ISettableObservable<ApproveClientState>;\n public readonly state: IObservable<ApproveClientState>;\n\n private readonly _manifest: IHubAccessManifest;\n private readonly _ownPrincipalId: string | undefined;\n private readonly _log: (line: string) => void;\n private readonly _reconnectDelayMs: number;\n private readonly _timeoutMs: number;\n private _watch: ReturnType<IHubAccessManifest['watchDesired']> | undefined;\n private _watchGeneration = 0;\n private _retryTimer: ReturnType<typeof setTimeout> | undefined;\n private _refreshPending = false;\n private _refreshPromise: Promise<void> | undefined;\n private _disposed = false;\n\n constructor(options: ApproveClientOptions) {\n this._manifest = options.manifest;\n this._ownPrincipalId = options.ownPrincipalId;\n this._log = options.log ?? (() => { /* no-op */ });\n this._reconnectDelayMs = options.reconnectDelayMs ?? 250;\n this._timeoutMs = options.timeoutMs ?? DEFAULT_RPC_TIMEOUT_MS;\n this._requests = observableValue(this, []);\n this.requests = this._requests;\n this._state = observableValue(this, 'connecting');\n this.state = this._state;\n\n // Subscribe before the first snapshot so a change during getDesired\n // schedules another pass instead of being lost.\n this._openWatch();\n void this.refresh();\n }\n\n /** Reconcile the observable with the latest complete desired snapshot. */\n public refresh(): Promise<void> {\n if (this._disposed) return Promise.resolve();\n this._refreshPending = true;\n if (!this._refreshPromise) {\n this._refreshPromise = this._drainRefreshes().finally(() => {\n this._refreshPromise = undefined;\n });\n }\n const active = this._refreshPromise;\n return active.then(() => {\n if (this._refreshPending && !this._disposed) return this.refresh();\n });\n }\n\n /**\n * Write a decision only for a request in the current snapshot, then reconcile\n * with the next authoritative snapshot. A successful write can still leave a\n * matching id pending when a federated snapshot lags or the consumer retries;\n * callers receive `still-pending` so they can report that state honestly.\n */\n public async decide(\n id: string,\n decision: HubAccessManifestDecision,\n ): Promise<'applied' | 'gone' | 'still-pending'> {\n if (!this._requests.get().some((request) => request.id === id)) return 'gone';\n await withRpcTimeout(this._manifest.setCurrent({\n patches: [{\n op: 'set',\n path: `/current/${escapePointer(id)}`,\n value: decision,\n }],\n }), 'hubAccessManifest::setCurrent', this._timeoutMs);\n await this.refresh();\n if (this._requests.get().some((request) => request.id === id)) {\n this._log(\n `hubAccess approver: decision accepted for '${safeId(id)}', `\n + 'but a matching request is still pending',\n );\n return 'still-pending';\n }\n return 'applied';\n }\n\n public dispose(): void {\n if (this._disposed) return;\n this._disposed = true;\n this._watchGeneration++;\n if (this._retryTimer !== undefined) {\n clearTimeout(this._retryTimer);\n this._retryTimer = undefined;\n }\n const watch = this._watch;\n this._watch = undefined;\n if (watch) void watch.cancel('approve client disposed').catch(() => { /* closing */ });\n }\n\n private async _drainRefreshes(): Promise<void> {\n while (this._refreshPending && !this._disposed) {\n this._refreshPending = false;\n try {\n const snapshot = await withRpcTimeout(\n this._manifest.getDesired({}),\n 'hubAccessManifest::getDesired',\n this._timeoutMs,\n );\n if (this._disposed) return;\n const requests = Object.entries(snapshot.requested)\n .filter(([, request]) => rootAccepted(request.acceptableRootIds, this._ownPrincipalId))\n .map(([id, request]) => ({ id, request, revision: snapshot.revision }));\n this._requests.set(requests, undefined);\n this._state.set('live', undefined);\n } catch (error) {\n if (this._disposed) return;\n this._state.set('stale', undefined);\n this._log(`hubAccess approver: getDesired failed: ${errorMessage(error)}`);\n this._scheduleReconnect();\n }\n }\n }\n\n private _openWatch(): void {\n if (this._disposed || this._watch !== undefined) return;\n const generation = ++this._watchGeneration;\n try {\n const watch = this._manifest.watchDesired({}, {\n onMessage: () => { void this.refresh(); },\n });\n this._watch = watch;\n watch.then(\n () => this._watchEnded(generation, undefined),\n (error: unknown) => this._watchEnded(generation, error),\n );\n } catch (error) {\n this._log(`hubAccess approver: watchDesired failed: ${errorMessage(error)}`);\n this._scheduleReconnect();\n }\n }\n\n private _watchEnded(generation: number, error: unknown): void {\n if (this._disposed || generation !== this._watchGeneration) return;\n this._watch = undefined;\n this._state.set('stale', undefined);\n if (error !== undefined) {\n this._log(`hubAccess approver: watchDesired ended: ${errorMessage(error)}`);\n }\n this._scheduleReconnect();\n }\n\n private _scheduleReconnect(): void {\n if (this._disposed || this._retryTimer !== undefined) return;\n this._retryTimer = setTimeout(() => {\n this._retryTimer = undefined;\n this._openWatch();\n void this.refresh();\n }, this._reconnectDelayMs);\n }\n}\n\nfunction rootAccepted(\n acceptableRootIds: readonly string[] | undefined,\n ownPrincipalId: string | undefined,\n): boolean {\n if (acceptableRootIds === undefined) return true;\n if (acceptableRootIds.length === 0 || ownPrincipalId === undefined) return false;\n return acceptableRootIds.includes(ownPrincipalId);\n}\n\nfunction escapePointer(segment: string): string {\n return segment.replace(/~/g, '~0').replace(/\\//g, '~1');\n}\n\nfunction safeId(id: string): string {\n return id.replace(/\\u0000/g, '\\\\0');\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n","/**\n * `runManifestApprover` — a connection-based consumer of `hubAccessManifest`.\n *\n * This is the approver side of the consent surface, factored out of the hub: it\n * reaches a manifest **only over an {@link LinkRpcConnection}** (`hubAccessManifest::\n * {getDesired,watchDesired,setCurrent}`), never by touching the in-process\n * {@link HubAccessManifestHost}. That indirection is deliberate — the exact same\n * approver runs against a *remote* hub's (or a participant's) manifest with no\n * code change. The hub stays keyless park-and-relay; the approver owns the UI,\n * the signing identity **and** (for `discover` entries) the candidate\n * resolution.\n *\n * Per desired entry it: skips entries whose `acceptableRootIds` it cannot\n * satisfy; for a `discover` entry resolves candidates against the directory\n * (fetched over its own connection) and picks a service; prompts the operator\n * (default: terminal y/N); mints a capability with its own\n * {@link CapabilityProposalIssuer} (honoring \"Allow once\" `callIntent`\n * byte-binding); and writes the decision back via `setCurrent`. Prompts run\n * serially. If an entry disappears from `getDesired` while its prompt is open\n * (decided elsewhere / consumer cancelled) the prompt is aborted.\n */\nimport {\n type SignedCapability,\n} from '@hediet/linkrpc';\nimport {\n type HubAccessManifestDecision,\n type HubAccessManifestRequest,\n type IHubAccessManifest,\n} from '@hediet/linkrpc/hub/common';\nimport { autorun } from '@vscode/observables';\nimport {\n type AccessDurationName,\n type AccessSlotRequest,\n type CapabilityProposalIssuer,\n candidatesForSlot,\n type DirectoryEntry,\n durationToExp,\n} from '../hub/server';\nimport { buildSlotPermissions } from './hubAccessConfig';\nimport {\n type ConsentPrompt,\n createTerminalConsentPrompt,\n describePermissions,\n toSignedPermissions,\n} from './consent';\nimport type { AccessDirectPermission } from '../hub/server';\nimport { ApproveClient } from './approveClient';\n\nexport interface ManifestApproverOptions {\n /**\n * The manifest to consume. Just the typed client of\n * {@link hubAccessManifestInterface} — obtained over any connection\n * (`connection.service(id).get(hubAccessManifestInterface)`), in-memory or\n * remote. The approver never touches a raw connection for the manifest\n * surface.\n */\n readonly manifest: IHubAccessManifest;\n /**\n * Resolve `discover` entries against the participant directory. Supplied by\n * the caller because directory access needs the approver's own signed\n * connection (the approver holds the key). Omit if this approver never\n * expects `discover` entries — such entries are then denied.\n */\n readonly fetchDirectory?: () => Promise<readonly DirectoryEntry[]>;\n /** Mints the approver's own capabilities (audience = the entry's consumer). */\n readonly issuer: CapabilityProposalIssuer;\n /**\n * This approver's own root principal. An entry is acted on only if its\n * `acceptableRootIds` is absent or includes this id —\n * otherwise the approver's signature would be useless to the consumer.\n * Defaults to the issuer's principal.\n */\n readonly ownPrincipalId?: string;\n /** Decision source. Defaults to a terminal y/N prompt on stdin. */\n readonly prompt?: ConsentPrompt;\n /** Human log sink. Defaults to stderr. */\n readonly log?: (line: string) => void;\n}\n\nexport interface ManifestApprover {\n /** Stop watching and abort any in-flight prompt. */\n dispose(): void;\n}\n\n/** What the approver resolves an entry to before prompting: perms + optional chosen service. */\ninterface ResolvedEntry {\n readonly permissions: readonly AccessDirectPermission[];\n /** Present for `discover`: the service the approver picked + its satisfied interfaces. */\n readonly resolvedSlot?: { readonly serviceId: string; readonly satisfiedInterfaces: readonly string[]; };\n}\n\n/**\n * Start consuming the manifest at `options.serviceId` over `options.connection`.\n * Runs until {@link ManifestApprover.dispose}.\n */\nexport function runManifestApprover(options: ManifestApproverOptions): ManifestApprover {\n const prompt = options.prompt ?? createTerminalConsentPrompt();\n const rawLog = options.log ?? ((line: string) => process.stderr.write(line + '\\n'));\n const log = (line: string): void => { try { rawLog(line); } catch { /* ignore */ } };\n const ownPrincipalId = options.ownPrincipalId ?? options.issuer.issuerPrincipalId;\n /** entryIds currently being prompted, with their abort handle. */\n const inFlight = new Map<string, AbortController>();\n let disposed = false;\n let tail: Promise<void> = Promise.resolve();\n const client = new ApproveClient({\n manifest: options.manifest,\n ownPrincipalId,\n log,\n });\n\n /** Resolve an entry to permissions (+ chosen service for discover). */\n const resolveEntry = async (entry: HubAccessManifestRequest): Promise<ResolvedEntry | { denied: string }> => {\n if (entry.kind === 'direct') {\n return { permissions: entry.permissions };\n }\n // discover: pick a candidate service from the directory.\n if (options.fetchDirectory === undefined) {\n return { denied: 'no directory available to resolve discover candidates' };\n }\n const directory = await options.fetchDirectory();\n const slot: AccessSlotRequest = {\n interfaces: entry.interfaces.map((i) => ({ id: i.id, required: i.required !== false, ...(i.hash !== undefined ? { hash: i.hash } : {}) })),\n members: entry.members.map((m) => ({ interfaceId: m.interfaceId, member: m.member, required: m.required !== false })),\n };\n const candidate = candidatesForSlot(slot, directory as DirectoryEntry[])[0];\n if (!candidate) {\n return { denied: 'no candidate service satisfies the requested interfaces' };\n }\n const present = new Set(candidate.satisfiedInterfaces.map((i) => i.id));\n const permissions = buildSlotPermissions(candidate.serviceId, slot.interfaces, slot.members, present) as AccessDirectPermission[];\n return {\n permissions,\n resolvedSlot: {\n serviceId: candidate.serviceId,\n satisfiedInterfaces: candidate.satisfiedInterfaces.map((i) => i.id),\n },\n };\n };\n\n const mint = async (\n consumerPrincipalId: string,\n permissions: readonly AccessDirectPermission[],\n duration: string | undefined,\n ): Promise<SignedCapability> => {\n const signed = await toSignedPermissions(permissions, consumerPrincipalId, duration);\n return options.issuer.mint({\n audience: consumerPrincipalId,\n permissions: signed,\n expiresAtMs: durationToExp(duration as AccessDurationName | undefined),\n });\n };\n\n const processEntry = (\n entryId: string,\n entry: HubAccessManifestRequest,\n ac: AbortController,\n ) => async (): Promise<void> => {\n if (ac.signal.aborted) {\n inFlight.delete(entryId);\n return;\n }\n try {\n const resolved = await resolveEntry(entry);\n if ('denied' in resolved) {\n await client.decide(entryId, { status: 'denied', reason: resolved.denied });\n return;\n }\n if (ac.signal.aborted) return;\n\n const decision = await prompt({\n requestId: entryId,\n kind: entry.kind === 'discover' ? 'request' : 'requestAccess',\n consumer: entry.consumer,\n consumerPrincipalId: entry.consumer.principal,\n permissions: resolved.permissions,\n grants: describePermissions(resolved.permissions),\n duration: entry.duration,\n signal: ac.signal,\n });\n if (ac.signal.aborted) return;\n\n if (!decision.grant) {\n await client.decide(entryId, decision.reason !== undefined\n ? { status: 'denied', reason: decision.reason }\n : { status: 'denied' });\n return;\n }\n\n const capabilities = decision.capabilities !== undefined && decision.capabilities.length > 0\n ? [...decision.capabilities]\n : [await mint(entry.consumer.principal, resolved.permissions, entry.duration)];\n\n const granted = resolved.resolvedSlot !== undefined\n ? {\n kind: 'discover' as const,\n serviceId: resolved.resolvedSlot.serviceId,\n satisfiedInterfaces: [...resolved.resolvedSlot.satisfiedInterfaces],\n capabilities,\n }\n : { kind: 'direct' as const, capabilities };\n await client.decide(entryId, { status: 'granted', granted } satisfies HubAccessManifestDecision);\n } catch (e) {\n log(`hubAccess approver: failed to decide ${entryId}: ${(e as Error).message}`);\n } finally {\n inFlight.delete(entryId);\n }\n };\n\n const subscription = autorun((reader) => {\n const requests = client.requests.read(reader);\n const present = new Set(requests.map((entry) => entry.id));\n // Abort prompts whose entry is gone (decided elsewhere / consumer left).\n for (const [entryId, ac] of inFlight) {\n if (!present.has(entryId)) ac.abort();\n }\n for (const { id: entryId, request: entry } of requests) {\n if (inFlight.has(entryId)) continue;\n const ac = new AbortController();\n inFlight.set(entryId, ac);\n // Serialize so only one terminal prompt is open at a time.\n tail = tail.then(processEntry(entryId, entry, ac));\n }\n });\n\n return {\n dispose: () => {\n if (disposed) return;\n disposed = true;\n for (const ac of inFlight.values()) ac.abort();\n subscription.dispose();\n client.dispose();\n },\n };\n}\n","/**\n * Helpers for `cmd-env` / `cmd-stdio` endpoints: a human-readable label for\n * log prefixing, line-prefixed piping of a child's console output, and\n * optional stdin forwarding for `--cmd-interactive`.\n */\nimport type { ChildProcess } from 'node:child_process';\nimport * as path from 'node:path';\nimport type { EndpointConfig } from '../config';\nimport type { EndpointCommand } from '@hediet/linkrpc/node';\n\n/**\n * Short label for a transport, used to prefix its console log lines.\n * Preference order: an explicit name (the `namedEndpoints` key) → the command\n * basename (`cmd` / `argv[0]`) → the URI host / socket basename → the kind.\n */\nexport function endpointLabel(ep: EndpointConfig, nameKey?: string): string {\n if (nameKey !== undefined && nameKey.length > 0) return nameKey;\n switch (ep.kind) {\n case 'cmd-env':\n case 'cmd-stdio': {\n const first = ep.cmd ?? ep.argv?.[0];\n if (first) return path.basename(first.split(/\\s+/)[0] ?? first);\n return ep.kind;\n }\n\n case 'uri':\n return _hostish(ep.uri);\n case 'ws':\n return _hostish(ep.url);\n case 'socket':\n return path.basename(ep.path) || 'socket';\n }\n}\n\nexport function endpointCommand(\n ep: Extract<EndpointConfig, { kind: 'cmd-env' | 'cmd-stdio'; }>,\n): EndpointCommand {\n if (ep.argv !== undefined && ep.argv.length > 0) return { argv: ep.argv };\n if (ep.cmd !== undefined) return { command: ep.cmd };\n throw new Error('cmd endpoint requires either `cmd` or `argv`');\n}\n\nexport function killChild(child: ChildProcess): void {\n if (!child.killed) child.kill();\n}\n\nfunction _hostish(uri: string): string {\n try {\n return new URL(uri).host || uri;\n } catch {\n return uri;\n }\n}\n\n/**\n * Pipe a child's stdout/stderr to `log`, one prefixed line at a time. Pass\n * `includeStdout: false` for `cmd-stdio`, whose stdout carries the RPC stream\n * (only stderr is human output there).\n */\nexport function pipeChildLogs(\n child: ChildProcess,\n label: string,\n log: (line: string) => void,\n opts: { includeStdout: boolean },\n): void {\n const emit = (chunk: string): void => {\n for (const line of chunk.split(/\\r?\\n/)) {\n if (line.length > 0) log(`[${label}] ${line}`);\n }\n };\n if (opts.includeStdout && child.stdout) {\n child.stdout.setEncoding('utf8');\n child.stdout.on('data', emit);\n }\n if (child.stderr) {\n child.stderr.setEncoding('utf8');\n child.stderr.on('data', emit);\n }\n}\n\n/**\n * Forward this process's stdin to a child's stdin (for `--cmd-interactive`).\n * Returns a teardown that detaches the listener and restores the tty.\n */\nexport function forwardStdin(child: ChildProcess): () => void {\n const stdin = process.stdin;\n if (!child.stdin) return () => { };\n const onData = (chunk: Buffer | string): void => {\n child.stdin?.write(chunk);\n };\n stdin.resume();\n stdin.on('data', onData);\n return () => {\n stdin.off('data', onData);\n stdin.pause();\n };\n}\n","/**\n * Static overlap guard for {@link module:./runHub}. The hub's forwarding table\n * silently overwrites a duplicate prefix; this catches a misconfigured hub at\n * startup instead — two transports claiming the same service id, or two\n * default routes — with a message naming both owners.\n *\n * Only *statically configured* routes are tracked here. Service ids that peers\n * claim dynamically through a listener are authorized by the hub's claim\n * policy, not this table.\n */\nexport class RouteTable {\n private readonly _claimed = new Map<string, string>();\n private _defaultOwner: string | undefined;\n\n /** Record that `owner` routes `serviceId`. Throws on a conflicting claim. */\n public claim(serviceId: string, owner: string): void {\n const existing = this._claimed.get(serviceId);\n if (existing !== undefined && existing !== owner) {\n throw new Error(\n `route conflict: service id '${serviceId}' is claimed by both `\n + `'${existing}' and '${owner}'`,\n );\n }\n this._claimed.set(serviceId, owner);\n }\n\n /** Record `owner` as the single default route. Throws on a second one. */\n public setDefault(owner: string): void {\n if (this._defaultOwner !== undefined && this._defaultOwner !== owner) {\n throw new Error(\n `default-route conflict: both '${this._defaultOwner}' and '${owner}' `\n + `set defaultRoute; at most one is allowed`,\n );\n }\n this._defaultOwner = owner;\n }\n}\n","import { type IMessageTransport, type JsonValue } from '@hediet/linkrpc';\nimport { hubGrantedServiceIdInterface } from '@hediet/linkrpc/hub/common';\nimport {\n connectNdjson,\n openWebSocket,\n parseEndpointUri,\n runInitializeHandshake,\n WebSocketTransport,\n} from '@hediet/linkrpc/node';\nimport * as net from 'node:net';\nimport type { ParticipantConnectorConfig } from '../config';\nimport { spawnCommand } from '../spawn';\nimport { endpointCommand, forwardStdin, killChild, pipeChildLogs } from './cmdEndpoint';\nimport { RouteTable } from './routeTable';\n\nconst REGISTER_METHOD = `${hubGrantedServiceIdInterface.info.id}::register`;\nconst INITIAL_BACKOFF_MS = 200;\nconst MAX_BACKOFF_MS = 5_000;\n\nexport interface ConfiguredParticipant {\n readonly name: string;\n readonly config: ParticipantConnectorConfig;\n}\n\nexport interface ConfigureParticipantsOptions {\n readonly participants: readonly ConfiguredParticipant[];\n /**\n * Attach a connected transport at the host's trust boundary. Standalone\n * hubs attach directly; embedded hosts can insert their capability gate.\n */\n readonly attachParticipant: (\n transport: IMessageTransport,\n ) => ConfiguredParticipantAttachment;\n readonly log?: (line: string) => void;\n /** Forward stdin to the single cmd-stdio participant. */\n readonly cmdInteractive?: boolean;\n}\n\nexport interface ConfiguredParticipants {\n dispose(): void;\n}\n\nexport interface ConfiguredParticipantAttachment {\n claimPrefix(prefix: string): void;\n setDefaultRoute(): void;\n request(method: string, params: JsonValue, timeoutMs?: number): Promise<JsonValue | undefined>;\n dispose(): void;\n}\n\n/**\n * Attach settings/config-defined outbound participants to an existing Hub.\n *\n * Each participant is supervised independently: it connects in the background,\n * claims its configured service ids on the far end, installs its local routes,\n * and reconnects with exponential backoff after a disconnect.\n */\nexport function configureParticipants(\n options: ConfigureParticipantsOptions,\n): ConfiguredParticipants {\n const log = options.log ?? ((line: string) => process.stderr.write(line + '\\n'));\n const disposers: Array<() => void> = [];\n const interactiveCommands = options.participants.filter(\n participant => participant.config.kind === 'cmd-stdio',\n ).length;\n if (options.cmdInteractive && interactiveCommands !== 1) {\n throw new Error(\n `cmdInteractive requires exactly one cmd-stdio participant, found ${interactiveCommands}`,\n );\n }\n\n validateConfiguredParticipants(options.participants);\n for (const participant of options.participants) {\n disposers.push(_startParticipant(\n participant,\n options.attachParticipant,\n log,\n options.cmdInteractive === true,\n ));\n }\n\n let disposed = false;\n return {\n dispose: () => {\n if (disposed) return;\n disposed = true;\n for (const dispose of disposers.reverse()) dispose();\n },\n };\n}\n\nexport function validateConfiguredParticipants(\n participants: readonly ConfiguredParticipant[],\n): void {\n const routes = new RouteTable();\n for (const participant of participants) {\n _validateParticipant(participant, routes);\n }\n}\n\nfunction _validateParticipant(\n participant: ConfiguredParticipant,\n routes: RouteTable,\n): void {\n const { config, name } = participant;\n if (config.connectionTokenBinder !== undefined) {\n throw new Error(\n `participant '${name}': connectionTokenBinder is only supported on cmd-env endpoints`,\n );\n }\n for (const serviceId of config.routeServiceIds) routes.claim(serviceId, name);\n if (config.defaultRoute) routes.setDefault(name);\n}\n\nfunction _startParticipant(\n participant: ConfiguredParticipant,\n attachParticipant: ConfigureParticipantsOptions['attachParticipant'],\n log: (line: string) => void,\n interactive: boolean,\n): () => void {\n const { config, name } = participant;\n const abort = new AbortController();\n let current: ConnectedParticipant | undefined;\n let connectingAttachment: ConfiguredParticipantAttachment | undefined;\n let stopped = false;\n\n const dispose = (): void => {\n if (stopped) return;\n stopped = true;\n abort.abort();\n connectingAttachment?.dispose();\n connectingAttachment = undefined;\n current?.attachment.dispose();\n current?.transport.dispose();\n current = undefined;\n };\n\n void (async () => {\n let backoff = INITIAL_BACKOFF_MS;\n let delayBeforeAttempt = 0;\n let hasConnected = false;\n while (!stopped) {\n if (\n delayBeforeAttempt > 0\n && !await _delayUnlessAborted(delayBeforeAttempt, abort.signal)\n ) {\n return;\n }\n try {\n const connected = await _connectParticipant(\n participant,\n attachParticipant,\n log,\n interactive,\n abort.signal,\n attachment => { connectingAttachment = attachment; },\n );\n if (stopped) {\n connected.attachment.dispose();\n connected.transport.dispose();\n return;\n }\n connectingAttachment = undefined;\n current = connected;\n log(`[${name}] ${hasConnected ? 'reconnected' : 'connected'}`);\n hasConnected = true;\n backoff = INITIAL_BACKOFF_MS;\n\n await connected.closed;\n connected.attachment.dispose();\n connected.transport.dispose();\n if (current === connected) current = undefined;\n if (stopped) return;\n\n delayBeforeAttempt = backoff;\n log(`[${name}] disconnected; reconnecting in ${delayBeforeAttempt} ms`);\n } catch (error) {\n connectingAttachment = undefined;\n if (stopped) return;\n delayBeforeAttempt = backoff;\n log(\n `[${name}] connection failed: ${_errorMessage(error)}; `\n + `retrying in ${delayBeforeAttempt} ms`,\n );\n backoff = Math.min(MAX_BACKOFF_MS, backoff * 2);\n }\n }\n })().catch((error) => {\n if (!stopped) log(`[${name}] reconnect loop failed: ${_errorMessage(error)}`);\n });\n\n return dispose;\n}\n\ninterface ConnectedParticipant {\n readonly transport: IMessageTransport;\n readonly closed: Promise<void>;\n readonly attachment: ConfiguredParticipantAttachment;\n}\n\ninterface OpenParticipant {\n readonly transport: IMessageTransport;\n readonly closed: Promise<void>;\n}\n\nasync function _connectParticipant(\n participant: ConfiguredParticipant,\n attachParticipant: ConfigureParticipantsOptions['attachParticipant'],\n log: (line: string) => void,\n interactive: boolean,\n signal: AbortSignal,\n onAttached: (attachment: ConfiguredParticipantAttachment | undefined) => void,\n): Promise<ConnectedParticipant> {\n const { config, name } = participant;\n const opened = await _openParticipant(config, name, log, interactive);\n if (signal.aborted) {\n opened.transport.dispose();\n throw new Error(`participant '${name}' stopped`);\n }\n const onAbort = () => opened.transport.dispose();\n signal.addEventListener('abort', onAbort, { once: true });\n let attachment: ConfiguredParticipantAttachment | undefined;\n try {\n attachment = attachParticipant(opened.transport);\n onAttached(attachment);\n for (const serviceId of config.claimServiceIds) {\n await _registerOnRemote(attachment, serviceId);\n }\n for (const serviceId of config.routeServiceIds) attachment.claimPrefix(serviceId);\n if (config.defaultRoute) attachment.setDefaultRoute();\n return { ...opened, attachment };\n } catch (error) {\n attachment?.dispose();\n opened.transport.dispose();\n throw new Error(`participant '${name}' registration failed: ${_errorMessage(error)}`, {\n cause: error,\n });\n } finally {\n onAttached(undefined);\n signal.removeEventListener('abort', onAbort);\n }\n}\n\nasync function _openParticipant(\n config: ParticipantConnectorConfig,\n name: string,\n log: (line: string) => void,\n interactive: boolean,\n): Promise<OpenParticipant> {\n switch (config.kind) {\n case 'ws':\n return _openWsTransport(config.url, config.token);\n case 'socket':\n return _openSocketTransport(config.path, config.token);\n case 'uri': {\n const resolved = parseEndpointUri(config.uri);\n if (resolved.kind === 'ws') {\n return _openWsTransport(resolved.url, config.token ?? resolved.token);\n }\n if (resolved.kind === 'socket') {\n return _openSocketTransport(resolved.path, config.token ?? resolved.token);\n }\n throw new Error(\n `participant '${name}': uri resolves to '${resolved.kind}'; `\n + `use kind 'cmd-stdio' instead`,\n );\n }\n case 'cmd-stdio': {\n const closeSignal = _closeSignal();\n const child = spawnCommand(endpointCommand(config), {\n stdio: ['pipe', 'pipe', 'pipe'],\n env: { ...process.env, ...config.env },\n ...(config.cwd !== undefined ? { cwd: config.cwd } : {}),\n });\n child.once('error', closeSignal.close);\n child.once('exit', closeSignal.close);\n if (!child.stdin || !child.stdout) {\n killChild(child);\n throw new Error(`participant '${name}': child exposes no stdio`);\n }\n pipeChildLogs(child, name, log, { includeStdout: false });\n const stopForwarding = interactive ? forwardStdin(child) : () => { };\n const { transport } = await connectNdjson({\n input: child.stdout,\n output: child.stdin,\n onClose: () => {\n stopForwarding();\n killChild(child);\n closeSignal.close();\n },\n });\n return { transport, closed: closeSignal.closed };\n }\n }\n}\n\nasync function _openSocketTransport(\n socketPath: string,\n token: string | undefined,\n): Promise<OpenParticipant> {\n const socket = net.createConnection(socketPath);\n const closeSignal = _closeSignal();\n socket.on('error', () => {\n socket.destroy();\n closeSignal.close();\n });\n try {\n await new Promise<void>((resolve, reject) => {\n const onError = (error: Error) => reject(error);\n socket.once('error', onError);\n socket.once('connect', () => {\n socket.off('error', onError);\n resolve();\n });\n });\n } catch (error) {\n socket.destroy();\n throw new Error(`connect '${socketPath}' failed: ${_errorMessage(error)}`, { cause: error });\n }\n const { transport } = await connectNdjson({\n input: socket,\n output: socket,\n onClose: () => {\n socket.destroy();\n closeSignal.close();\n },\n initialize: { kind: 'client', token: token ?? '' },\n });\n return { transport, closed: closeSignal.closed };\n}\n\nasync function _openWsTransport(\n url: string,\n token: string | undefined,\n): Promise<OpenParticipant> {\n const ws = await openWebSocket(url);\n const closeSignal = _closeSignal();\n const transport = new WebSocketTransport(ws, () => {\n try {\n ws.close();\n } catch { /* ignore */ }\n closeSignal.close();\n });\n try {\n await runInitializeHandshake(transport, { kind: 'client', token: token ?? '' });\n } catch (error) {\n transport.dispose();\n throw error;\n }\n return { transport, closed: closeSignal.closed };\n}\n\nfunction _registerOnRemote(\n attachment: ConfiguredParticipantAttachment,\n prefix: string,\n timeoutMs = 10_000,\n): Promise<JsonValue | undefined> {\n return attachment.request(REGISTER_METHOD, { serviceId: prefix }, timeoutMs);\n}\n\nfunction _closeSignal(): { readonly closed: Promise<void>; readonly close: () => void; } {\n let close!: () => void;\n const closed = new Promise<void>((resolve) => {\n let didClose = false;\n close = () => {\n if (didClose) return;\n didClose = true;\n resolve();\n };\n });\n return { closed, close };\n}\n\nfunction _delayUnlessAborted(ms: number, signal: AbortSignal): Promise<boolean> {\n if (signal.aborted) return Promise.resolve(false);\n return new Promise<boolean>((resolve) => {\n const timer = setTimeout(() => {\n signal.removeEventListener('abort', onAbort);\n resolve(true);\n }, ms);\n const onAbort = (): void => {\n clearTimeout(timer);\n resolve(false);\n };\n signal.addEventListener('abort', onAbort, { once: true });\n });\n}\n\nfunction _errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n","/**\n * The hub engine: turn one {@link HubConfig} into a running {@link Hub} with all\n * its listeners and endpoints wired up. `serve`, `connect`, and `tunnel` are\n * thin config synthesizers over this; the client commands run it in-process\n * (via the private control socket) when given `-c, --config`.\n *\n * Wiring rules, per transport:\n * - **listener** → a {@link SocketServer}/{@link WebSocketServer} fronted by a\n * {@link HubConnectionAcceptor}; peers claim their own service ids.\n * - **endpoint** (`ws`/`socket`/`cmd-stdio`/`uri`) → a far end we dial: open the\n * raw transport, claim our `claimServiceIds` through its connection-granted\n * namespace, `hub.attach` it for inbound routing, `claimPrefix` its\n * `routeServiceIds`, and `setUplink` it when it is the `defaultRoute`. Lost\n * far-end links reconnect and repeat that registration before routing resumes.\n * - **endpoint** (`cmd-env`) → a child spawned against a private hub socket; it\n * joins this hub as a participant and claims its own prefix.\n */\nimport {\n type LinkRpcConnection,\n type Identity,\n KeypairSigningIdentity,\n type ManagedIdentityStorageBackend,\n type PrincipalId,\n type SigningIdentity,\n} from '@hediet/linkrpc';\nimport {\n CapabilityProposalIssuer,\n Hub,\n HubConnectionAcceptor,\n createHubServiceInterfaces,\n createFlowLogger,\n createSqliteIdentityKeystore,\n fetchFullDirectory,\n registerConnectionTokenBinderService,\n anonymousHandler,\n staticTokenHandler,\n boundTokenHandler,\n resolveConnectionHandler,\n type ConnectionHandlerFactory,\n type RootProvision,\n type HubServices,\n type RegisterConnectionTokenBinderOptions,\n type SqliteIdentityKeystore,\n type SqliteIdentitySlot,\n} from '../hub/server';\nimport {\n type NodeSocketTransport,\n type NodeWebSocketTransport,\n SocketServer,\n WebSocketServer,\n} from '../hub/server/node';\nimport {\n loadOrCreateIdentity,\n} from '@hediet/linkrpc/node';\nimport { createHash, randomBytes } from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as http from 'node:http';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport type {\n ConnectionHandlerConfig,\n ConnectionTokenBinderConfig,\n EndpointConfig,\n HubConfig,\n ListenerConfig,\n ParticipantConnectorConfig,\n ProvisionConfig,\n} from '../config';\nimport { spawnCommand } from '../spawn';\nimport { HubAccessManifestHost, registerHubAccessManifest } from './hubAccessManifest';\nimport { hubAccessManifestInterface } from '@hediet/linkrpc/hub/common';\nimport { runManifestApprover } from './manifestApprover';\nimport { endpointCommand, endpointLabel, forwardStdin, killChild, pipeChildLogs } from './cmdEndpoint';\nimport { configureParticipants } from './configuredParticipants';\nimport { RouteTable } from './routeTable';\nimport { TokenIdentityStore } from '../hub/server/tokenIdentityStore';\n\n/**\n * Resolved forward-checking policy: the listener-acceptor flags plus the\n * admin id used to install the signed front doors, and the consent front-door\n * config the acceptor installs at each overlay root.\n */\ninterface ForwardCheckingState {\n readonly verifyForwardedCalls: boolean;\n readonly requireForwardedCapability: boolean;\n readonly adminIds: readonly PrincipalId[];\n readonly hubServiceId: string;\n /** Installs the consent front door (`hubAccess::*`) at an overlay root. */\n readonly installHubAccess?: (root: LinkRpcConnection<unknown>) => void;\n}\n\n/** Where persistent managed identities for `managedIdentity` slots are stored. */\nconst PROVISION_SUBDIR = 'provisioned-identities';\n\nexport interface RunHubOptions {\n readonly config: HubConfig;\n /** Sink for human log lines (child output, listener bindings). Default: stderr. */\n readonly log?: (line: string) => void;\n /**\n * Forward this process's stdin to the single `cmd-*` endpoint. Throws at\n * startup when more than one `cmd-*` endpoint is configured.\n */\n readonly cmdInteractive?: boolean;\n /**\n * Log every JSON-RPC message routed through the hub to {@link log}, one\n * coalesced flow per line (the same rendering as the VS Code \"linkrpc\n * Flows\" channel). Off by default — when omitted the hub installs no\n * transit observer and pays no cost.\n */\n readonly logMessages?: boolean;\n}\n\n/** A bound listener, reported for logging / `serve` startup output. */\nexport interface ListenerInfo {\n readonly type: ListenerConfig['type'];\n readonly address: string;\n}\n\n/** A running hub. Connect a local client via {@link controlEndpoint}. */\nexport interface RunningHub {\n readonly hub: Hub;\n readonly listeners: readonly ListenerInfo[];\n /** Private local socket (allow-all) for in-process CLI clients. */\n readonly controlEndpoint: { readonly path: string; readonly token: string; };\n dispose(): void;\n}\n\n/** Build + start a hub from a config. Resolves once all transports are wired. */\nexport async function runHub(opts: RunHubOptions): Promise<RunningHub> {\n const log = opts.log ?? ((line: string) => process.stderr.write(line + '\\n'));\n const config = opts.config;\n // Off by default: only attach a transit observer when message logging is\n // requested, so a plain hub pays no inspection cost.\n const flowLogger = opts.logMessages ? createFlowLogger({ log }) : undefined;\n const hub = flowLogger ? new Hub({ onTransit: flowLogger.onTransit }) : new Hub();\n\n const routes = new RouteTable();\n const disposers: Array<() => void> = [];\n const listeners: ListenerInfo[] = [];\n\n // Shared connection-token store: trusted binder endpoints\n // (`connectionTokenBinder`) populate it via\n // `connectionTokenBinder::bindConnectionToken`; `managedIdentity: { mode:\n // \"fromToken\" }` / `grantedServiceId: { mode: \"fromToken\" }` listeners\n // redeem from it. One per hub.\n const tokenStore = new TokenIdentityStore();\n\n // Shared managed-identity provisioner: maps an identity slot to a lazily\n // loaded, cached persistent identity. Used by handlers (config + bound\n // tokens) and cmd-env endpoints alike.\n const identities = new IdentityProvisioner();\n\n const forwardChecking = await _setupForwardChecking(hub, config, log, disposers, tokenStore);\n\n if (flowLogger) disposers.push(() => flowLogger.dispose());\n\n const cmdEndpointCount =\n config.endpoints.filter((e) => e.kind === 'cmd-env' || e.kind === 'cmd-stdio').length\n + Object.values(config.namedEndpoints).filter(\n (e) => e.kind === 'cmd-env' || e.kind === 'cmd-stdio',\n ).length;\n if (opts.cmdInteractive && cmdEndpointCount > 1) {\n throw new Error(\n `--cmd-interactive requires exactly one cmd endpoint, found ${cmdEndpointCount}`,\n );\n }\n const interactive = opts.cmdInteractive === true && cmdEndpointCount === 1;\n\n const dispose = (): void => {\n for (const d of disposers.reverse()) {\n try {\n d();\n } catch { /* best effort */ }\n }\n };\n\n try {\n // Private control socket: local CLI clients connect here (allow-all).\n const controlEndpoint = await _startControlSocket(hub, disposers);\n\n for (const listener of config.listeners) {\n const info = await _wireListener(\n hub,\n listener,\n forwardChecking,\n config.hubServiceId,\n disposers,\n log,\n tokenStore,\n identities,\n );\n listeners.push(info);\n }\n\n // namedEndpoints are folded into endpoints; the map key is their label.\n const planned: Array<{ label: string; ep: EndpointConfig; }> = [\n ...config.endpoints.map((ep) => ({ label: endpointLabel(ep), ep })),\n ...Object.entries(config.namedEndpoints).map(([label, ep]) => ({\n label: endpointLabel(ep, label),\n ep,\n })),\n ];\n\n // Validate conflicts across both reusable connector participants and the\n // host-specific cmd-env participants before starting either category.\n for (const { label, ep } of planned) {\n for (const serviceId of ep.routeServiceIds) routes.claim(serviceId, label);\n if (ep.defaultRoute) routes.setDefault(label);\n }\n\n const connectorParticipants = planned\n .filter((entry): entry is { label: string; ep: ParticipantConnectorConfig; } =>\n entry.ep.kind !== 'cmd-env')\n .map(({ label, ep }) => ({ name: label, config: ep }));\n const configuredParticipants = configureParticipants({\n participants: connectorParticipants,\n attachParticipant: transport => {\n const link = hub.attach(transport);\n return {\n claimPrefix: prefix => link.addPrefixRoute(prefix),\n setDefaultRoute: () => hub.setUplink(transport),\n request: (method, params, timeoutMs) =>\n link.request(method, params, timeoutMs),\n dispose: () => link.dispose(),\n };\n },\n log,\n cmdInteractive: interactive\n && connectorParticipants.some(entry => entry.config.kind === 'cmd-stdio'),\n });\n disposers.push(() => configuredParticipants.dispose());\n\n for (const { label, ep } of planned) {\n if (ep.kind !== 'cmd-env') continue;\n await _wireCmdEnvEndpoint(\n hub, label, ep, log, interactive, forwardChecking, config.hubServiceId, tokenStore, identities, disposers,\n );\n }\n\n return { hub, listeners, controlEndpoint, dispose };\n } catch (e) {\n dispose();\n throw e;\n }\n}\n\n// -- forward checking -----------------------------------------------------\n\n/**\n * Install the hub's global services and, when {@link HubConfig.forwardChecking}\n * is enabled, the `hubAccess` consent front door + the hub-served\n * `hubAccessManifest`.\n *\n * The hub itself is **keyless park-and-relay**: a `hubAccess` request is parked\n * as a desired manifest entry and blocks; an *approver* decides it by relaying a\n * signed capability via `setCurrent`. Approvers are manifest **clients** (over a\n * connection), never special cases inside the hub:\n *\n * - The built-in **terminal approver** ({@link runManifestApprover}) is started\n * when stdin is a TTY and {@link HubConfig.consentApprover} is not `false`.\n * It mints with the hub's persistent admin identity (loaded only then) and\n * consents on stdin. It reaches the manifest over the in-process services\n * connection — the same path a remote approver would use.\n * - A non-interactive hub is **keyless**: it loads no key, and grants come\n * solely from external approvers (configured `rootPrincipalIds`) deciding via\n * the manifest with their own self-signed capabilities.\n *\n * Returns the acceptor flags to apply to every inbound listener, or `undefined`\n * for an open (unchecked) hub.\n */\nasync function _setupForwardChecking(\n hub: Hub,\n config: HubConfig,\n log: (line: string) => void,\n disposers: Array<() => void>,\n tokenStore: TokenIdentityStore,\n): Promise<ForwardCheckingState | undefined> {\n const fc = config.forwardChecking;\n const verifySignatures = fc === true ? true : fc === false ? false : fc.verifySignatures;\n const requireCapability = fc === true ? true : fc === false ? false : fc.requireCapability;\n\n if (!verifySignatures && !requireCapability) {\n // Open hub: no admin identity, no signed register, no consent surface.\n const openServices = createHubServiceInterfaces(hub, { hubServiceId: config.hubServiceId });\n _registerCentralConnectionTokenBinder(openServices, config, tokenStore, log);\n return undefined;\n }\n\n // The hub is keyless park-and-relay. A persistent admin signing identity is\n // loaded only to back the built-in *terminal approver*, which exists only\n // when stdin is a TTY and `consentApprover` is not `false`. Everything else\n // (non-interactive, or `consentApprover: false`) runs without a hub key and\n // relies on external approvers.\n const interactive = process.stdin.isTTY === true;\n const approverEnabled = requireCapability && interactive && config.consentApprover !== false;\n let admin: SigningIdentity | undefined;\n let adminId: PrincipalId | undefined;\n if (approverEnabled) {\n const persisted = await loadOrCreateIdentity({\n id: config.adminIdentitySlot,\n storeDir: _provisionDir(),\n });\n admin = KeypairSigningIdentity.fromKeypair(persisted.keypair);\n adminId = admin.publicSigningIdentity.principal;\n }\n\n const services = createHubServiceInterfaces(hub, {\n hubServiceId: config.hubServiceId,\n });\n _registerCentralConnectionTokenBinder(services, config, tokenStore, log);\n\n // The accepted capability roots: the hub's own admin identity (when a local\n // approver exists), plus any externally configured roots (e.g. a remote\n // vscode/CLI approver). These are both the forwarded-call gate's trust\n // anchors and the `acceptableRootIds` the manifest advertises to approvers.\n const adminIds: PrincipalId[] = [\n ...(adminId !== undefined ? [adminId] : []),\n ...config.rootPrincipalIds,\n ];\n\n // Install the keyless consent surface: the manifest host registers\n // `hubAccess` DIRECTLY at each overlay root (no hub-side directory), parking\n // every request as a manifest entry and awaiting a relayed capability. The\n // host never mints — approvers (terminal or remote) do.\n let installHubAccess: ((root: LinkRpcConnection<unknown>) => void) | undefined;\n if (requireCapability) {\n const manifest = new HubAccessManifestHost({ acceptableRootIds: adminIds, log });\n registerHubAccessManifest(\n services.connection as unknown as LinkRpcConnection,\n manifest,\n { serviceId: services.hubServiceId },\n );\n installHubAccess = (root) => manifest.registerHubAccessAtRoot(root);\n\n // Start the built-in terminal approver as an ordinary manifest client\n // over the in-process services connection (RPC, never the host object).\n // It mints with the hub admin identity and consents on stdin.\n if (approverEnabled && admin !== undefined) {\n const approverServiceId = config.consentApprover === true\n ? services.hubServiceId\n : (config.consentApprover as { serviceId: string }).serviceId;\n const approver = runManifestApprover({\n manifest: services.connection.service(approverServiceId).get(hubAccessManifestInterface),\n fetchDirectory: () => fetchFullDirectory(services.connection as unknown as LinkRpcConnection, approverServiceId),\n issuer: new CapabilityProposalIssuer(admin),\n ownPrincipalId: adminId,\n log,\n });\n disposers.push(() => approver.dispose());\n }\n }\n\n if (requireCapability && adminIds.length === 0) {\n log(\n 'WARNING: requireCapability is on but this hub has no accepted roots '\n + '(no local approver — non-interactive or consentApprover:false — and '\n + 'no rootPrincipalIds configured). No capability can be issued or '\n + 'accepted — every access request will hang in the manifest with no one '\n + 'able to approve it. Configure rootPrincipalIds or enable the approver.',\n );\n }\n\n log(\n `forward checking on (verifySignatures=${verifySignatures}, `\n + `requireCapability=${requireCapability}, admin=${adminId ?? '(keyless)'}`\n + `${config.rootPrincipalIds.length > 0 ? `, extraRoots=[${config.rootPrincipalIds.join(', ')}]` : ''})`,\n );\n return {\n verifyForwardedCalls: verifySignatures,\n requireForwardedCapability: requireCapability,\n adminIds,\n hubServiceId: services.hubServiceId,\n ...(installHubAccess !== undefined ? { installHubAccess } : {}),\n };\n}\n\n/**\n * Offer the connection-token binder as a **routable hub service** under\n * `${hubServiceId}::connectionTokenBinder`, in addition to the per-endpoint\n * root form each `cmd-env` binder installs on its own overlay root.\n *\n * The mint policy is the union of every configured `cmd-env` binder's prefixes:\n * a call may bind an `identitySlot` under any configured `identitySlotPrefix`\n * and a `serviceIdNamespace` under any configured `serviceIdPrefix`. Skipped\n * entirely when no endpoint configures a binder.\n *\n * Forwarded calls to this serviceId go through the hub's forwarded-call gate, so\n * on a checked hub a capability is required. On an **open** hub (no gate) it is\n * reachable unauthenticated — consistent with an open hub's trust-all posture,\n * but note that this is a privileged minter.\n */\nfunction _registerCentralConnectionTokenBinder(\n services: HubServices,\n config: HubConfig,\n tokenStore: TokenIdentityStore,\n log: (line: string) => void,\n): void {\n const binders: ConnectionTokenBinderConfig[] = [\n ...config.endpoints,\n ...Object.values(config.namedEndpoints),\n ]\n .filter((ep) => ep.kind === 'cmd-env' && ep.connectionTokenBinder !== undefined)\n .map((ep) => ep.connectionTokenBinder as ConnectionTokenBinderConfig);\n if (binders.length === 0) return;\n\n const identitySlotPrefixes = binders\n .map((b) => b.identitySlotPrefix)\n .filter((p): p is string => p !== undefined);\n const serviceIdPrefixes = binders\n .map((b) => b.serviceIdPrefix)\n .filter((p): p is string => p !== undefined);\n\n registerConnectionTokenBinderService(\n services.connection as unknown as LinkRpcConnection<unknown>,\n {\n store: tokenStore,\n identitySlotPrefixes,\n serviceIdPrefixes,\n serviceId: services.hubServiceId,\n },\n );\n log(`connectionTokenBinder served on ${services.hubServiceId}::connectionTokenBinder`);\n}\n\n\nasync function _startControlSocket(\n hub: Hub,\n disposers: Array<() => void>,\n): Promise<{ path: string; token: string; }> {\n const socketPath = SocketServer.allocSocketPath();\n const token = randomBytes(16).toString('hex');\n const server = await SocketServer.start({ endpoint: socketPath });\n // No policy / provision: a local control client just routes calls, admitted\n // anonymously (any token) with no root services beyond the base front door.\n const acceptor = new HubConnectionAcceptor<NodeSocketTransport>({\n server,\n hub,\n handlers: [anonymousHandler({})],\n });\n disposers.push(() => {\n acceptor.dispose();\n server.dispose();\n _unlinkSocket(socketPath);\n });\n return { path: socketPath, token };\n}\n\n// -- listeners ------------------------------------------------------------\n\n/**\n * Build the forward-checking gate options spread into a {@link\n * HubConnectionAcceptor}. Shared by inbound listeners and spawned `cmd-env`\n * children, so a child participant's forwarded calls are gated identically to\n * an external peer's (otherwise capability enforcement would silently apply\n * only to listeners, leaving spawned services ungated).\n */\nfunction _buildGate(\n forwardChecking: ForwardCheckingState | undefined,\n hubServiceId: string,\n) {\n const forwardPolicy = !forwardChecking || !forwardChecking.verifyForwardedCalls\n ? { verifyForwardedCalls: false as const }\n : forwardChecking.requireForwardedCapability\n ? {\n verifyForwardedCalls: true as const,\n requireForwardedCapability: true as const,\n adminIds: forwardChecking.adminIds,\n }\n : {\n verifyForwardedCalls: true as const,\n adminIds: forwardChecking.adminIds,\n };\n return forwardChecking\n ? {\n ...forwardPolicy,\n hubServiceId: forwardChecking.hubServiceId,\n ...(forwardChecking.installHubAccess !== undefined ? { installHubAccess: forwardChecking.installHubAccess } : {}),\n }\n : { ...forwardPolicy, hubServiceId };\n}\n\nasync function _wireListener(\n hub: Hub,\n listener: ListenerConfig,\n forwardChecking: ForwardCheckingState | undefined,\n hubServiceId: string,\n disposers: Array<() => void>,\n log: (line: string) => void,\n tokenStore: TokenIdentityStore,\n identities: IdentityProvisioner,\n): Promise<ListenerInfo> {\n const gate = _buildGate(forwardChecking, hubServiceId);\n const handlers = _buildHandlers(listener.handlers, tokenStore, identities);\n // Pre-handshake gate: admit a token iff some handler would claim it (the\n // handler chain then re-resolves and provisions at wiring time).\n const isTokenAccepted = (token: string | undefined): Promise<boolean> =>\n Promise.resolve(resolveConnectionHandler(handlers, token) !== undefined);\n\n if (listener.type === 'websocket') {\n const server = await WebSocketServer.start({\n host: listener.host,\n port: listener.port,\n path: listener.path,\n isTokenAccepted,\n allowedOrigins: listener.allowedOrigins,\n maxPayload: listener.maxPayload,\n requestListener: listener.healthPath\n ? _healthHandler(listener.healthPath)\n : undefined,\n });\n const acceptor = new HubConnectionAcceptor<NodeWebSocketTransport>({\n server,\n hub,\n ...gate,\n handlers,\n });\n disposers.push(() => {\n acceptor.dispose();\n server.dispose();\n });\n const address = `ws://${listener.host}:${server.port}${listener.path}`;\n log(`listening (websocket) on ${address}`);\n return { type: 'websocket', address };\n }\n\n // socket\n const server = await SocketServer.start({\n endpoint: listener.path,\n isTokenAccepted,\n });\n const acceptor = new HubConnectionAcceptor<NodeSocketTransport>({\n server,\n hub,\n ...gate,\n handlers,\n });\n disposers.push(() => {\n acceptor.dispose();\n server.dispose();\n _unlinkSocket(listener.path);\n });\n log(`listening (socket) on ${listener.path}`);\n return { type: 'socket', address: listener.path };\n}\n\n/**\n * Map a config {@link ProvisionConfig} to a resolved {@link RootProvision}:\n * turn `managedIdentity.slot` into a lazy resolver, `grantedServiceId` into a\n * namespace, and `connectionTokenBinder` into registrar options.\n */\nfunction _provisionFromConfig(\n provision: ProvisionConfig,\n tokenStore: TokenIdentityStore,\n identities: IdentityProvisioner,\n): RootProvision {\n return {\n ...(provision.grantedServiceId !== undefined\n ? { grantedServiceIdNamespace: provision.grantedServiceId }\n : {}),\n ...(provision.managedIdentity !== undefined\n ? identities.slotFor(provision.managedIdentity.slot)\n : {}),\n ...(provision.connectionTokenBinder !== undefined\n ? { connectionTokenBinder: _binderOptions(provision.connectionTokenBinder, tokenStore) }\n : {}),\n };\n}\n\n/** Build the acceptor's ordered handler factories from a listener's config. */\nfunction _buildHandlers(\n configs: readonly ConnectionHandlerConfig[],\n tokenStore: TokenIdentityStore,\n identities: IdentityProvisioner,\n): ConnectionHandlerFactory[] {\n return configs.map((h) => {\n switch (h.token) {\n case 'anonymous':\n return anonymousHandler(_provisionFromConfig(h, tokenStore, identities));\n case 'static':\n return staticTokenHandler(h.value, _provisionFromConfig(h, tokenStore, identities));\n case 'bound':\n return boundTokenHandler(tokenStore, (slot) => identities.slotFor(slot));\n }\n });\n}\n\n/**\n * Loads and caches persistent managed identities by slot, backed by a single\n * SQLite keystore. One per hub; shared between config handlers, bound-token\n * redemption, and cmd-env endpoints so a slot resolves to the same identity and\n * per-identity storage everywhere.\n *\n * Runs in the keystore's **unencrypted mode**. Identities created by a previous\n * (file-per-slot plaintext) build are migrated lazily on first resolve, keeping\n * the same principal — see {@link _migrateLegacy}.\n */\nclass IdentityProvisioner {\n private readonly _dir = _provisionDir();\n private _keystore: SqliteIdentityKeystore | undefined;\n\n /**\n * A lazily-resolved managed identity plus its per-identity storage for\n * `slot`. Spread directly into a {@link RootProvision}.\n */\n public slotFor(slot: string): {\n resolveIdentity: () => Promise<Identity>;\n storage: ManagedIdentityStorageBackend;\n } {\n const s = this._keystoreFor().slotById(slot);\n return {\n resolveIdentity: () => this._resolve(slot, s),\n storage: s.storage,\n };\n }\n\n /**\n * Open the keystore on first use — creating the provision dir first, since\n * `DatabaseSync` cannot create its file in a missing directory. Keyless hubs\n * (no managed identity) therefore never touch disk.\n */\n private _keystoreFor(): SqliteIdentityKeystore {\n if (this._keystore === undefined) {\n fs.mkdirSync(this._dir, { recursive: true });\n this._keystore = createSqliteIdentityKeystore({\n dbPath: path.join(this._dir, 'keystore.db'),\n });\n }\n return this._keystore;\n }\n\n private async _resolve(slot: string, s: SqliteIdentitySlot): Promise<Identity> {\n const existing = await s.peekIdentity();\n if (existing) return existing;\n const migrated = await this._migrateLegacy(slot, s);\n if (migrated) return migrated;\n return s.getOrCreateIdentity();\n }\n\n /**\n * Import a pre-SQLite plaintext identity file for `slot` (if one exists)\n * into the keystore, preserving its Ed25519 keypair — and therefore its\n * principal — then rename the file to `.migrated` as an idempotent backup.\n * Returns the imported identity, or `undefined` when there is nothing to\n * migrate.\n */\n private async _migrateLegacy(slot: string, s: SqliteIdentitySlot): Promise<Identity | undefined> {\n const file = path.join(this._dir, `${_legacySlotName(slot)}.json`);\n try {\n await fs.promises.access(file);\n } catch {\n return undefined;\n }\n const persisted = await loadOrCreateIdentity({ id: slot, file });\n const identity = await s.importIdentity(persisted.keypair, persisted.wrapKeypair);\n await fs.promises.rename(file, `${file}.migrated`).catch(() => { });\n return identity;\n }\n}\n\n/**\n * The legacy on-disk filename for a slot (`sha256(slot)` hex, first 16 bytes),\n * as written by the pre-SQLite `loadOrCreateIdentity` under {@link _provisionDir}.\n * Used only to locate files to migrate.\n */\nfunction _legacySlotName(slot: string): string {\n return createHash('sha256').update(slot).digest('hex').slice(0, 32);\n}\n\nfunction _healthHandler(healthPath: string): http.RequestListener {\n return (req, res) => {\n if (req.url === healthPath) {\n res.writeHead(200, { 'content-type': 'text/plain' });\n res.end('ok');\n return;\n }\n res.writeHead(426, { 'content-type': 'text/plain' });\n res.end('upgrade required');\n };\n}\n\n// -- host-specific cmd-env participants -----------------------------------\n\nasync function _wireCmdEnvEndpoint(\n hub: Hub,\n label: string,\n ep: Extract<EndpointConfig, { kind: 'cmd-env'; }>,\n log: (line: string) => void,\n interactive: boolean,\n forwardChecking: ForwardCheckingState | undefined,\n hubServiceId: string,\n tokenStore: TokenIdentityStore,\n identities: IdentityProvisioner,\n disposers: Array<() => void>,\n): Promise<void> {\n if (ep.defaultRoute) {\n throw new Error(`endpoint '${label}': defaultRoute is not supported on cmd-env endpoints`);\n }\n if (ep.claimServiceIds.length > 0) {\n throw new Error(`endpoint '${label}': claimServiceIds is not supported on cmd-env endpoints`);\n }\n // The child claims its own prefix dynamically. Static route conflicts were\n // checked before any configured participant was started.\n const namespace = ep.grantedServiceId ?? ep.routeServiceIds[0];\n\n const socketPath = SocketServer.allocSocketPath();\n const token = randomBytes(16).toString('hex');\n const server = await SocketServer.start({ endpoint: socketPath });\n // Gate the child's forwarded calls exactly like an inbound peer's, so\n // capability enforcement covers spawned services too.\n const gate = _buildGate(forwardChecking, hubServiceId);\n // The dial-in child is admitted unconditionally (no inbound token to gate)\n // and provisioned with this endpoint's fixed root services: granted\n // namespace, managed identity, and — when configured — the token-minting\n // front door (also offered on `${hubServiceId}::connectionTokenBinder` via\n // `_registerCentralConnectionTokenBinder`).\n const provision: RootProvision = {\n ...(namespace !== undefined ? { grantedServiceIdNamespace: namespace } : {}),\n ...(ep.managedIdentity !== undefined\n ? identities.slotFor(ep.managedIdentity.slot)\n : {}),\n ...(ep.connectionTokenBinder !== undefined\n ? { connectionTokenBinder: _binderOptions(ep.connectionTokenBinder, tokenStore) }\n : {}),\n };\n const acceptor = new HubConnectionAcceptor<NodeSocketTransport>({\n server,\n hub,\n ...gate,\n handlers: [anonymousHandler(provision)],\n });\n\n const child = spawnCommand(endpointCommand(ep), {\n stdio: interactive ? ['pipe', 'pipe', 'pipe'] : ['ignore', 'pipe', 'pipe'],\n env: { ...process.env, ...ep.env, LINKRPC_ENDPOINT: socketPath, LINKRPC_TOKEN: token },\n ...(ep.cwd !== undefined ? { cwd: ep.cwd } : {}),\n });\n pipeChildLogs(child, label, log, { includeStdout: true });\n if (interactive) disposers.push(forwardStdin(child));\n\n disposers.push(() => {\n killChild(child);\n acceptor.dispose();\n server.dispose();\n _unlinkSocket(socketPath);\n });\n}\n\n// -- identity / namespace helpers ----------------------------------------\n\n/**\n * Build the root-form {@link RegisterConnectionTokenBinderOptions} for a\n * `cmd-env` endpoint's `connectionTokenBinder` config: each optional prefix\n * becomes a single-element allow-list (absent → empty → that axis disabled).\n */\nfunction _binderOptions(\n binder: ConnectionTokenBinderConfig,\n tokenStore: TokenIdentityStore,\n): RegisterConnectionTokenBinderOptions {\n return {\n store: tokenStore,\n identitySlotPrefixes: binder.identitySlotPrefix !== undefined ? [binder.identitySlotPrefix] : [],\n serviceIdPrefixes: binder.serviceIdPrefix !== undefined ? [binder.serviceIdPrefix] : [],\n };\n}\n\nfunction _unlinkSocket(socketPath: string): void {\n if (process.platform === 'win32') return;\n try {\n fs.unlinkSync(socketPath);\n } catch { /* ignore */ }\n}\n\nfunction _provisionDir(): string {\n const home = os.homedir();\n let base: string;\n if (process.platform === 'win32') {\n base = process.env.APPDATA ?? path.join(home, 'AppData', 'Roaming');\n } else if (process.platform === 'darwin') {\n base = path.join(home, 'Library', 'Application Support');\n } else {\n base = process.env.XDG_CONFIG_HOME ?? path.join(home, '.config');\n }\n return path.join(base, 'linkrpc', PROVISION_SUBDIR);\n}\n"],"mappings":"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"}