@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":"hubConnectionAcceptor-B5-8JsFY.js","names":["nodeInterface","_withRequestId","nodeInterface"],"sources":["../../src/hub/server/routing/forwardingTable.ts","../../src/hub/server/routing/participantRoots.ts","../../src/hub/server/routing/peerDiscovery.ts","../../src/hub/server/routing/routingTopology.ts","../../src/hub/server/routing/routingHub.ts","../../src/hub/server/hubInspector.ts","../../src/hub/server/routing/overlaySplitter.ts","../../src/hub/server/routing/rootOverlay.ts","../../src/hub/server/rootServices.ts","../../src/hub/server/hubRegister.ts","../../src/hub/server/hubServices.ts","../../src/hub/server/connectionTokenBinderService.ts","../../src/hub/server/connectionHandler.ts","../../src/hub/server/verifiedSignature.ts","../../src/hub/server/forwardedCallGate.ts","../../src/hub/server/hubConnectionAcceptor.ts"],"sourcesContent":["import { isValidServiceId, ROOT_SERVICE_ID, SERVICE_ID_SEPARATOR, type ServiceId } from '@hediet/linkrpc/hub/common';\n\n/**\n * A longest-prefix routing table keyed by {@link ServiceId} prefixes — the\n * hub's equivalent of an IP forwarding table.\n *\n * A prefix `\"a/b\"` owns every serviceId equal to it or beneath it\n * (`\"a/b\"`, `\"a/b/c\"`, …) *unless* a longer claimed prefix matches first.\n * Matching is segment-aware: `\"a/bc\"` is **not** under `\"a/b\"`.\n *\n * The table is intentionally a plain stateful container with no opinion on\n * *who* may claim what — that policy lives in {@link Hub.claimPrefix}. This\n * keeps the data structure trivially testable in isolation.\n */\nexport class ForwardingTable<T> {\n private readonly _entries = new Map<ServiceId, T>();\n /**\n * Reverse index: value → the set of prefixes claimed for it. Kept in\n * lock-step with {@link _entries} so {@link deleteByValue} (used when a\n * link detaches) is O(claims-for-that-value) instead of an O(size) scan.\n */\n private readonly _prefixesByValue = new Map<T, Set<ServiceId>>();\n\n /** Number of claimed prefixes. */\n public get size(): number {\n return this._entries.size;\n }\n\n public has(prefix: ServiceId): boolean {\n return this._entries.has(prefix);\n }\n\n public get(prefix: ServiceId): T | undefined {\n return this._entries.get(prefix);\n }\n\n /**\n * Claim `prefix` for `value`. Overwrites any existing claim — callers\n * that want claim-once semantics must check {@link has} first (the hub\n * does).\n */\n public set(prefix: ServiceId, value: T): void {\n const prev = this._entries.get(prefix);\n if (prev !== undefined && prev !== value) this._dropFromIndex(prev, prefix);\n this._entries.set(prefix, value);\n let prefixes = this._prefixesByValue.get(value);\n if (!prefixes) {\n prefixes = new Set();\n this._prefixesByValue.set(value, prefixes);\n }\n prefixes.add(prefix);\n }\n\n public delete(prefix: ServiceId): boolean {\n const value = this._entries.get(prefix);\n if (value === undefined) return false;\n this._entries.delete(prefix);\n this._dropFromIndex(value, prefix);\n return true;\n }\n\n /**\n * Remove every claim bound to `value` (matched by reference/equality).\n * O(number of prefixes that value owns). Returns the removed prefixes.\n */\n public deleteByValue(value: T): ServiceId[] {\n const prefixes = this._prefixesByValue.get(value);\n if (!prefixes) return [];\n this._prefixesByValue.delete(value);\n for (const prefix of prefixes) this._entries.delete(prefix);\n return [...prefixes];\n }\n\n private _dropFromIndex(value: T, prefix: ServiceId): void {\n const prefixes = this._prefixesByValue.get(value);\n if (!prefixes) return;\n prefixes.delete(prefix);\n if (prefixes.size === 0) this._prefixesByValue.delete(value);\n }\n\n public entries(): IterableIterator<[ServiceId, T]> {\n return this._entries.entries();\n }\n\n public prefixes(): ServiceId[] {\n return [...this._entries.keys()];\n }\n\n /**\n * Find the value owning the longest claimed prefix of `serviceId`.\n * Walks up the `'/'` segments — `\"a/b/c\"` tries `\"a/b/c\"`, `\"a/b\"`,\n * `\"a\"` in that order — and returns the first hit, or `undefined` if\n * none of its ancestors are claimed.\n */\n public longestPrefixMatch(serviceId: ServiceId): { prefix: ServiceId; value: T; } | undefined {\n let candidate = serviceId;\n while (candidate.length > 0) {\n const value = this._entries.get(candidate);\n if (value !== undefined) return { prefix: candidate, value };\n const slash = candidate.lastIndexOf(SERVICE_ID_SEPARATOR);\n if (slash === -1) break;\n candidate = candidate.slice(0, slash);\n }\n return undefined;\n }\n}\n\n/**\n * Validate a forwarding-table **prefix**: a non-root {@link ServiceId}. The\n * root (`\"\"`) is a valid service id but cannot be claimed as a prefix (it\n * would capture every address); the uplink is the route of last resort\n * instead. Returns an error string, or `undefined` when well-formed.\n */\nexport function validatePrefix(prefix: unknown): string | undefined {\n if (typeof prefix !== 'string' || prefix === ROOT_SERVICE_ID) return 'prefix required';\n if (!isValidServiceId(prefix)) return \"prefix must be a valid serviceId (no leading/trailing/empty '/' segments)\";\n return undefined;\n}\n","import type { IMessageTransport } from '@hediet/linkrpc';\nimport type { JsonValue } from '@hediet/linkrpc';\nimport type { ServiceId } from '@hediet/linkrpc/hub/common';\n\ninterface Disposable {\n dispose(): void;\n}\n\nexport interface ParticipantRootsOptions {\n readonly forwardingEntries: () => Iterable<readonly [ServiceId, IMessageTransport]>;\n readonly prefixOwner: (prefix: ServiceId) => IMessageTransport | undefined;\n readonly uplink: () => IMessageTransport | undefined;\n readonly requestOnLink: (\n link: IMessageTransport,\n method: string,\n params: JsonValue,\n ) => Promise<JsonValue | undefined>;\n readonly watchOnLink: (\n link: IMessageTransport,\n method: string,\n params: JsonValue,\n onTick: () => void,\n onSettled: () => void,\n onEstablished: () => void,\n ) => Disposable;\n readonly onDidChangeRouting: (listener: () => void) => () => void;\n}\n\n/** Reconciles participant-root queries and watches over the Hub's routing links. */\nexport class ParticipantRoots {\n constructor(private readonly _options: ParticipantRootsOptions) {}\n\n public async query(\n method: string,\n params: JsonValue,\n excludePrefix?: ServiceId,\n ): Promise<JsonValue[]> {\n const settled = await Promise.all(\n [...this._participantLinks(excludePrefix)].map((link) =>\n this._options.requestOnLink(link, method, params).then(\n (result) => result,\n () => undefined,\n )),\n );\n return settled.filter((result): result is JsonValue => result !== undefined);\n }\n\n public watch(\n method: string,\n params: JsonValue,\n onTick: () => void,\n excludePrefix?: ServiceId,\n ): Disposable {\n interface ParticipantWatchState {\n watch?: Disposable;\n retry?: ReturnType<typeof setTimeout>;\n retryDelayMs: number;\n }\n const watches = new Map<IMessageTransport, ParticipantWatchState>();\n let disposed = false;\n const stopState = (state: ParticipantWatchState): void => {\n if (state.retry !== undefined) clearTimeout(state.retry);\n state.retry = undefined;\n state.watch?.dispose();\n state.watch = undefined;\n };\n const start = (link: IMessageTransport, state: ParticipantWatchState): void => {\n if (disposed || !this._participantLinks(excludePrefix).has(link)) return;\n state.watch = this._options.watchOnLink(\n link,\n method,\n params,\n onTick,\n () => {\n queueMicrotask(() => {\n if (disposed || watches.get(link) !== state) return;\n state.watch = undefined;\n state.retry = setTimeout(() => {\n state.retry = undefined;\n start(link, state);\n }, state.retryDelayMs);\n state.retryDelayMs = Math.min(5_000, state.retryDelayMs * 2);\n });\n },\n () => {\n state.retryDelayMs = 200;\n onTick();\n },\n );\n };\n const reconcile = (): void => {\n const current = this._participantLinks(excludePrefix);\n for (const [link, state] of watches) {\n if (current.has(link)) continue;\n stopState(state);\n watches.delete(link);\n }\n for (const link of current) {\n if (watches.has(link)) continue;\n const state: ParticipantWatchState = { retryDelayMs: 200 };\n watches.set(link, state);\n start(link, state);\n }\n };\n reconcile();\n const unsubscribe = this._options.onDidChangeRouting(reconcile);\n return {\n dispose: () => {\n if (disposed) return;\n disposed = true;\n unsubscribe();\n for (const state of watches.values()) stopState(state);\n watches.clear();\n },\n };\n }\n\n private _participantLinks(excludePrefix?: ServiceId): Set<IMessageTransport> {\n const exclude = excludePrefix !== undefined\n ? this._options.prefixOwner(excludePrefix)\n : undefined;\n const uplink = this._options.uplink();\n const links = new Set<IMessageTransport>();\n for (const [, link] of this._options.forwardingEntries()) {\n if (link === exclude || link === uplink) continue;\n links.add(link);\n }\n return links;\n }\n}\n","import { ErrorCode, RpcError, type IMessageTransport, type JsonValue } from '@hediet/linkrpc';\nimport { nodeInterface, type NodeInfo } from '@hediet/linkrpc/inspection';\nimport { safeParse } from 'zod/v4/core';\n\nexport const GET_NODE_ID_METHOD = `${nodeInterface.info.id}::getNodeId`;\n\ninterface PeerState {\n info?: NodeInfo;\n status: 'identified' | 'pending' | 'unsupported' | 'error';\n attempt?: Promise<NodeInfo>;\n timer?: ReturnType<typeof setTimeout>;\n retryDelayMs: number;\n}\n\ninterface PeerDiscoveryOptions {\n readonly timeoutMs?: number;\n readonly request: (link: IMessageTransport, timeoutMs: number) => Promise<JsonValue | undefined>;\n readonly onDidChange: () => void;\n}\n\n/** Background policy for direct-peer identity; forwarding never waits for it. */\nexport class PeerDiscovery {\n private readonly _peers = new WeakMap<IMessageTransport, PeerState>();\n private readonly _timeoutMs: number;\n\n constructor(private readonly _options: PeerDiscoveryOptions) {\n this._timeoutMs = _options.timeoutMs ?? 1_000;\n if (!Number.isFinite(this._timeoutMs) || this._timeoutMs <= 0) {\n throw new Error('peerIdentificationTimeoutMs must be a positive finite number');\n }\n }\n\n public attach(link: IMessageTransport): void {\n if (this._peers.has(link)) return;\n const state: PeerState = { status: 'pending', retryDelayMs: 200 };\n this._peers.set(link, state);\n this._schedule(link, state, 0);\n }\n\n public detach(link: IMessageTransport): void {\n const state = this._peers.get(link);\n if (state?.timer !== undefined) clearTimeout(state.timer);\n this._peers.delete(link);\n // The request owner cancels/settles in-flight requests on detach.\n }\n\n public info(link: IMessageTransport): NodeInfo | undefined {\n return this._peers.get(link)?.info;\n }\n\n public status(link: IMessageTransport): PeerState['status'] {\n return this._peers.get(link)?.status ?? 'pending';\n }\n\n public identify(link: IMessageTransport): Promise<NodeInfo> {\n const state = this._peers.get(link);\n if (state === undefined) return Promise.reject(new Error('identifyPeer: link is detached'));\n if (state.info !== undefined) return Promise.resolve(state.info);\n if (state.attempt !== undefined) return state.attempt;\n if (state.timer !== undefined) clearTimeout(state.timer);\n state.timer = undefined;\n\n // Defer dispatch so even a synchronous transport cannot reenter before\n // the in-flight attempt has been registered.\n const attempt = Promise.resolve().then(async () => {\n if (this._peers.get(link) !== state) throw new Error('identifyPeer: link is detached');\n const raw = await this._options.request(link, this._timeoutMs);\n const parsed = safeParse(nodeInterface.members.getNodeId.resultSchema, raw);\n if (!parsed.success || parsed.data.nodeId.length === 0 || parsed.data.portId.length === 0) {\n throw new Error(`identifyPeer: invalid result from ${GET_NODE_ID_METHOD}`);\n }\n const info = parsed.data;\n if (this._peers.get(link) !== state) throw new Error('identifyPeer: link is detached');\n state.info = info;\n state.status = 'identified';\n this._options.onDidChange();\n return info;\n }).catch((error: unknown) => {\n if (this._peers.get(link) === state) {\n const status = error instanceof RpcError && error.code === ErrorCode.methodNotFound\n ? 'unsupported' : 'error';\n if (state.status !== status) {\n state.status = status;\n this._options.onDidChange();\n }\n const delay = state.status === 'unsupported' ? 30_000 : state.retryDelayMs;\n state.retryDelayMs = Math.min(5_000, state.retryDelayMs * 2);\n this._schedule(link, state, delay * (0.8 + Math.random() * 0.4));\n }\n throw new Error(\n `identifyPeer: ${GET_NODE_ID_METHOD} failed: ${\n error instanceof Error ? error.message : String(error)\n }`,\n { cause: error },\n );\n }).finally(() => {\n state.attempt = undefined;\n });\n state.attempt = attempt;\n return attempt;\n }\n\n private _schedule(link: IMessageTransport, state: PeerState, delayMs: number): void {\n if (this._peers.get(link) !== state) return;\n state.timer = setTimeout(() => {\n state.timer = undefined;\n if (this._peers.get(link) !== state) return;\n // Failures are exposed through peerState and retried by identify().\n void this.identify(link).catch(() => {});\n }, delayMs);\n state.timer.unref();\n }\n}\n","import type { IMessageTransport } from '@hediet/linkrpc';\nimport type { JsonValue } from '@hediet/linkrpc';\nimport {\n type NodeInfo,\n type ParticipantDescriptorSource,\n type TopologyGraph,\n type TopologyTransportInfo,\n type TopologyIdGenerator,\n} from '@hediet/linkrpc/inspection';\nimport type { ServiceId } from '@hediet/linkrpc/hub/common';\n\nimport { GET_NODE_ID_METHOD, PeerDiscovery } from './peerDiscovery';\nexport { GET_NODE_ID_METHOD } from './peerDiscovery';\n\nexport interface ManagedRoutingTopology {\n readonly node: TopologyGraph['nodes'][number];\n readonly hubLinks: readonly {\n readonly hubPortId: string;\n readonly nodePortId: string;\n readonly label?: string;\n }[];\n readonly peerPortId: string;\n readonly peerLinkLabel?: string;\n readonly peerTransport?: TopologyTransportInfo;\n readonly adjacentNodes?: TopologyGraph['nodes'];\n readonly adjacentLinks?: TopologyGraph['links'];\n}\n\nexport interface ManagedTopologyFragment {\n readonly nodes: TopologyGraph['nodes'];\n readonly links?: TopologyGraph['links'];\n readonly routes?: TopologyGraph['routes'];\n}\n\ninterface Disposable {\n dispose(): void;\n}\n\nexport interface RoutingTopologyOptions {\n readonly nodeId: string;\n readonly generateTopologyId: TopologyIdGenerator;\n readonly debugName?: string;\n readonly descriptors?: readonly ParticipantDescriptorSource[];\n readonly peerIdentificationTimeoutMs?: number;\n readonly links: () => Iterable<IMessageTransport>;\n readonly forwardingEntries: () => Iterable<readonly [ServiceId, IMessageTransport]>;\n readonly edgeId: (link: IMessageTransport) => string;\n readonly transportInfo: (link: IMessageTransport) => TopologyTransportInfo | undefined;\n readonly isAttached: (link: IMessageTransport) => boolean;\n readonly requestOnLink: (\n link: IMessageTransport,\n method: string,\n params: JsonValue,\n timeoutMs?: number,\n ) => Promise<JsonValue | undefined>;\n readonly onDidChange: () => void;\n}\n\n/**\n * Owns the Hub's inspection-facing topology state. Routing remains in Hub;\n * this class only consumes snapshots and low-level request callbacks.\n */\nexport class RoutingTopology {\n private readonly _portIds = new WeakMap<IMessageTransport, string>();\n private readonly _handleLinks = new WeakMap<object, IMessageTransport>();\n private readonly _peers: PeerDiscovery;\n private readonly _inspectionServices = new WeakMap<IMessageTransport, Set<string>>();\n private readonly _managedRoutingTopologies =\n new WeakMap<IMessageTransport, ManagedRoutingTopology>();\n private readonly _managedTopologyFragments = new Set<ManagedTopologyFragment>();\n\n constructor(private readonly _options: RoutingTopologyOptions) {\n this._peers = new PeerDiscovery({\n timeoutMs: _options.peerIdentificationTimeoutMs,\n request: (link, timeoutMs) =>\n _options.requestOnLink(link, GET_NODE_ID_METHOD, {}, timeoutMs),\n onDidChange: _options.onDidChange,\n });\n }\n\n public attachLink(link: IMessageTransport): void {\n this._peers.attach(link);\n }\n\n public portId(link: IMessageTransport): string {\n let id = this._portIds.get(link);\n if (id === undefined) {\n id = this._options.generateTopologyId('port');\n this._portIds.set(link, id);\n }\n return id;\n }\n\n public registerHandle(handle: object, link: IMessageTransport): void {\n this._handleLinks.set(handle, link);\n }\n\n public identifyPeer(link: IMessageTransport): Promise<NodeInfo> {\n return this._peers.identify(link);\n }\n\n public registerManagedRoutingTopology(\n attached: object,\n topology: ManagedRoutingTopology,\n ): Disposable {\n const link = this._attachedLink(attached, 'registerManagedRoutingTopology');\n this._managedRoutingTopologies.set(link, topology);\n this._options.onDidChange();\n let disposed = false;\n return {\n dispose: () => {\n if (disposed) return;\n disposed = true;\n if (this._managedRoutingTopologies.get(link) !== topology) return;\n this._managedRoutingTopologies.delete(link);\n this._options.onDidChange();\n },\n };\n }\n\n public registerManagedTopologyFragment(fragment: ManagedTopologyFragment): Disposable {\n this._managedTopologyFragments.add(fragment);\n this._options.onDidChange();\n let disposed = false;\n return {\n dispose: () => {\n if (disposed) return;\n disposed = true;\n this._managedTopologyFragments.delete(fragment);\n this._options.onDidChange();\n },\n };\n }\n\n public markInspectionService(attached: object, serviceId: ServiceId): void {\n const link = this._attachedLink(attached, 'markInspectionService');\n let services = this._inspectionServices.get(link);\n if (services === undefined) {\n services = new Set();\n this._inspectionServices.set(link, services);\n }\n services.add(serviceId);\n }\n\n public isInspectionService(link: IMessageTransport, serviceId: string): boolean {\n return this._inspectionServices.get(link)?.has(serviceId) === true;\n }\n\n public getTopologyGraph(observerServiceId: string): TopologyGraph {\n const allLinks = [...this._options.links()];\n const visibleLinks = allLinks.filter((link) => !this._inspectionServices.has(link));\n const hubPorts = allLinks.map((link) => ({\n portId: this.portId(link),\n label: this._options.edgeId(link),\n }));\n for (const link of visibleLinks) {\n for (const hubLink of this._managedRoutingTopologies.get(link)?.hubLinks ?? []) {\n if (!hubPorts.some((port) => port.portId === hubLink.hubPortId)) {\n hubPorts.push({\n portId: hubLink.hubPortId,\n label: hubLink.label ?? hubLink.hubPortId,\n });\n }\n }\n }\n const nodes: TopologyGraph['nodes'] = [{\n nodeId: this._options.nodeId,\n kind: 'hub',\n ...(this._options.debugName !== undefined\n ? { label: this._options.debugName }\n : {}),\n ...(this._options.descriptors !== undefined\n ? { descriptors: [...this._options.descriptors] }\n : {}),\n ports: hubPorts,\n }];\n const peerNodes = new Map<string, TopologyGraph['nodes'][number]>();\n const links: TopologyGraph['links'] = [];\n\n for (const link of visibleLinks) {\n const peer = this._topologyPeer(link);\n const managed = this._managedRoutingTopologies.get(link);\n let peerNode = peerNodes.get(peer.nodeId);\n if (peerNode === undefined) {\n peerNode = { nodeId: peer.nodeId, ports: [] };\n peerNodes.set(peer.nodeId, peerNode);\n nodes.push(peerNode);\n }\n if (!peerNode.ports.some((port) => port.portId === peer.portId)) {\n peerNode.ports.push({ portId: peer.portId });\n }\n if (managed !== undefined) {\n nodes.push({\n ...managed.node,\n ports: [...managed.node.ports],\n });\n for (const adjacentNode of managed.adjacentNodes ?? []) {\n nodes.push({\n ...adjacentNode,\n ports: [...adjacentNode.ports],\n });\n }\n for (const hubLink of managed.hubLinks) {\n links.push({\n from: { nodeId: this._options.nodeId, portId: hubLink.hubPortId },\n to: { nodeId: managed.node.nodeId, portId: hubLink.nodePortId },\n ...(hubLink.label !== undefined ? { label: hubLink.label } : {}),\n });\n }\n links.push({\n from: { nodeId: managed.node.nodeId, portId: managed.peerPortId },\n to: peer,\n ...(managed.peerLinkLabel !== undefined\n ? { label: managed.peerLinkLabel }\n : {}),\n ...(managed.peerTransport !== undefined\n ? { transport: managed.peerTransport }\n : {}),\n peerState: this._peers.status(link),\n });\n links.push(...(managed.adjacentLinks ?? []));\n continue;\n }\n const transport = this._options.transportInfo(link);\n links.push({\n from: { nodeId: this._options.nodeId, portId: this.portId(link) },\n to: peer,\n label: this._options.edgeId(link),\n peerState: this._peers.status(link),\n ...(transport !== undefined ? { transport } : {}),\n });\n }\n\n const routes: TopologyGraph['routes'] = [];\n for (const [serviceId, link] of this._options.forwardingEntries()) {\n if (this.isInspectionService(link, serviceId)) {\n routes.push({\n serviceId,\n nodeId: this._options.nodeId,\n portId: this.portId(link),\n match: 'prefix',\n });\n continue;\n }\n const peer = this._topologyPeer(link);\n routes.push({\n serviceId,\n nodeId: peer.nodeId,\n portId: peer.portId,\n match: 'prefix',\n });\n }\n for (const fragment of this._managedTopologyFragments) {\n nodes.push(...fragment.nodes.map((node) => ({\n ...node,\n ports: [...node.ports],\n })));\n links.push(...(fragment.links ?? []));\n routes.push(...(fragment.routes ?? []));\n }\n\n return {\n observerServiceId,\n entryNodeId: this._options.nodeId,\n nodes,\n links,\n routes,\n };\n }\n\n public cleanupLink(link: IMessageTransport): void {\n this._inspectionServices.delete(link);\n this._peers.detach(link);\n this._managedRoutingTopologies.delete(link);\n }\n\n private _attachedLink(attached: object, operation: string): IMessageTransport {\n const link = this._handleLinks.get(attached);\n if (link === undefined || !this._options.isAttached(link)) {\n throw new Error(`${operation}: link is not attached to this hub`);\n }\n return link;\n }\n\n private _topologyPeer(link: IMessageTransport): { nodeId: string; portId: string; } {\n const identified = this._peers.info(link);\n if (identified !== undefined) return identified;\n const localPortId = this.portId(link);\n return {\n nodeId: `${this._options.nodeId}:unidentified:${localPortId}`,\n portId: `unidentified:${localPortId}`,\n };\n }\n}\n","import { randomUUID } from 'node:crypto';\nimport { ErrorCode, isNotification, isRequest, isResponse, RpcError, TransportPair } from '@hediet/linkrpc';\nimport type { IMessageTransport, JsonRpcMessage, JsonRpcRequest, JsonRpcResponse, RequestId } from '@hediet/linkrpc';\nimport type { JsonValue } from '@hediet/linkrpc';\nimport { parseMethodName } from '@hediet/linkrpc';\nimport type { NodeTransit, NodeTransitObserver, TransitEndpoint, TransitError } from '../nodeTransit';\nimport {\n STREAM_METHOD,\n StreamControlReason,\n StreamControlType,\n StreamDir,\n type StreamSendParams,\n} from '@hediet/linkrpc';\nimport { ForwardingTable, validatePrefix } from './forwardingTable';\nimport {\n type NodeInfo,\n type ParticipantDescriptorSource,\n type TopologyGraph,\n type TopologyTransportInfo,\n type TopologyIdGenerator,\n} from '@hediet/linkrpc/inspection';\nimport type { ServiceId } from '@hediet/linkrpc/hub/common';\nimport { ParticipantRoots } from './participantRoots';\nimport {\n GET_NODE_ID_METHOD,\n RoutingTopology,\n type ManagedRoutingTopology,\n type ManagedTopologyFragment,\n} from './routingTopology';\n\nexport type { ManagedRoutingTopology, ManagedTopologyFragment } from './routingTopology';\n\n/** A forwarded request awaiting its response, keyed by the hub's rewritten id. */\ninterface PendingForward {\n /** Link the original request arrived on; the response is returned here. */\n readonly origin: IMessageTransport;\n /** Id the origin used; restored onto the response before returning it. */\n readonly originalId: RequestId;\n /** Fully-qualified method, for {@link Hub.pendingRequests} diagnostics. */\n readonly method: string;\n /** When the request was forwarded (ms), for in-flight age reporting. */\n readonly startedAtMs: number;\n /**\n * Link the request was forwarded to. The response is only accepted from\n * this exact link, so a downstream cannot forge a reply (with a guessed\n * sequential id) to a request that was actually routed elsewhere.\n */\n readonly target: IMessageTransport;\n /**\n * Idle-timeout handle. Armed when the request is forwarded, reset on\n * every stream message (incl. keepalive pings), and cleared when the\n * entry is deleted. Bounds `_pending` so a target that never replies\n * (and a caller that never pings) cannot leak an entry forever — which\n * is also the hub's slow-loris / DDoS backstop.\n */\n timer?: ReturnType<typeof setTimeout>;\n}\n\n/**\n * How a method name resolves against this hub's routing state. The\n * structural invariant lives here: root-addressed calls (`bare`/`interface`\n * form) can only ever resolve to loopback — they are **never**\n * forwarded to a prefix owner or the uplink.\n */\ntype Resolution =\n | { readonly kind: 'malformed'; }\n | { readonly kind: 'loopback'; readonly link: IMessageTransport | undefined; }\n | { readonly kind: 'prefix'; readonly link: IMessageTransport; readonly prefix: ServiceId; }\n | { readonly kind: 'uplink'; readonly link: IMessageTransport | undefined; };\n\n/**\n * Diagnostics sink for a {@link Hub}. Deliberately structurally compatible\n * with VS Code's `LogOutputChannel`, so an extension can pass its log channel\n * straight in without an adapter.\n *\n * The hub only ever logs *routing decisions* — method names, the resolution\n * kind, claimed prefixes and error reasons — never message **payloads**\n * (params/results), so attaching a logger never leaks call arguments.\n */\nexport interface IHubLogger {\n trace(message: string): void;\n debug(message: string): void;\n info(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n}\n\nexport interface HubOptions {\n /** Name used in error payloads / diagnostics. */\n readonly debugName?: string;\n /** Optional diagnostic descriptor for this routing node. */\n readonly descriptors?: readonly ParticipantDescriptorSource[];\n /** Stable topology identity for this hub. A random id is generated by default. */\n readonly nodeId?: string;\n /** Topology node/port ID generator. Defaults to random UUIDs; never used for security nonces. */\n readonly generateTopologyId?: TopologyIdGenerator;\n /**\n * Optional diagnostics sink. When omitted the hub logs nothing and pays no\n * string-formatting cost (log calls short-circuit on the missing logger).\n */\n readonly logger?: IHubLogger;\n /**\n * Per-request idle timeout in milliseconds. A forwarded request whose\n * stream is idle for this long (no response, no stream message, no\n * keepalive ping) is cancelled toward its target and failed back to its\n * origin with a `requestTimeout` error. Defaults to 30 minutes. Set to\n * `0` (or a negative value) to disable — only sensible in tests, since\n * it removes the hub's bound on `_pending` growth.\n */\n readonly idleTimeoutMs?: number;\n /** Positive deadline per automatic peer probe, in ms (default 1000). Failures retry in the background. */\n readonly peerIdentificationTimeoutMs?: number;\n /**\n * Optional initial node-transit observer. Additional observers can be\n * attached dynamically with {@link Hub.observeTransits}. When set, the hub emits a\n * {@link NodeTransit} for every message it routes (requests, responses,\n * notifications, stream frames). Off by default — when omitted the emit\n * sites short-circuit and allocate nothing. Never carries more than the\n * method/params/result the hub already handles.\n */\n readonly onTransit?: NodeTransitObserver;\n}\n\nconst DEFAULT_IDLE_TIMEOUT_MS = 30 * 60_000;\n\n/** Minimal disposable handle; calling `dispose` detaches the link. */\nexport interface IDisposable {\n dispose(): void;\n}\n\n/** A snapshot row from {@link Hub.pendingRequests}: one in-flight forward. */\nexport interface PendingRequestInfo {\n /** Hub-rewritten id the target sees. */\n readonly hubId: string;\n /** Original id the origin used. */\n readonly originalId: RequestId;\n /** Fully-qualified method. */\n readonly method: string;\n /** Edge the request arrived on. */\n readonly originEdgeId: string;\n /** Edge the request was forwarded to. */\n readonly targetEdgeId: string;\n /** Milliseconds the request has been in flight. */\n readonly ageMs: number;\n}\n\n/**\n * Handle returned by {@link Hub.attach}. Beyond detaching the link, it lets\n * the caller claim/release prefixes *bound to this specific link* without\n * holding a reference to the link itself — the seam a {@link RootOverlay}\n * uses to let its root services claim upstream on the participant's behalf.\n */\nexport interface AttachedLink extends IDisposable {\n /** Make this link the hub's root handler. Throws if another link already holds the role. */\n setAsLoopback(): void;\n /** Bind `prefix` to this link (see {@link Hub.claimPrefix}). */\n addPrefixRoute(prefix: ServiceId): void;\n /** Release `prefix` from the table. Returns `true` if it existed. */\n releasePrefix(prefix: ServiceId): boolean;\n /**\n * The stable inspection id the hub uses for this link in its\n * {@link NodeTransit} events. A neighbouring node (e.g. an\n * {@link import('./overlaySplitter').OverlaySplitter}) should label the\n * *same physical edge* with this id so a {@link TransitAggregator} chains\n * the two nodes' transits across the boundary.\n */\n readonly edgeId: string;\n /** Stable topology port identity, independent of the mutable friendly edge label. */\n readonly portId: string;\n /** Await or retry peer discovery. Discovery also runs automatically after attachment. */\n identifyPeer(): Promise<NodeInfo>;\n /** Send a bounded root request to the far end while the Hub owns dispatch. */\n request(method: string, params: JsonValue, timeoutMs?: number): Promise<JsonValue | undefined>;\n}\n\nexport interface AttachLinkOptions {\n readonly edgeId?: string;\n readonly transport?: TopologyTransportInfo;\n /** Make this link the sole hub-root handler. Throws if another link already holds the role. */\n readonly exclusiveHubRootHandler?: boolean;\n /** Initial prefix routes. All must be valid, distinct, and unclaimed. */\n readonly routePrefixes?: readonly ServiceId[];\n}\n\n/**\n * A **Hub** is the entire routing concept of linkrpc v2 — the only noun.\n * It is a tiny message router with an unauthenticated topology-correlation\n * identity and exactly three moving\n * parts, all expressed as {@link IMessageTransport} links:\n *\n * - **forwarding table** — longest-prefix serviceId → link map (the\n * downstream neighbours / claimed subnets).\n * - **loopback** — an optional link to the local root services (`bare`/\n * `interface`-form calls land here and *never* leave the hub). This is\n * the routing equivalent of `127.0.0.1`.\n * - **uplink** — an optional default route. A hub *with* an uplink is also\n * a participant of its parent hub, which is how hubs **nest** (a VS Code\n * window hub uplinks to an OS hub uplinks to a home-server hub).\n *\n * Routing is pure longest-prefix forwarding with JSON-RPC id rewriting:\n * a forwarded request keeps its full method name verbatim; only its `id`\n * is swapped for a hub-local one so responses can be demultiplexed back to\n * the originating link. There is no notion of identity, capabilities, or\n * trust at this layer — those are policies layered on top.\n *\n * The single privileged write seam is {@link claimPrefix}; everything else\n * is mechanical message shuffling.\n */\nexport class Hub {\n /** Unauthenticated topology-correlation identity for this hub. */\n public readonly nodeId: string;\n\n private readonly _table = new ForwardingTable<IMessageTransport>();\n private readonly _links = new Set<IMessageTransport>();\n private readonly _pending = new Map<string, PendingForward>();\n\n private _uplink: IMessageTransport | undefined;\n private _loopback: IMessageTransport | undefined;\n private _nextId = 1;\n\n private readonly _log: IHubLogger | undefined;\n private readonly _transitObservers = new Set<NodeTransitObserver>();\n\n /**\n * Listeners notified whenever the forwarding table changes (a prefix is\n * claimed or released, or a link detaches dropping its claims). Coarse, by\n * design: it carries no payload — consumers re-query the directory. This is\n * the \"poll now\" nudge that backs `hubrpc.directory::watch`.\n */\n private readonly _routingListeners = new Set<() => void>();\n private readonly _topologyListeners = new Set<() => void>();\n\n /** Stable inspection label per link; assigned lazily / by prefix claim. */\n private readonly _edgeIds = new WeakMap<IMessageTransport, string>();\n private readonly _transportInfo = new WeakMap<IMessageTransport, TopologyTransportInfo>();\n private _nextEdgeId = 1;\n private readonly _topology: RoutingTopology;\n private readonly _participantRoots: ParticipantRoots;\n\n /** Per-request idle timeout in ms; `<= 0` disables. See {@link HubOptions.idleTimeoutMs}. */\n private readonly _idleMs: number;\n\n constructor(private readonly _options: HubOptions = {}) {\n const generateTopologyId: TopologyIdGenerator = _options.generateTopologyId ?? (() => randomUUID());\n this.nodeId = _options.nodeId ?? generateTopologyId('node');\n this._log = _options.logger;\n if (_options.onTransit !== undefined) this._transitObservers.add(_options.onTransit);\n this._idleMs = _options.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS;\n this._topology = new RoutingTopology({\n nodeId: this.nodeId,\n generateTopologyId,\n debugName: _options.debugName,\n descriptors: _options.descriptors,\n peerIdentificationTimeoutMs: _options.peerIdentificationTimeoutMs,\n links: () => this._links,\n forwardingEntries: () => this._table.entries(),\n edgeId: (link) => this._edgeId(link),\n transportInfo: (link) => this._transportInfo.get(link),\n isAttached: (link) => this._links.has(link),\n requestOnLink: (link, method, params, timeoutMs) =>\n this._requestOnLink(link, method, params, timeoutMs),\n onDidChange: () => this._fireTopologyChanged(),\n });\n this._participantRoots = new ParticipantRoots({\n forwardingEntries: () => this._table.entries(),\n prefixOwner: (prefix) => this._table.get(prefix),\n uplink: () => this._uplink,\n requestOnLink: (link, method, params) => this._requestOnLink(link, method, params),\n watchOnLink: (link, method, params, onTick, onSettled, onEstablished) =>\n this._watchOnLink(link, method, params, onTick, onSettled, onEstablished),\n onDidChangeRouting: (listener) => this.onDidChangeRouting(listener),\n });\n }\n\n /** Prefix for log lines; identifies this hub when nested. */\n private _tag(): string {\n return this._options.debugName !== undefined ? `[${this._options.debugName}] ` : '';\n }\n\n /** Stable inspection label for a link; auto-assigned on first use. */\n private _edgeId(link: IMessageTransport): string {\n let id = this._edgeIds.get(link);\n if (id === undefined) {\n id = `e${this._nextEdgeId++}`;\n this._edgeIds.set(link, id);\n }\n return id;\n }\n\n /** Give `link` a friendly inspection label (prefix / loopback / uplink). */\n private _labelEdge(link: IMessageTransport, label: string): void {\n const cur = this._edgeIds.get(link);\n // Don't clobber a meaningful label with a later, less specific one.\n if (cur === undefined || /^e\\d+$/.test(cur)) this._edgeIds.set(link, label);\n }\n\n /** Emit a pre-built node transit. Callers guard construction by observer count. */\n private _emit(t: NodeTransit): void {\n for (const observer of [...this._transitObservers]) {\n try {\n observer(t);\n } catch (err) {\n this._log?.warn(`${this._tag()}transit observer threw: ${String(err)}`);\n }\n }\n }\n\n private _transitEndpoint(\n link: IMessageTransport,\n requestId?: RequestId,\n ): TransitEndpoint {\n return {\n edgeId: this._edgeId(link),\n portId: this._topology.portId(link),\n ...(requestId !== undefined ? { requestId } : {}),\n };\n }\n\n /** Number of live transit observers. */\n public get transitObserverCount(): number {\n return this._transitObservers.size;\n }\n\n /** Observe routed messages until the returned handle is disposed. */\n public observeTransits(observer: NodeTransitObserver): IDisposable {\n this._transitObservers.add(observer);\n let disposed = false;\n return {\n dispose: () => {\n if (disposed) return;\n disposed = true;\n this._transitObservers.delete(observer);\n },\n };\n }\n\n /**\n * Publish a transit from a routing node managed by this Hub. Callers should\n * check {@link transitObserverCount} before constructing the transit.\n */\n public publishManagedTransit(transit: NodeTransit): void {\n if (this._transitObservers.size === 0) return;\n this._emit(transit);\n }\n\n /** Replace an attached link's direct topology edge with a managed routing node. */\n public registerManagedRoutingTopology(\n attached: AttachedLink,\n topology: ManagedRoutingTopology,\n ): IDisposable {\n return this._topology.registerManagedRoutingTopology(attached, topology);\n }\n\n /** Add an in-process endpoint or routing fragment to this Hub's topology. */\n public registerManagedTopologyFragment(fragment: ManagedTopologyFragment): IDisposable {\n return this._topology.registerManagedTopologyFragment(fragment);\n }\n\n /**\n * Subscribe to coarse routing-table changes (prefix claim/release/detach).\n * The listener receives no arguments — it is a \"something changed; re-query\"\n * nudge. Returns an unsubscribe function.\n */\n public onDidChangeRouting(listener: () => void): () => void {\n this._routingListeners.add(listener);\n return () => {\n this._routingListeners.delete(listener);\n };\n }\n\n /** Subscribe to topology changes, including routing and background peer discovery. */\n public onDidChangeTopology(listener: () => void): () => void {\n this._topologyListeners.add(listener);\n return () => { this._topologyListeners.delete(listener); };\n }\n\n /** Number of active routing invalidation observers. */\n public get routingObserverCount(): number {\n return this._routingListeners.size;\n }\n\n public get topologyObserverCount(): number {\n return this._topologyListeners.size;\n }\n\n /** Fire all routing-change listeners. Best-effort; one throwing listener does not block the rest. */\n private _fireRoutingChanged(): void {\n this._notifyListeners(this._routingListeners);\n this._fireTopologyChanged();\n }\n\n private _fireTopologyChanged(): void {\n this._notifyListeners(this._topologyListeners);\n }\n\n private _notifyListeners(listeners: ReadonlySet<() => void>): void {\n for (const listener of [...listeners]) {\n try {\n listener();\n } catch (err) {\n this._log?.warn(`${this._tag()}change listener threw: ${String(err)}`);\n }\n }\n }\n\n /** Emit a stream transit with the owning request's correlated endpoints. */\n private _emitStream(note: JsonRpcMessage, inEp: TransitEndpoint, outEp: TransitEndpoint): void {\n if (this._transitObservers.size === 0) return;\n this._emit({\n timeMs: Date.now(),\n nodeId: this.nodeId,\n in: inEp,\n out: outEp,\n disposition: 'forwarded',\n kind: 'stream',\n method: STREAM_METHOD,\n params: (note as { params?: JsonValue }).params,\n });\n }\n\n /**\n * Snapshot the requests currently in flight through this hub. Each row is\n * one {@link _pending} entry — the authoritative in-flight set — annotated\n * with its method, the edges it bridges, and how long it has waited. Useful\n * for surfacing stuck/slow requests in an inspector.\n */\n public pendingRequests(): PendingRequestInfo[] {\n const now = Date.now();\n const out: PendingRequestInfo[] = [];\n for (const [hubId, p] of this._pending) {\n out.push({\n hubId,\n originalId: p.originalId,\n method: p.method,\n originEdgeId: this._edgeId(p.origin),\n targetEdgeId: this._edgeId(p.target),\n ageMs: now - p.startedAtMs,\n });\n }\n return out;\n }\n\n // -- topology ---------------------------------------------------\n\n /**\n * Begin routing the messages of `link`. The hub installs itself as the\n * link's listener; do not also attach another listener. Returns a\n * disposable that stops routing the link (detaching the listener and\n * dropping any forwarding entries, uplink/loopback slots, and pending\n * responses bound to it) when disposed. Peer discovery starts in the\n * background; unresolved or unsupported peers never block routing.\n */\n public attach(link: IMessageTransport, opts?: AttachLinkOptions): AttachedLink {\n const prefixes = opts?.routePrefixes ?? [];\n const seen = new Set<ServiceId>();\n for (const prefix of prefixes) {\n this._validatePrefixClaim(prefix);\n if (seen.has(prefix)) throw new Error(`claimPrefix: duplicate prefix '${prefix}'`);\n seen.add(prefix);\n }\n if (opts?.exclusiveHubRootHandler === true && this._loopback !== undefined && this._loopback !== link) {\n throw new Error('exclusiveHubRootHandler: another link is already the hub-root handler');\n }\n if (opts?.edgeId !== undefined) this._edgeIds.set(link, opts.edgeId);\n if (opts?.transport !== undefined) this._transportInfo.set(link, opts.transport);\n let disposed = false;\n const handle: AttachedLink = {\n dispose: () => {\n if (disposed) return;\n disposed = true;\n this._detach(link);\n },\n setAsLoopback: () => {\n if (disposed || !this._links.has(link)) {\n throw new Error('setAsLoopback: link is detached');\n }\n this.setLoopback(link);\n },\n addPrefixRoute: (prefix) => this.claimPrefix(link, prefix),\n releasePrefix: (prefix) => this.releasePrefix(prefix),\n edgeId: this._edgeId(link),\n portId: this._topology.portId(link),\n identifyPeer: () => this._topology.identifyPeer(link),\n request: (method, params, timeoutMs) =>\n this._requestOnLink(link, method, params, timeoutMs),\n };\n this._topology.registerHandle(handle, link);\n const isNew = !this._links.has(link);\n const loopbackChanged = opts?.exclusiveHubRootHandler === true && this._loopback !== link;\n if (isNew) {\n this._links.add(link);\n this._topology.attachLink(link);\n }\n if (opts?.exclusiveHubRootHandler === true) {\n this._loopback = link;\n this._labelEdge(link, 'loopback');\n }\n for (const prefix of prefixes) this._claimPrefix(link, prefix);\n if (isNew) link.setListener((m) => this._onMessage(link, m));\n if (isNew || loopbackChanged || prefixes.length !== 0) this._fireRoutingChanged();\n return handle;\n }\n\n /**\n * Attach a fresh in-memory link and hand back its far end alongside the\n * {@link AttachedLink} handle. Creates a {@link TransportPair} internally,\n * {@link attach}es the near side to the hub, and returns the attach handle\n * augmented with `transport` — the far side for a peer (a consumer\n * connection, an in-process participant, …) to drive. Equivalent to\n * `const p = new TransportPair(); const link = hub.attach(p.a);\n * return { ...link, transport: p.b };`. Disposing the returned link also\n * disposes `transport`.\n */\n public attachOut(opts?: AttachLinkOptions): AttachedLink & { readonly transport: IMessageTransport } {\n const pair = new TransportPair();\n const link = this.attach(pair.a, opts);\n const result: AttachedLink & { readonly transport: IMessageTransport } = {\n ...link,\n transport: pair.b,\n dispose: () => {\n link.dispose();\n pair.b.dispose();\n },\n };\n this._topology.registerHandle(result, pair.a);\n return result;\n }\n\n private _detach(link: IMessageTransport): void {\n if (!this._links.has(link)) {\n return;\n }\n link.setListener(undefined);\n this._links.delete(link);\n this._topology.cleanupLink(link);\n this._table.deleteByValue(link);\n if (this._uplink === link) {\n this._uplink = undefined;\n }\n if (this._loopback === link) {\n this._loopback = undefined;\n }\n for (const [id, p] of [...this._pending]) {\n if (p.origin === link) {\n // The caller is gone. Cancel the callee's now-orphaned work\n // (it streams to nobody) before dropping the entry.\n this._injectCancel(p.target, id, StreamControlReason.clientDisconnected);\n if (this._transitObservers.size !== 0) {\n this._emit({\n timeMs: Date.now(),\n nodeId: this.nodeId,\n in: this._transitEndpoint(p.target, id),\n disposition: 'dropped',\n kind: 'response',\n method: p.method,\n error: { code: ErrorCode.peerDisconnected, message: 'origin disconnected' },\n });\n }\n this._deletePending(id);\n } else if (p.target === link) {\n // The target vanished mid-flight; fail the waiting origin\n // instead of leaking the entry and stalling forever.\n this._deletePending(id);\n this._log?.warn(\n `${this._tag()}target detached mid-request (hubId=${id}); failing origin`,\n );\n if (this._transitObservers.size !== 0) {\n this._emit({\n timeMs: Date.now(),\n nodeId: this.nodeId,\n in: this._transitEndpoint(p.target, id),\n out: this._transitEndpoint(p.origin, p.originalId),\n disposition: 'forwarded',\n kind: 'response',\n method: p.method,\n error: { code: ErrorCode.peerDisconnected, message: 'target detached before responding' },\n });\n }\n this._replyError(\n p.origin,\n p.originalId,\n ErrorCode.peerDisconnected,\n 'target detached before responding',\n );\n }\n }\n this._fireRoutingChanged();\n }\n\n /** Set (or clear) the default route. Automatically attaches the link. */\n public setUplink(link: IMessageTransport | undefined): void {\n const changed = this._uplink !== link;\n this._uplink = link;\n if (link) {\n this.attach(link);\n this._labelEdge(link, 'uplink');\n }\n if (changed) this._fireRoutingChanged();\n }\n\n /** Set (or clear) the root handler. Clear the existing handler before assigning a different link. */\n public setLoopback(link: IMessageTransport | undefined): void {\n if (link !== undefined) {\n this.attach(link, { exclusiveHubRootHandler: true });\n } else if (this._loopback !== undefined) {\n this._loopback = undefined;\n this._fireRoutingChanged();\n }\n }\n\n // -- the one privileged seam ------------------------------------\n\n /**\n * Bind a serviceId `prefix` to `link`. Like initial attachment routes,\n * this is a privileged operation; higher layers enforce who may claim.\n *\n * Claim-once: throws if the prefix is malformed or already owned.\n */\n public claimPrefix(link: IMessageTransport, prefix: ServiceId): void {\n this.attach(link, { routePrefixes: [prefix] });\n }\n\n private _validatePrefixClaim(prefix: ServiceId): void {\n const err = validatePrefix(prefix);\n if (err) throw new Error(`claimPrefix: ${err}`);\n if (this._table.has(prefix)) {\n throw new Error(`claimPrefix: prefix '${prefix}' is already claimed`);\n }\n }\n\n private _claimPrefix(link: IMessageTransport, prefix: ServiceId): void {\n this._table.set(prefix, link);\n this._labelEdge(link, prefix);\n this._log?.debug(`${this._tag()}claim prefix '${prefix}'`);\n }\n\n public releasePrefix(prefix: ServiceId): boolean {\n const released = this._table.delete(prefix);\n if (released) {\n this._log?.debug(`${this._tag()}release prefix '${prefix}'`);\n this._fireRoutingChanged();\n }\n return released;\n }\n\n /** Snapshot of currently-claimed prefixes. */\n public claimedPrefixes(): ServiceId[] {\n return this._table.prefixes();\n }\n\n /**\n * Trust the inspection interfaces mounted for `serviceId` on this attached\n * in-process link. Only exact reserved inspection interface calls are hidden.\n */\n public markInspectionService(attached: AttachedLink, serviceId: ServiceId): void {\n this._topology.markInspectionService(attached, serviceId);\n }\n\n /** Build a topology snapshot on demand for the addressed observer service. */\n public getTopologyGraph(observerServiceId: string): TopologyGraph {\n return this._topology.getTopologyGraph(observerServiceId);\n }\n\n /**\n * Fan a **root-form** request out to every distinct downstream participant\n * link (the claimed-prefix owners), skipping the link that owns\n * `excludePrefix` (typically the hub's own services prefix) and the uplink.\n * Each participant is queried **once** even if it owns several prefixes.\n * Failures (unreachable participant, timeout, no root handler) are dropped,\n * so the result holds one entry per link that answered.\n *\n * The request is delivered to each participant's **root** services — on an\n * overlay uplink the splitter routes a root-form method to the participant\n * (`H·root → P`), which is never forwarded and never gated. That is what\n * lets the hub's global directory gather participant self-listings without\n * signing or capabilities.\n */\n public async queryParticipantRoots(\n method: string,\n params: JsonValue,\n excludePrefix?: ServiceId,\n ): Promise<JsonValue[]> {\n return this._participantRoots.query(method, params, excludePrefix);\n }\n\n /**\n * Keep a root-form streaming request open on every current participant.\n * Routing changes reconcile the participant set; application stream payloads\n * are collapsed into a coarse callback so callers can re-query.\n */\n public watchParticipantRoots(\n method: string,\n params: JsonValue,\n onTick: () => void,\n excludePrefix?: ServiceId,\n ): IDisposable {\n return this._participantRoots.watch(method, params, onTick, excludePrefix);\n }\n\n /**\n * Send a single request down `link` and resolve with its result — the\n * hub-originated analogue of {@link _routeRequest}. It allocates a hub id,\n * parks a {@link _pending} entry whose `origin` is a tiny in-memory sink\n * that settles this promise on the matching response, and writes the\n * request to `link`. It therefore reuses the full demux / idle-timeout /\n * detach machinery: a response routes back through {@link _demux} into the\n * sink, an idle target fails it via {@link _onIdleTimeout}, and a detaching\n * target fails it via {@link _detach}.\n */\n private _requestOnLink(\n link: IMessageTransport,\n method: string,\n params: JsonValue,\n timeoutMs?: number,\n ): Promise<JsonValue | undefined> {\n return new Promise<JsonValue | undefined>((resolve, reject) => {\n const hubId = this._nextId++;\n const key = String(hubId);\n let settled = false;\n let requestTimeout: ReturnType<typeof setTimeout> | undefined;\n const finish = (error: unknown, result?: JsonValue): void => {\n if (settled) return;\n settled = true;\n if (requestTimeout !== undefined) clearTimeout(requestTimeout);\n if (error !== undefined) reject(error);\n else resolve(result);\n };\n const origin: IMessageTransport = {\n send: (m) => {\n const r = m as JsonRpcResponse;\n const err = (r as {\n error?: { code?: number; message?: string; data?: JsonValue; };\n }).error;\n if (err) {\n finish(new RpcError(\n err.message ?? 'request failed',\n err.code ?? ErrorCode.internalError,\n err.data,\n ));\n } else {\n finish(undefined, (r as { result?: JsonValue; }).result);\n }\n },\n setListener: () => { /* sink: never delivers inbound */ },\n dispose: () => { /* nothing to release */ },\n };\n this._pending.set(key, {\n origin,\n originalId: hubId,\n target: link,\n method,\n startedAtMs: Date.now(),\n });\n this._armIdle(key);\n if (timeoutMs !== undefined && timeoutMs > 0) {\n requestTimeout = setTimeout(() => {\n if (this._pending.get(key)?.origin !== origin) return;\n this._injectCancel(link, key, StreamControlReason.clientDisconnected);\n this._deletePending(key);\n finish(new Error(`${method} timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n requestTimeout.unref();\n }\n const onSendError = (error: unknown): void => {\n if (this._pending.get(key)?.origin !== origin) return;\n this._deletePending(key);\n finish(error instanceof Error ? error : new Error(String(error)));\n };\n try {\n Promise.resolve(link.send({\n jsonrpc: '2.0',\n id: hubId,\n method,\n params,\n } as JsonRpcRequest)).catch(onSendError);\n } catch (error) {\n onSendError(error);\n }\n });\n }\n\n private _watchOnLink(\n link: IMessageTransport,\n method: string,\n params: JsonValue,\n onTick: () => void,\n onSettled: () => void,\n onEstablished: () => void,\n ): IDisposable {\n const hubId = this._nextId++;\n const key = String(hubId);\n let active = true;\n let pingTimer: ReturnType<typeof setInterval> | undefined;\n let establishedTimer: ReturnType<typeof setTimeout> | undefined;\n const stop = (cancel: boolean): void => {\n if (!active) return;\n active = false;\n if (pingTimer !== undefined) clearInterval(pingTimer);\n if (establishedTimer !== undefined) clearTimeout(establishedTimer);\n if (this._pending.get(key)?.origin === origin) {\n if (cancel) this._injectCancel(link, key, StreamControlReason.clientDisconnected);\n this._deletePending(key);\n }\n if (!cancel) onSettled();\n };\n const sendControl = (control: StreamSendParams['control'], dir: StreamDir): void => {\n const message = {\n jsonrpc: '2.0',\n method: STREAM_METHOD,\n params: {\n requestId: hubId,\n dir,\n control,\n },\n } as const;\n try {\n Promise.resolve(link.send(message)).catch(() => stop(false));\n } catch {\n stop(false);\n }\n };\n const origin: IMessageTransport = {\n send: (message) => {\n if (isNotification(message) && message.method === STREAM_METHOD) {\n const stream = _streamParams(message);\n if (stream?.dir !== StreamDir.toCaller) return;\n if (stream.control?.type === StreamControlType.ping) {\n sendControl({\n type: StreamControlType.pong,\n nonce: stream.control.nonce,\n }, StreamDir.toCallee);\n }\n if (stream.payload !== undefined) onTick();\n } else if (isResponse(message)) {\n stop(false);\n }\n },\n setListener: () => { /* synthetic caller receives through send */ },\n dispose: () => stop(true),\n };\n this._pending.set(key, {\n origin,\n originalId: hubId,\n target: link,\n method,\n startedAtMs: Date.now(),\n });\n this._armIdle(key);\n establishedTimer = setTimeout(() => {\n establishedTimer = undefined;\n if (active && this._pending.get(key)?.origin === origin) onEstablished();\n }, 10);\n if (this._idleMs > 0) {\n pingTimer = setInterval(() => {\n if (!active || this._pending.get(key)?.origin !== origin) {\n stop(false);\n return;\n }\n this._resetIdle(key);\n sendControl({\n type: StreamControlType.ping,\n nonce: randomUUID(),\n }, StreamDir.toCallee);\n }, Math.max(10, Math.floor(this._idleMs / 3)));\n }\n const onSendError = (): void => stop(false);\n try {\n Promise.resolve(link.send({\n jsonrpc: '2.0',\n id: hubId,\n method,\n params,\n } as JsonRpcRequest)).catch(onSendError);\n } catch {\n onSendError();\n }\n return { dispose: () => stop(true) };\n }\n\n /**\n * The link a still-in-flight forwarded request originally arrived on,\n * keyed by the **hub-rewritten** id the request now carries (i.e. the\n * `id` a target sees on its delivered message). Valid from the moment the\n * hub forwards the request until its response is demultiplexed; returns\n * `undefined` for unknown / already-answered ids.\n *\n * This is the seam a hub-hosted participant uses to learn *which* link a\n * call it is handling came from, so it can bind a prefix claim to that\n * exact link via {@link claimPrefix} without the routing core ever\n * growing a notion of authenticated identity.\n */\n public getSourceTransport(requestId: RequestId): IMessageTransport | undefined {\n return this._pending.get(String(requestId))?.origin;\n }\n\n // -- routing ----------------------------------------------------\n\n private _onMessage(from: IMessageTransport, m: JsonRpcMessage): void {\n if (isResponse(m)) {\n this._demux(from, m);\n } else if (isRequest(m)) {\n if (m.method === GET_NODE_ID_METHOD) {\n void from.send({\n jsonrpc: '2.0',\n id: m.id,\n result: { nodeId: this.nodeId, portId: this._topology.portId(from) },\n });\n return;\n }\n this._routeRequest(from, m);\n } else if (isNotification(m)) {\n // `$stream::send` is correlated to an in-flight request by\n // `requestId`, *not* addressed by method name. It must follow that\n // request's established path (like a response demux), never the\n // method-form table — routing it as an interface-form notification\n // would wrongly send it to loopback. See {@link _routeStream}.\n if ((m as { method?: unknown; }).method === STREAM_METHOD) {\n this._routeStream(from, m);\n } else {\n this._routeNotification(from, m);\n }\n }\n }\n\n private _resolve(method: string, from: IMessageTransport): Resolution {\n const parsed = parseMethodName(method);\n if (!parsed) return { kind: 'malformed' };\n // Root-addressed: loopback only. Structural invariant — never forwarded.\n if (parsed.kind === 'bare' || parsed.kind === 'interface') {\n return { kind: 'loopback', link: this._loopback };\n }\n const match = this._table.longestPrefixMatch(parsed.serviceId);\n if (match) return { kind: 'prefix', link: match.value, prefix: match.prefix };\n // No table hit: fall back to the default route, unless that *is*\n // where the message came from (a loop with no owner downstream).\n if (this._uplink !== undefined && this._uplink === from) {\n return { kind: 'uplink', link: undefined };\n }\n return { kind: 'uplink', link: this._uplink };\n }\n\n private _routeRequest(from: IMessageTransport, req: JsonRpcRequest): void {\n const res = this._resolve(req.method, from);\n const target = res.kind === 'malformed' ? undefined : res.link;\n if (!target) {\n const message = this._noTargetMessage(res, req.method);\n this._log?.warn(\n `${this._tag()}unroutable request '${req.method}' (id=${String(req.id)}): ${message}`,\n );\n if (this._transitObservers.size !== 0) {\n this._emit({\n timeMs: Date.now(),\n nodeId: this.nodeId,\n in: this._transitEndpoint(from, req.id),\n disposition: 'unroutable',\n kind: 'request',\n method: req.method,\n params: req.params as JsonValue | undefined,\n });\n }\n this._replyError(from, req.id, this._noTargetCode(res), message);\n return;\n }\n const hubId = this._nextId++;\n const key = String(hubId);\n this._pending.set(key, {\n origin: from,\n originalId: req.id,\n target,\n method: req.method,\n startedAtMs: Date.now(),\n });\n this._armIdle(key);\n this._log?.trace(\n `${this._tag()}route '${req.method}' (${res.kind}${res.kind === 'prefix' ? ` ${res.prefix}` : ''\n }) id=${String(req.id)}\\u2192${hubId}`,\n );\n if (this._transitObservers.size !== 0) {\n this._emit({\n timeMs: Date.now(),\n nodeId: this.nodeId,\n in: this._transitEndpoint(from, req.id),\n out: this._transitEndpoint(target, hubId),\n disposition: 'forwarded',\n kind: 'request',\n method: req.method,\n params: req.params as JsonValue | undefined,\n });\n }\n const forwarded = { ...req, id: hubId };\n const onSendError = (error: unknown): void => {\n const pending = this._pending.get(key);\n if (pending === undefined || pending.target !== target) return;\n this._deletePending(key);\n const message = `target send failed: ${\n error instanceof Error ? error.message : String(error)\n }`;\n this._log?.warn(`${this._tag()}${message} (hubId=${key})`);\n if (this._transitObservers.size !== 0) {\n this._emit({\n timeMs: Date.now(),\n nodeId: this.nodeId,\n in: this._transitEndpoint(pending.target, hubId),\n out: this._transitEndpoint(pending.origin, pending.originalId),\n disposition: 'dropped',\n kind: 'response',\n method: pending.method,\n error: { code: ErrorCode.peerDisconnected, message },\n });\n }\n this._replyError(\n pending.origin,\n pending.originalId,\n ErrorCode.peerDisconnected,\n message,\n );\n };\n try {\n Promise.resolve(target.send(forwarded)).catch(onSendError);\n } catch (error) {\n onSendError(error);\n }\n }\n\n private _routeNotification(from: IMessageTransport, note: JsonRpcMessage): void {\n const method = (note as { method: string; }).method;\n const params = (note as { params?: unknown; }).params as JsonValue | undefined;\n const res = this._resolve(method, from);\n const target = res.kind === 'malformed' ? undefined : res.link;\n // Notifications cannot be answered; silently drop when unroutable.\n if (target) {\n if (this._transitObservers.size !== 0) {\n this._emit({\n timeMs: Date.now(),\n nodeId: this.nodeId,\n in: this._transitEndpoint(from),\n out: this._transitEndpoint(target),\n disposition: 'forwarded',\n kind: 'notification',\n method,\n params,\n });\n }\n void target.send(note);\n } else {\n if (this._transitObservers.size !== 0) {\n this._emit({\n timeMs: Date.now(),\n nodeId: this.nodeId,\n in: this._transitEndpoint(from),\n disposition: res.kind === 'malformed' ? 'unroutable' : 'dropped',\n kind: 'notification',\n method,\n params,\n });\n }\n this._log?.trace(`${this._tag()}drop unroutable notification '${method}'`);\n }\n }\n\n private _demux(from: IMessageTransport, res: JsonRpcResponse): void {\n if (res.id === null) return;\n const key = String(res.id);\n const pending = this._pending.get(key);\n if (!pending) return; // unknown / late response — drop\n // Only the link the request was forwarded to may answer it. This\n // blocks a malicious downstream from forging a reply (with a guessed\n // sequential id) to a request routed to a different link.\n if (from !== pending.target) return;\n this._deletePending(key);\n if (this._transitObservers.size !== 0) {\n this._emit({\n timeMs: Date.now(),\n nodeId: this.nodeId,\n in: this._transitEndpoint(pending.target, res.id),\n out: this._transitEndpoint(pending.origin, pending.originalId),\n disposition: 'forwarded',\n kind: 'response',\n method: pending.method,\n result: (res as { result?: JsonValue; }).result,\n error: (res as { error?: TransitError; }).error,\n });\n }\n void pending.origin.send({ ...res, id: pending.originalId });\n }\n\n /**\n * Route a `$stream::send` notification. Unlike an ordinary notification, a\n * stream message is **correlated to an in-flight request by `requestId`**,\n * not addressed by method name — so it follows the same path the request\n * established (recorded in {@link _pending}), exactly like a\n * {@link _demux | response}, and the hub rewrites `requestId` across the\n * forwarding boundary the same way it rewrites a response `id`.\n *\n * The message's explicit `dir` picks the traversal — no inference from the\n * arriving link:\n *\n * - **`toCaller`** (callee → caller progress): routed like a response. The\n * streamer used the hub-rewritten id it *received*, so `requestId` is a\n * pending hub id; only the link the request was forwarded to may stream\n * on it. Restore the origin's original id and forward to the origin.\n * - **`toCallee`** (caller → callee input / cancel / ping): the reverse\n * traversal of the same entry. The streamer used the original id it\n * *sent*; rewrite `requestId` to the hub id the target was handed and\n * forward to the target. Only the origin may stream this direction.\n *\n * Every routed stream message resets the request's idle timer (a keepalive\n * ping is exactly a `toCallee` control with no payload). A `$stream::send`\n * matching no in-flight request is dropped (late / unknown correlation).\n */\n private _routeStream(from: IMessageTransport, note: JsonRpcMessage): void {\n const p = _streamParams(note);\n if (!p || p.requestId === undefined) {\n this._log?.trace(`${this._tag()}drop malformed '${STREAM_METHOD}' (no requestId)`);\n return;\n }\n if (p.dir === StreamDir.toCaller) {\n // Like a response: keyed by the hub-rewritten id; only the link the\n // request was forwarded to may stream back toward the caller.\n const key = String(p.requestId);\n const pending = this._pending.get(key);\n if (!pending || from !== pending.target) {\n this._log?.trace(\n `${this._tag()}drop unroutable toCaller '${STREAM_METHOD}' requestId=${String(p.requestId)}`,\n );\n return;\n }\n this._resetIdle(key);\n void pending.origin.send(_withRequestId(note, pending.originalId));\n this._emitStream(\n note,\n this._transitEndpoint(pending.target, p.requestId),\n this._transitEndpoint(pending.origin, pending.originalId),\n );\n return;\n }\n // toCallee: reverse traversal. The origin streams with the id it sent;\n // rewrite `requestId` to the hub-local id the target was handed.\n for (const [hubId, pending] of this._pending) {\n if (pending.origin === from && String(pending.originalId) === String(p.requestId)) {\n this._resetIdle(hubId);\n void pending.target.send(_withRequestId(note, Number(hubId)));\n this._emitStream(\n note,\n this._transitEndpoint(pending.origin, p.requestId),\n this._transitEndpoint(pending.target, Number(hubId)),\n );\n return;\n }\n }\n this._log?.trace(\n `${this._tag()}drop unroutable toCallee '${STREAM_METHOD}' requestId=${String(p.requestId)}`,\n );\n }\n\n // -- pending lifecycle ------------------------------------------\n\n /** Delete a pending entry and clear its idle timer. */\n private _deletePending(key: string): void {\n const p = this._pending.get(key);\n if (!p) return;\n if (p.timer !== undefined) clearTimeout(p.timer);\n this._pending.delete(key);\n }\n\n /** Arm (or re-arm) the idle timer for a pending entry. No-op when disabled. */\n private _armIdle(key: string): void {\n if (this._idleMs <= 0) return;\n const t = setTimeout(() => this._onIdleTimeout(key), this._idleMs);\n (t as { unref?: () => void; }).unref?.();\n const p = this._pending.get(key);\n if (p) p.timer = t;\n else clearTimeout(t);\n }\n\n /** Reset the idle timer on stream activity. */\n private _resetIdle(key: string): void {\n const p = this._pending.get(key);\n if (!p) return;\n if (p.timer !== undefined) clearTimeout(p.timer);\n this._armIdle(key);\n }\n\n /**\n * A request went idle past {@link _idleMs}. Cancel the (presumably hung)\n * callee, fail the caller with a `requestTimeout`, and drop the entry —\n * the bound that keeps `_pending` from growing without limit.\n */\n private _onIdleTimeout(key: string): void {\n const p = this._pending.get(key);\n if (!p) return;\n this._log?.warn(`${this._tag()}request idle-timed-out (hubId=${key}); cancelling + failing origin`);\n this._injectCancel(p.target, key, StreamControlReason.idleTimeout);\n this._deletePending(key);\n if (this._transitObservers.size !== 0) {\n this._emit({\n timeMs: Date.now(),\n nodeId: this.nodeId,\n in: this._transitEndpoint(p.target, key),\n out: this._transitEndpoint(p.origin, p.originalId),\n disposition: 'forwarded',\n kind: 'response',\n method: p.method,\n error: { code: ErrorCode.requestTimeout, message: 'request idle-timed-out' },\n });\n }\n this._replyError(\n p.origin,\n p.originalId,\n ErrorCode.requestTimeout,\n 'request idle-timed-out',\n );\n }\n\n /**\n * Author a `toCallee` cancel toward `target` for the request the target\n * knows as `hubId`. Used on caller-disconnect and idle-timeout — the hub\n * itself originates the message, which is why `dir` is explicit on the\n * wire (there is no inbound link to infer it from).\n */\n private _injectCancel(target: IMessageTransport, hubId: string, reason: string): void {\n const params: StreamSendParams = {\n requestId: Number(hubId),\n dir: StreamDir.toCallee,\n control: { type: StreamControlType.cancel, reason },\n };\n try {\n Promise.resolve(\n target.send({ jsonrpc: '2.0', method: STREAM_METHOD, params } as unknown as JsonRpcMessage),\n ).catch(() => undefined);\n } catch {\n // Best-effort cancellation during teardown/timeout.\n }\n }\n\n // -- error replies ----------------------------------------------\n\n private _noTargetCode(res: Resolution): number {\n return res.kind === 'malformed' ? ErrorCode.invalidRequest : ErrorCode.methodNotFound;\n }\n\n private _noTargetMessage(res: Resolution, method: string): string {\n switch (res.kind) {\n case 'malformed':\n return `malformed method name: ${method}`;\n case 'loopback':\n return `no local root services to handle: ${method}`;\n case 'uplink':\n return `no route for: ${method}`;\n default:\n return `unroutable: ${method}`;\n }\n }\n\n private _replyError(to: IMessageTransport, id: RequestId, code: number, message: string): void {\n const error: JsonRpcResponse = {\n jsonrpc: '2.0',\n id,\n error: this._options.debugName !== undefined ?\n { code, message, data: { hub: this._options.debugName } } :\n { code, message },\n };\n void to.send(error);\n }\n}\n\n/** Read the params off a {@link STREAM_METHOD} notification. */\nfunction _streamParams(m: JsonRpcMessage): StreamSendParams | undefined {\n const params = (m as { params?: unknown; }).params;\n if (params === null || typeof params !== 'object') return undefined;\n return params as StreamSendParams;\n}\n\n/** Clone a {@link STREAM_METHOD} notification with `requestId` replaced. */\nfunction _withRequestId(m: JsonRpcMessage, requestId: RequestId): JsonRpcMessage {\n const params = { ...(m as { params?: object; }).params, requestId };\n return { ...m, params } as JsonRpcMessage;\n}\n","import {\n BoundedTrafficSubscription,\n TrafficWatchFlowTracker,\n} from '@hediet/linkrpc/inspection';\nimport type {\n TrafficEvent,\n TrafficSubscription,\n TrafficSubscriptionOptions,\n TrafficTransitEvent,\n} from '@hediet/linkrpc/inspection';\nimport type { NodeTransit, TransitEndpoint } from './nodeTransit';\nimport type { Hub, IDisposable } from './routing/routingHub';\n\nexport interface HubTrafficWatchOptions extends TrafficSubscriptionOptions {}\n\nexport interface HubTrafficSubscription extends IDisposable, TrafficSubscription {}\n\nexport interface HubTrafficSource {\n observe(observer: (transit: TrafficTransitEvent) => void): IDisposable;\n}\n\ninterface RegisteredTrafficSource {\n readonly source: HubTrafficSource;\n observation?: IDisposable;\n}\n\n/** Publishes dynamically observed raw node transits through bounded traffic streams. */\nexport class HubInspector implements IDisposable {\n private readonly _subscribers = new Set<BoundedTrafficSubscription>();\n private readonly _trafficSources = new Set<RegisteredTrafficSource>();\n private readonly _trafficWatches = new TrafficWatchFlowTracker();\n private readonly _observation: IDisposable;\n\n constructor(private readonly _hub: Hub) {\n this._observation = this._hub.observeTransits((transit) => {\n this._onTransit(transit);\n });\n }\n\n public get observerCount(): number {\n return this._subscribers.size;\n }\n\n public subscribe(\n options: HubTrafficWatchOptions,\n send: (event: TrafficEvent) => Promise<void>,\n ): HubTrafficSubscription {\n if (\n options.trafficIgnoreKey !== undefined\n && !this._trafficWatches.claim(options.trafficIgnoreKey)\n ) {\n throw new Error('Traffic watch request was not observed before subscription');\n }\n const subscriber = new BoundedTrafficSubscription(options, send, () => {\n this._subscribers.delete(subscriber);\n if (this._subscribers.size === 0) this._stopTrafficSources();\n });\n if (this._subscribers.size === 0) this._startTrafficSources();\n this._subscribers.add(subscriber);\n return subscriber;\n }\n\n public dispose(): void {\n for (const subscriber of [...this._subscribers]) subscriber.dispose();\n this._subscribers.clear();\n this._observation.dispose();\n this._trafficWatches.clear();\n this._stopTrafficSources();\n this._trafficSources.clear();\n }\n\n /** Add an endpoint traffic source managed by this Hub inspection service. */\n public addTrafficSource(source: HubTrafficSource): IDisposable {\n const registered: RegisteredTrafficSource = { source };\n this._trafficSources.add(registered);\n if (this._subscribers.size !== 0) this._startTrafficSource(registered);\n let disposed = false;\n return {\n dispose: () => {\n if (disposed) return;\n disposed = true;\n this._trafficSources.delete(registered);\n registered.observation?.dispose();\n registered.observation = undefined;\n },\n };\n }\n\n private _startTrafficSources(): void {\n for (const source of this._trafficSources) this._startTrafficSource(source);\n }\n\n private _startTrafficSource(source: RegisteredTrafficSource): void {\n source.observation ??= source.source.observe((transit) => this._emitTransit(transit));\n }\n\n private _stopTrafficSources(): void {\n for (const source of this._trafficSources) {\n source.observation?.dispose();\n source.observation = undefined;\n }\n }\n\n private _onTransit(transit: NodeTransit): void {\n const event: TrafficTransitEvent = {\n type: 'transit',\n timeMs: transit.timeMs,\n nodeId: transit.nodeId,\n ...(transit.in !== undefined ? { in: normalizeEndpoint(transit.in) } : {}),\n ...(transit.out !== undefined ? { out: normalizeEndpoint(transit.out) } : {}),\n disposition: transit.disposition,\n kind: transit.kind,\n method: transit.method,\n params: transit.params,\n result: transit.result,\n error: transit.error,\n };\n if (this._trafficWatches.accept(event)) return;\n if (this._subscribers.size !== 0) this._emitTransit(event);\n }\n\n private _emitTransit(transit: TrafficTransitEvent): void {\n for (const subscriber of this._subscribers) subscriber.enqueue(transit);\n }\n}\n\nfunction normalizeEndpoint(endpoint: TransitEndpoint) {\n return {\n edgeId: endpoint.edgeId,\n portId: endpoint.portId ?? endpoint.edgeId,\n ...(endpoint.requestId !== undefined ? { requestId: endpoint.requestId } : {}),\n };\n}\n","import { isNotification, isRequest, isResponse } from '@hediet/linkrpc';\nimport type {\n MessageWithCtx, IMessageTransport,\n JsonRpcMessage,\n RequestId\n} from '@hediet/linkrpc';\nimport type { JsonValue } from '@hediet/linkrpc';\nimport { parseMethodName } from '@hediet/linkrpc';\nimport { STREAM_METHOD, StreamDir } from '@hediet/linkrpc';\nimport type { NodeTransit, NodeTransitObserver, TransitError, TransitKind } from '../nodeTransit';\n\n/** Which upstream port an inbound-to-participant request came from. */\ntype Origin = 'H' | 'C';\n\n/** Separator for return-path tags. NUL never appears in JSON-RPC ids. */\nconst SEP = '\\u0000';\n\n/**\n * Inspection wiring for an {@link OverlaySplitter}. When supplied, the splitter\n * emits a {@link NodeTransit} for every message it routes. The three port edge\n * ids name the splitter's own edges; **`edges.h` must equal the parent hub\n * link's `edgeId`** so a {@link TransitAggregator} chains the splitter's and\n * hub's transits across the shared boundary (the splitter forwards request ids\n * verbatim there, so the `(edgeId, requestId)` endpoints line up).\n */\nexport interface OverlaySplitterInspection {\n readonly nodeId: string;\n readonly onTransit: NodeTransitObserver;\n readonly edges: { readonly p: string; readonly c: string; readonly h: string; };\n}\n\n/**\n * A fixed three-port message splitter — the per-participant primitive that\n * replaces a nested {@link import('./routingHub').Hub} inside a\n * {@link import('./rootOverlay').RootOverlay}.\n *\n * Ports:\n * - **P** — the participant (downstream connection),\n * - **C** — the local root-services connection (`hubServiceIdRegistry::registerServiceId`,\n * `hubrpc.directory`, `identity::*`, …),\n * - **H** — the uplink to the parent hub.\n *\n * Routing rules (verbatim to the design):\n * ```\n * P·root → C P·* → H\n * H·* → P H·root → P\n * C·* → P\n * ```\n * where `root` means a bare/interface-form method and `*` a fully-qualified\n * (`serviceId::…`) method. Responses follow the reverse path. `H·root → P`\n * lets the parent hub reach the participant's *own* root services (e.g. the\n * participant-served root directory) — distinct from `P·root → C`, which is\n * the participant *consuming* the overlay's root services; the two are\n * opposite directions served by different connections, so they never collide.\n *\n * ### `$stream::send` — correlated by `requestId`, not by method form\n *\n * A {@link STREAM_METHOD} (`$stream::send`) notification is *interface-form*\n * (`$stream::send`), so the method-form rules above would naively treat it as\n * `root` and send a participant's stream to **C** (and route an inbound one as\n * a root call to **P**). That is wrong: a stream message belongs to an in-flight\n * request's lifetime and must follow **that request's** path, exactly like a\n * response does. So `$stream::send` bypasses the method-form table and is\n * routed like a response instead:\n *\n * - **P → ?**: the participant streams using the `requestId` it *observed*,\n * which for a request it serves is the tag the splitter stamped on the\n * delivered request id (`H\\0…` / `C\\0…`). We {@link _decodeId | decode} that\n * tag, restore the original id, and forward to the tagged origin (H or C) —\n * the same demux responses get. An **untagged** `requestId` means the\n * participant *initiated* the request (P→H or P→C); we cannot tell which\n * statelessly, so we default to the **uplink** (the common case: streaming\n * to a fully-qualified service via the parent).\n * - **H/C → P**: forwarded verbatim to the participant (never dropped), as a\n * response would be — the parent has already restored P's original\n * `requestId`, symmetric to response-id rewriting.\n *\n * PARTICIPANT-INITIATED STREAMS — the one stateful case: because `requestId`\n * lives in `params` (not a structural top-level id the splitter rewrites in\n * lock-step), a stream frame for a request the participant *initiated* (`P→C`\n * or `P→H`) carries P's *own untagged* id, which alone cannot say whether the\n * call went to the root (C) or the uplink (H). The splitter therefore keeps a\n * small `requestId → target` map ({@link _pInitiated}), populated when P sends\n * such a request and cleared when its response returns, and consults it to\n * route those frames. This is the splitter's *only* per-request state; every\n * other path still routes statelessly via id-tagging.\n *\n * ### Stateless demux via id-tagging\n *\n * P is the only port that receives requests from *two* sources (H and C),\n * so a response from P is ambiguous and ids can collide (`H` and `C` may\n * each send `id:5`). Rather than a pending-request map (with its attendant\n * timeout/leak problem), the splitter rewrites **only requests destined for\n * P**, prepending the origin and original id type to the id:\n *\n * ```\n * H→P: id' = \"H\\0n\\042\" (push origin tag)\n * C→P: id' = \"C\\0s\\0abc\"\n * P→?: decode id' → route to H or C, restore the original id\n * ```\n *\n * Every other edge (P→H, P→C and the responses coming back from H/C to P)\n * passes **verbatim** — those targets each have a single peer, so there is no\n * response ambiguity. The sole exception is *stream* frames for\n * participant-initiated requests, whose target is recovered from the small\n * {@link _pInitiated} map (see above); apart from that the id encodes its own\n * return path.\n *\n * NOTE: unlike the central {@link import('./routingHub').Hub}, the tag is\n * not authenticated. A misbehaving participant could emit a forged tagged\n * response toward H or C; each endpoint still drops ids it has no pending\n * request for, and identity/signing live in a higher layer. For the\n * single-participant overlay this is an acceptable trade for being fully\n * stateless. If unforgeable return paths are ever required here, HMAC the\n * tag with a splitter-private secret.\n */\nexport class OverlaySplitter<TContext = undefined> {\n private _disposed = false;\n private readonly _inspect: OverlaySplitterInspection | undefined;\n /**\n * Per-request routing target (`C` or `H`) for requests the participant\n * *initiated*, keyed by P's own request id. Streams for those requests\n * carry P's untagged id, which alone can't say whether the call went to the\n * root (C) or the uplink (H); this map recovers it. Populated when P sends\n * the request, cleared when its response returns. The splitter's only\n * per-request state — every other path routes statelessly via id-tagging.\n */\n private readonly _pInitiated = new Map<RequestId, {\n readonly target: 'C' | 'H';\n }>();\n\n constructor(\n private readonly _participant: IMessageTransport<MessageWithCtx<TContext>>,\n private readonly _root: IMessageTransport<JsonRpcMessage, MessageWithCtx<TContext>>,\n private readonly _uplink: IMessageTransport,\n inspection?: OverlaySplitterInspection,\n ) {\n this._inspect = inspection;\n this._participant.setListener((m) => this._onFromParticipant(m));\n this._root.setListener((m) => this._onFromUpstream(m, 'C'));\n this._uplink.setListener((m) => this._onFromUpstream(m, 'H'));\n }\n\n /** Detach all three ports. Does not dispose the transports themselves. */\n public dispose(): void {\n if (this._disposed) return;\n this._disposed = true;\n this._participant.setListener(undefined);\n this._root.setListener(undefined);\n this._uplink.setListener(undefined);\n this._pInitiated.clear();\n }\n\n /** Edge id of an upstream origin port. */\n private _originEdge(origin: Origin): string {\n return origin === 'H' ? this._inspect!.edges.h : this._inspect!.edges.c;\n }\n\n /** Emit a node transit if inspection is enabled. Zero-cost otherwise. */\n private _emit(t: NodeTransit): void {\n if (this._inspect) this._inspect.onTransit(t);\n }\n\n private _onFromParticipant(m: MessageWithCtx<TContext>): void {\n if (isResponse(m)) {\n // Answer to a tagged inbound request — route by the return tag.\n if (m.id === null) return;\n const dec = _decodeId(m.id);\n if (!dec) return; // untagged response from P → unexpected, drop\n if (dec.origin === 'H') {\n if (this._inspect) {\n this._emit(this._mkResponse(this._inspect.edges.p, m.id, this._inspect.edges.h, dec.id, m));\n }\n void this._uplink.send({ ...m, id: dec.id });\n } else {\n if (this._inspect) {\n this._emit(this._mkResponse(this._inspect.edges.p, m.id, this._inspect.edges.c, dec.id, m));\n }\n // An ordinary context-stamping transport uses an enumerable\n // `context`; the spread preserves its value while the cast\n // restores the typed root port's static witness.\n void this._root.send({ ...m, id: dec.id } as MessageWithCtx<TContext>);\n }\n return;\n }\n const method = _methodOf(m);\n if (method === undefined) return;\n // `$stream::send` is correlated by `requestId`, not by method form:\n // route it like a response (see the class doc), never by the table.\n if (method === STREAM_METHOD) {\n this._routeParticipantStream(m);\n return;\n }\n const rootForm = _isRootForm(method);\n if (rootForm === undefined) {\n // malformed method → drop (no port to route to).\n if (this._inspect) {\n this._emit(this._mkForward(this._inspect.edges.p, m, undefined, method, 'dropped'));\n }\n return;\n }\n // root-form → local root services (C); prefixed → parent (H). The context\n // stamp (if any) rides along verbatim so the root connection can read it.\n // Remember the resolved target for a participant-initiated *request* so\n // its (untagged) stream frames can be routed back to the same port.\n if (rootForm) {\n if (this._inspect) {\n this._emit(this._mkForward(this._inspect.edges.p, m, this._inspect.edges.c, method, 'forwarded'));\n }\n if (isRequest(m)) this._pInitiated.set(m.id, { target: 'C' });\n void this._root.send(m);\n } else {\n if (this._inspect) {\n this._emit(this._mkForward(this._inspect.edges.p, m, this._inspect.edges.h, method, 'forwarded'));\n }\n if (isRequest(m)) this._pInitiated.set(m.id, { target: 'H' });\n void this._uplink.send(m);\n }\n }\n\n /**\n * Route a participant-emitted `$stream::send` by its `requestId` tag,\n * mirroring how a {@link _onFromParticipant | response} is demuxed. The\n * participant streams with the id it *observed*; for a request it serves\n * that id carries the origin tag the splitter stamped, so decoding it\n * yields the return port and the original id. Untagged → a request the\n * participant *initiated*; recover its target (C or H) from {@link\n * _pInitiated}, defaulting to the uplink.\n */\n private _routeParticipantStream(m: MessageWithCtx<TContext>): void {\n const requestId = _streamRequestId(m);\n const dec = requestId !== undefined ? _decodeId(requestId) : undefined;\n if (dec) {\n const restored = _withRequestId(m, dec.id);\n if (dec.origin === 'H') {\n void this._uplink.send(restored);\n } else {\n void this._root.send(restored as MessageWithCtx<TContext>);\n }\n return;\n }\n // Untagged → participant-initiated request: its id is P's own, so the\n // form-derived target was recorded when the request was forwarded.\n const initiated = requestId !== undefined ? this._pInitiated.get(requestId) : undefined;\n if (initiated?.target === 'C') {\n void this._root.send(m as MessageWithCtx<TContext>);\n return;\n }\n void this._uplink.send(m);\n }\n\n private _onFromUpstream(m: JsonRpcMessage, origin: Origin): void {\n if (isResponse(m)) {\n // Answer to a participant-initiated request — verbatim to P. The\n // request is now complete, so drop its stream-routing entry.\n const initiated = m.id === null ? undefined : this._pInitiated.get(m.id);\n if (m.id !== null) this._pInitiated.delete(m.id);\n if (this._inspect) {\n this._emit(this._mkResponse(this._originEdge(origin), m.id, this._inspect.edges.p, m.id, m));\n }\n void this._participant.send(m);\n return;\n }\n const method = _methodOf(m);\n if (method === undefined) return;\n // `$stream::send` is correlated by `requestId`, not by method form, so\n // it must reach the participant like a response — never be dropped by\n // the malformed-drop rule below. For a request this overlay forwarded\n // *to* the participant (participant is the callee), the participant\n // observes that request under an origin-encoded id, so an inbound\n // `toCallee` frame must be re-tagged with the same encoded id to match\n // the participant's stream listener. A `toCaller` frame answers a\n // participant-initiated request and keeps the participant's own id.\n if (method === STREAM_METHOD) {\n if (_streamDir(m) === StreamDir.toCallee) {\n const requestId = _streamRequestId(m);\n if (requestId !== undefined) {\n void this._participant.send(_withRequestId(m, _encodeId(origin, requestId)));\n return;\n }\n }\n void this._participant.send(m);\n return;\n }\n // Malformed → drop (no port to route to). Everything well-formed from H\n // or C reaches P: prefixed H·* → P, root-form H·root → P (the\n // participant serves its own root services), and all C·* → P.\n if (_isRootForm(method) === undefined) {\n if (this._inspect) {\n this._emit(this._mkForward(this._originEdge(origin), m, undefined, method, 'dropped'));\n }\n return;\n }\n\n if (isRequest(m)) {\n const encodedId = _encodeId(origin, m.id);\n if (this._inspect) {\n this._emit(this._mkForward(this._originEdge(origin), m, this._inspect.edges.p, method, 'forwarded', encodedId));\n }\n void this._participant.send({ ...m, id: encodedId });\n } else if (isNotification(m)) {\n if (this._inspect) {\n this._emit(this._mkForward(this._originEdge(origin), m, this._inspect.edges.p, method, 'forwarded'));\n }\n void this._participant.send(m);\n }\n }\n\n /** Build a request/notification transit (`out` absent ⇒ dropped here). */\n private _mkForward(\n inEdge: string,\n m: JsonRpcMessage,\n outEdge: string | undefined,\n method: string,\n disposition: 'forwarded' | 'dropped',\n outRequestId?: RequestId,\n ): NodeTransit {\n const id = (m as { id?: RequestId; }).id;\n const isReq = isRequest(m);\n const inEp = { edgeId: inEdge, ...(isReq && id !== undefined ? { requestId: id } : {}) };\n const outEp = outEdge === undefined\n ? undefined\n : { edgeId: outEdge, ...(isReq ? { requestId: outRequestId ?? id } : {}) };\n return {\n timeMs: Date.now(),\n nodeId: this._inspect!.nodeId,\n in: inEp,\n out: outEp,\n disposition,\n kind: (isReq ? 'request' : 'notification') as TransitKind,\n method,\n params: (m as { params?: JsonValue; }).params,\n };\n }\n\n /** Build a response transit crossing from `inEdge`/`inId` to `outEdge`/`outId`. */\n private _mkResponse(\n inEdge: string,\n inId: RequestId | null,\n outEdge: string,\n outId: RequestId | null,\n m: JsonRpcMessage,\n ): NodeTransit {\n return {\n timeMs: Date.now(),\n nodeId: this._inspect!.nodeId,\n in: { edgeId: inEdge, ...(inId !== null ? { requestId: inId } : {}) },\n out: { edgeId: outEdge, ...(outId !== null ? { requestId: outId } : {}) },\n disposition: 'forwarded',\n kind: 'response',\n result: (m as { result?: JsonValue; }).result,\n error: (m as { error?: TransitError; }).error,\n };\n }\n}\n\nfunction _methodOf(m: JsonRpcMessage): string | undefined {\n const method = (m as { method?: unknown; }).method;\n return typeof method === 'string' ? method : undefined;\n}\n\n/** Read the `requestId` correlator off a `$stream::send` notification. */\nfunction _streamRequestId(m: JsonRpcMessage): RequestId | undefined {\n const params = (m as { params?: unknown; }).params;\n if (params === null || typeof params !== 'object') return undefined;\n const requestId = (params as { requestId?: unknown; }).requestId;\n return typeof requestId === 'number' || typeof requestId === 'string' ? requestId : undefined;\n}\n\n/** Read the `dir` discriminator off a `$stream::send` notification. */\nfunction _streamDir(m: JsonRpcMessage): StreamDir | undefined {\n const params = (m as { params?: unknown; }).params;\n if (params === null || typeof params !== 'object') return undefined;\n const dir = (params as { dir?: unknown; }).dir;\n return dir === StreamDir.toCaller || dir === StreamDir.toCallee ? dir : undefined;\n}\n\n/** Clone a `$stream::send` notification with `requestId` replaced (id restore). */\nfunction _withRequestId(m: JsonRpcMessage, requestId: RequestId): JsonRpcMessage {\n const params = { ...(m as { params?: object; }).params, requestId };\n return { ...m, params } as JsonRpcMessage;\n}\n\n/** `true` for bare/interface form, `false` for fully-qualified, `undefined` if malformed. */\nfunction _isRootForm(method: string): boolean | undefined {\n const p = parseMethodName(method);\n if (!p) return undefined;\n return p.kind === 'bare' || p.kind === 'interface';\n}\n\nfunction _encodeId(origin: Origin, id: RequestId): string {\n const type = typeof id === 'number' ? 'n' : 's';\n return `${origin}${SEP}${type}${SEP}${String(id)}`;\n}\n\nfunction _decodeId(id: RequestId | null): { origin: Origin; id: RequestId; } | undefined {\n if (typeof id !== 'string') return undefined;\n const i1 = id.indexOf(SEP);\n if (i1 < 0) return undefined;\n const origin = id.slice(0, i1);\n if (origin !== 'H' && origin !== 'C') return undefined;\n const i2 = id.indexOf(SEP, i1 + 1);\n if (i2 < 0) return undefined;\n const type = id.slice(i1 + 1, i2);\n const raw = id.slice(i2 + 1);\n return { origin, id: type === 'n' ? Number(raw) : raw };\n}\n","import {\n type MessageWithCtx,\n type ChannelTransport,\n type IMessageTransport,\n type JsonRpcMessage,\n LinkRpcConnection,\n TransportPair,\n} from '@hediet/linkrpc';\nimport { nodeInterface, type TopologyTransportInfo } from '@hediet/linkrpc/inspection';\nimport { randomUUID } from 'node:crypto';\nimport { OverlaySplitter, type OverlaySplitterInspection } from './overlaySplitter';\nimport type { ManagedRoutingTopology } from './routingTopology';\n\nexport interface RootOverlayOptions {\n /**\n * The uplink transport to the parent hub. The overlay forwards all\n * prefixed (`serviceId::…`) participant traffic here and receives the\n * parent's routed traffic back. Obtain it from `parentHub.attach(pair.b)`\n * and pass `pair.a`.\n */\n readonly uplink: IMessageTransport;\n /**\n * Optional inspection wiring forwarded to the underlying\n * {@link OverlaySplitter}. Set `edges.h` to the parent hub link's `edgeId`\n * (from `parentHub.attach(...).edgeId`) so transits chain across the\n * boundary.\n */\n readonly inspection?: OverlaySplitterInspection;\n /** Parent-facing topology port. Defaults to a generated connection-lifetime id. */\n readonly uplinkPortId?: string;\n}\n\n/**\n * A **RootOverlay** is the per-participant front door. It is a pure\n * {@link OverlaySplitter} wiring with no routing table, no nested hub, and —\n * deliberately — **no knowledge of which services it serves**. It exposes:\n *\n * - {@link root} — the connection serving this participant's root services.\n * Install bootstrap/identity modules onto it with `registerHubServices` /\n * `registerIdentityServices` *before or after* connecting the participant.\n * - {@link connectParticipant} — wires the downstream participant through the\n * splitter (`P·root → root`, `P·* → uplink`, `uplink·* → P`).\n *\n * Because an overlay represents exactly one participant, prefix claims happen\n * only on the parent (via the {@link import('./routingHub').AttachedLink} that\n * `registerHubServices` was given); there is no local table to write.\n *\n * The overlay is generic over the per-call `TContext` its {@link root}\n * connection sees. Pass a context-stamping {@link ChannelTransport} to\n * {@link connectParticipant} to attach per-call context. Most callers connect a\n * plain (or signature-verifying) transport and leave `TContext` as `undefined`\n * (context-free).\n */\nexport class RootOverlay<TContext = undefined> {\n /**\n * The per-participant root connection. Register the overlay's root\n * services here — e.g. `registerHubServices(overlay.root, upstream)` and\n * `registerIdentityServices(overlay.root, { resolveIdentity })`. Reachable\n * only by this overlay's participant (root-addressed calls land here).\n *\n * Its inbound transport carries the overlay's `TContext`, so identity-aware\n * front doors — notably the consent `hubAccess` service — can be served here\n * for the interface-form calls a participant addresses to its own root.\n */\n public readonly root: LinkRpcConnection<TContext>;\n public readonly nodeId = `overlay:${randomUUID()}`;\n public readonly participantPortId = `port:${randomUUID()}`;\n public readonly rootPortId = `port:${randomUUID()}`;\n public readonly rootNodeId = `endpoint:${randomUUID()}`;\n public readonly uplinkPortId: string;\n\n private readonly _uplink: IMessageTransport;\n private readonly _rootPair: TransportPair<MessageWithCtx<TContext>, JsonRpcMessage>;\n private readonly _inspection: OverlaySplitterInspection | undefined;\n private _splitter: OverlaySplitter<TContext> | undefined;\n private _disposed = false;\n\n constructor(options: RootOverlayOptions) {\n this._uplink = options.uplink;\n this._inspection = options.inspection;\n this.uplinkPortId = options.uplinkPortId ?? `port:${randomUUID()}`;\n this._rootPair = new TransportPair<MessageWithCtx<TContext>, JsonRpcMessage>();\n this.root = LinkRpcConnection.fromTransport<TContext>(this._rootPair.b);\n this.root.register(nodeInterface, {\n getNodeId: () => ({\n nodeId: this.nodeId,\n portId: this.participantPortId,\n }),\n });\n }\n\n public managedTopology(\n edgeLabel?: string,\n peerTransport?: TopologyTransportInfo,\n ): ManagedRoutingTopology {\n return {\n node: {\n nodeId: this.nodeId,\n kind: 'hub',\n label: 'Root overlay',\n ports: [\n { portId: this.participantPortId, label: 'participant' },\n { portId: this.rootPortId, label: 'root' },\n { portId: this.uplinkPortId, label: 'uplink' },\n ],\n },\n hubLinks: [{\n hubPortId: this.uplinkPortId,\n nodePortId: this.uplinkPortId,\n ...(edgeLabel !== undefined ? { label: edgeLabel } : {}),\n }],\n peerPortId: this.participantPortId,\n ...(peerTransport !== undefined ? { peerTransport } : {}),\n adjacentNodes: [{\n nodeId: this.rootNodeId,\n kind: 'endpoint',\n label: 'Root services',\n ports: [{ portId: this.rootPortId }],\n }],\n adjacentLinks: [{\n from: { nodeId: this.nodeId, portId: this.rootPortId },\n to: { nodeId: this.rootNodeId, portId: this.rootPortId },\n }],\n };\n }\n\n /**\n * Connect the downstream participant. Root-addressed calls from it hit the\n * {@link root} services; prefixed calls forward via the uplink. May be\n * called once.\n *\n * Connect a context-stamping {@link ChannelTransport} when `TContext` is\n * concrete; otherwise connect the raw participant transport directly.\n */\n public connectParticipant(participant: IMessageTransport<MessageWithCtx<TContext>>): void {\n if (this._splitter) throw new Error('RootOverlay: participant already connected');\n this._splitter = new OverlaySplitter<TContext>(participant, this._rootPair.a, this._uplink, this._inspection);\n }\n\n /**\n * Tear the overlay down: detach the splitter and dispose the internal root\n * transport pair. The caller owns the uplink and the participant transport\n * and disposes them separately (disposing the uplink's\n * {@link import('./routingHub').AttachedLink} releases any claimed prefixes\n * on the parent). Idempotent.\n */\n public dispose(): void {\n if (this._disposed) return;\n this._disposed = true;\n this._splitter?.dispose();\n this._rootPair.a.dispose();\n this._rootPair.b.dispose();\n }\n}\n","import {\n directoryInterface,\n ErrorCode,\n type Identity,\n type ManagedIdentityStorageBackend,\n registerLazyIdentityOnOverlay,\n RpcError,\n schemasInterface,\n type RootPrincipalSet,\n type ServiceIdPattern,\n type LinkRpcConnection\n} from '@hediet/linkrpc';\nimport {\n hubGrantedServiceIdInterface,\n isServiceIdUnder,\n serviceIdMatchesScopes,\n type ServiceId,\n} from '@hediet/linkrpc/hub/common';\nimport type { AttachedLink } from './routing/routingHub';\n\nexport interface RegisterHubServicesOptions {\n /**\n * ServiceId under which the parent serves its global reflection services.\n * The overlay's directory listing *refers* world-view queries here.\n * Defaults to `'hub'`.\n */\n readonly hubServiceId?: string;\n /**\n * Absolute serviceId region this connection may claim freely (anything\n * at/under it, no capability needed), surfaced verbatim through\n * `hubGrantedServiceId::get` as `grantedServiceIdNamespace`. Typically the\n * connection's attested identity key. Defaults to `''` — \"claim nothing\n * freely\" — which still lets `authorizeClaim` admit claims.\n */\n readonly grantedServiceIdNamespace?: string;\n /**\n * Consulted in `hubGrantedServiceId::register` before the prefix is\n * claimed. Return `{ ok: false, reason }` to deny (surfaced to the\n * participant as an error). When omitted, claims default to \"must be within\n * `grantedServiceIdNamespace`\".\n */\n authorizeClaim?(requestedPrefix: ServiceId): { ok: true; } | { ok: false; reason: string; };\n}\n\n/**\n * Install a participant's **connection root services** onto its overlay root\n * connection `root`:\n *\n * - `hubGrantedServiceId::get` — the connection round-trip: reports the\n * `grantedServiceIdNamespace` this connection may claim freely.\n * - `hubGrantedServiceId::register` — claims a prefix on\n * `upstream` (the parent hub link) within the connection's granted namespace,\n * gated by `authorizeClaim` (default: namespace membership). Because an\n * overlay represents a single participant, *one* upstream claim suffices: all\n * prefixed traffic the parent routes to this overlay is for this participant,\n * so the {@link OverlaySplitter} delivers it without any local table.\n * - `hubrpc.directory::list` — by default a **referral** (own root interfaces\n * plus one row pointing at `<hubServiceId>::hubrpc.directory`); an\n * implementation is free to aggregate the parent's listing instead.\n * - `hubrpc.schemas::get` — schemas for this overlay's own root interfaces.\n *\n * The hub's consent front door (`hubAccess::*`) is installed separately at the\n * overlay root by {@link registerHubAccessService}; it needs no capability of\n * its own because the root is never forwarded.\n *\n * The overlay itself stays unaware of which services it serves; this is the\n * routing module that gives it its front door.\n */\nexport function registerHubServices(\n root: LinkRpcConnection<unknown>,\n upstream: AttachedLink,\n options: RegisterHubServicesOptions = {},\n): void {\n const hubServiceId = options.hubServiceId ?? 'hub';\n const grantedServiceIdNamespace = options.grantedServiceIdNamespace ?? '';\n const authorizeClaim = options.authorizeClaim;\n\n root.register(hubGrantedServiceIdInterface, {\n get: () => {\n return { grantedServiceIdNamespace };\n },\n\n getHubServiceId: () => {\n return { hubServiceId };\n },\n\n // Capability-free claim within the connection's provenance-granted\n // namespace. A single upstream claim suffices — the parent then routes\n // this prefix to the overlay, and the splitter forwards all such\n // traffic to the participant. Claims outside the namespace must go\n // through the admin-gated `hubServiceIdRegistry::registerServiceId`\n // door.\n register: ({ serviceId }) => {\n const verdict = authorizeClaim\n ? authorizeClaim(serviceId)\n : grantedServiceIdNamespace !== '' &&\n isServiceIdUnder(serviceId, grantedServiceIdNamespace)\n ? { ok: true as const }\n : {\n ok: false as const,\n reason:\n `\"${serviceId}\" is outside this connection's granted ` +\n `namespace \"${grantedServiceIdNamespace}\"`,\n };\n if (!verdict.ok) {\n throw new RpcError(`claim denied: ${verdict.reason}`, ErrorCode.invalidRequest);\n }\n upstream.addPrefixRoute(serviceId);\n return {};\n },\n });\n\n root.register(directoryInterface, {\n list: ({ interfaceId, interfaceIdPrefix, serviceId, serviceIdScopes }) => {\n const referral = {\n serviceId: hubServiceId,\n interfaceId: directoryInterface.info.id,\n interfaceHash: directoryInterface.schemaHash,\n // This is the connection's explicit entry point to the global\n // directory, which may list services outside the `hub` subtree.\n reachableServiceIds: [{ prefix: '' }] as const,\n };\n const items = [...root.listRegisteredInterfaces(), referral]\n .filter((it) => interfaceId === undefined || it.interfaceId === interfaceId)\n .filter((it) => interfaceIdPrefix === undefined || it.interfaceId.startsWith(interfaceIdPrefix))\n .filter((it) => serviceId === undefined || it.serviceId === serviceId)\n .filter((it) => serviceIdMatchesScopes(it.serviceId, serviceIdScopes))\n .map((it) => {\n const entry: {\n serviceId: string;\n interfaceId: string;\n interfaceHash: string;\n serviceDescription?: string;\n rootPrincipalSets?: RootPrincipalSet[];\n reachableServiceIds?: ServiceIdPattern[];\n } = {\n serviceId: it.serviceId,\n interfaceId: it.interfaceId,\n interfaceHash: it.interfaceHash,\n };\n const desc = (it as { serviceDescription?: string; }).serviceDescription;\n if (desc !== undefined) entry.serviceDescription = desc;\n const sets = (it as { rootPrincipalSets?: readonly RootPrincipalSet[]; }).rootPrincipalSets;\n if (sets !== undefined) entry.rootPrincipalSets = sets.map((s) => [...s]);\n const reachable = (it as { reachableServiceIds?: readonly ServiceIdPattern[]; })\n .reachableServiceIds;\n if (reachable !== undefined) entry.reachableServiceIds = [...reachable];\n return entry;\n });\n return { items };\n },\n watch: (_params, _ctx, stream) => new Promise<Record<string, never>>((resolve) => {\n if (stream.signal.aborted) {\n resolve({});\n return;\n }\n let pending = false;\n const flush = () => {\n pending = false;\n if (!stream.signal.aborted) void stream.send({}).catch(() => undefined);\n };\n const unsubscribe = root.onDidChangeDirectory(() => {\n if (pending) return;\n pending = true;\n queueMicrotask(flush);\n });\n stream.signal.addEventListener('abort', () => {\n unsubscribe();\n resolve({});\n }, { once: true });\n }),\n });\n\n root.register(schemasInterface, {\n get: ({ interfaceId, hash }) => {\n const iface = root.findRegisteredInterface(interfaceId, hash);\n if (!iface) {\n throw new RpcError(\n 'Interface not found',\n ErrorCode.methodNotFound,\n { reason: 'unknown-interface', interfaceId, hash },\n );\n }\n return { schema: iface.toSchema() as unknown };\n },\n });\n}\n\nexport interface RegisterIdentityServicesOptions {\n /**\n * Resolve the managed identity for this participant. Called **lazily** —\n * only when the participant first invokes `identity::*` — so registering\n * the service does not mint or load any key material (matches the consent\n * model: serving `identity::*` costs nothing until the participant opts in).\n */\n resolveIdentity(): Promise<Identity>;\n /**\n * Optional per-identity persistent key/value store, registered as\n * `identity.storage::*` alongside `identity::*`.\n */\n storage?: ManagedIdentityStorageBackend;\n}\n\n/**\n * Install `identity::*` (and optionally `identity.storage::*`) onto a\n * participant's overlay root connection. The identity is resolved lazily on\n * first use — see {@link registerLazyIdentityOnOverlay}.\n *\n * This is the identity counterpart to {@link registerHubServices}: a small,\n * composable module the overlay does not need to know about.\n */\nexport function registerIdentityServices(\n root: LinkRpcConnection<unknown>,\n options: RegisterIdentityServicesOptions,\n): void {\n registerLazyIdentityOnOverlay(root, options.resolveIdentity, options.storage);\n}\n","import {\n type ChannelTransport,\n ErrorCode,\n type LinkRpcConnection,\n type IMessageTransport,\n isRequest,\n type RequestId,\n RpcError,\n} from '@hediet/linkrpc';\nimport { hubServiceIdRegistryInterface } from '@hediet/linkrpc/hub/common';\nimport { validatePrefix } from './routing/forwardingTable';\nimport type { Hub } from './routing/routingHub';\n\n/**\n * Out-of-band, per-call context produced by {@link withRequestIdContext}. A\n * typed handler only ever sees the zod-stripped params (the `$hubrpc` envelope\n * and the wire id are gone), so the originating request's wire id is smuggled\n * alongside the message via the channel's `context` slot — never over a wire.\n *\n * The register handler uses it to resolve the link a forwarded claim arrived on\n * via {@link Hub.getSourceTransport}.\n */\nexport interface RegisterCallContext {\n /**\n * The hub-rewritten wire id of the inbound request, or `undefined` for\n * responses / notifications. Keyed lookups into\n * {@link Hub.getSourceTransport} use exactly this id.\n */\n readonly requestId: RequestId | undefined;\n}\n\n/**\n * Annotate an inbound transport so every request carries its wire id in a\n * {@link RegisterCallContext}. Synchronous and signature-agnostic: it neither\n * verifies signatures nor checks capabilities (that has already happened on the\n * forwarded path — see {@link registerHubServiceIdRegistry}). It exists only so\n * a hub-hosted handler can recover the request id the typed channel would\n * otherwise strip.\n */\nexport function withRequestIdContext(\n link: IMessageTransport,\n): ChannelTransport<RegisterCallContext> {\n return {\n send: (message) => link.send(message),\n setListener: (listener) => {\n if (listener === undefined) {\n link.setListener(undefined);\n return;\n }\n link.setListener((message) => {\n const requestId = isRequest(message) ? message.id : undefined;\n const contextual = { ...message, context: { requestId } };\n Object.defineProperty(contextual, 'context', { enumerable: false, writable: false });\n listener(contextual);\n });\n },\n dispose: () => link.dispose(),\n };\n}\n\nexport interface HubRegisterOptions {\n /** The central hub whose forwarding-table claims are written. */\n readonly hub: Hub;\n /** ServiceId the register endpoint (and the rest of the hub services) is mounted under. */\n readonly hubServiceId: string;\n}\n\n/**\n * Install the hub's privileged **claim front door** — the typed\n * `hubServiceIdRegistry::registerServiceId` handler — onto the hub services\n * `connection` (mounted under `hubServiceId`).\n *\n * Unlike the per-overlay `registerHubServices` front door — which only lets a\n * participant claim *within its provenance-granted namespace* — this endpoint\n * is the path for claiming a prefix **outside** that namespace.\n *\n * The handler is a **pure side effect**. Authentication (signature) and\n * authorization (an admin-rooted capability that permits\n * `hub::hubServiceIdRegistry::registerServiceId` for the requested\n * `requestedPrefix`) are enforced *before* the call ever reaches here, by the\n * {@link import('./forwardedCallGate').withForwardedCallGate forwarded-call\n * gate} every untrusted participant sits behind. By the time the request lands,\n * it is already known to be authentic and authorized, so the handler only:\n *\n * 1. validates the prefix is well-formed;\n * 2. resolves the link the request was forwarded from via\n * {@link Hub.getSourceTransport} (keyed by {@link RegisterCallContext.requestId});\n * and\n * 3. binds the prefix to that link via {@link Hub.claimPrefix}.\n *\n * The source transport answers only *where* to route the prefix, never\n * *whether* the claim is allowed.\n */\nexport function registerHubServiceIdRegistry(\n connection: LinkRpcConnection<RegisterCallContext>,\n options: HubRegisterOptions,\n): void {\n const { hub, hubServiceId } = options;\n\n connection.register(hubServiceIdRegistryInterface, {\n registerServiceId: async ({ requestedPrefix }, ctx) => {\n const prefixError = validatePrefix(requestedPrefix);\n if (prefixError) {\n throw new RpcError(prefixError, ErrorCode.invalidParams);\n }\n\n // Resolve the link this forwarded request originally arrived on. The\n // pending entry lives until the response flows, so it is still\n // available while this handler runs.\n const origin = ctx.requestId !== undefined\n ? hub.getSourceTransport(ctx.requestId)\n : undefined;\n if (origin === undefined) {\n // No pending entry — the request was not forwarded through the\n // hub (or already answered). Nothing to bind a claim to.\n throw new RpcError('no source link for claim', ErrorCode.invalidRequest);\n }\n\n try {\n hub.claimPrefix(origin, requestedPrefix);\n } catch (e) {\n throw new RpcError(\n e instanceof Error ? e.message : String(e),\n ErrorCode.invalidRequest,\n { prefix: requestedPrefix },\n );\n }\n\n return {};\n },\n }, { serviceId: hubServiceId });\n}\n","import {\n directoryInterface,\n directoryWatchNever,\n ErrorCode, nodeInterface,\n type RootPrincipalSet,\n type ServiceIdPattern,\n RpcError,\n schemasInterface,\n LinkRpcConnection\n} from '@hediet/linkrpc';\nimport type { StreamApi } from '@hediet/linkrpc';\nimport {\n topologyInterface,\n trafficInterface,\n type TrafficEvent,\n type TrafficWatchResult,\n type ParticipantDescriptorSource,\n} from '@hediet/linkrpc/inspection';\nimport { normalizeServiceIdScopes, serviceIdMatchesScopes } from '@hediet/linkrpc/hub/common';\nimport { HubInspector, type HubTrafficWatchOptions } from './hubInspector';\nimport { registerHubServiceIdRegistry, type RegisterCallContext, withRequestIdContext } from './hubRegister';\nimport type { Hub } from './routing/routingHub';\n\nexport interface HubServicesOptions {\n /** ServiceId the global services are mounted under. Defaults to `'hub'`. */\n readonly hubServiceId?: string;\n /** Optional diagnostic descriptor for the hub participant. */\n readonly descriptors?: readonly ParticipantDescriptorSource[];\n /** Runs before serving a global directory list or starting a directory watch. */\n readonly beforeDirectoryQuery?: () => void | Promise<void>;\n}\n\nexport interface HubServices {\n /** The in-process connection backing the hub's global services. */\n readonly connection: LinkRpcConnection<RegisterCallContext>;\n /** ServiceId the services are mounted under. */\n readonly hubServiceId: string;\n /** Traffic/topology inspector backing the hub's inspection services. */\n readonly inspector: HubInspector;\n /** Close the connection and detach the in-process link from the hub. */\n dispose(): void;\n}\n\ninterface Listing {\n serviceId: string;\n interfaceId: string;\n interfaceHash: string;\n serviceDescription?: string;\n rootPrincipalSets?: readonly RootPrincipalSet[];\n reachableServiceIds?: readonly ServiceIdPattern[];\n}\n\nexport function createHubServiceInterfaces(hub: Hub, options: HubServicesOptions = {}): HubServices {\n const hubServiceId = options.hubServiceId ?? 'hub';\n const link = hub.attachOut({ exclusiveHubRootHandler: true, routePrefixes: [hubServiceId] });\n hub.markInspectionService(link, hubServiceId);\n const connection = LinkRpcConnection.fromTransport(withRequestIdContext(link.transport));\n\n const inspector = new HubInspector(hub);\n registerInspectionInterfaces(connection, hub, inspector, hubServiceId, link.portId, options.descriptors);\n registerHubReflection(connection, hub, hubServiceId, options.beforeDirectoryQuery);\n registerHubServiceIdRegistry(connection, { hub, hubServiceId });\n\n return {\n connection,\n hubServiceId,\n inspector,\n dispose: () => {\n inspector.dispose();\n connection.close();\n link.dispose();\n },\n };\n}\n\nfunction registerInspectionInterfaces(\n connection: LinkRpcConnection<RegisterCallContext>,\n hub: Hub,\n inspector: HubInspector,\n hubServiceId: string,\n portId: string,\n descriptors: readonly ParticipantDescriptorSource[] | undefined,\n): void {\n connection.register(nodeInterface, {\n getNodeId: () => ({\n nodeId: hub.nodeId,\n portId,\n ...(descriptors !== undefined ? { descriptors: [...descriptors] } : {}),\n }),\n }, { serviceId: hubServiceId });\n\n connection.register(topologyInterface, {\n getGraph: () => hub.getTopologyGraph(hubServiceId),\n watchGraph: (_params, _ctx, stream) => new Promise<Record<string, never>>((resolve) => {\n if (stream.signal.aborted) {\n resolve({});\n return;\n }\n let pending = false;\n const flush = () => {\n pending = false;\n if (!stream.signal.aborted) void stream.send({}).catch(() => undefined);\n };\n const unsubscribe = hub.onDidChangeTopology(() => {\n if (pending) return;\n pending = true;\n queueMicrotask(flush);\n });\n stream.signal.addEventListener('abort', () => {\n unsubscribe();\n resolve({});\n }, { once: true });\n }),\n }, { serviceId: hubServiceId });\n\n connection.register(trafficInterface, {\n watch: ({ methodPrefix, trafficIgnoreKey, focusRequest }, _ctx, stream) =>\n runTrafficWatch(inspector, { methodPrefix, trafficIgnoreKey, focusRequest }, stream),\n watchWithPayloads: ({ methodPrefix, maxPayloadBytes, trafficIgnoreKey, focusRequest }, _ctx, stream) =>\n runTrafficWatch(inspector, {\n methodPrefix,\n maxPayloadBytes,\n trafficIgnoreKey,\n focusRequest,\n }, stream),\n }, { serviceId: hubServiceId });\n}\n\nasync function runTrafficWatch(\n inspector: HubInspector,\n options: HubTrafficWatchOptions,\n stream: StreamApi<unknown, TrafficEvent>,\n): Promise<TrafficWatchResult> {\n const subscription = inspector.subscribe(options, (event) => stream.send(event));\n const dispose = () => subscription.dispose();\n if (stream.signal.aborted) {\n dispose();\n } else {\n stream.signal.addEventListener('abort', dispose, { once: true });\n }\n try {\n return await subscription.closed;\n } finally {\n stream.signal.removeEventListener('abort', dispose);\n subscription.dispose();\n }\n}\n\n/**\n * Register the hub's **reflection** surface — `hubrpc.directory::list` /\n * `hubrpc.schemas::get` — on `connection`, mounted under `hubServiceId`.\n *\n * This is the always-on half of {@link createHubServiceInterfaces}: the\n * destination every {@link RootOverlay} directory *refers* world-view queries\n * to, independent of whether the signed, capability-gated claim front door\n * ({@link registerHubServiceIdRegistry}) is enabled.\n *\n * `directory.list` returns the hub's own services plus the referrals explicitly\n * returned by participant connection-root directories. Routing claims do not\n * create directory entries: a routable service that is not explicitly listed\n * remains callable when already known but is not discoverable.\n */\nfunction registerHubReflection(\n connection: LinkRpcConnection,\n hub: Hub,\n hubServiceId: string,\n beforeDirectoryQuery: (() => void | Promise<void>) | undefined,\n): void {\n // Every hub is also a participant on each adjacent connection. Its\n // connection-root directory explicitly refers to the addressed global\n // directory; parents discover this entry through their 1:1 root call.\n connection.register(directoryInterface, {\n list: ({ interfaceId, interfaceIdPrefix, serviceId, serviceIdScopes }) => {\n const referral = {\n serviceId: hubServiceId,\n interfaceId: directoryInterface.info.id,\n interfaceHash: directoryInterface.schemaHash,\n reachableServiceIds: [{ prefix: hubServiceId }],\n };\n const items = [referral]\n .filter((it) => interfaceId === undefined || it.interfaceId === interfaceId)\n .filter((it) => interfaceIdPrefix === undefined\n || it.interfaceId.startsWith(interfaceIdPrefix))\n .filter((it) => serviceId === undefined || it.serviceId === serviceId)\n .filter((it) => serviceIdMatchesScopes(it.serviceId, serviceIdScopes));\n return { items };\n },\n watch: directoryWatchNever,\n });\n connection.register(schemasInterface, {\n get: ({ interfaceId, hash }) => {\n const iface = connection.findRegisteredInterface(interfaceId, hash);\n if (!iface) {\n throw new RpcError(\n 'Interface not found',\n ErrorCode.methodNotFound,\n { reason: 'unknown-interface', interfaceId, hash },\n );\n }\n return { schema: iface.toSchema() as unknown };\n },\n });\n\n connection.register(directoryInterface, {\n list: async ({ interfaceId, interfaceIdPrefix, serviceId, serviceIdScopes }) => {\n await beforeDirectoryQuery?.();\n const items: Listing[] = [];\n\n // The hub's own services (mounted under hubServiceId).\n for (const r of connection.listRegisteredInterfaces()) {\n items.push(r);\n }\n\n // Gather each connected participant's self-listing from its ROOT\n // directory (`H·root → P`): one root-form `hubrpc.directory::list`\n // per participant link, filtered to `hubrpc.directory` rows so we\n // surface only its `<serviceId>::hubrpc.directory` referrals, never\n // its leaves. Root services are never forwarded and never gated, so\n // this needs no signing or capabilities. Consumers recurse into the\n // referrals via `walkHubDetailed`; transitive root-node-id\n // requirements are folded in during that walk, not here.\n const rootListings = await hub.queryParticipantRoots(\n `${directoryInterface.info.id}::list`,\n { interfaceId: directoryInterface.info.id },\n hubServiceId,\n );\n for (const raw of rootListings) {\n const page = raw as { items?: Listing[]; } | null;\n if (!page || !Array.isArray(page.items)) continue;\n for (const it of page.items) {\n // Skip the participant's own root self-row (serviceId === '');\n // we want its per-service directory referrals.\n if (it.serviceId === '') continue;\n items.push(it);\n }\n }\n\n const deduplicated = new Map<string, Listing>();\n for (const item of items) {\n const key = `${item.serviceId}\\0${item.interfaceId}\\0${item.interfaceHash}`;\n const previous = deduplicated.get(key);\n if (previous === undefined) {\n deduplicated.set(key, item);\n continue;\n }\n const preferred = item.serviceDescription !== undefined\n || item.rootPrincipalSets !== undefined\n ? item\n : previous;\n if (item.interfaceId !== directoryInterface.info.id) {\n deduplicated.set(key, preferred);\n continue;\n }\n const previousScopes = previous.reachableServiceIds\n ?? [{ prefix: previous.serviceId }];\n const itemScopes = item.reachableServiceIds\n ?? [{ prefix: item.serviceId }];\n deduplicated.set(key, {\n ...preferred,\n reachableServiceIds: normalizeServiceIdScopes([\n ...previousScopes,\n ...itemScopes,\n ]),\n });\n }\n\n const filtered = [...deduplicated.values()]\n .filter((it) => interfaceId === undefined || it.interfaceId === interfaceId)\n .filter((it) => interfaceIdPrefix === undefined || it.interfaceId.startsWith(interfaceIdPrefix))\n .filter((it) => serviceId === undefined || it.serviceId === serviceId)\n .filter((it) => serviceIdMatchesScopes(it.serviceId, serviceIdScopes))\n .map((it) => ({\n serviceId: it.serviceId,\n interfaceId: it.interfaceId,\n interfaceHash: it.interfaceHash,\n ...(it.serviceDescription !== undefined\n ? { serviceDescription: it.serviceDescription }\n : {}),\n ...(it.rootPrincipalSets !== undefined\n ? { rootPrincipalSets: it.rootPrincipalSets.map((s) => [...s]) }\n : {}),\n ...(it.reachableServiceIds !== undefined\n ? { reachableServiceIds: [...it.reachableServiceIds] }\n : {}),\n }));\n return { items: filtered };\n },\n watch: async (params, _ctx, stream) => {\n await beforeDirectoryQuery?.();\n // Coalesce local registrations, participant-root directory ticks,\n // and participant-set changes into one \"re-list now\" nudge.\n return new Promise<Record<string, never>>((resolve) => {\n if (stream.signal.aborted) {\n resolve({});\n return;\n }\n let pending = false;\n const flush = () => {\n pending = false;\n if (stream.signal.aborted) return;\n void stream.send({}).catch(() => undefined);\n };\n const notify = () => {\n if (pending) return;\n pending = true;\n queueMicrotask(flush);\n };\n const unsubscribeRouting = hub.onDidChangeRouting(notify);\n const unsubscribeLocal = connection.onDidChangeDirectory(notify);\n const participantWatches = hub.watchParticipantRoots(\n `${directoryInterface.info.id}::watch`,\n params,\n notify,\n hubServiceId,\n );\n stream.signal.addEventListener(\n \"abort\",\n () => {\n unsubscribeRouting();\n unsubscribeLocal();\n participantWatches.dispose();\n resolve({});\n },\n { once: true },\n );\n });\n },\n }, { serviceId: hubServiceId });\n\n connection.register(schemasInterface, {\n get: ({ interfaceId, hash }) => {\n const iface = connection.findRegisteredInterface(interfaceId, hash);\n if (!iface) {\n throw new RpcError(\n 'Interface not found',\n ErrorCode.methodNotFound,\n { reason: 'unknown-interface', interfaceId, hash },\n );\n }\n return { schema: iface.toSchema() as unknown };\n },\n }, { serviceId: hubServiceId });\n}\n","import { ErrorCode, type LinkRpcConnection, RpcError } from '@hediet/linkrpc';\nimport { connectionTokenBinderInterface } from './connectionTokenBinder.interfaces';\nimport type { TokenIdentityBinding, TokenIdentityStore } from './tokenIdentityStore';\n\nexport interface RegisterConnectionTokenBinderOptions {\n /** Shared mint/redeem store (the same instance the redeem-side listener reads). */\n readonly store: TokenIdentityStore;\n /**\n * Literal `identitySlot` prefixes this binder may mint identities for (e.g.\n * `[\"docker/\"]`). A `bindConnectionToken({ identitySlot })` call is rejected\n * unless `identitySlot` starts with one of these. Empty → identity binding\n * is disabled (any `identitySlot` request is rejected).\n */\n readonly identitySlotPrefixes: readonly string[];\n /**\n * Literal `serviceIdNamespace` prefixes this binder may grant (e.g.\n * `[\"docker/\"]`). A `bindConnectionToken({ serviceIdNamespace })` call is\n * rejected unless `serviceIdNamespace` starts with one of these. Empty →\n * serviceId granting is disabled (any `serviceIdNamespace` request is\n * rejected).\n */\n readonly serviceIdPrefixes: readonly string[];\n /** Optional per-token TTL (ms); falls back to the store's default. */\n readonly ttlMs?: number;\n /**\n * Mount point when registering as a **forwarded hub service** (reachable via\n * routing as `<serviceId>::connectionTokenBinder`). Omit for the **root\n * form**: an interface-form registration on an overlay root, never forwarded\n * → never gated.\n */\n readonly serviceId?: string;\n}\n\nfunction assertUnderPrefix(\n value: string,\n prefixes: readonly string[],\n field: 'identitySlot' | 'serviceIdNamespace',\n configuredPrefix: 'identitySlotPrefix' | 'serviceIdPrefix',\n): void {\n if (!prefixes.some((p) => value.startsWith(p))) {\n throw new RpcError(\n `${field} \"${value}\" is outside this binder's granted ` +\n `${configuredPrefix} ${JSON.stringify(prefixes)}`,\n ErrorCode.invalidRequest,\n );\n }\n}\n\n/**\n * Install `connectionTokenBinder::bindConnectionToken` on `connection`.\n *\n * Two forms, selected by {@link RegisterConnectionTokenBinderOptions.serviceId}:\n *\n * - **root form** (no `serviceId`): installed at a participant's overlay root\n * (root form, never forwarded → never gated). Safe because only the specific\n * trusted connection the acceptor installed it on can reach it.\n * - **forwarded form** (`serviceId` set): mounted as a routable hub service so\n * any participant can discover and call it. Safe only because forwarded calls\n * go through the hub's forwarded-call gate; the same prefix checks still bound\n * what any caller may mint.\n *\n * Each call mints a single-use token binding the requested `identitySlot` and/or\n * `serviceIdNamespace`, provided each requested field falls under the matching\n * configured prefix. Omitting a field leaves that axis unbound.\n */\nexport function registerConnectionTokenBinderService(\n connection: LinkRpcConnection<unknown>,\n options: RegisterConnectionTokenBinderOptions,\n): void {\n const { store, identitySlotPrefixes, serviceIdPrefixes, ttlMs, serviceId } = options;\n connection.register(\n connectionTokenBinderInterface,\n {\n bindConnectionToken: ({ identitySlot, serviceIdNamespace }) => {\n const binding: TokenIdentityBinding = {};\n if (identitySlot !== undefined) {\n assertUnderPrefix(identitySlot, identitySlotPrefixes, 'identitySlot', 'identitySlotPrefix');\n (binding as { identitySlot?: string }).identitySlot = identitySlot;\n }\n if (serviceIdNamespace !== undefined) {\n assertUnderPrefix(serviceIdNamespace, serviceIdPrefixes, 'serviceIdNamespace', 'serviceIdPrefix');\n (binding as { grantedServiceIdNamespace?: string }).grantedServiceIdNamespace = serviceIdNamespace;\n }\n const minted = ttlMs !== undefined ? store.mint(binding, ttlMs) : store.mint(binding);\n return { token: minted.token, expiresAt: minted.expiresAt };\n },\n },\n serviceId !== undefined ? { serviceId } : {},\n );\n}\n","import type {\n LinkRpcConnection,\n Identity,\n IMessageTransport,\n ManagedIdentityStorageBackend,\n} from '@hediet/linkrpc';\nimport type { ServiceId } from '@hediet/linkrpc/hub/common';\nimport { registerHubServices, registerIdentityServices } from './rootServices';\nimport {\n registerConnectionTokenBinderService,\n type RegisterConnectionTokenBinderOptions,\n} from './connectionTokenBinderService';\nimport type { TokenIdentityStore } from './tokenIdentityStore';\nimport type { AttachedLink, Hub } from './routing/routingHub';\n\n/**\n * Everything a {@link ConnectionHandler} needs to install a participant's root\n * services. Built by {@link import('./hubConnectionAcceptor').HubConnectionAcceptor}\n * once per accepted connection: the connection-specific bits (`root`,\n * `upstream`, `transport`, `token`) plus the connection-independent policy the\n * acceptor was configured with (`hubServiceId`, `authorizeClaim`,\n * `installHubAccess`).\n */\nexport interface ConnectionContext {\n /** The overlay root to install this participant's front doors on. */\n readonly root: LinkRpcConnection<unknown>;\n /** The participant's link to the central hub (for `hubGrantedServiceId::register`). */\n readonly upstream: AttachedLink;\n /** The central hub. */\n readonly hub: Hub;\n /** The accepted transport (custom handlers may read attestation off it). */\n readonly transport: IMessageTransport;\n /** The `hubrpc::initialize` token the connection presented (if any). */\n readonly token: string | undefined;\n /** ServiceId the global reflection services are mounted under. */\n readonly hubServiceId: string;\n /** Per-connection claim authorizer (from the acceptor's policy), if any. */\n readonly authorizeClaim?: (requestedPrefix: ServiceId) => { ok: true; } | { ok: false; reason: string; };\n /** Installs the consent front door at the overlay root, if configured. */\n readonly installHubAccess?: (root: LinkRpcConnection<unknown>) => void;\n}\n\n/**\n * The resolved root services a claiming handler provisions. Every field is\n * optional; {@link provisionRoot} installs the always-on parts (claim/directory\n * front door + consent) unconditionally and the rest only when present.\n */\nexport interface RootProvision {\n /** Freely-claimable serviceId namespace (`hubGrantedServiceId::get`). */\n readonly grantedServiceIdNamespace?: string;\n /** Lazily-resolved managed identity (`identity::*`). Omit for no identity. */\n readonly resolveIdentity?: () => Promise<Identity>;\n /** Optional per-identity persistent storage (`identity.storage::*`). */\n readonly storage?: ManagedIdentityStorageBackend;\n /** Token-minting front door (`connectionTokenBinder::*`). Omit for none. */\n readonly connectionTokenBinder?: RegisterConnectionTokenBinderOptions;\n}\n\n/**\n * A claiming connection handler: installs the participant's root services and\n * returns. Built-ins delegate the actual registration to {@link provisionRoot}.\n */\nexport type ConnectionHandler = (ctx: ConnectionContext) => void;\n\n/**\n * Selects and (on claim) provisions a connection by its `hubrpc::initialize`\n * token. `handle` is **non-consuming** — it may be called at the pre-handshake\n * gate to answer \"would you accept this token?\" — and returns a\n * {@link ConnectionHandler} that does the (possibly consuming) installation, or\n * `undefined` to pass to the next factory.\n */\nexport interface ConnectionHandlerFactory {\n handle(token: string | undefined): ConnectionHandler | undefined;\n}\n\n/**\n * Walk `factories` in order; return the first handler that claims `token`, or\n * `undefined` if none do (the caller drops the connection).\n */\nexport function resolveConnectionHandler(\n factories: readonly ConnectionHandlerFactory[],\n token: string | undefined,\n): ConnectionHandler | undefined {\n for (const factory of factories) {\n const handler = factory.handle(token);\n if (handler !== undefined) return handler;\n }\n return undefined;\n}\n\n/**\n * Install a participant's root services from a resolved {@link RootProvision}:\n * the always-on claim/directory front door and consent surface, plus (when\n * present) the minting front door and lazy managed identity. This is the single\n * shared installer every built-in handler funnels through.\n */\nexport function provisionRoot(ctx: ConnectionContext, provision: RootProvision): void {\n registerHubServices(ctx.root, ctx.upstream, {\n hubServiceId: ctx.hubServiceId,\n ...(provision.grantedServiceIdNamespace !== undefined\n ? { grantedServiceIdNamespace: provision.grantedServiceIdNamespace }\n : {}),\n ...(ctx.authorizeClaim !== undefined ? { authorizeClaim: ctx.authorizeClaim } : {}),\n });\n\n // Consent front door (root form, never forwarded → never gated).\n ctx.installHubAccess?.(ctx.root);\n\n if (provision.connectionTokenBinder !== undefined) {\n registerConnectionTokenBinderService(ctx.root, provision.connectionTokenBinder);\n }\n\n if (provision.resolveIdentity !== undefined) {\n registerIdentityServices(ctx.root, {\n resolveIdentity: provision.resolveIdentity,\n ...(provision.storage !== undefined ? { storage: provision.storage } : {}),\n });\n }\n}\n\n/**\n * A factory that claims **any** connection (optionally gated by `claims`) and\n * provisions a fixed root. Used for the `anonymous` handler (claims all), the\n * `static` handler (claims a matching token), and dial-in endpoints (claims all,\n * no token).\n */\nexport function fixedProvisionHandler(\n provision: RootProvision,\n claims: (token: string | undefined) => boolean = () => true,\n): ConnectionHandlerFactory {\n return {\n handle: (token) => (claims(token) ? (ctx) => provisionRoot(ctx, provision) : undefined),\n };\n}\n\n/** The `anonymous` handler: claims every connection, provisioning `provision`. */\nexport function anonymousHandler(provision: RootProvision): ConnectionHandlerFactory {\n return fixedProvisionHandler(provision);\n}\n\n/** The `static` handler: claims connections whose token equals `value`. */\nexport function staticTokenHandler(value: string, provision: RootProvision): ConnectionHandlerFactory {\n return fixedProvisionHandler(provision, (token) => token === value);\n}\n\n/**\n * The `bound` handler: claims connections whose token is live in `store`, and on\n * claim **redeems** it (single-use) to derive the provisioned identity slot\n * and/or granted serviceId namespace. `resolveSlot` turns a redeemed slot into\n * a lazy identity resolver plus its per-identity storage (injected so this stays\n * node-agnostic).\n */\nexport function boundTokenHandler(\n store: TokenIdentityStore,\n resolveSlot: (slot: string) => {\n resolveIdentity: () => Promise<Identity>;\n storage: ManagedIdentityStorageBackend;\n },\n): ConnectionHandlerFactory {\n return {\n handle: (token) => {\n if (!store.peek(token)) return undefined;\n return (ctx) => {\n const binding = store.redeem(token);\n if (binding === undefined) {\n throw new Error('bound token was consumed between accept and redeem');\n }\n const provision: RootProvision = {\n ...(binding.grantedServiceIdNamespace !== undefined\n ? { grantedServiceIdNamespace: binding.grantedServiceIdNamespace }\n : {}),\n ...(binding.identitySlot !== undefined\n ? resolveSlot(binding.identitySlot)\n : {}),\n };\n provisionRoot(ctx, provision);\n };\n },\n };\n}\n","import {\n ErrorCode,\n type IMessageTransport,\n isRequest,\n type JsonRpcMessage,\n verifyRpcCall,\n} from '@hediet/linkrpc';\n\n/**\n * Wrap an inbound transport so every request's `$hubrpc` signature is verified\n * **eagerly, at the door** — a pure authenticity gate with no capability check:\n *\n * - a **valid** signature → the request is delivered unchanged;\n * - an **invalid** signature → the request is **rejected** here (an error\n * response is sent and the message is never delivered);\n * - an **unsigned** call (no envelope) → delivered unchanged, so keyless\n * connections still work.\n *\n * This is the signature half of the hub's trust model. *Authorization*\n * (capability chains) is **not** this wrapper's job — that is enforced\n * separately by {@link import('./forwardedCallGate').withForwardedCallGate} on\n * the hub-facing (forwarded) path. The root overlay uses this wrapper on its own\n * root-form calls (consent / identity front doors), which never pass through the\n * forwarded-call gate and so need their authenticity established here.\n *\n * When `verifySignatures` is not `true`, the transport is returned unchanged (no\n * verification, every message passes verbatim).\n *\n * Verification is async but in-order delivery is preserved via a per-link\n * promise chain.\n */\nexport function withVerifiedSignature(\n link: IMessageTransport,\n options: { readonly verifySignatures?: boolean } = {},\n): IMessageTransport {\n if (options.verifySignatures !== true) {\n return link;\n }\n return {\n send: (message) => link.send(message),\n setListener: (listener) => {\n if (listener === undefined) {\n link.setListener(undefined);\n return;\n }\n let chain: Promise<void> = Promise.resolve();\n link.setListener((message) => {\n chain = chain\n .then(async () => {\n if (await _rejectedBadSignature(link, message)) {\n return;\n }\n listener(message);\n })\n .catch((e) => {\n console.error('Error in inbound signature verification:', e);\n // A verification fault must never wedge the link; drop the\n // offending message and keep the ordering chain alive.\n });\n });\n },\n dispose: () => link.dispose(),\n };\n}\n\n/**\n * Verify a single inbound request's signature. Returns `true` (and sends an\n * error response over `link`) when the signature is present but invalid;\n * returns `false` — the message should be delivered — for a valid signature, an\n * unsigned call, or a non-request.\n */\nasync function _rejectedBadSignature(\n link: IMessageTransport,\n message: JsonRpcMessage,\n): Promise<boolean> {\n if (!isRequest(message)) {\n return false;\n }\n const res = await verifyRpcCall({\n wireMethod: message.method,\n wireParams: message.params,\n });\n if (!res.ok) {\n link.send({\n jsonrpc: '2.0',\n id: message.id,\n error: { code: ErrorCode.invalidRequest, message: res.reason },\n });\n return true;\n }\n return false;\n}\n","import {\n type AcceptedRootIssuer,\n ErrorCode,\n type IMessageTransport,\n isNotification,\n isRequest,\n type JsonRpcMessage,\n type JsonRpcNotification,\n type JsonRpcRequest,\n methodNameToTarget, permits,\n parseMethodName,\n type PublicSigningIdentity,\n verifyCall\n} from '@hediet/linkrpc';\n\n/** Options common to both gate modes (authenticity-only and capability). */\ninterface ForwardedCallGateBaseOptions {\n /**\n * ServiceId prefixes whose calls pass **verbatim**, unverified — an\n * opt-in escape hatch. **Empty by default**: reflection and forwarded\n * service calls are gated like any other. The consent front door\n * (`hubAccess::*`) is served at the connection root (never forwarded), so it\n * is reached directly and never passes through this gate.\n */\n readonly exemptPrefixes?: Iterable<string>;\n /** Override the clock (Unix milliseconds) used for skew / expiry checks. Testing seam. */\n readonly nowMs?: () => number;\n}\n\n/**\n * Per-service trust anchors, consulted with the call's `serviceId`. A\n * capability authorises only if its chain roots at one of the anchors returned\n * for that service, so a participant cannot self-issue authority. An empty\n * result rejects every capability (fail closed) — there is deliberately no\n * \"accept any root\" affordance. Anchors flagged `isPublic` are named in\n * rejection messages.\n */\ntype AcceptedRootIssuerResolver = (serviceId: string) => readonly AcceptedRootIssuer[];\n\n/**\n * Gate configuration. A **discriminated union on `requireCapability`** so the\n * type system enforces the one combination that is actually safe:\n *\n * - **authenticity only** (`requireCapability` omitted / `false`): a valid\n * `$hubrpc` signature is enough; *authorization* is left to the target\n * service / capability layer. `acceptedRootIssuers` is optional here.\n * - **capability mode** (`requireCapability: true`): a bare signature is not\n * enough — the request must also present a capability that {@link permits}\n * the concrete call, rooted at an accepted issuer. Because there is no safe\n * default trust anchor, either fixed `trustedRoots` or a service-specific\n * `acceptedRootIssuers` resolver is **required at compile time**. This makes\n * it impossible to request enforcement while silently forgetting whose\n * capabilities to trust.\n */\nexport type ForwardedCallGateOptions =\n | (ForwardedCallGateBaseOptions & {\n readonly requireCapability?: false;\n readonly acceptedRootIssuers?: AcceptedRootIssuerResolver;\n readonly trustedRoots?: never;\n })\n | (ForwardedCallGateBaseOptions & {\n readonly requireCapability: true;\n } & (\n | {\n readonly acceptedRootIssuers: AcceptedRootIssuerResolver;\n readonly trustedRoots?: never;\n }\n | {\n /** Fixed public trust roots accepted for every forwarded service. */\n readonly trustedRoots: readonly PublicSigningIdentity[];\n readonly acceptedRootIssuers?: never;\n }\n ));\n\n\n/**\n * A **signature front door** for fully-qualified calls. Wrap an incoming\n * transport with this before attaching it to a hub or constructing the serving\n * connection, so every `serviceId::interfaceId::member` call must carry a\n * valid `$hubrpc` signature.\n * Unsigned or tampered calls are rejected with an error response and never\n * reach the downstream hub or connection.\n *\n * What passes **verbatim** (ungated):\n * - responses;\n * - root-addressed requests (`interfaceId::member`) and bare requests\n * (`member`) — these always terminate at the connection root and are never\n * forwarded; and\n * - requests targeting an {@link ForwardedCallGateOptions.exemptPrefixes exempt\n * prefix} (the hub's own services, which gate themselves).\n *\n * The gate **does not strip** the envelope: signed wire params keep the real\n * call params at the top level alongside `$hubrpc`/`$hubrpcUnsigned`, so the\n * target's typed handler recovers them via schema-stripping while a target that\n * cares may re-verify as defense-in-depth. Authorization is *not* this gate's\n * job (unless {@link ForwardedCallGateOptions.requireCapability} is set): it\n * proves *who* is calling, leaving *whether they may* to the capability layer.\n *\n * In-order delivery toward the hub is preserved across the async verification:\n * inbound messages are processed through a single serial queue.\n */\nexport function withForwardedCallGate(\n inner: IMessageTransport,\n options: ForwardedCallGateOptions,\n): IMessageTransport {\n return withFullyQualifiedCallGate(inner, options);\n}\n\n/** Explicitly named alias for {@link withForwardedCallGate}. */\nexport function withFullyQualifiedCallGate(\n inner: IMessageTransport,\n options: ForwardedCallGateOptions,\n): IMessageTransport {\n return new ForwardedCallGate(inner, options);\n}\n\nclass ForwardedCallGate implements IMessageTransport {\n private readonly _exempt: Set<string>;\n /**\n * Per-call nonces already admitted on this link. A call replaying a\n * nonce is rejected — this is the single replay ledger, and it makes any\n * `callBind`-scoped capability single-use for free.\n */\n private readonly _seenNonces = new Set<string>();\n private _downstream: ((m: JsonRpcMessage) => void) | undefined;\n /** Serializes inbound processing so async verification never reorders the stream. */\n private _tail: Promise<void> = Promise.resolve();\n\n constructor(\n private readonly _inner: IMessageTransport,\n private readonly _options: ForwardedCallGateOptions,\n ) {\n this._exempt = new Set(_options.exemptPrefixes ?? []);\n }\n\n\n /** hub → participant: verbatim, never gated. */\n public send(message: JsonRpcMessage): void {\n void this._inner.send(message);\n }\n\n public setListener(listener: ((m: JsonRpcMessage) => void) | undefined): void {\n this._downstream = listener;\n this._inner.setListener(listener === undefined\n ? undefined\n : (message) => {\n this._tail = this._tail.then(() => this._process(message));\n });\n }\n\n public dispose(): void {\n this._inner.dispose();\n }\n\n private async _process(m: JsonRpcMessage): Promise<void> {\n if (!isRequest(m) && !isNotification(m)) {\n this._downstream?.(m);\n return;\n }\n const parsed = parseMethodName(m.method);\n // Only fully-qualified (cross-service) requests are forwarded by the\n // hub and thus gated. Root-form / malformed / exempt-prefix requests\n // pass through; the hub or the participant's overlay deals with them.\n //\n // SECURITY NOTE: `exemptPrefixes` is an opt-in escape hatch and is\n // **empty by default** — nothing, not even reflection, bypasses the\n // gate. The consent front door (`hubAccess::*`) is served at the\n // connection root (root form, never forwarded), so it is reached\n // directly and never reaches this gate. Callers that still pass a prefix\n // here accept that those services are reachable signed-but-uncapped.\n if (!parsed || parsed.kind !== 'full' || this._exempt.has(parsed.serviceId)) {\n this._downstream?.(m);\n return;\n }\n await this._gate(m);\n }\n\n private async _gate(call: JsonRpcRequest | JsonRpcNotification): Promise<void> {\n const nowMs = this._options.nowMs?.();\n const res = await verifyCall({\n method: call.method,\n params: call.params,\n parseMethod: methodNameToTarget,\n requireCapability: this._options.requireCapability === true,\n ...(nowMs !== undefined ? { nowMs } : {}),\n });\n if (!res.ok) {\n // `capability` → caller must present/acquire authority; anything\n // else (missing/bad signature, malformed) is a bad request.\n const code = res.kind === 'capability'\n ? ErrorCode.permissionRequired\n : ErrorCode.invalidRequest;\n this._reject(call, code, res.reason);\n return;\n }\n\n // Replay defense: every authentic forwarded call's nonce is\n // single-use on this link. (callBind grants ride on this for free.)\n if (this._seenNonces.has(res.nonce)) {\n this._reject(call, ErrorCode.invalidRequest, 'replayed request nonce');\n return;\n }\n\n // Authorization (capability mode): a presented capability must\n // `permits` the concrete call, rooting at an issuer this gate accepts\n // for the call's service.\n if (this._options.requireCapability === true) {\n const verdict = await permits(\n res.call,\n res.capabilities,\n (serviceId) => this._acceptedRootIssuers(serviceId),\n nowMs ?? Date.now(),\n );\n if (!verdict.ok) {\n this._reject(call, ErrorCode.permissionRequired, verdict.reason);\n return;\n }\n }\n\n // Admitted: record the nonce, then forward verbatim (envelope intact\n // for re-verification / schema-stripping at the target).\n this._seenNonces.add(res.nonce);\n this._downstream?.(call);\n }\n\n private _reject(\n call: JsonRpcRequest | JsonRpcNotification,\n code: number,\n message: string,\n ): void {\n if (!isRequest(call)) {\n return;\n }\n void this._inner.send({\n jsonrpc: '2.0',\n id: call.id,\n error: { code, message },\n });\n }\n\n private _acceptedRootIssuers(serviceId: string): readonly AcceptedRootIssuer[] {\n if (this._options.requireCapability !== true) {\n return [];\n }\n if (this._options.trustedRoots !== undefined) {\n return this._options.trustedRoots.map(({ principal }) => ({ principal, isPublic: true }));\n }\n return this._options.acceptedRootIssuers(serviceId);\n }\n}\n","import { type IMessageTransport, type PrincipalId, TransportPair } from '@hediet/linkrpc';\nimport { withForwardedCallGate } from './forwardedCallGate';\nimport { withVerifiedSignature } from './verifiedSignature';\nimport type { PrefixPolicy } from './prefixPolicy';\nimport { RootOverlay } from './routing/rootOverlay';\nimport { type HubAccessHandlers } from './hubAccessService';\nimport {\n type ConnectionContext,\n type ConnectionHandlerFactory,\n resolveConnectionHandler,\n} from './connectionHandler';\nimport type { LinkRpcConnection } from '@hediet/linkrpc';\nimport type { DirectoryEntry } from './accessCandidates';\nimport type { AttachedLink, Hub } from './routing/routingHub';\nimport type { ITransportServer, Transport } from '@hediet/linkrpc/hub/common';\n\n/**\n * A data shape describing an imperative consent front door — the handlers plus\n * the directory source `registerHubAccessService` needs. Retained as a\n * convenience type; the acceptor installs consent via the more general\n * {@link HubConnectionAcceptorBaseOptions.installHubAccess} callback.\n */\nexport interface HubAccessConfig {\n readonly handlers: HubAccessHandlers;\n fetchDirectory(): Promise<readonly DirectoryEntry[]>;\n}\n\nexport interface HubConnectionAcceptorBaseOptions<TTransport extends Transport> {\n /**\n * Source of inbound transports. Often a provenance-annotated server\n * (`withProvenance(socketServer, provider)`), but any\n * {@link ITransportServer} works — provenance is read via `resolveIdentity`\n * and the policy, not required by the acceptor's types.\n */\n readonly server: ITransportServer<TTransport>;\n /** The central hub all accepted participants attach under. */\n readonly hub: Hub;\n /**\n * Ordered connection handlers. For each accepted transport the acceptor\n * resolves the first handler whose {@link ConnectionHandlerFactory.handle}\n * claims the presented `hubrpc::initialize` token; that handler installs the\n * participant's root services (identity, granted namespace, minting, …). If\n * no handler claims, the connection is dropped. An empty array accepts\n * nothing.\n */\n readonly handlers: readonly ConnectionHandlerFactory[];\n /**\n * Authorizes each prefix claim a participant makes. Omit to allow every\n * well-formed claim.\n */\n readonly policy?: PrefixPolicy<TTransport>;\n /** ServiceId of the global reflection services. Defaults to `'hub'`. */\n readonly hubServiceId?: string;\n /**\n * Install the consent front door at each accepted participant's overlay\n * root (root form, never forwarded → never gated). The callback receives the\n * root connection and registers `hubAccess::*` on it however it likes — the\n * imperative `registerHubAccessService(root, …)` or the keyless\n * `HubAccessManifestHost.registerHubAccessAtRoot(root)`. Omit on open hubs;\n * then no consent surface is served.\n */\n installHubAccess?(root: LinkRpcConnection<unknown>): void;\n /** Fired after a participant's overlay is attached. */\n onAttached?(info: { overlay: RootOverlay; }): void;\n /** Fired when accepting a connection throws. */\n onError?(error: Error): void;\n}\n\n/**\n * Forwarded-call gating policy — a **discriminated union** so the type system\n * enforces the safe combinations and rules out the dangerous \"ask for\n * capability enforcement but forget the trust anchors\" misconfiguration:\n *\n * - **off** (default): forwarded calls reach the hub unverified.\n * - **authenticity only** (`verifyForwardedCalls: true`): forwarded calls must\n * carry a valid `$hubrpc` signature; `adminIds` is optional.\n * - **capability** (`verifyForwardedCalls: true` + `requireForwardedCapability:\n * true`): forwarded calls must additionally present a capability rooted at one\n * of `adminIds`. Because an empty/absent anchor set fails closed (rejecting\n * *every* capability, including validly granted ones), `adminIds` is\n * **required at compile time** in this arm.\n */\nexport type ForwardCheckingPolicy =\n | {\n readonly verifyForwardedCalls?: false;\n readonly requireForwardedCapability?: false;\n readonly adminIds?: undefined;\n }\n | {\n /**\n * Every accepted participant's hub-facing link is wrapped in a\n * {@link withForwardedCallGate signature front door}: forwarded\n * (fully-qualified) requests must carry a valid `$hubrpc` signature to\n * reach the hub. Requests to the hub's own `hubServiceId` prefix are\n * exempt (those services self-gate).\n */\n readonly verifyForwardedCalls: true;\n readonly requireForwardedCapability?: false;\n /**\n * Optional root trust anchors. With authenticity-only verification a\n * capability is not required, but when present a call's chain is still\n * checked against these anchors.\n */\n readonly adminIds?: Iterable<PrincipalId>;\n }\n | {\n readonly verifyForwardedCalls: true;\n /**\n * The forwarded-call gate also requires a capability, not just a\n * signature: a forwarded call authorises only if its capability chain\n * roots at one of {@link adminIds} (accepted for every service). The\n * gate also dedups each request nonce, so `callBind` grants are\n * single-use for free.\n */\n readonly requireForwardedCapability: true;\n /** Root trust anchors. Typically the hub admin's PrincipalId. Required (fail-closed otherwise). */\n readonly adminIds: Iterable<PrincipalId>;\n };\n\nexport type HubConnectionAcceptorOptions<TTransport extends Transport> =\n HubConnectionAcceptorBaseOptions<TTransport> & ForwardCheckingPolicy;\n\ninterface AcceptedConnection {\n readonly overlay: RootOverlay;\n readonly upstream: AttachedLink;\n readonly topology: { dispose(): void; };\n}\n\n/**\n * Bridges accepted transports onto the hubv2 graph via a pluggable chain of\n * {@link ConnectionHandlerFactory connection handlers}. For each transport it:\n *\n * 1. attaches an uplink to the central hub and builds a {@link RootOverlay};\n * 2. resolves the first handler whose token check claims the connection and\n * lets it install the participant's root services (claim/directory front\n * door + consent, and optionally identity, granted namespace, minting) —\n * dropping the connection if none claim; and\n * 3. connects the participant, disposing the overlay and detaching the uplink\n * (which releases its claimed prefixes) when the transport closes.\n *\n * It never names a backend transport type — hand it any {@link ITransportServer}.\n */\nexport class HubConnectionAcceptor<TTransport extends Transport> {\n private readonly _accepted = new Set<AcceptedConnection>();\n private _disposed = false;\n\n constructor(private readonly _options: HubConnectionAcceptorOptions<TTransport>) {\n this._options.server.setConnectionHandler((t) => {\n this._accept(t);\n });\n }\n\n private _accept(transport: TTransport): void {\n if (this._disposed) {\n transport.dispose();\n return;\n }\n\n let accepted: AcceptedConnection;\n try {\n accepted = this._wire(transport);\n } catch (e) {\n this._options.onError?.(e instanceof Error ? e : new Error(String(e)));\n transport.dispose();\n return;\n }\n\n this._accepted.add(accepted);\n transport.onDidClose(() => {\n accepted.overlay.dispose();\n accepted.topology.dispose();\n accepted.upstream.dispose();\n this._accepted.delete(accepted);\n });\n\n this._options.onAttached?.({ overlay: accepted.overlay });\n }\n\n /**\n * Wrap the hub-facing link per the {@link ForwardCheckingPolicy}. The\n * option union guarantees that capability mode always carries its\n * `adminIds` trust anchors, so this can never silently fail closed by\n * forgetting them.\n */\n private _gateHubFacing(inner: IMessageTransport): IMessageTransport {\n if (this._options.verifyForwardedCalls !== true) {\n return inner;\n }\n // No exempt prefixes: even the hub's own services (reflection) go\n // through the gate. The consent front door (`hubAccess::*`) is served at\n // the connection root (never forwarded), so it needs no capability and\n // is reached directly.\n if (this._options.requireForwardedCapability === true) {\n // `adminIds` is required by the union arm — no fail-closed surprise.\n const adminIds = [...this._options.adminIds];\n return withForwardedCallGate(inner, {\n requireCapability: true,\n acceptedRootIssuers: () => adminIds.map((nodeId) => ({ principal: nodeId, isPublic: true })),\n });\n }\n const adminIds = this._options.adminIds !== undefined\n ? [...this._options.adminIds]\n : undefined;\n return withForwardedCallGate(inner, {\n ...(adminIds !== undefined\n ? { acceptedRootIssuers: () => adminIds.map((nodeId) => ({ principal: nodeId, isPublic: true })) }\n : {}),\n });\n }\n\n private _wire(transport: TTransport): AcceptedConnection {\n // Resolve the claiming handler from the presented token before we commit\n // any hub resources, so an unclaimed connection is a clean rejection.\n const token = (transport as { initializeToken?: string | undefined; }).initializeToken;\n const handler = resolveConnectionHandler(this._options.handlers, token);\n if (handler === undefined) {\n throw new Error('no connection handler accepted the presented token');\n }\n\n const pair = new TransportPair();\n // Optionally gate the hub-facing link so unsigned/unauthorized forwarded\n // calls are rejected before they reach the routing core.\n const hubFacing = this._gateHubFacing(pair.b);\n const upstream = this._options.hub.attach(hubFacing);\n const overlay = new RootOverlay({\n uplink: pair.a,\n uplinkPortId: upstream.portId,\n });\n const topology = this._options.hub.registerManagedRoutingTopology(\n upstream,\n overlay.managedTopology(upstream.edgeId, transport.topologyInfo),\n );\n\n const policy = this._options.policy;\n const ctx: ConnectionContext = {\n root: overlay.root,\n upstream,\n hub: this._options.hub,\n transport,\n token,\n hubServiceId: this._options.hubServiceId ?? 'hub',\n ...(policy !== undefined\n ? {\n authorizeClaim: (requestedPrefix) =>\n policy.authorizeClaim({ principal: undefined, transport, requestedPrefix }),\n }\n : {}),\n ...(this._options.installHubAccess !== undefined\n ? { installHubAccess: this._options.installHubAccess }\n : {}),\n };\n // The handler installs the participant's root services (claim/directory\n // front door + consent, and optionally identity, granted namespace,\n // minting) via the shared `provisionRoot`.\n try {\n handler(ctx);\n\n // The overlay root verifies inbound signatures (when the hub checks them\n // at all) so root-form front doors establish caller authenticity.\n // Unsigned calls still pass for keyless connections; the consent front\n // door (`hubAccess::*`) takes its audience from `consumer.principal` and\n // so does not depend on this.\n const verifySignatures = this._options.verifyForwardedCalls === true;\n overlay.connectParticipant(withVerifiedSignature(transport, { verifySignatures }));\n return { overlay, upstream, topology };\n } catch (error) {\n overlay.dispose();\n topology.dispose();\n upstream.dispose();\n throw error;\n }\n }\n\n public dispose(): void {\n if (this._disposed) return;\n this._disposed = true;\n for (const accepted of this._accepted) {\n accepted.overlay.dispose();\n accepted.topology.dispose();\n accepted.upstream.dispose();\n }\n this._accepted.clear();\n this._options.server.dispose();\n }\n}\n"],"mappings":"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"}