@hediet/linkrpc-infra 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.
- package/README.md +155 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/inspection/index.d.ts +169 -0
- package/dist/inspection/index.js +734 -0
- package/dist/inspection/index.js.map +1 -0
- package/dist/json-document/index.d.ts +76 -0
- package/dist/json-document/index.js +131 -0
- package/dist/json-document/index.js.map +1 -0
- package/dist/json-rpc/index.d.ts +82 -0
- package/dist/json-rpc/index.js +439 -0
- package/dist/json-rpc/index.js.map +1 -0
- package/dist/logging/index.d.ts +118 -0
- package/dist/logging/index.js +68 -0
- package/dist/logging/index.js.map +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/inspection/nodeInfoClient.ts","../../src/inspection/topologyClient.ts","../../src/inspection/trafficClient.ts","../../src/inspection/topologyGraph.ts","../../src/inspection/networkInspectionClient.ts","../../src/inspection/topologyNetworkClient.ts"],"sourcesContent":["import type { LinkRpcConnection } from '@hediet/linkrpc';\nimport { nodeInterface, type NodeInfo } from '@hediet/linkrpc/inspection';\n\n/** Typed convenience client for root and service-scoped node identity. */\nexport class NodeInfoClient<TInCtx = unknown, TOutCtx = unknown> {\n constructor(\n private readonly _connection: LinkRpcConnection<TInCtx, TOutCtx>,\n ) { }\n\n public getPeer(): Promise<NodeInfo> {\n return this._connection.get(nodeInterface).getNodeId({});\n }\n\n public getForService(serviceId: string): Promise<NodeInfo> {\n return this._connection.service(serviceId).get(nodeInterface).getNodeId({});\n }\n}\n","import {\n DEFAULT_RPC_TIMEOUT_MS,\n type LinkRpcConnection,\n withRpcTimeout,\n} from '@hediet/linkrpc';\nimport {\n topologyInterface,\n type TopologyGraph,\n} from '@hediet/linkrpc/inspection';\n\nexport interface TopologyWatch {\n /** Resolves with the initial snapshot after its callback has run. */\n readonly ready: Promise<TopologyGraph>;\n /** Resolves after cancellation and all queued re-fetches complete. */\n readonly done: Promise<void>;\n cancel(reason?: string): Promise<void>;\n}\n\nexport interface TopologyWatchCallbacks {\n onGraph(graph: TopologyGraph): void;\n onError?(error: unknown): void;\n}\n\n/** Snapshot and invalidation-watch client for one inspected service. */\nexport class TopologyClient<TInCtx = unknown, TOutCtx = unknown> {\n constructor(\n private readonly _connection: LinkRpcConnection<TInCtx, TOutCtx>,\n public readonly serviceId: string,\n private readonly _timeoutMs = DEFAULT_RPC_TIMEOUT_MS,\n ) { }\n\n public getGraph(): Promise<TopologyGraph> {\n const request = this._connection.service(this.serviceId)\n .get(topologyInterface)\n .getGraph({});\n return withRpcTimeout(\n request,\n `topology service '${this.serviceId}'`,\n this._timeoutMs,\n );\n }\n\n public watch(callbacks: TopologyWatchCallbacks): TopologyWatch {\n const client = this._connection.service(this.serviceId).get(topologyInterface);\n let active = true;\n let dirty = false;\n let refreshing = false;\n let refreshTail: Promise<void> = Promise.resolve();\n let readySettled = false;\n let resolveReady!: (graph: TopologyGraph) => void;\n let rejectReady!: (error: unknown) => void;\n const ready = new Promise<TopologyGraph>((resolve, reject) => {\n resolveReady = resolve;\n rejectReady = reject;\n });\n\n const reportError = (error: unknown): void => {\n try {\n callbacks.onError?.(error);\n } catch {\n // Consumer callbacks never participate in watch lifecycle.\n }\n };\n const requestRefresh = (): void => {\n if (!active) return;\n dirty = true;\n if (refreshing) return;\n refreshing = true;\n refreshTail = (async () => {\n while (active && dirty) {\n dirty = false;\n try {\n const graph = await withRpcTimeout(\n client.getGraph({}),\n `topology service '${this.serviceId}'`,\n this._timeoutMs,\n );\n if (!active) break;\n try {\n callbacks.onGraph(graph);\n } catch (error) {\n reportError(error);\n }\n if (!readySettled) {\n readySettled = true;\n resolveReady(graph);\n }\n } catch (error) {\n reportError(error);\n if (!readySettled) {\n readySettled = true;\n rejectReady(error);\n }\n }\n }\n })().finally(() => {\n refreshing = false;\n if (active && dirty) requestRefresh();\n });\n };\n\n const call = client.watchGraph({}, {\n onMessage: requestRefresh,\n });\n requestRefresh();\n const done = (async () => {\n try {\n await call;\n } catch (error) {\n reportError(error);\n throw error;\n } finally {\n active = false;\n }\n await refreshTail;\n })();\n\n return {\n ready,\n done,\n cancel: async (reason?: string) => {\n active = false;\n if (!readySettled) {\n readySettled = true;\n rejectReady(new Error(reason ?? 'Topology watch cancelled'));\n }\n try {\n await call.cancel(reason);\n } finally {\n call.dispose?.(reason);\n }\n },\n };\n }\n}\n","import type { LinkRpcConnection } from '@hediet/linkrpc';\nimport {\n trafficInterface,\n type TrafficOverflowEvent,\n type TrafficTransitEvent,\n type TrafficWatchResult,\n type TrafficRequestRef,\n} from '@hediet/linkrpc/inspection';\n\nexport interface TrafficCallbacks {\n onTransit(transit: TrafficTransitEvent): void;\n onOverflow?(overflow: TrafficOverflowEvent): void;\n onError?(error: unknown): void;\n}\n\nexport interface TrafficWatch {\n readonly done: Promise<TrafficWatchResult>;\n cancel(reason?: string): Promise<void>;\n}\n\nexport interface TrafficWatchOptions {\n readonly methodPrefix?: string;\n readonly trafficIgnoreKey?: string;\n readonly focusRequest?: TrafficRequestRef;\n}\n\nexport interface TrafficWatchWithPayloadsOptions extends TrafficWatchOptions {\n readonly maxPayloadBytes: number;\n}\n\n/** Traffic stream client for the endpoint node hosting one service. */\nexport class TrafficClient<TInCtx = unknown, TOutCtx = unknown> {\n constructor(\n private readonly _connection: LinkRpcConnection<TInCtx, TOutCtx>,\n public readonly serviceId: string,\n ) { }\n\n public watch(\n options: TrafficWatchOptions,\n callbacks: TrafficCallbacks,\n ): TrafficWatch {\n const call = this._connection.service(this.serviceId)\n .get(trafficInterface)\n .watch(withTrafficIgnoreKey(options), { onMessage: (event) => {\n dispatchTrafficEvent(event, callbacks);\n } });\n void call.catch((error) => reportTrafficError(callbacks, error));\n return {\n done: call,\n cancel: async (reason?: string) => {\n try {\n await call.cancel(reason);\n await call;\n } finally {\n call.dispose?.(reason);\n }\n },\n };\n }\n\n public watchWithPayloads(\n options: TrafficWatchWithPayloadsOptions,\n callbacks: TrafficCallbacks,\n ): TrafficWatch {\n const call = this._connection.service(this.serviceId)\n .get(trafficInterface)\n .watchWithPayloads(withTrafficIgnoreKey(options), { onMessage: (event) => {\n dispatchTrafficEvent(event, callbacks);\n } });\n void call.catch((error) => reportTrafficError(callbacks, error));\n return {\n done: call,\n cancel: async (reason?: string) => {\n try {\n await call.cancel(reason);\n await call;\n } finally {\n call.dispose?.(reason);\n }\n },\n };\n }\n}\n\nfunction withTrafficIgnoreKey<T extends TrafficWatchOptions>(\n options: T,\n): T & { trafficIgnoreKey: string; } {\n return {\n ...options,\n trafficIgnoreKey: options.trafficIgnoreKey ?? createTrafficIgnoreKey(),\n };\n}\n\nfunction createTrafficIgnoreKey(): string {\n if (typeof globalThis.crypto?.randomUUID === 'function') {\n return globalThis.crypto.randomUUID();\n }\n const bytes = new Uint8Array(16);\n globalThis.crypto.getRandomValues(bytes);\n return Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('');\n}\n\nfunction dispatchTrafficEvent(\n event: TrafficTransitEvent | TrafficOverflowEvent,\n callbacks: TrafficCallbacks,\n): void {\n try {\n if (event.type === 'transit') callbacks.onTransit(event);\n else callbacks.onOverflow?.(event);\n } catch (error) {\n reportTrafficError(callbacks, error);\n }\n}\n\nfunction reportTrafficError(callbacks: TrafficCallbacks, error: unknown): void {\n try {\n callbacks.onError?.(error);\n } catch {\n // Consumer callbacks never participate in transport lifecycle.\n }\n}\n","import type {\n RouteClaim,\n TopologyGraph,\n TopologyLink,\n TopologyLinkEndpoint,\n TopologyNode,\n} from '@hediet/linkrpc/inspection';\n\nexport interface SourcedTopologyNode extends TopologyNode {\n readonly sources: readonly string[];\n}\n\nexport interface SourcedTopologyLink extends TopologyLink {\n readonly sources: readonly string[];\n}\n\nexport interface SourcedRouteClaim extends RouteClaim {\n readonly sources: readonly string[];\n}\n\nexport interface NetworkTopologyGraph {\n readonly nodes: readonly SourcedTopologyNode[];\n readonly links: readonly SourcedTopologyLink[];\n readonly routes: readonly SourcedRouteClaim[];\n readonly sources: readonly {\n serviceId: string;\n observerServiceId: string;\n entryNodeId: string;\n }[];\n}\n\nexport function mergeTopologyGraphs(\n inputs: readonly { source: string; graph: TopologyGraph; }[],\n): NetworkTopologyGraph {\n const nodes = new Map<string, { value: TopologyNode; sources: Set<string>; }>();\n const links = new Map<string, { value: TopologyLink; sources: Set<string>; }>();\n const routes = new Map<string, { value: RouteClaim; sources: Set<string>; }>();\n\n for (const { source, graph } of [...inputs].sort((a, b) => a.source.localeCompare(b.source))) {\n for (const node of graph.nodes) {\n const existing = nodes.get(node.nodeId);\n if (existing === undefined) {\n nodes.set(node.nodeId, { value: cloneTopologyNode(node), sources: new Set([source]) });\n } else {\n existing.sources.add(source);\n if (node.kind === 'hub') {\n existing.value.kind = 'hub';\n }\n existing.value.label ??= node.label;\n for (const port of node.ports) {\n const current = existing.value.ports.find((candidate) =>\n candidate.portId === port.portId);\n if (current === undefined) {\n existing.value.ports.push({ ...port });\n } else {\n current.label ??= port.label;\n }\n }\n const descriptors = existing.value.descriptors ?? [];\n const descriptorKeys = new Set(descriptors.map(descriptorKey));\n for (const descriptor of node.descriptors ?? []) {\n const key = descriptorKey(descriptor);\n if (!descriptorKeys.has(key)) {\n descriptors.push(cloneParticipantDescriptorSource(descriptor));\n descriptorKeys.add(key);\n }\n }\n if (descriptors.length > 0) existing.value.descriptors = descriptors;\n }\n }\n for (const link of graph.links) {\n const isReversed = endpointKey(link.from) > endpointKey(link.to);\n const [from, to] = canonicalEndpoints(link.from, link.to);\n const key = `${endpointKey(from)}\\u0000${endpointKey(to)}`;\n const value: TopologyLink = {\n ...link,\n from,\n to,\n ...(link.transport === undefined\n ? {}\n : { transport: cloneTopologyTransport(link.transport, isReversed) }),\n };\n const existing = links.get(key);\n if (existing === undefined) {\n links.set(key, { value, sources: new Set([source]) });\n } else {\n existing.sources.add(source);\n existing.value.transport ??= value.transport;\n }\n }\n for (const route of graph.routes) {\n const key = `${route.serviceId}\\u0000${route.nodeId}\\u0000${route.portId}\\u0000${route.match}`;\n const existing = routes.get(key);\n if (existing === undefined) {\n routes.set(key, { value: { ...route }, sources: new Set([source]) });\n } else {\n existing.sources.add(source);\n }\n }\n }\n\n const sourcedRoutes = [...routes.values()].map(({ value, sources }) => ({\n ...value,\n sources: [...sources].sort(),\n }));\n return {\n nodes: [...nodes.values()].map(({ value, sources }) => ({\n ...value,\n ports: [...value.ports].sort((a, b) => a.portId.localeCompare(b.portId)),\n ...(value.descriptors === undefined ? {} : {\n descriptors: [...value.descriptors].sort((a, b) =>\n descriptorKey(a).localeCompare(descriptorKey(b))),\n }),\n sources: [...sources].sort(),\n })).sort((a, b) => a.nodeId.localeCompare(b.nodeId)),\n links: [...links.values()].map(({ value, sources }) => ({\n ...value,\n sources: [...sources].sort(),\n })).sort((a, b) =>\n endpointKey(a.from).localeCompare(endpointKey(b.from))\n || endpointKey(a.to).localeCompare(endpointKey(b.to))),\n routes: sourcedRoutes.sort((a, b) =>\n a.serviceId.localeCompare(b.serviceId)\n || a.nodeId.localeCompare(b.nodeId)\n || a.portId.localeCompare(b.portId)\n || a.match.localeCompare(b.match)),\n sources: [...inputs].sort((a, b) => a.source.localeCompare(b.source)).map(({ source, graph }) => ({\n serviceId: source,\n observerServiceId: graph.observerServiceId,\n entryNodeId: graph.entryNodeId,\n })),\n };\n}\n\nfunction cloneTopologyNode(node: TopologyNode): TopologyNode {\n return {\n ...node,\n ports: node.ports.map((port) => ({ ...port })),\n ...(node.descriptors === undefined ? {} : {\n descriptors: node.descriptors.map(cloneParticipantDescriptorSource),\n }),\n };\n}\n\nfunction cloneParticipantDescriptorSource(\n source: NonNullable<TopologyNode['descriptors']>[number],\n): NonNullable<TopologyNode['descriptors']>[number] {\n return {\n ...source,\n descriptor: {\n ...source.descriptor,\n ...(source.descriptor.metadata === undefined\n ? {}\n : { metadata: { ...source.descriptor.metadata } }),\n },\n };\n}\n\nfunction cloneTopologyTransport(\n transport: NonNullable<TopologyLink['transport']>,\n reverse: boolean,\n): NonNullable<TopologyLink['transport']> {\n const {\n local: reportedLocal,\n remote: reportedRemote,\n metadata,\n ...rest\n } = transport;\n const local = reverse ? reportedRemote : reportedLocal;\n const remote = reverse ? reportedLocal : reportedRemote;\n return {\n ...rest,\n ...(local === undefined ? {} : { local: { ...local } }),\n ...(remote === undefined ? {} : { remote: { ...remote } }),\n ...(metadata === undefined ? {} : { metadata: { ...metadata } }),\n };\n}\n\nfunction descriptorKey(\n source: NonNullable<TopologyNode['descriptors']>[number],\n): string {\n const descriptor = source.descriptor;\n const metadata = descriptor.metadata === undefined\n ? undefined\n : Object.fromEntries(Object.entries(descriptor.metadata).sort(([a], [b]) =>\n a.localeCompare(b)));\n return JSON.stringify({\n source: source.source,\n descriptor: {\n ...descriptor,\n ...(metadata === undefined ? {} : { metadata }),\n },\n });\n}\n\nfunction canonicalEndpoints(\n a: TopologyLinkEndpoint,\n b: TopologyLinkEndpoint,\n): readonly [TopologyLinkEndpoint, TopologyLinkEndpoint] {\n return endpointKey(a) <= endpointKey(b) ? [a, b] : [b, a];\n}\n\nfunction endpointKey(endpoint: TopologyLinkEndpoint): string {\n return `${endpoint.nodeId}\\u0000${endpoint.portId}`;\n}\n","import type { LinkRpcConnection } from '@hediet/linkrpc';\nimport type {\n TopologyGraph,\n TrafficOverflowEvent,\n TrafficTransitEvent,\n} from '@hediet/linkrpc/inspection';\nimport {\n TrafficClient,\n type TrafficCallbacks,\n type TrafficWatch,\n type TrafficWatchOptions,\n type TrafficWatchWithPayloadsOptions,\n} from './trafficClient';\nimport { TopologyClient, type TopologyWatch } from './topologyClient';\nimport { mergeTopologyGraphs, type NetworkTopologyGraph } from './topologyGraph';\n\nexport interface NetworkInspectionClientOptions {\n onGraph?(graph: NetworkTopologyGraph): void;\n onError?(error: unknown, sourceServiceId: string): void;\n}\n\nexport interface NetworkTrafficCallbacks {\n onTransit(transit: TrafficTransitEvent, sourceServiceId: string): void;\n onOverflow?(overflow: TrafficOverflowEvent, sourceServiceId: string): void;\n onError?(error: unknown, sourceServiceId: string): void;\n}\n\nexport interface NetworkTrafficWatch {\n readonly done: Promise<void>;\n cancel(reason?: string): Promise<void>;\n}\n\ninterface TopologySource {\n readonly client: TopologyClient<unknown, unknown>;\n readonly watch: TopologyWatch;\n graph: TopologyGraph | undefined;\n}\n\n/**\n * Merges independently observed service graphs. Traffic is deliberately not\n * deduplicated: each source remains identified so consumers can stitch flows.\n */\nexport class NetworkInspectionClient {\n private readonly _sources = new Map<string, TopologySource>();\n private readonly _trafficGroups = new Set<NetworkTrafficGroup>();\n\n constructor(\n private readonly _connection: LinkRpcConnection<unknown, unknown>,\n private readonly _options: NetworkInspectionClientOptions = {},\n ) { }\n\n public async addTopologyService(serviceId: string): Promise<void> {\n const existing = this._sources.get(serviceId);\n if (existing !== undefined) {\n await existing.watch.ready;\n return;\n }\n\n const client = new TopologyClient(this._connection, serviceId);\n let source!: TopologySource;\n const watch = client.watch({\n onGraph: (graph) => {\n source.graph = graph;\n this._options.onGraph?.(this.getGraph());\n },\n onError: (error) => this._options.onError?.(error, serviceId),\n });\n source = { client, watch, graph: undefined };\n this._sources.set(serviceId, source);\n for (const group of this._trafficGroups) group.add(serviceId);\n try {\n await watch.ready;\n } catch (error) {\n if (this._sources.get(serviceId) === source) {\n await this.removeTopologyService(serviceId);\n } else {\n await source.watch.cancel('source-replaced').catch(() => undefined);\n await source.watch.done.catch(() => undefined);\n }\n throw error;\n }\n }\n\n public async removeTopologyService(serviceId: string): Promise<void> {\n const source = this._sources.get(serviceId);\n if (source === undefined) return;\n this._sources.delete(serviceId);\n await Promise.all([...this._trafficGroups].map((group) => group.remove(serviceId)));\n await source.watch.cancel('source-removed');\n await source.watch.done.catch(() => undefined);\n this._options.onGraph?.(this.getGraph());\n }\n\n public getGraph(): NetworkTopologyGraph {\n return mergeTopologyGraphs(\n [...this._sources.entries()]\n .flatMap(([source, value]) =>\n value.graph === undefined ? [] : [{ source, graph: value.graph }]),\n );\n }\n\n public watchTraffic(\n options: TrafficWatchOptions | TrafficWatchWithPayloadsOptions,\n callbacks: NetworkTrafficCallbacks,\n ): NetworkTrafficWatch {\n const group = new NetworkTrafficGroup(\n this._connection,\n options,\n callbacks,\n () => this._trafficGroups.delete(group),\n );\n this._trafficGroups.add(group);\n for (const serviceId of this._sources.keys()) group.add(serviceId);\n return group;\n }\n\n public async dispose(): Promise<void> {\n const failures: unknown[] = [];\n const trafficResults = await Promise.allSettled(\n [...this._trafficGroups].map((group) => group.cancel('disposed')),\n );\n failures.push(...trafficResults.flatMap((result) =>\n result.status === 'rejected' ? [result.reason] : []));\n const sourceResults = await Promise.allSettled(\n [...this._sources.keys()].map((serviceId) => this.removeTopologyService(serviceId)),\n );\n failures.push(...sourceResults.flatMap((result) =>\n result.status === 'rejected' ? [result.reason] : []));\n if (failures.length !== 0) {\n throw new AggregateError(failures, 'Failed to dispose network inspection');\n }\n }\n}\n\nclass NetworkTrafficGroup implements NetworkTrafficWatch {\n private readonly _watches = new Map<string, TrafficWatch>();\n private _active = true;\n private readonly _resolveDone: () => void;\n public readonly done: Promise<void>;\n\n constructor(\n private readonly _connection: LinkRpcConnection<unknown, unknown>,\n private readonly _options: TrafficWatchOptions | TrafficWatchWithPayloadsOptions,\n private readonly _callbacks: NetworkTrafficCallbacks,\n private readonly _onCancel: () => void,\n ) {\n let resolve!: () => void;\n this.done = new Promise<void>((r) => resolve = r);\n this._resolveDone = resolve;\n }\n\n public add(serviceId: string): void {\n if (!this._active || this._watches.has(serviceId)) return;\n const client = new TrafficClient(this._connection, serviceId);\n const callbacks: TrafficCallbacks = {\n onTransit: (transit) => this._callbacks.onTransit(transit, serviceId),\n onOverflow: (overflow) => this._callbacks.onOverflow?.(overflow, serviceId),\n onError: (error) => this._callbacks.onError?.(error, serviceId),\n };\n const watch = 'maxPayloadBytes' in this._options\n ? client.watchWithPayloads(this._options, callbacks)\n : client.watch(this._options, callbacks);\n this._watches.set(serviceId, watch);\n }\n\n public async remove(serviceId: string): Promise<void> {\n const watch = this._watches.get(serviceId);\n if (watch === undefined) return;\n this._watches.delete(serviceId);\n await watch.cancel('source-removed').catch(() => undefined);\n await watch.done.catch(() => undefined);\n }\n\n public async cancel(reason?: string): Promise<void> {\n if (!this._active) return this.done;\n this._active = false;\n this._onCancel();\n const watches = [...this._watches.values()];\n this._watches.clear();\n const failures: unknown[] = [];\n try {\n const results = await Promise.allSettled(watches.map(async (watch) => {\n await watch.cancel(reason);\n await watch.done;\n }));\n failures.push(...results.flatMap((result) =>\n result.status === 'rejected' ? [result.reason] : []));\n } finally {\n this._resolveDone();\n }\n if (failures.length !== 0) {\n throw new AggregateError(failures, 'Failed to cancel network traffic watches');\n }\n }\n}\n","import { DEFAULT_RPC_TIMEOUT_MS, type LinkRpcConnection } from '@hediet/linkrpc';\nimport {\n HubDirectoryExplorer,\n type HubDirectoryGraphSnapshot,\n} from '@hediet/linkrpc/hub/common';\nimport { topologyInterface, type TopologyGraph } from '@hediet/linkrpc/inspection';\nimport {\n mergeTopologyGraphs,\n type NetworkTopologyGraph,\n} from './topologyGraph';\nimport { TopologyClient, type TopologyWatch } from './topologyClient';\n\nexport type TopologySourceState = 'loading' | 'ready' | 'error';\n\nexport interface TopologySourceSnapshot {\n readonly serviceId: string;\n readonly state: TopologySourceState;\n readonly graph?: TopologyGraph;\n readonly error?: string;\n}\n\nexport interface TopologyNetworkSnapshot {\n readonly revision: number;\n readonly complete: boolean;\n readonly directory?: HubDirectoryGraphSnapshot;\n readonly directoryError?: string;\n readonly sources: readonly TopologySourceSnapshot[];\n readonly graph: NetworkTopologyGraph;\n}\n\nexport interface TopologyNetworkOptions {\n /**\n * Fixed topology providers. When omitted, providers are discovered through\n * the directory graph by their `hubrpc.topology` interface.\n */\n readonly sourceServiceIds?: readonly string[];\n readonly maxDepth?: number;\n /** Hard deadline for each directory and topology request. Defaults to 5 seconds. */\n readonly timeoutMs?: number;\n}\n\nexport interface TopologyNetworkQueryCallbacks {\n onSnapshot?(snapshot: TopologyNetworkSnapshot): void;\n}\n\nexport interface TopologyNetworkWatch {\n readonly snapshot: TopologyNetworkSnapshot;\n readonly ready: Promise<TopologyNetworkSnapshot>;\n readonly done: Promise<void>;\n subscribe(listener: (snapshot: TopologyNetworkSnapshot) => void): () => void;\n cancel(reason?: string): Promise<void>;\n}\n\n/**\n * Queries or watches a merged topology graph from one, many, or dynamically\n * discovered topology providers. Query mode never registers directory or\n * topology watches; progress snapshots describe its finite request fan-out.\n */\nexport class TopologyNetworkClient {\n public constructor(\n private readonly _connection: LinkRpcConnection<unknown, unknown>,\n ) {}\n\n public async query(\n options: TopologyNetworkOptions = {},\n callbacks: TopologyNetworkQueryCallbacks = {},\n ): Promise<TopologyNetworkSnapshot> {\n const store = new TopologyNetworkStore();\n const unsubscribe = callbacks.onSnapshot === undefined\n ? undefined\n : store.subscribe(callbacks.onSnapshot);\n try {\n if (options.sourceServiceIds !== undefined) {\n const serviceIds = uniqueSorted(options.sourceServiceIds);\n store.reconcileSources(serviceIds);\n await Promise.all(serviceIds.map((serviceId) =>\n this._querySource(store, serviceId, options.timeoutMs)));\n } else {\n await this._queryDiscovered(store, options);\n }\n store.setComplete();\n return store.snapshot;\n } finally {\n unsubscribe?.();\n }\n }\n\n public watch(options: TopologyNetworkOptions = {}): TopologyNetworkWatch {\n return new TopologyNetworkWatchImpl(this._connection, options);\n }\n\n private async _queryDiscovered(\n store: TopologyNetworkStore,\n options: TopologyNetworkOptions,\n ): Promise<void> {\n const explorer = new HubDirectoryExplorer(this._connection.channel, {\n interfaceId: topologyInterface.info.id,\n maxDepth: options.maxDepth,\n timeoutMs: options.timeoutMs ?? DEFAULT_RPC_TIMEOUT_MS,\n });\n const queries = new Map<string, Promise<void>>();\n const reconcile = (snapshot: HubDirectoryGraphSnapshot): void => {\n store.setDirectory(snapshot);\n const serviceIds = topologyServiceIds(snapshot);\n store.reconcileSources(serviceIds);\n for (const serviceId of serviceIds) {\n if (!queries.has(serviceId)) {\n queries.set(serviceId, this._querySource(store, serviceId, options.timeoutMs));\n }\n }\n };\n const unsubscribe = explorer.subscribe((event) => reconcile(event.snapshot));\n try {\n await explorer.explore();\n reconcile(explorer.graphSnapshot);\n } catch (error) {\n store.setDirectoryError(error);\n } finally {\n unsubscribe();\n explorer.dispose();\n }\n await Promise.all(queries.values());\n }\n\n private async _querySource(\n store: TopologyNetworkStore,\n serviceId: string,\n timeoutMs = DEFAULT_RPC_TIMEOUT_MS,\n ): Promise<void> {\n try {\n const graph = await new TopologyClient(\n this._connection,\n serviceId,\n timeoutMs,\n ).getGraph();\n if (store.hasSource(serviceId)) store.setSourceGraph(serviceId, graph);\n } catch (error) {\n if (store.hasSource(serviceId)) store.setSourceError(serviceId, error);\n }\n }\n}\n\nclass TopologyNetworkWatchImpl implements TopologyNetworkWatch {\n private readonly _store = new TopologyNetworkStore();\n private readonly _sourceWatches = new Map<string, TopologyWatch>();\n private readonly _initialSourceReady = new Map<string, Promise<void>>();\n private readonly _explorer: HubDirectoryExplorer | undefined;\n private _stopDirectoryWatch: (() => void) | undefined;\n private _cancelled = false;\n private _resolveDone!: () => void;\n private _resolveReady!: (snapshot: TopologyNetworkSnapshot) => void;\n private _readySettled = false;\n\n public readonly ready = new Promise<TopologyNetworkSnapshot>((resolve) => {\n this._resolveReady = resolve;\n });\n public readonly done = new Promise<void>((resolve) => {\n this._resolveDone = resolve;\n });\n\n public constructor(\n private readonly _connection: LinkRpcConnection<unknown, unknown>,\n private readonly _options: TopologyNetworkOptions,\n ) {\n this._explorer = _options.sourceServiceIds === undefined\n ? new HubDirectoryExplorer(_connection.channel, {\n interfaceId: topologyInterface.info.id,\n maxDepth: _options.maxDepth,\n timeoutMs: _options.timeoutMs ?? DEFAULT_RPC_TIMEOUT_MS,\n })\n : undefined;\n void this._initialize();\n }\n\n public get snapshot(): TopologyNetworkSnapshot {\n return this._store.snapshot;\n }\n\n public subscribe(listener: (snapshot: TopologyNetworkSnapshot) => void): () => void {\n return this._store.subscribe(listener);\n }\n\n public async cancel(reason = 'topology watch cancelled'): Promise<void> {\n if (this._cancelled) return this.done;\n this._cancelled = true;\n this._stopDirectoryWatch?.();\n this._stopDirectoryWatch = undefined;\n this._explorer?.dispose();\n const watches = [...this._sourceWatches.values()];\n this._sourceWatches.clear();\n await Promise.allSettled(watches.map((watch) => watch.cancel(reason)));\n if (!this._readySettled) this._settleReady();\n this._resolveDone();\n }\n\n private async _initialize(): Promise<void> {\n try {\n if (this._options.sourceServiceIds !== undefined) {\n const serviceIds = uniqueSorted(this._options.sourceServiceIds);\n this._store.reconcileSources(serviceIds);\n for (const serviceId of serviceIds) this._startSourceWatch(serviceId);\n } else {\n const explorer = this._explorer!;\n explorer.subscribe((event) => this._reconcileDirectory(event.snapshot));\n this._stopDirectoryWatch = await explorer.watch(() => {});\n this._reconcileDirectory(explorer.graphSnapshot);\n }\n await Promise.allSettled(this._initialSourceReady.values());\n if (!this._cancelled) {\n this._store.setComplete();\n this._settleReady();\n }\n } catch (error) {\n if (!this._cancelled) {\n this._store.setDirectoryError(error);\n this._store.setComplete();\n this._settleReady();\n }\n }\n }\n\n private _reconcileDirectory(snapshot: HubDirectoryGraphSnapshot): void {\n if (this._cancelled) return;\n this._store.setDirectory(snapshot);\n const serviceIds = topologyServiceIds(snapshot);\n const desired = new Set(serviceIds);\n for (const serviceId of serviceIds) this._startSourceWatch(serviceId);\n for (const [serviceId, watch] of this._sourceWatches) {\n if (desired.has(serviceId)) continue;\n this._sourceWatches.delete(serviceId);\n this._initialSourceReady.delete(serviceId);\n this._store.removeSource(serviceId);\n void watch.cancel('topology source removed').catch(() => undefined);\n }\n }\n\n private _startSourceWatch(serviceId: string): void {\n if (this._sourceWatches.has(serviceId) || this._cancelled) return;\n this._store.ensureSource(serviceId);\n const watch = new TopologyClient(\n this._connection,\n serviceId,\n this._options.timeoutMs,\n ).watch({\n onGraph: (graph) => {\n if (!this._cancelled && this._sourceWatches.get(serviceId) === watch) {\n this._store.setSourceGraph(serviceId, graph);\n }\n },\n onError: (error) => {\n if (!this._cancelled && this._sourceWatches.get(serviceId) === watch) {\n this._store.setSourceError(serviceId, error);\n }\n },\n });\n this._sourceWatches.set(serviceId, watch);\n const initial = watch.ready.then(\n () => undefined,\n (error) => {\n if (!this._cancelled && this._sourceWatches.get(serviceId) === watch) {\n this._store.setSourceError(serviceId, error);\n }\n },\n );\n this._initialSourceReady.set(serviceId, initial);\n void watch.done.catch((error) => {\n if (!this._cancelled && this._sourceWatches.get(serviceId) === watch) {\n this._store.setSourceError(serviceId, error);\n }\n });\n }\n\n private _settleReady(): void {\n if (this._readySettled) return;\n this._readySettled = true;\n this._resolveReady(this._store.snapshot);\n }\n}\n\ninterface MutableTopologySource {\n readonly serviceId: string;\n state: TopologySourceState;\n graph?: TopologyGraph;\n error?: string;\n}\n\nclass TopologyNetworkStore {\n private readonly _sources = new Map<string, MutableTopologySource>();\n private readonly _listeners = new Set<(snapshot: TopologyNetworkSnapshot) => void>();\n private _revision = 0;\n private _complete = false;\n private _directory: HubDirectoryGraphSnapshot | undefined;\n private _directoryError: string | undefined;\n\n public get snapshot(): TopologyNetworkSnapshot {\n const sources = [...this._sources.values()]\n .sort((a, b) => a.serviceId.localeCompare(b.serviceId))\n .map((source): TopologySourceSnapshot => ({\n serviceId: source.serviceId,\n state: source.state,\n ...(source.graph !== undefined ? { graph: source.graph } : {}),\n ...(source.error !== undefined ? { error: source.error } : {}),\n }));\n return {\n revision: this._revision,\n complete: this._complete,\n ...(this._directory !== undefined ? { directory: this._directory } : {}),\n ...(this._directoryError !== undefined\n ? { directoryError: this._directoryError }\n : {}),\n sources,\n graph: mergeTopologyGraphs(sources.flatMap((source) =>\n source.graph === undefined\n ? []\n : [{ source: source.serviceId, graph: source.graph }])),\n };\n }\n\n public subscribe(listener: (snapshot: TopologyNetworkSnapshot) => void): () => void {\n this._listeners.add(listener);\n listener(this.snapshot);\n return () => this._listeners.delete(listener);\n }\n\n public hasSource(serviceId: string): boolean {\n return this._sources.has(serviceId);\n }\n\n public ensureSource(serviceId: string): void {\n if (this._sources.has(serviceId)) return;\n this._sources.set(serviceId, { serviceId, state: 'loading' });\n this._emit();\n }\n\n public reconcileSources(serviceIds: readonly string[]): void {\n const desired = new Set(serviceIds);\n let changed = false;\n for (const serviceId of serviceIds) {\n if (!this._sources.has(serviceId)) {\n this._sources.set(serviceId, { serviceId, state: 'loading' });\n changed = true;\n }\n }\n for (const serviceId of this._sources.keys()) {\n if (!desired.has(serviceId)) {\n this._sources.delete(serviceId);\n changed = true;\n }\n }\n if (changed) this._emit();\n }\n\n public removeSource(serviceId: string): void {\n if (this._sources.delete(serviceId)) this._emit();\n }\n\n public setSourceGraph(serviceId: string, graph: TopologyGraph): void {\n const source = this._sources.get(serviceId);\n if (source === undefined) return;\n source.state = 'ready';\n source.graph = graph;\n source.error = undefined;\n this._emit();\n }\n\n public setSourceError(serviceId: string, error: unknown): void {\n const source = this._sources.get(serviceId);\n if (source === undefined) return;\n source.state = 'error';\n source.error = errorMessage(error);\n this._emit();\n }\n\n public setDirectory(snapshot: HubDirectoryGraphSnapshot): void {\n this._directory = snapshot;\n this._directoryError = undefined;\n this._emit();\n }\n\n public setDirectoryError(error: unknown): void {\n this._directoryError = errorMessage(error);\n this._emit();\n }\n\n public setComplete(): void {\n if (this._complete) return;\n this._complete = true;\n this._emit();\n }\n\n private _emit(): void {\n this._revision++;\n const snapshot = this.snapshot;\n for (const listener of [...this._listeners]) {\n try {\n listener(snapshot);\n } catch {\n // A consumer cannot disrupt source reconciliation.\n }\n }\n }\n}\n\nfunction topologyServiceIds(snapshot: HubDirectoryGraphSnapshot): string[] {\n return uniqueSorted(snapshot.result.listings\n .filter((listing) => listing.interfaceId === topologyInterface.info.id)\n .map((listing) => listing.serviceId));\n}\n\nfunction uniqueSorted(values: readonly string[]): string[] {\n return [...new Set(values)].sort((a, b) => a.localeCompare(b));\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"],"mappings":";;;;;AAIA,IAAa,iBAAb,MAAiE;CAExC;CADrB,YACI,aACF;EADmB,KAAA,cAAA;CACjB;CAEJ,UAAoC;EAChC,OAAO,KAAK,YAAY,IAAI,aAAa,CAAC,CAAC,UAAU,CAAC,CAAC;CAC3D;CAEA,cAAqB,WAAsC;EACvD,OAAO,KAAK,YAAY,QAAQ,SAAS,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,UAAU,CAAC,CAAC;CAC9E;AACJ;;;;ACQA,IAAa,iBAAb,MAAiE;CAExC;CACD;CACC;CAHrB,YACI,aACA,WACA,aAA8B,wBAChC;EAHmB,KAAA,cAAA;EACD,KAAA,YAAA;EACC,KAAA,aAAA;CACjB;CAEJ,WAA0C;EACtC,MAAM,UAAU,KAAK,YAAY,QAAQ,KAAK,SAAS,CAAC,CACnD,IAAI,iBAAiB,CAAC,CACtB,SAAS,CAAC,CAAC;EAChB,OAAO,eACH,SACA,qBAAqB,KAAK,UAAU,IACpC,KAAK,UACT;CACJ;CAEA,MAAa,WAAkD;EAC3D,MAAM,SAAS,KAAK,YAAY,QAAQ,KAAK,SAAS,CAAC,CAAC,IAAI,iBAAiB;EAC7E,IAAI,SAAS;EACb,IAAI,QAAQ;EACZ,IAAI,aAAa;EACjB,IAAI,cAA6B,QAAQ,QAAQ;EACjD,IAAI,eAAe;EACnB,IAAI;EACJ,IAAI;EACJ,MAAM,QAAQ,IAAI,SAAwB,SAAS,WAAW;GAC1D,eAAe;GACf,cAAc;EAClB,CAAC;EAED,MAAM,eAAe,UAAyB;GAC1C,IAAI;IACA,UAAU,UAAU,KAAK;GAC7B,QAAQ,CAER;EACJ;EACA,MAAM,uBAA6B;GAC/B,IAAI,CAAC,QAAQ;GACb,QAAQ;GACR,IAAI,YAAY;GAChB,aAAa;GACb,eAAe,YAAY;IACvB,OAAO,UAAU,OAAO;KACpB,QAAQ;KACR,IAAI;MACA,MAAM,QAAQ,MAAM,eAChB,OAAO,SAAS,CAAC,CAAC,GAClB,qBAAqB,KAAK,UAAU,IACpC,KAAK,UACT;MACA,IAAI,CAAC,QAAQ;MACb,IAAI;OACA,UAAU,QAAQ,KAAK;MAC3B,SAAS,OAAO;OACZ,YAAY,KAAK;MACrB;MACA,IAAI,CAAC,cAAc;OACf,eAAe;OACf,aAAa,KAAK;MACtB;KACJ,SAAS,OAAO;MACZ,YAAY,KAAK;MACjB,IAAI,CAAC,cAAc;OACf,eAAe;OACf,YAAY,KAAK;MACrB;KACJ;IACJ;GACJ,EAAA,CAAG,CAAC,CAAC,cAAc;IACf,aAAa;IACb,IAAI,UAAU,OAAO,eAAe;GACxC,CAAC;EACL;EAEA,MAAM,OAAO,OAAO,WAAW,CAAC,GAAG,EAC/B,WAAW,eACf,CAAC;EACD,eAAe;EAaf,OAAO;GACH;GACA,OAdU,YAAY;IACtB,IAAI;KACA,MAAM;IACV,SAAS,OAAO;KACZ,YAAY,KAAK;KACjB,MAAM;IACV,UAAU;KACN,SAAS;IACb;IACA,MAAM;GACV,EAAA,CAIO;GACH,QAAQ,OAAO,WAAoB;IAC/B,SAAS;IACT,IAAI,CAAC,cAAc;KACf,eAAe;KACf,YAAY,IAAI,MAAM,UAAU,0BAA0B,CAAC;IAC/D;IACA,IAAI;KACA,MAAM,KAAK,OAAO,MAAM;IAC5B,UAAU;KACN,KAAK,UAAU,MAAM;IACzB;GACJ;EACJ;CACJ;AACJ;;;;ACvGA,IAAa,gBAAb,MAAgE;CAEvC;CACD;CAFpB,YACI,aACA,WACF;EAFmB,KAAA,cAAA;EACD,KAAA,YAAA;CAChB;CAEJ,MACI,SACA,WACY;EACZ,MAAM,OAAO,KAAK,YAAY,QAAQ,KAAK,SAAS,CAAC,CAChD,IAAI,gBAAgB,CAAC,CACrB,MAAM,qBAAqB,OAAO,GAAG,EAAE,YAAY,UAAU;GAC1D,qBAAqB,OAAO,SAAS;EACzC,EAAE,CAAC;EACP,KAAU,OAAO,UAAU,mBAAmB,WAAW,KAAK,CAAC;EAC/D,OAAO;GACH,MAAM;GACN,QAAQ,OAAO,WAAoB;IAC/B,IAAI;KACA,MAAM,KAAK,OAAO,MAAM;KACxB,MAAM;IACV,UAAU;KACN,KAAK,UAAU,MAAM;IACzB;GACJ;EACJ;CACJ;CAEA,kBACI,SACA,WACY;EACZ,MAAM,OAAO,KAAK,YAAY,QAAQ,KAAK,SAAS,CAAC,CAChD,IAAI,gBAAgB,CAAC,CACrB,kBAAkB,qBAAqB,OAAO,GAAG,EAAE,YAAY,UAAU;GACtE,qBAAqB,OAAO,SAAS;EACzC,EAAE,CAAC;EACP,KAAU,OAAO,UAAU,mBAAmB,WAAW,KAAK,CAAC;EAC/D,OAAO;GACH,MAAM;GACN,QAAQ,OAAO,WAAoB;IAC/B,IAAI;KACA,MAAM,KAAK,OAAO,MAAM;KACxB,MAAM;IACV,UAAU;KACN,KAAK,UAAU,MAAM;IACzB;GACJ;EACJ;CACJ;AACJ;AAEA,SAAS,qBACL,SACiC;CACjC,OAAO;EACH,GAAG;EACH,kBAAkB,QAAQ,oBAAoB,uBAAuB;CACzE;AACJ;AAEA,SAAS,yBAAiC;CACtC,IAAI,OAAO,WAAW,QAAQ,eAAe,YACzC,OAAO,WAAW,OAAO,WAAW;CAExC,MAAM,wBAAQ,IAAI,WAAW,EAAE;CAC/B,WAAW,OAAO,gBAAgB,KAAK;CACvC,OAAO,MAAM,KAAK,QAAQ,SAAS,KAAK,SAAS,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE;AAClF;AAEA,SAAS,qBACL,OACA,WACI;CACJ,IAAI;EACA,IAAI,MAAM,SAAS,WAAW,UAAU,UAAU,KAAK;OAClD,UAAU,aAAa,KAAK;CACrC,SAAS,OAAO;EACZ,mBAAmB,WAAW,KAAK;CACvC;AACJ;AAEA,SAAS,mBAAmB,WAA6B,OAAsB;CAC3E,IAAI;EACA,UAAU,UAAU,KAAK;CAC7B,QAAQ,CAER;AACJ;;;ACzFA,SAAgB,oBACZ,QACoB;CACpB,MAAM,wBAAQ,IAAI,IAA4D;CAC9E,MAAM,wBAAQ,IAAI,IAA4D;CAC9E,MAAM,yBAAS,IAAI,IAA0D;CAE7E,KAAK,MAAM,EAAE,QAAQ,WAAW,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,OAAO,cAAc,EAAE,MAAM,CAAC,GAAG;EAC1F,KAAK,MAAM,QAAQ,MAAM,OAAO;GAC5B,MAAM,WAAW,MAAM,IAAI,KAAK,MAAM;GACtC,IAAI,aAAa,KAAA,GACb,MAAM,IAAI,KAAK,QAAQ;IAAE,OAAO,kBAAkB,IAAI;IAAG,yBAAS,IAAI,IAAI,CAAC,MAAM,CAAC;GAAE,CAAC;QAClF;IACH,SAAS,QAAQ,IAAI,MAAM;IAC3B,IAAI,KAAK,SAAS,OACd,SAAS,MAAM,OAAO;IAE1B,SAAS,MAAM,UAAU,KAAK;IAC9B,KAAK,MAAM,QAAQ,KAAK,OAAO;KAC3B,MAAM,UAAU,SAAS,MAAM,MAAM,MAAM,cACvC,UAAU,WAAW,KAAK,MAAM;KACpC,IAAI,YAAY,KAAA,GACZ,SAAS,MAAM,MAAM,KAAK,EAAE,GAAG,KAAK,CAAC;UAErC,QAAQ,UAAU,KAAK;IAE/B;IACA,MAAM,cAAc,SAAS,MAAM,eAAe,CAAC;IACnD,MAAM,iBAAiB,IAAI,IAAI,YAAY,IAAI,aAAa,CAAC;IAC7D,KAAK,MAAM,cAAc,KAAK,eAAe,CAAC,GAAG;KAC7C,MAAM,MAAM,cAAc,UAAU;KACpC,IAAI,CAAC,eAAe,IAAI,GAAG,GAAG;MAC1B,YAAY,KAAK,iCAAiC,UAAU,CAAC;MAC7D,eAAe,IAAI,GAAG;KAC1B;IACJ;IACA,IAAI,YAAY,SAAS,GAAG,SAAS,MAAM,cAAc;GAC7D;EACJ;EACA,KAAK,MAAM,QAAQ,MAAM,OAAO;GAC5B,MAAM,aAAa,YAAY,KAAK,IAAI,IAAI,YAAY,KAAK,EAAE;GAC/D,MAAM,CAAC,MAAM,MAAM,mBAAmB,KAAK,MAAM,KAAK,EAAE;GACxD,MAAM,MAAM,GAAG,YAAY,IAAI,EAAE,QAAQ,YAAY,EAAE;GACvD,MAAM,QAAsB;IACxB,GAAG;IACH;IACA;IACA,GAAI,KAAK,cAAc,KAAA,IACjB,CAAC,IACD,EAAE,WAAW,uBAAuB,KAAK,WAAW,UAAU,EAAE;GAC1E;GACA,MAAM,WAAW,MAAM,IAAI,GAAG;GAC9B,IAAI,aAAa,KAAA,GACb,MAAM,IAAI,KAAK;IAAE;IAAO,yBAAS,IAAI,IAAI,CAAC,MAAM,CAAC;GAAE,CAAC;QACjD;IACH,SAAS,QAAQ,IAAI,MAAM;IAC3B,SAAS,MAAM,cAAc,MAAM;GACvC;EACJ;EACA,KAAK,MAAM,SAAS,MAAM,QAAQ;GAC9B,MAAM,MAAM,GAAG,MAAM,UAAU,QAAQ,MAAM,OAAO,QAAQ,MAAM,OAAO,QAAQ,MAAM;GACvF,MAAM,WAAW,OAAO,IAAI,GAAG;GAC/B,IAAI,aAAa,KAAA,GACb,OAAO,IAAI,KAAK;IAAE,OAAO,EAAE,GAAG,MAAM;IAAG,yBAAS,IAAI,IAAI,CAAC,MAAM,CAAC;GAAE,CAAC;QAEnE,SAAS,QAAQ,IAAI,MAAM;EAEnC;CACJ;CAEA,MAAM,gBAAgB,CAAC,GAAG,OAAO,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,eAAe;EACpE,GAAG;EACH,SAAS,CAAC,GAAG,OAAO,CAAC,CAAC,KAAK;CAC/B,EAAE;CACF,OAAO;EACH,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,eAAe;GACpD,GAAG;GACH,OAAO,CAAC,GAAG,MAAM,KAAK,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,OAAO,cAAc,EAAE,MAAM,CAAC;GACvE,GAAI,MAAM,gBAAgB,KAAA,IAAY,CAAC,IAAI,EACvC,aAAa,CAAC,GAAG,MAAM,WAAW,CAAC,CAAC,MAAM,GAAG,MACzC,cAAc,CAAC,CAAC,CAAC,cAAc,cAAc,CAAC,CAAC,CAAC,EACxD;GACA,SAAS,CAAC,GAAG,OAAO,CAAC,CAAC,KAAK;EAC/B,EAAE,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,OAAO,cAAc,EAAE,MAAM,CAAC;EACnD,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,eAAe;GACpD,GAAG;GACH,SAAS,CAAC,GAAG,OAAO,CAAC,CAAC,KAAK;EAC/B,EAAE,CAAC,CAAC,MAAM,GAAG,MACT,YAAY,EAAE,IAAI,CAAC,CAAC,cAAc,YAAY,EAAE,IAAI,CAAC,KAClD,YAAY,EAAE,EAAE,CAAC,CAAC,cAAc,YAAY,EAAE,EAAE,CAAC,CAAC;EACzD,QAAQ,cAAc,MAAM,GAAG,MAC3B,EAAE,UAAU,cAAc,EAAE,SAAS,KAClC,EAAE,OAAO,cAAc,EAAE,MAAM,KAC/B,EAAE,OAAO,cAAc,EAAE,MAAM,KAC/B,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC;EACrC,SAAS,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,OAAO,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,QAAQ,aAAa;GAC9F,WAAW;GACX,mBAAmB,MAAM;GACzB,aAAa,MAAM;EACvB,EAAE;CACN;AACJ;AAEA,SAAS,kBAAkB,MAAkC;CACzD,OAAO;EACH,GAAG;EACH,OAAO,KAAK,MAAM,KAAK,UAAU,EAAE,GAAG,KAAK,EAAE;EAC7C,GAAI,KAAK,gBAAgB,KAAA,IAAY,CAAC,IAAI,EACtC,aAAa,KAAK,YAAY,IAAI,gCAAgC,EACtE;CACJ;AACJ;AAEA,SAAS,iCACL,QACgD;CAChD,OAAO;EACH,GAAG;EACH,YAAY;GACR,GAAG,OAAO;GACV,GAAI,OAAO,WAAW,aAAa,KAAA,IAC7B,CAAC,IACD,EAAE,UAAU,EAAE,GAAG,OAAO,WAAW,SAAS,EAAE;EACxD;CACJ;AACJ;AAEA,SAAS,uBACL,WACA,SACsC;CACtC,MAAM,EACF,OAAO,eACP,QAAQ,gBACR,UACA,GAAG,SACH;CACJ,MAAM,QAAQ,UAAU,iBAAiB;CACzC,MAAM,SAAS,UAAU,gBAAgB;CACzC,OAAO;EACH,GAAG;EACH,GAAI,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE;EACrD,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,OAAO,EAAE;EACxD,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,SAAS,EAAE;CAClE;AACJ;AAEA,SAAS,cACL,QACM;CACN,MAAM,aAAa,OAAO;CAC1B,MAAM,WAAW,WAAW,aAAa,KAAA,IACnC,KAAA,IACA,OAAO,YAAY,OAAO,QAAQ,WAAW,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OACjE,EAAE,cAAc,CAAC,CAAC,CAAC;CAC3B,OAAO,KAAK,UAAU;EAClB,QAAQ,OAAO;EACf,YAAY;GACR,GAAG;GACH,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS;EACjD;CACJ,CAAC;AACL;AAEA,SAAS,mBACL,GACA,GACqD;CACrD,OAAO,YAAY,CAAC,KAAK,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;AAC5D;AAEA,SAAS,YAAY,UAAwC;CACzD,OAAO,GAAG,SAAS,OAAO,QAAQ,SAAS;AAC/C;;;;;;;AClKA,IAAa,0BAAb,MAAqC;CAKZ;CACA;CALrB,2BAA4B,IAAI,IAA4B;CAC5D,iCAAkC,IAAI,IAAyB;CAE/D,YACI,aACA,WAA4D,CAAC,GAC/D;EAFmB,KAAA,cAAA;EACA,KAAA,WAAA;CACjB;CAEJ,MAAa,mBAAmB,WAAkC;EAC9D,MAAM,WAAW,KAAK,SAAS,IAAI,SAAS;EAC5C,IAAI,aAAa,KAAA,GAAW;GACxB,MAAM,SAAS,MAAM;GACrB;EACJ;EAEA,MAAM,SAAS,IAAI,eAAe,KAAK,aAAa,SAAS;EAC7D,IAAI;EACJ,MAAM,QAAQ,OAAO,MAAM;GACvB,UAAU,UAAU;IAChB,OAAO,QAAQ;IACf,KAAK,SAAS,UAAU,KAAK,SAAS,CAAC;GAC3C;GACA,UAAU,UAAU,KAAK,SAAS,UAAU,OAAO,SAAS;EAChE,CAAC;EACD,SAAS;GAAE;GAAQ;GAAO,OAAO,KAAA;EAAU;EAC3C,KAAK,SAAS,IAAI,WAAW,MAAM;EACnC,KAAK,MAAM,SAAS,KAAK,gBAAgB,MAAM,IAAI,SAAS;EAC5D,IAAI;GACA,MAAM,MAAM;EAChB,SAAS,OAAO;GACZ,IAAI,KAAK,SAAS,IAAI,SAAS,MAAM,QACjC,MAAM,KAAK,sBAAsB,SAAS;QACvC;IACH,MAAM,OAAO,MAAM,OAAO,iBAAiB,CAAC,CAAC,YAAY,KAAA,CAAS;IAClE,MAAM,OAAO,MAAM,KAAK,YAAY,KAAA,CAAS;GACjD;GACA,MAAM;EACV;CACJ;CAEA,MAAa,sBAAsB,WAAkC;EACjE,MAAM,SAAS,KAAK,SAAS,IAAI,SAAS;EAC1C,IAAI,WAAW,KAAA,GAAW;EAC1B,KAAK,SAAS,OAAO,SAAS;EAC9B,MAAM,QAAQ,IAAI,CAAC,GAAG,KAAK,cAAc,CAAC,CAAC,KAAK,UAAU,MAAM,OAAO,SAAS,CAAC,CAAC;EAClF,MAAM,OAAO,MAAM,OAAO,gBAAgB;EAC1C,MAAM,OAAO,MAAM,KAAK,YAAY,KAAA,CAAS;EAC7C,KAAK,SAAS,UAAU,KAAK,SAAS,CAAC;CAC3C;CAEA,WAAwC;EACpC,OAAO,oBACH,CAAC,GAAG,KAAK,SAAS,QAAQ,CAAC,CAAC,CACvB,SAAS,CAAC,QAAQ,WACf,MAAM,UAAU,KAAA,IAAY,CAAC,IAAI,CAAC;GAAE;GAAQ,OAAO,MAAM;EAAM,CAAC,CAAC,CAC7E;CACJ;CAEA,aACI,SACA,WACmB;EACnB,MAAM,QAAQ,IAAI,oBACd,KAAK,aACL,SACA,iBACM,KAAK,eAAe,OAAO,KAAK,CAC1C;EACA,KAAK,eAAe,IAAI,KAAK;EAC7B,KAAK,MAAM,aAAa,KAAK,SAAS,KAAK,GAAG,MAAM,IAAI,SAAS;EACjE,OAAO;CACX;CAEA,MAAa,UAAyB;EAClC,MAAM,WAAsB,CAAC;EAC7B,MAAM,iBAAiB,MAAM,QAAQ,WACjC,CAAC,GAAG,KAAK,cAAc,CAAC,CAAC,KAAK,UAAU,MAAM,OAAO,UAAU,CAAC,CACpE;EACA,SAAS,KAAK,GAAG,eAAe,SAAS,WACrC,OAAO,WAAW,aAAa,CAAC,OAAO,MAAM,IAAI,CAAC,CAAC,CAAC;EACxD,MAAM,gBAAgB,MAAM,QAAQ,WAChC,CAAC,GAAG,KAAK,SAAS,KAAK,CAAC,CAAC,CAAC,KAAK,cAAc,KAAK,sBAAsB,SAAS,CAAC,CACtF;EACA,SAAS,KAAK,GAAG,cAAc,SAAS,WACpC,OAAO,WAAW,aAAa,CAAC,OAAO,MAAM,IAAI,CAAC,CAAC,CAAC;EACxD,IAAI,SAAS,WAAW,GACpB,MAAM,IAAI,eAAe,UAAU,sCAAsC;CAEjF;AACJ;AAEA,IAAM,sBAAN,MAAyD;CAOhC;CACA;CACA;CACA;CATrB,2BAA4B,IAAI,IAA0B;CAC1D,UAAkB;CAClB;CACA;CAEA,YACI,aACA,UACA,YACA,WACF;EAJmB,KAAA,cAAA;EACA,KAAA,WAAA;EACA,KAAA,aAAA;EACA,KAAA,YAAA;EAEjB,IAAI;EACJ,KAAK,OAAO,IAAI,SAAe,MAAM,UAAU,CAAC;EAChD,KAAK,eAAe;CACxB;CAEA,IAAW,WAAyB;EAChC,IAAI,CAAC,KAAK,WAAW,KAAK,SAAS,IAAI,SAAS,GAAG;EACnD,MAAM,SAAS,IAAI,cAAc,KAAK,aAAa,SAAS;EAC5D,MAAM,YAA8B;GAChC,YAAY,YAAY,KAAK,WAAW,UAAU,SAAS,SAAS;GACpE,aAAa,aAAa,KAAK,WAAW,aAAa,UAAU,SAAS;GAC1E,UAAU,UAAU,KAAK,WAAW,UAAU,OAAO,SAAS;EAClE;EACA,MAAM,QAAQ,qBAAqB,KAAK,WAClC,OAAO,kBAAkB,KAAK,UAAU,SAAS,IACjD,OAAO,MAAM,KAAK,UAAU,SAAS;EAC3C,KAAK,SAAS,IAAI,WAAW,KAAK;CACtC;CAEA,MAAa,OAAO,WAAkC;EAClD,MAAM,QAAQ,KAAK,SAAS,IAAI,SAAS;EACzC,IAAI,UAAU,KAAA,GAAW;EACzB,KAAK,SAAS,OAAO,SAAS;EAC9B,MAAM,MAAM,OAAO,gBAAgB,CAAC,CAAC,YAAY,KAAA,CAAS;EAC1D,MAAM,MAAM,KAAK,YAAY,KAAA,CAAS;CAC1C;CAEA,MAAa,OAAO,QAAgC;EAChD,IAAI,CAAC,KAAK,SAAS,OAAO,KAAK;EAC/B,KAAK,UAAU;EACf,KAAK,UAAU;EACf,MAAM,UAAU,CAAC,GAAG,KAAK,SAAS,OAAO,CAAC;EAC1C,KAAK,SAAS,MAAM;EACpB,MAAM,WAAsB,CAAC;EAC7B,IAAI;GACA,MAAM,UAAU,MAAM,QAAQ,WAAW,QAAQ,IAAI,OAAO,UAAU;IAClE,MAAM,MAAM,OAAO,MAAM;IACzB,MAAM,MAAM;GAChB,CAAC,CAAC;GACF,SAAS,KAAK,GAAG,QAAQ,SAAS,WAC9B,OAAO,WAAW,aAAa,CAAC,OAAO,MAAM,IAAI,CAAC,CAAC,CAAC;EAC5D,UAAU;GACN,KAAK,aAAa;EACtB;EACA,IAAI,SAAS,WAAW,GACpB,MAAM,IAAI,eAAe,UAAU,0CAA0C;CAErF;AACJ;;;;;;;;ACxIA,IAAa,wBAAb,MAAmC;CAEV;CADrB,YACI,aACF;EADmB,KAAA,cAAA;CAClB;CAEH,MAAa,MACT,UAAkC,CAAC,GACnC,YAA2C,CAAC,GACZ;EAChC,MAAM,QAAQ,IAAI,qBAAqB;EACvC,MAAM,cAAc,UAAU,eAAe,KAAA,IACvC,KAAA,IACA,MAAM,UAAU,UAAU,UAAU;EAC1C,IAAI;GACA,IAAI,QAAQ,qBAAqB,KAAA,GAAW;IACxC,MAAM,aAAa,aAAa,QAAQ,gBAAgB;IACxD,MAAM,iBAAiB,UAAU;IACjC,MAAM,QAAQ,IAAI,WAAW,KAAK,cAC9B,KAAK,aAAa,OAAO,WAAW,QAAQ,SAAS,CAAC,CAAC;GAC/D,OACI,MAAM,KAAK,iBAAiB,OAAO,OAAO;GAE9C,MAAM,YAAY;GAClB,OAAO,MAAM;EACjB,UAAU;GACN,cAAc;EAClB;CACJ;CAEA,MAAa,UAAkC,CAAC,GAAyB;EACrE,OAAO,IAAI,yBAAyB,KAAK,aAAa,OAAO;CACjE;CAEA,MAAc,iBACV,OACA,SACa;EACb,MAAM,WAAW,IAAI,qBAAqB,KAAK,YAAY,SAAS;GAChE,aAAa,kBAAkB,KAAK;GACpC,UAAU,QAAQ;GAClB,WAAW,QAAQ,aAAa;EACpC,CAAC;EACD,MAAM,0BAAU,IAAI,IAA2B;EAC/C,MAAM,aAAa,aAA8C;GAC7D,MAAM,aAAa,QAAQ;GAC3B,MAAM,aAAa,mBAAmB,QAAQ;GAC9C,MAAM,iBAAiB,UAAU;GACjC,KAAK,MAAM,aAAa,YACpB,IAAI,CAAC,QAAQ,IAAI,SAAS,GACtB,QAAQ,IAAI,WAAW,KAAK,aAAa,OAAO,WAAW,QAAQ,SAAS,CAAC;EAGzF;EACA,MAAM,cAAc,SAAS,WAAW,UAAU,UAAU,MAAM,QAAQ,CAAC;EAC3E,IAAI;GACA,MAAM,SAAS,QAAQ;GACvB,UAAU,SAAS,aAAa;EACpC,SAAS,OAAO;GACZ,MAAM,kBAAkB,KAAK;EACjC,UAAU;GACN,YAAY;GACZ,SAAS,QAAQ;EACrB;EACA,MAAM,QAAQ,IAAI,QAAQ,OAAO,CAAC;CACtC;CAEA,MAAc,aACV,OACA,WACA,YAAY,wBACC;EACb,IAAI;GACA,MAAM,QAAQ,MAAM,IAAI,eACpB,KAAK,aACL,WACA,SACJ,CAAC,CAAC,SAAS;GACX,IAAI,MAAM,UAAU,SAAS,GAAG,MAAM,eAAe,WAAW,KAAK;EACzE,SAAS,OAAO;GACZ,IAAI,MAAM,UAAU,SAAS,GAAG,MAAM,eAAe,WAAW,KAAK;EACzE;CACJ;AACJ;AAEA,IAAM,2BAAN,MAA+D;CAmBtC;CACA;CAnBrB,SAA0B,IAAI,qBAAqB;CACnD,iCAAkC,IAAI,IAA2B;CACjE,sCAAuC,IAAI,IAA2B;CACtE;CACA;CACA,aAAqB;CACrB;CACA;CACA,gBAAwB;CAExB,QAAwB,IAAI,SAAkC,YAAY;EACtE,KAAK,gBAAgB;CACzB,CAAC;CACD,OAAuB,IAAI,SAAe,YAAY;EAClD,KAAK,eAAe;CACxB,CAAC;CAED,YACI,aACA,UACF;EAFmB,KAAA,cAAA;EACA,KAAA,WAAA;EAEjB,KAAK,YAAY,SAAS,qBAAqB,KAAA,IACzC,IAAI,qBAAqB,YAAY,SAAS;GAC5C,aAAa,kBAAkB,KAAK;GACpC,UAAU,SAAS;GACnB,WAAW,SAAS,aAAa;EACrC,CAAC,IACC,KAAA;EACN,KAAU,YAAY;CAC1B;CAEA,IAAW,WAAoC;EAC3C,OAAO,KAAK,OAAO;CACvB;CAEA,UAAiB,UAAmE;EAChF,OAAO,KAAK,OAAO,UAAU,QAAQ;CACzC;CAEA,MAAa,OAAO,SAAS,4BAA2C;EACpE,IAAI,KAAK,YAAY,OAAO,KAAK;EACjC,KAAK,aAAa;EAClB,KAAK,sBAAsB;EAC3B,KAAK,sBAAsB,KAAA;EAC3B,KAAK,WAAW,QAAQ;EACxB,MAAM,UAAU,CAAC,GAAG,KAAK,eAAe,OAAO,CAAC;EAChD,KAAK,eAAe,MAAM;EAC1B,MAAM,QAAQ,WAAW,QAAQ,KAAK,UAAU,MAAM,OAAO,MAAM,CAAC,CAAC;EACrE,IAAI,CAAC,KAAK,eAAe,KAAK,aAAa;EAC3C,KAAK,aAAa;CACtB;CAEA,MAAc,cAA6B;EACvC,IAAI;GACA,IAAI,KAAK,SAAS,qBAAqB,KAAA,GAAW;IAC9C,MAAM,aAAa,aAAa,KAAK,SAAS,gBAAgB;IAC9D,KAAK,OAAO,iBAAiB,UAAU;IACvC,KAAK,MAAM,aAAa,YAAY,KAAK,kBAAkB,SAAS;GACxE,OAAO;IACH,MAAM,WAAW,KAAK;IACtB,SAAS,WAAW,UAAU,KAAK,oBAAoB,MAAM,QAAQ,CAAC;IACtE,KAAK,sBAAsB,MAAM,SAAS,YAAY,CAAC,CAAC;IACxD,KAAK,oBAAoB,SAAS,aAAa;GACnD;GACA,MAAM,QAAQ,WAAW,KAAK,oBAAoB,OAAO,CAAC;GAC1D,IAAI,CAAC,KAAK,YAAY;IAClB,KAAK,OAAO,YAAY;IACxB,KAAK,aAAa;GACtB;EACJ,SAAS,OAAO;GACZ,IAAI,CAAC,KAAK,YAAY;IAClB,KAAK,OAAO,kBAAkB,KAAK;IACnC,KAAK,OAAO,YAAY;IACxB,KAAK,aAAa;GACtB;EACJ;CACJ;CAEA,oBAA4B,UAA2C;EACnE,IAAI,KAAK,YAAY;EACrB,KAAK,OAAO,aAAa,QAAQ;EACjC,MAAM,aAAa,mBAAmB,QAAQ;EAC9C,MAAM,UAAU,IAAI,IAAI,UAAU;EAClC,KAAK,MAAM,aAAa,YAAY,KAAK,kBAAkB,SAAS;EACpE,KAAK,MAAM,CAAC,WAAW,UAAU,KAAK,gBAAgB;GAClD,IAAI,QAAQ,IAAI,SAAS,GAAG;GAC5B,KAAK,eAAe,OAAO,SAAS;GACpC,KAAK,oBAAoB,OAAO,SAAS;GACzC,KAAK,OAAO,aAAa,SAAS;GAClC,MAAW,OAAO,yBAAyB,CAAC,CAAC,YAAY,KAAA,CAAS;EACtE;CACJ;CAEA,kBAA0B,WAAyB;EAC/C,IAAI,KAAK,eAAe,IAAI,SAAS,KAAK,KAAK,YAAY;EAC3D,KAAK,OAAO,aAAa,SAAS;EAClC,MAAM,QAAQ,IAAI,eACd,KAAK,aACL,WACA,KAAK,SAAS,SAClB,CAAC,CAAC,MAAM;GACJ,UAAU,UAAU;IAChB,IAAI,CAAC,KAAK,cAAc,KAAK,eAAe,IAAI,SAAS,MAAM,OAC3D,KAAK,OAAO,eAAe,WAAW,KAAK;GAEnD;GACA,UAAU,UAAU;IAChB,IAAI,CAAC,KAAK,cAAc,KAAK,eAAe,IAAI,SAAS,MAAM,OAC3D,KAAK,OAAO,eAAe,WAAW,KAAK;GAEnD;EACJ,CAAC;EACD,KAAK,eAAe,IAAI,WAAW,KAAK;EACxC,MAAM,UAAU,MAAM,MAAM,WAClB,KAAA,IACL,UAAU;GACP,IAAI,CAAC,KAAK,cAAc,KAAK,eAAe,IAAI,SAAS,MAAM,OAC3D,KAAK,OAAO,eAAe,WAAW,KAAK;EAEnD,CACJ;EACA,KAAK,oBAAoB,IAAI,WAAW,OAAO;EAC/C,MAAW,KAAK,OAAO,UAAU;GAC7B,IAAI,CAAC,KAAK,cAAc,KAAK,eAAe,IAAI,SAAS,MAAM,OAC3D,KAAK,OAAO,eAAe,WAAW,KAAK;EAEnD,CAAC;CACL;CAEA,eAA6B;EACzB,IAAI,KAAK,eAAe;EACxB,KAAK,gBAAgB;EACrB,KAAK,cAAc,KAAK,OAAO,QAAQ;CAC3C;AACJ;AASA,IAAM,uBAAN,MAA2B;CACvB,2BAA4B,IAAI,IAAmC;CACnE,6BAA8B,IAAI,IAAiD;CACnF,YAAoB;CACpB,YAAoB;CACpB;CACA;CAEA,IAAW,WAAoC;EAC3C,MAAM,UAAU,CAAC,GAAG,KAAK,SAAS,OAAO,CAAC,CAAC,CACtC,MAAM,GAAG,MAAM,EAAE,UAAU,cAAc,EAAE,SAAS,CAAC,CAAC,CACtD,KAAK,YAAoC;GACtC,WAAW,OAAO;GAClB,OAAO,OAAO;GACd,GAAI,OAAO,UAAU,KAAA,IAAY,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;GAC5D,GAAI,OAAO,UAAU,KAAA,IAAY,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;EAChE,EAAE;EACN,OAAO;GACH,UAAU,KAAK;GACf,UAAU,KAAK;GACf,GAAI,KAAK,eAAe,KAAA,IAAY,EAAE,WAAW,KAAK,WAAW,IAAI,CAAC;GACtE,GAAI,KAAK,oBAAoB,KAAA,IACvB,EAAE,gBAAgB,KAAK,gBAAgB,IACvC,CAAC;GACP;GACA,OAAO,oBAAoB,QAAQ,SAAS,WACxC,OAAO,UAAU,KAAA,IACX,CAAC,IACD,CAAC;IAAE,QAAQ,OAAO;IAAW,OAAO,OAAO;GAAM,CAAC,CAAC,CAAC;EAClE;CACJ;CAEA,UAAiB,UAAmE;EAChF,KAAK,WAAW,IAAI,QAAQ;EAC5B,SAAS,KAAK,QAAQ;EACtB,aAAa,KAAK,WAAW,OAAO,QAAQ;CAChD;CAEA,UAAiB,WAA4B;EACzC,OAAO,KAAK,SAAS,IAAI,SAAS;CACtC;CAEA,aAAoB,WAAyB;EACzC,IAAI,KAAK,SAAS,IAAI,SAAS,GAAG;EAClC,KAAK,SAAS,IAAI,WAAW;GAAE;GAAW,OAAO;EAAU,CAAC;EAC5D,KAAK,MAAM;CACf;CAEA,iBAAwB,YAAqC;EACzD,MAAM,UAAU,IAAI,IAAI,UAAU;EAClC,IAAI,UAAU;EACd,KAAK,MAAM,aAAa,YACpB,IAAI,CAAC,KAAK,SAAS,IAAI,SAAS,GAAG;GAC/B,KAAK,SAAS,IAAI,WAAW;IAAE;IAAW,OAAO;GAAU,CAAC;GAC5D,UAAU;EACd;EAEJ,KAAK,MAAM,aAAa,KAAK,SAAS,KAAK,GACvC,IAAI,CAAC,QAAQ,IAAI,SAAS,GAAG;GACzB,KAAK,SAAS,OAAO,SAAS;GAC9B,UAAU;EACd;EAEJ,IAAI,SAAS,KAAK,MAAM;CAC5B;CAEA,aAAoB,WAAyB;EACzC,IAAI,KAAK,SAAS,OAAO,SAAS,GAAG,KAAK,MAAM;CACpD;CAEA,eAAsB,WAAmB,OAA4B;EACjE,MAAM,SAAS,KAAK,SAAS,IAAI,SAAS;EAC1C,IAAI,WAAW,KAAA,GAAW;EAC1B,OAAO,QAAQ;EACf,OAAO,QAAQ;EACf,OAAO,QAAQ,KAAA;EACf,KAAK,MAAM;CACf;CAEA,eAAsB,WAAmB,OAAsB;EAC3D,MAAM,SAAS,KAAK,SAAS,IAAI,SAAS;EAC1C,IAAI,WAAW,KAAA,GAAW;EAC1B,OAAO,QAAQ;EACf,OAAO,QAAQ,aAAa,KAAK;EACjC,KAAK,MAAM;CACf;CAEA,aAAoB,UAA2C;EAC3D,KAAK,aAAa;EAClB,KAAK,kBAAkB,KAAA;EACvB,KAAK,MAAM;CACf;CAEA,kBAAyB,OAAsB;EAC3C,KAAK,kBAAkB,aAAa,KAAK;EACzC,KAAK,MAAM;CACf;CAEA,cAA2B;EACvB,IAAI,KAAK,WAAW;EACpB,KAAK,YAAY;EACjB,KAAK,MAAM;CACf;CAEA,QAAsB;EAClB,KAAK;EACL,MAAM,WAAW,KAAK;EACtB,KAAK,MAAM,YAAY,CAAC,GAAG,KAAK,UAAU,GACtC,IAAI;GACA,SAAS,QAAQ;EACrB,QAAQ,CAER;CAER;AACJ;AAEA,SAAS,mBAAmB,UAA+C;CACvE,OAAO,aAAa,SAAS,OAAO,SAC/B,QAAQ,YAAY,QAAQ,gBAAgB,kBAAkB,KAAK,EAAE,CAAC,CACtE,KAAK,YAAY,QAAQ,SAAS,CAAC;AAC5C;AAEA,SAAS,aAAa,QAAqC;CACvD,OAAO,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,cAAc,CAAC,CAAC;AACjE;AAEA,SAAS,aAAa,OAAwB;CAC1C,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAChE"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { JsonValue } from "@hediet/linkrpc";
|
|
2
|
+
import { output } from "zod/v4/core";
|
|
3
|
+
//#region src/json-document/index.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Incremental edits addressed by RFC 6901 JSON Pointers.
|
|
6
|
+
*
|
|
7
|
+
* `set` and `remove` replace/remove values, while `append`, `splice`, and
|
|
8
|
+
* `insert` efficiently update streamed text and arrays without retransmitting
|
|
9
|
+
* the containing document.
|
|
10
|
+
*/
|
|
11
|
+
declare const jsonDocumentEditSchema: import("zod/mini").ZodMiniDiscriminatedUnion<[import("zod/mini").ZodMiniObject<{
|
|
12
|
+
op: import("zod/mini").ZodMiniLiteral<"set">;
|
|
13
|
+
path: import("zod/mini").ZodMiniString<string>;
|
|
14
|
+
value: import("zod/mini").ZodMiniUnknown;
|
|
15
|
+
}, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
|
|
16
|
+
op: import("zod/mini").ZodMiniLiteral<"remove">;
|
|
17
|
+
path: import("zod/mini").ZodMiniString<string>;
|
|
18
|
+
}, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
|
|
19
|
+
op: import("zod/mini").ZodMiniLiteral<"append">;
|
|
20
|
+
path: import("zod/mini").ZodMiniString<string>;
|
|
21
|
+
value: import("zod/mini").ZodMiniString<string>;
|
|
22
|
+
}, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
|
|
23
|
+
op: import("zod/mini").ZodMiniLiteral<"splice">;
|
|
24
|
+
path: import("zod/mini").ZodMiniString<string>;
|
|
25
|
+
offset: import("zod/mini").ZodMiniNumber<number>;
|
|
26
|
+
delete: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
|
|
27
|
+
insert: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
|
|
28
|
+
}, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
|
|
29
|
+
op: import("zod/mini").ZodMiniLiteral<"insert">;
|
|
30
|
+
path: import("zod/mini").ZodMiniString<string>;
|
|
31
|
+
index: import("zod/mini").ZodMiniNumber<number>;
|
|
32
|
+
value: import("zod/mini").ZodMiniUnknown;
|
|
33
|
+
}, import("zod/v4/core").$strip>], "op">;
|
|
34
|
+
type JsonDocumentEdit = output<typeof jsonDocumentEditSchema>;
|
|
35
|
+
type RevisionedDocumentEvent<T> = {
|
|
36
|
+
readonly type: 'snapshot';
|
|
37
|
+
readonly revision: number;
|
|
38
|
+
readonly document: T;
|
|
39
|
+
} | {
|
|
40
|
+
readonly type: 'patch';
|
|
41
|
+
readonly revision: number;
|
|
42
|
+
readonly edits: readonly JsonDocumentEdit[];
|
|
43
|
+
};
|
|
44
|
+
declare function parseJsonPointer(pointer: string): string[];
|
|
45
|
+
declare function applyJsonDocumentEdit(root: JsonValue, edit: JsonDocumentEdit): JsonValue;
|
|
46
|
+
declare function applyJsonDocumentEdits(root: JsonValue, edits: readonly JsonDocumentEdit[]): JsonValue;
|
|
47
|
+
declare const jsonDocumentPatchSchema: import("zod/mini").ZodMiniObject<{
|
|
48
|
+
type: import("zod/mini").ZodMiniLiteral<"patch">;
|
|
49
|
+
revision: import("zod/mini").ZodMiniNumber<number>;
|
|
50
|
+
edits: import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniDiscriminatedUnion<[import("zod/mini").ZodMiniObject<{
|
|
51
|
+
op: import("zod/mini").ZodMiniLiteral<"set">;
|
|
52
|
+
path: import("zod/mini").ZodMiniString<string>;
|
|
53
|
+
value: import("zod/mini").ZodMiniUnknown;
|
|
54
|
+
}, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
|
|
55
|
+
op: import("zod/mini").ZodMiniLiteral<"remove">;
|
|
56
|
+
path: import("zod/mini").ZodMiniString<string>;
|
|
57
|
+
}, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
|
|
58
|
+
op: import("zod/mini").ZodMiniLiteral<"append">;
|
|
59
|
+
path: import("zod/mini").ZodMiniString<string>;
|
|
60
|
+
value: import("zod/mini").ZodMiniString<string>;
|
|
61
|
+
}, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
|
|
62
|
+
op: import("zod/mini").ZodMiniLiteral<"splice">;
|
|
63
|
+
path: import("zod/mini").ZodMiniString<string>;
|
|
64
|
+
offset: import("zod/mini").ZodMiniNumber<number>;
|
|
65
|
+
delete: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
|
|
66
|
+
insert: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
|
|
67
|
+
}, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
|
|
68
|
+
op: import("zod/mini").ZodMiniLiteral<"insert">;
|
|
69
|
+
path: import("zod/mini").ZodMiniString<string>;
|
|
70
|
+
index: import("zod/mini").ZodMiniNumber<number>;
|
|
71
|
+
value: import("zod/mini").ZodMiniUnknown;
|
|
72
|
+
}, import("zod/v4/core").$strip>], "op">>;
|
|
73
|
+
}, import("zod/v4/core").$strip>;
|
|
74
|
+
//#endregion
|
|
75
|
+
export { JsonDocumentEdit, RevisionedDocumentEvent, applyJsonDocumentEdit, applyJsonDocumentEdits, jsonDocumentEditSchema, jsonDocumentPatchSchema, parseJsonPointer };
|
|
76
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { array, discriminatedUnion, literal, number, object, optional, string, unknown } from "zod/mini";
|
|
2
|
+
//#region src/json-document/index.ts
|
|
3
|
+
/**
|
|
4
|
+
* Incremental edits addressed by RFC 6901 JSON Pointers.
|
|
5
|
+
*
|
|
6
|
+
* `set` and `remove` replace/remove values, while `append`, `splice`, and
|
|
7
|
+
* `insert` efficiently update streamed text and arrays without retransmitting
|
|
8
|
+
* the containing document.
|
|
9
|
+
*/
|
|
10
|
+
const jsonDocumentEditSchema = discriminatedUnion("op", [
|
|
11
|
+
object({
|
|
12
|
+
op: literal("set"),
|
|
13
|
+
path: string(),
|
|
14
|
+
value: unknown()
|
|
15
|
+
}),
|
|
16
|
+
object({
|
|
17
|
+
op: literal("remove"),
|
|
18
|
+
path: string()
|
|
19
|
+
}),
|
|
20
|
+
object({
|
|
21
|
+
op: literal("append"),
|
|
22
|
+
path: string(),
|
|
23
|
+
value: string()
|
|
24
|
+
}),
|
|
25
|
+
object({
|
|
26
|
+
op: literal("splice"),
|
|
27
|
+
path: string(),
|
|
28
|
+
offset: number(),
|
|
29
|
+
delete: optional(number()),
|
|
30
|
+
insert: optional(string())
|
|
31
|
+
}),
|
|
32
|
+
object({
|
|
33
|
+
op: literal("insert"),
|
|
34
|
+
path: string(),
|
|
35
|
+
index: number(),
|
|
36
|
+
value: unknown()
|
|
37
|
+
})
|
|
38
|
+
]);
|
|
39
|
+
function parseJsonPointer(pointer) {
|
|
40
|
+
if (pointer === "") return [];
|
|
41
|
+
if (!pointer.startsWith("/")) throw new Error(`Invalid JSON Pointer (must start with '/'): ${pointer}`);
|
|
42
|
+
return pointer.slice(1).split("/").map((token) => token.replaceAll("~1", "/").replaceAll("~0", "~"));
|
|
43
|
+
}
|
|
44
|
+
function resolveParent(root, tokens) {
|
|
45
|
+
let current = root;
|
|
46
|
+
for (const token of tokens.slice(0, -1)) if (Array.isArray(current)) {
|
|
47
|
+
const index = parseArrayIndex(token, current.length, false);
|
|
48
|
+
current = current[index];
|
|
49
|
+
} else if (isJsonObject(current)) current = current[token];
|
|
50
|
+
else throw new Error(`Cannot descend into non-container at token '${token}'`);
|
|
51
|
+
const key = tokens.at(-1);
|
|
52
|
+
if (key === void 0) throw new Error("JSON Pointer does not address a child");
|
|
53
|
+
if (!Array.isArray(current) && !isJsonObject(current)) throw new Error(`Cannot resolve parent for JSON Pointer token '${key}'`);
|
|
54
|
+
return {
|
|
55
|
+
container: current,
|
|
56
|
+
key
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function readChild(parent) {
|
|
60
|
+
if (Array.isArray(parent.container)) return parent.container[parseArrayIndex(parent.key, parent.container.length, false)];
|
|
61
|
+
return parent.container[parent.key];
|
|
62
|
+
}
|
|
63
|
+
function writeChild(parent, value) {
|
|
64
|
+
if (Array.isArray(parent.container)) {
|
|
65
|
+
const index = parseArrayIndex(parent.key, parent.container.length, false);
|
|
66
|
+
parent.container[index] = value;
|
|
67
|
+
} else parent.container[parent.key] = value;
|
|
68
|
+
}
|
|
69
|
+
function parseArrayIndex(token, length, allowEnd) {
|
|
70
|
+
if (!/^(0|[1-9]\d*)$/.test(token)) throw new Error(`Invalid array index '${token}'`);
|
|
71
|
+
const index = Number(token);
|
|
72
|
+
const upperBound = allowEnd ? length : length - 1;
|
|
73
|
+
if (!Number.isSafeInteger(index) || index < 0 || index > upperBound) throw new Error(`Array index '${token}' is out of bounds`);
|
|
74
|
+
return index;
|
|
75
|
+
}
|
|
76
|
+
function isJsonObject(value) {
|
|
77
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
78
|
+
}
|
|
79
|
+
function applyJsonDocumentEdit(root, edit) {
|
|
80
|
+
const tokens = parseJsonPointer(edit.path);
|
|
81
|
+
if (tokens.length === 0) {
|
|
82
|
+
if (edit.op === "set") return structuredClone(edit.value);
|
|
83
|
+
throw new Error(`Operation '${edit.op}' cannot target the document root`);
|
|
84
|
+
}
|
|
85
|
+
const parent = resolveParent(root, tokens);
|
|
86
|
+
switch (edit.op) {
|
|
87
|
+
case "set":
|
|
88
|
+
writeChild(parent, structuredClone(edit.value));
|
|
89
|
+
return root;
|
|
90
|
+
case "remove":
|
|
91
|
+
if (Array.isArray(parent.container)) parent.container.splice(parseArrayIndex(parent.key, parent.container.length, false), 1);
|
|
92
|
+
else delete parent.container[parent.key];
|
|
93
|
+
return root;
|
|
94
|
+
case "append": {
|
|
95
|
+
const current = readChild(parent) ?? "";
|
|
96
|
+
if (typeof current !== "string") throw new Error(`Append target is not a string at '${edit.path}'`);
|
|
97
|
+
writeChild(parent, current + edit.value);
|
|
98
|
+
return root;
|
|
99
|
+
}
|
|
100
|
+
case "splice": {
|
|
101
|
+
const current = readChild(parent) ?? "";
|
|
102
|
+
if (typeof current !== "string") throw new Error(`Splice target is not a string at '${edit.path}'`);
|
|
103
|
+
if (!Number.isSafeInteger(edit.offset) || edit.offset < 0 || edit.offset > current.length) throw new Error(`Splice offset is out of bounds at '${edit.path}'`);
|
|
104
|
+
const deleteCount = edit.delete ?? 0;
|
|
105
|
+
if (!Number.isSafeInteger(deleteCount) || deleteCount < 0) throw new Error(`Splice delete count is invalid at '${edit.path}'`);
|
|
106
|
+
writeChild(parent, current.slice(0, edit.offset) + (edit.insert ?? "") + current.slice(edit.offset + deleteCount));
|
|
107
|
+
return root;
|
|
108
|
+
}
|
|
109
|
+
case "insert": {
|
|
110
|
+
const target = readChild(parent);
|
|
111
|
+
if (!Array.isArray(target)) throw new Error(`Insert target is not an array at '${edit.path}'`);
|
|
112
|
+
const index = edit.index === -1 ? target.length : parseArrayIndex(String(edit.index), target.length, true);
|
|
113
|
+
target.splice(index, 0, structuredClone(edit.value));
|
|
114
|
+
return root;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function applyJsonDocumentEdits(root, edits) {
|
|
119
|
+
let current = structuredClone(root);
|
|
120
|
+
for (const edit of edits) current = applyJsonDocumentEdit(current, edit);
|
|
121
|
+
return current;
|
|
122
|
+
}
|
|
123
|
+
const jsonDocumentPatchSchema = object({
|
|
124
|
+
type: literal("patch"),
|
|
125
|
+
revision: number(),
|
|
126
|
+
edits: array(jsonDocumentEditSchema)
|
|
127
|
+
});
|
|
128
|
+
//#endregion
|
|
129
|
+
export { applyJsonDocumentEdit, applyJsonDocumentEdits, jsonDocumentEditSchema, jsonDocumentPatchSchema, parseJsonPointer };
|
|
130
|
+
|
|
131
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/json-document/index.ts"],"sourcesContent":["import {\n array,\n discriminatedUnion,\n literal,\n number,\n object,\n optional,\n string,\n unknown,\n} from 'zod/mini';\nimport type { output as zInfer } from 'zod/v4/core';\nimport type { JsonValue } from '@hediet/linkrpc';\n\n/**\n * Incremental edits addressed by RFC 6901 JSON Pointers.\n *\n * `set` and `remove` replace/remove values, while `append`, `splice`, and\n * `insert` efficiently update streamed text and arrays without retransmitting\n * the containing document.\n */\nexport const jsonDocumentEditSchema = discriminatedUnion('op', [\n object({ op: literal('set'), path: string(), value: unknown() }),\n object({ op: literal('remove'), path: string() }),\n object({ op: literal('append'), path: string(), value: string() }),\n object({\n op: literal('splice'),\n path: string(),\n offset: number(),\n delete: optional(number()),\n insert: optional(string()),\n }),\n object({ op: literal('insert'), path: string(), index: number(), value: unknown() }),\n]);\n\nexport type JsonDocumentEdit = zInfer<typeof jsonDocumentEditSchema>;\n\nexport type RevisionedDocumentEvent<T> =\n | { readonly type: 'snapshot'; readonly revision: number; readonly document: T; }\n | { readonly type: 'patch'; readonly revision: number; readonly edits: readonly JsonDocumentEdit[]; };\n\nexport function parseJsonPointer(pointer: string): string[] {\n if (pointer === '') return [];\n if (!pointer.startsWith('/')) {\n throw new Error(`Invalid JSON Pointer (must start with '/'): ${pointer}`);\n }\n return pointer\n .slice(1)\n .split('/')\n .map((token) => token.replaceAll('~1', '/').replaceAll('~0', '~'));\n}\n\ninterface Parent {\n readonly container: Record<string, JsonValue | undefined> | JsonValue[];\n readonly key: string;\n}\n\nfunction resolveParent(root: JsonValue, tokens: readonly string[]): Parent {\n let current: JsonValue | undefined = root;\n for (const token of tokens.slice(0, -1)) {\n if (Array.isArray(current)) {\n const index = parseArrayIndex(token, current.length, false);\n current = current[index];\n } else if (isJsonObject(current)) {\n current = current[token];\n } else {\n throw new Error(`Cannot descend into non-container at token '${token}'`);\n }\n }\n const key = tokens.at(-1);\n if (key === undefined) throw new Error('JSON Pointer does not address a child');\n if (!Array.isArray(current) && !isJsonObject(current)) {\n throw new Error(`Cannot resolve parent for JSON Pointer token '${key}'`);\n }\n return { container: current, key };\n}\n\nfunction readChild(parent: Parent): JsonValue | undefined {\n if (Array.isArray(parent.container)) {\n return parent.container[parseArrayIndex(parent.key, parent.container.length, false)];\n }\n return parent.container[parent.key];\n}\n\nfunction writeChild(parent: Parent, value: JsonValue): void {\n if (Array.isArray(parent.container)) {\n const index = parseArrayIndex(parent.key, parent.container.length, false);\n parent.container[index] = value;\n } else {\n parent.container[parent.key] = value;\n }\n}\n\nfunction parseArrayIndex(token: string, length: number, allowEnd: boolean): number {\n if (!/^(0|[1-9]\\d*)$/.test(token)) {\n throw new Error(`Invalid array index '${token}'`);\n }\n const index = Number(token);\n const upperBound = allowEnd ? length : length - 1;\n if (!Number.isSafeInteger(index) || index < 0 || index > upperBound) {\n throw new Error(`Array index '${token}' is out of bounds`);\n }\n return index;\n}\n\nfunction isJsonObject(value: JsonValue | undefined): value is Record<string, JsonValue | undefined> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function applyJsonDocumentEdit(root: JsonValue, edit: JsonDocumentEdit): JsonValue {\n const tokens = parseJsonPointer(edit.path);\n if (tokens.length === 0) {\n if (edit.op === 'set') return structuredClone(edit.value) as JsonValue;\n throw new Error(`Operation '${edit.op}' cannot target the document root`);\n }\n\n const parent = resolveParent(root, tokens);\n switch (edit.op) {\n case 'set':\n writeChild(parent, structuredClone(edit.value) as JsonValue);\n return root;\n case 'remove':\n if (Array.isArray(parent.container)) {\n parent.container.splice(parseArrayIndex(parent.key, parent.container.length, false), 1);\n } else {\n delete parent.container[parent.key];\n }\n return root;\n case 'append': {\n const current = readChild(parent) ?? '';\n if (typeof current !== 'string') {\n throw new Error(`Append target is not a string at '${edit.path}'`);\n }\n writeChild(parent, current + edit.value);\n return root;\n }\n case 'splice': {\n const current = readChild(parent) ?? '';\n if (typeof current !== 'string') {\n throw new Error(`Splice target is not a string at '${edit.path}'`);\n }\n if (!Number.isSafeInteger(edit.offset) || edit.offset < 0 || edit.offset > current.length) {\n throw new Error(`Splice offset is out of bounds at '${edit.path}'`);\n }\n const deleteCount = edit.delete ?? 0;\n if (!Number.isSafeInteger(deleteCount) || deleteCount < 0) {\n throw new Error(`Splice delete count is invalid at '${edit.path}'`);\n }\n writeChild(\n parent,\n current.slice(0, edit.offset)\n + (edit.insert ?? '')\n + current.slice(edit.offset + deleteCount),\n );\n return root;\n }\n case 'insert': {\n const target = readChild(parent);\n if (!Array.isArray(target)) {\n throw new Error(`Insert target is not an array at '${edit.path}'`);\n }\n const index = edit.index === -1\n ? target.length\n : parseArrayIndex(String(edit.index), target.length, true);\n target.splice(index, 0, structuredClone(edit.value) as JsonValue);\n return root;\n }\n }\n}\n\nexport function applyJsonDocumentEdits(\n root: JsonValue,\n edits: readonly JsonDocumentEdit[],\n): JsonValue {\n let current = structuredClone(root);\n for (const edit of edits) current = applyJsonDocumentEdit(current, edit);\n return current;\n}\n\nexport const jsonDocumentPatchSchema = object({\n type: literal('patch'),\n revision: number(),\n edits: array(jsonDocumentEditSchema),\n});\n"],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { IMessageTransport, InterfaceClient, InterfaceRegistration, JsonRpcMessage, JsonValue, LinkRpcConnection } from "@hediet/linkrpc";
|
|
2
|
+
//#region src/json-rpc/interface.d.ts
|
|
3
|
+
declare const jsonRpcConnectionCloseReasonSchema: import("zod/mini").ZodMiniEnum<{
|
|
4
|
+
cancelled: "cancelled";
|
|
5
|
+
closed: "closed";
|
|
6
|
+
disposed: "disposed";
|
|
7
|
+
remoteClosed: "remoteClosed";
|
|
8
|
+
}>;
|
|
9
|
+
type JsonRpcConnectionCloseReason = 'cancelled' | 'closed' | 'disposed' | 'remoteClosed';
|
|
10
|
+
/**
|
|
11
|
+
* Opens a transparent JSON-RPC transport over one duplex LinkRPC request.
|
|
12
|
+
* Frames are intentionally opaque; the endpoint owns JSON-RPC semantics.
|
|
13
|
+
*/
|
|
14
|
+
declare const jsonRpcConnectionInterface: import("@hediet/linkrpc").InterfaceDefinition<{
|
|
15
|
+
connectRaw: import("@hediet/linkrpc").RequestType<{
|
|
16
|
+
params?: unknown;
|
|
17
|
+
}, {
|
|
18
|
+
reason: "cancelled" | "closed" | "disposed" | "remoteClosed";
|
|
19
|
+
}, void, {
|
|
20
|
+
frame: unknown;
|
|
21
|
+
}, {
|
|
22
|
+
type: "ready";
|
|
23
|
+
} | {
|
|
24
|
+
type: "frame";
|
|
25
|
+
frame: unknown;
|
|
26
|
+
}>;
|
|
27
|
+
}>;
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/json-rpc/transport.d.ts
|
|
30
|
+
interface Disposable {
|
|
31
|
+
dispose(): void;
|
|
32
|
+
}
|
|
33
|
+
/** A message-oriented transport carrying already parsed JSON-RPC frames. */
|
|
34
|
+
interface JsonRpcTransport {
|
|
35
|
+
readonly closed: boolean;
|
|
36
|
+
send(frame: JsonValue): Promise<void>;
|
|
37
|
+
onMessage(listener: (frame: JsonValue) => void): Disposable;
|
|
38
|
+
onClose(listener: (reason?: string) => void): Disposable;
|
|
39
|
+
close(reason?: string): void;
|
|
40
|
+
}
|
|
41
|
+
declare function connectJsonRpcTransports(left: JsonRpcTransport, right: JsonRpcTransport): Disposable;
|
|
42
|
+
declare class JsonRpcTransportPair {
|
|
43
|
+
readonly a: JsonRpcTransport;
|
|
44
|
+
readonly b: JsonRpcTransport;
|
|
45
|
+
constructor();
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region src/json-rpc/client.d.ts
|
|
49
|
+
type JsonRpcConnectionClient = InterfaceClient<typeof jsonRpcConnectionInterface>;
|
|
50
|
+
declare function connectRawJsonRpcTransport(client: JsonRpcConnectionClient, params?: JsonValue): Promise<JsonRpcTransport>;
|
|
51
|
+
//#endregion
|
|
52
|
+
//#region src/json-rpc/messageTransport.d.ts
|
|
53
|
+
interface CloseAwareMessageTransport<TIncoming = JsonRpcMessage, TOutgoing = JsonRpcMessage> extends IMessageTransport<TIncoming, TOutgoing> {
|
|
54
|
+
readonly closed: boolean;
|
|
55
|
+
readonly closeReason: string | undefined;
|
|
56
|
+
onClose(listener: (reason?: string) => void): Disposable;
|
|
57
|
+
}
|
|
58
|
+
/** Adapt a parsed JSON-RPC transport to the transport consumed by LinkRpcConnection. */
|
|
59
|
+
declare function adaptJsonRpcTransport(transport: JsonRpcTransport, options?: {
|
|
60
|
+
maxPendingMessages?: number;
|
|
61
|
+
}): CloseAwareMessageTransport<JsonRpcMessage, JsonRpcMessage>;
|
|
62
|
+
declare function assertJsonRpcMessage(value: unknown): JsonRpcMessage;
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/json-rpc/server.d.ts
|
|
65
|
+
interface RegisterJsonRpcConnectionServiceOptions {
|
|
66
|
+
readonly connection: LinkRpcConnection<unknown>;
|
|
67
|
+
readonly serviceId?: string;
|
|
68
|
+
readonly openTransport: (params: JsonValue | undefined, signal: AbortSignal) => Promise<JsonRpcTransport>;
|
|
69
|
+
}
|
|
70
|
+
/** Register a raw JSON-RPC transport factory on a LinkRPC connection. */
|
|
71
|
+
declare function registerJsonRpcConnectionService(options: RegisterJsonRpcConnectionServiceOptions): InterfaceRegistration;
|
|
72
|
+
//#endregion
|
|
73
|
+
//#region src/json-rpc/stdio.d.ts
|
|
74
|
+
interface NdjsonJsonRpcTransportOptions {
|
|
75
|
+
readonly input: NodeJS.ReadableStream;
|
|
76
|
+
readonly output: NodeJS.WritableStream;
|
|
77
|
+
}
|
|
78
|
+
/** Adapt newline-delimited JSON-RPC stdio streams to a message transport. */
|
|
79
|
+
declare function createNdjsonJsonRpcTransport(options: NdjsonJsonRpcTransportOptions): JsonRpcTransport;
|
|
80
|
+
//#endregion
|
|
81
|
+
export { CloseAwareMessageTransport, Disposable, JsonRpcConnectionCloseReason, JsonRpcTransport, JsonRpcTransportPair, NdjsonJsonRpcTransportOptions, RegisterJsonRpcConnectionServiceOptions, adaptJsonRpcTransport, assertJsonRpcMessage, connectJsonRpcTransports, connectRawJsonRpcTransport, createNdjsonJsonRpcTransport, jsonRpcConnectionCloseReasonSchema, jsonRpcConnectionInterface, registerJsonRpcConnectionService };
|
|
82
|
+
//# sourceMappingURL=index.d.ts.map
|