@hediet/linkrpc 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 (39) hide show
  1. package/README.md +383 -0
  2. package/dist/chunks/_empty-crypto-Bi0tGx5K.js +8 -0
  3. package/dist/chunks/boundedTrafficSubscription-1L592xc7.js +1126 -0
  4. package/dist/chunks/boundedTrafficSubscription-1L592xc7.js.map +1 -0
  5. package/dist/chunks/hub.interfaces-BzWfsVT2.js +526 -0
  6. package/dist/chunks/hub.interfaces-BzWfsVT2.js.map +1 -0
  7. package/dist/chunks/hubAccess-DwTZPiI8.d.ts +79 -0
  8. package/dist/chunks/hubAccess-DwTZPiI8.d.ts.map +1 -0
  9. package/dist/chunks/hubFacade-CQflVkVC.js +85 -0
  10. package/dist/chunks/hubFacade-CQflVkVC.js.map +1 -0
  11. package/dist/chunks/hubFacade-Dkgw2pTi.d.ts +101 -0
  12. package/dist/chunks/hubFacade-Dkgw2pTi.d.ts.map +1 -0
  13. package/dist/chunks/linkRpcConnection-CtlQmetO.d.ts +3623 -0
  14. package/dist/chunks/linkRpcConnection-CtlQmetO.d.ts.map +1 -0
  15. package/dist/chunks/rolldown-runtime-4LSo1kEK.js +17 -0
  16. package/dist/chunks/src-D3NUIwyo.js +7795 -0
  17. package/dist/chunks/src-D3NUIwyo.js.map +1 -0
  18. package/dist/hub/client/index.d.ts +50 -0
  19. package/dist/hub/client/index.d.ts.map +1 -0
  20. package/dist/hub/client/index.js +97 -0
  21. package/dist/hub/client/index.js.map +1 -0
  22. package/dist/hub/common/index.d.ts +1189 -0
  23. package/dist/hub/common/index.d.ts.map +1 -0
  24. package/dist/hub/common/index.js +267 -0
  25. package/dist/hub/common/index.js.map +1 -0
  26. package/dist/index.d.ts +6 -0
  27. package/dist/index.js +7 -0
  28. package/dist/inspection/index.d.ts +66 -0
  29. package/dist/inspection/index.d.ts.map +1 -0
  30. package/dist/inspection/index.js +6 -0
  31. package/dist/node.d.ts +548 -0
  32. package/dist/node.d.ts.map +1 -0
  33. package/dist/node.js +1087 -0
  34. package/dist/node.js.map +1 -0
  35. package/dist/web.d.ts +44 -0
  36. package/dist/web.d.ts.map +1 -0
  37. package/dist/web.js +58 -0
  38. package/dist/web.js.map +1 -0
  39. package/package.json +59 -0
@@ -0,0 +1,3623 @@
1
+ import { $ZodType, output } from "zod/v4/core";
2
+ import { z } from "zod";
3
+ //#region src/protocol/jsonValue.d.ts
4
+ /**
5
+ * The JSON value lattice. Anything the wire can carry.
6
+ *
7
+ * Object values are `JsonValue | undefined` so `undefined`-valued fields
8
+ * may be present in source and are simply omitted at canonicalisation
9
+ * time (rather than serialised as `null`).
10
+ */
11
+ type JsonValue = null | boolean | number | string | JsonValue[] | {
12
+ [key: string]: JsonValue | undefined;
13
+ };
14
+ //#endregion
15
+ //#region src/protocol/jsonRpc.d.ts
16
+ type RequestId = number | string;
17
+ interface JsonRpcRequest<TParams = JsonValue> {
18
+ jsonrpc: "2.0";
19
+ id: RequestId;
20
+ method: string;
21
+ params?: TParams;
22
+ }
23
+ interface JsonRpcNotification<TParams = JsonValue> {
24
+ jsonrpc: "2.0";
25
+ method: string;
26
+ params?: TParams;
27
+ }
28
+ interface JsonRpcSuccess {
29
+ jsonrpc: "2.0";
30
+ id: RequestId | null;
31
+ result: JsonValue;
32
+ }
33
+ interface JsonRpcError {
34
+ jsonrpc: "2.0";
35
+ id: RequestId | null;
36
+ error: {
37
+ code: number;
38
+ message: string;
39
+ data?: JsonValue;
40
+ };
41
+ }
42
+ type JsonRpcResponse = JsonRpcSuccess | JsonRpcError;
43
+ type JsonRpcMessage = JsonRpcRequest | JsonRpcNotification | JsonRpcResponse;
44
+ declare const ErrorCode: {
45
+ readonly parseError: -32700;
46
+ readonly invalidRequest: -32600;
47
+ readonly methodNotFound: -32601;
48
+ readonly invalidParams: -32602;
49
+ readonly internalError: -32603;
50
+ /** Caller is authenticated but lacks a capability covering the call. */
51
+ readonly permissionRequired: -32401;
52
+ /** The peer a request was routed to detached before it could respond. */
53
+ readonly peerDisconnected: -32402;
54
+ /** The request exceeded the hub's idle timeout with no stream activity. */
55
+ readonly requestTimeout: -32403;
56
+ /** The request was cancelled (by the caller, or by the hub on disconnect). */
57
+ readonly cancelled: -32800;
58
+ };
59
+ declare function isRequest(m: JsonRpcMessage): m is JsonRpcRequest;
60
+ declare function isNotification(m: JsonRpcMessage): m is JsonRpcNotification;
61
+ declare function isResponse(m: JsonRpcMessage): m is JsonRpcResponse;
62
+ //#endregion
63
+ //#region src/schema/linkRpcJsonSchema.d.ts
64
+ type LinkRpcJsonSchema = true | false | NullSchema | BooleanSchema | NumberSchema | IntegerSchema | StringSchema | ConstSchema | EnumSchema | ArraySchema | TupleSchema | ObjectSchema | UnionSchema | OneOfSchema | RefSchema;
65
+ interface SchemaBase {
66
+ [key: `x-${string}`]: unknown;
67
+ title?: string;
68
+ description?: string;
69
+ /**
70
+ * Additional draft 2020-12 constraints that refine (never replace) this
71
+ * node. This extension is non-normative for LinkRPC identity; use
72
+ * {@link materializeJsonSchema} when exporting to a general validator.
73
+ */
74
+ "x-json-schema"?: boolean | Record<string, unknown>;
75
+ }
76
+ interface NullSchema extends SchemaBase {
77
+ type: "null";
78
+ }
79
+ interface BooleanSchema extends SchemaBase {
80
+ type: "boolean";
81
+ }
82
+ interface NumberSchema extends SchemaBase {
83
+ type: "number";
84
+ /** Opaque well-known refinement tag, e.g. "float32", "percentage". */
85
+ format?: string;
86
+ }
87
+ interface IntegerSchema extends SchemaBase {
88
+ type: "integer";
89
+ /** Opaque well-known refinement tag, e.g. "int32", "uint8", "unix-time". */
90
+ format?: string;
91
+ }
92
+ interface StringSchema extends SchemaBase {
93
+ type: "string";
94
+ /** Opaque well-known refinement tag, e.g. "email", "uri", "uuid", "date-time". */
95
+ format?: string;
96
+ }
97
+ /** Single literal value. */
98
+ interface ConstSchema extends SchemaBase {
99
+ const: JsonValue;
100
+ }
101
+ /** Finite set of literal values. */
102
+ interface EnumSchema extends SchemaBase {
103
+ enum: JsonValue[];
104
+ }
105
+ /** Homogeneous array. */
106
+ interface ArraySchema extends SchemaBase {
107
+ type: "array";
108
+ items: LinkRpcJsonSchema;
109
+ }
110
+ /** Fixed-length head plus optional rest element type. */
111
+ interface TupleSchema extends SchemaBase {
112
+ type: "array";
113
+ prefixItems: LinkRpcJsonSchema[];
114
+ /** `false` => exact length; schema => typed rest; omitted => exact length. */
115
+ items?: LinkRpcJsonSchema | false;
116
+ }
117
+ interface ObjectSchema extends SchemaBase {
118
+ type: "object";
119
+ properties: Record<string, LinkRpcJsonSchema>;
120
+ /** Names of required properties. Must all be keys of `properties`. */
121
+ required?: string[];
122
+ /** `false` => closed; schema => value type for unknown keys. */
123
+ additionalProperties: LinkRpcJsonSchema | false;
124
+ }
125
+ /** Untagged union. Assignability distributes over branches. */
126
+ interface UnionSchema extends SchemaBase {
127
+ anyOf: LinkRpcJsonSchema[];
128
+ }
129
+ /**
130
+ * Tagged-or-disjoint union (`oneOf`). Structurally treated the same as
131
+ * `UnionSchema` for assignability; the distinction is preserved so the
132
+ * wire schema faithfully reflects whether the source was a
133
+ * discriminated union (e.g. Zod's `z.discriminatedUnion`) or a plain
134
+ * union.
135
+ *
136
+ * `discriminator`, when present, is a pure consumer hint: it names the
137
+ * property that branches dispatch on. Every branch SHOULD be an object
138
+ * with that property set to a distinct `const` value, but the subset
139
+ * does not enforce this — broken discriminators are tolerated.
140
+ */
141
+ interface OneOfSchema extends SchemaBase {
142
+ oneOf: LinkRpcJsonSchema[];
143
+ discriminator?: DiscriminatorSchema;
144
+ }
145
+ interface DiscriminatorSchema {
146
+ propertyName: string;
147
+ }
148
+ /** Reference to a named entry in `SvcInterfaceSchema.components.schemas`. */
149
+ interface RefSchema extends SchemaBase {
150
+ /** JSON Pointer, restricted to "#/components/schemas/<name>". */
151
+ $ref: string;
152
+ }
153
+ //#endregion
154
+ //#region src/schema/linkRpcInterfaceSchema.d.ts
155
+ /**
156
+ * Minimal interface schema for linkrpc. A strict subset of OpenRPC 1.x:
157
+ * identity & addressing live in linkrpc, so this format only describes the
158
+ * contract of a single interface (methods + reusable JSON Schemas).
159
+ */
160
+ interface LinkRpcInterfaceSchema {
161
+ [key: `x-${string}`]: unknown;
162
+ /** Stable interface id, e.g. "de.hediet.notification-target". */
163
+ id: string;
164
+ /**
165
+ * Content hash of the normalized schema. Pairs with `id` to form `id@hash`.
166
+ * Normalization: serialize this object with `hash` omitted, object keys
167
+ * sorted recursively, and no insignificant whitespace; hash the bytes.
168
+ */
169
+ hash: string;
170
+ /**
171
+ * Normative human description (GitHub-flavored markdown). Part of the
172
+ * interface hash — changing `description` is a contract change. Use it
173
+ * for the canonical purpose / semantics of the interface.
174
+ */
175
+ description?: string;
176
+ /**
177
+ * Non-normative implementation notes (markdown). Stripped from the hash,
178
+ * so editing `comment` never changes the interface identity. Use it for
179
+ * rationale, changelog notes, examples, etc.
180
+ */
181
+ comment?: string;
182
+ /** Methods keyed by local member name. */
183
+ methods: Record<string, MethodSchema>;
184
+ /** Reusable schema definitions, referenced via `#/components/schemas/<name>`. */
185
+ components?: {
186
+ schemas?: Record<string, LinkRpcJsonSchema>;
187
+ };
188
+ }
189
+ interface MethodSchema {
190
+ [key: `x-${string}`]: unknown;
191
+ /** Schema for the user params object. */
192
+ params: LinkRpcJsonSchema;
193
+ /** Result schema. Omit to declare a notification-only method. */
194
+ result?: LinkRpcJsonSchema;
195
+ /**
196
+ * Schema for client-emitted stream messages (`$stream::send` from
197
+ * caller to callee) on an in-flight call. Absent means the client
198
+ * may not stream on this method.
199
+ */
200
+ clientStream?: LinkRpcJsonSchema;
201
+ /**
202
+ * Schema for server-emitted stream messages (`$stream::send` from
203
+ * callee to caller) on an in-flight call. Absent means the server
204
+ * may not stream on this method.
205
+ */
206
+ serverStream?: LinkRpcJsonSchema;
207
+ /** Application-level errors. Codes MUST be unique. */
208
+ errors?: ErrorSchema[];
209
+ summary?: string;
210
+ /**
211
+ * Normative description of this method's contract (markdown). Part of
212
+ * the interface hash — changing it is a contract change.
213
+ */
214
+ description?: string;
215
+ /** Non-normative implementation notes. Stripped from the hash. */
216
+ comment?: string;
217
+ deprecated?: boolean;
218
+ /**
219
+ * Behavioral claims about this method. All flags default to `false`;
220
+ * setting one is always a positive refinement of the contract.
221
+ * Part of the interface hash — these are normative claims callers
222
+ * may rely on, so changing them is a contract change.
223
+ */
224
+ annotations?: MemberAnnotations;
225
+ }
226
+ /**
227
+ * Behavioral claims about a method. Every flag is a positive assertion
228
+ * (default `false` ≡ "no claim"); setting one strengthens the contract
229
+ * the caller may rely on.
230
+ *
231
+ * These are normative — they are included in the interface hash.
232
+ */
233
+ interface MemberAnnotations {
234
+ /**
235
+ * The method does not modify any observable state on the callee
236
+ * (or anywhere reachable from it). Pure query.
237
+ *
238
+ * Implies `idempotent` and `reversible` (a no-op has nothing to
239
+ * undo and repeats trivially).
240
+ */
241
+ readOnly?: boolean;
242
+ /**
243
+ * Calling N times with the same params has the same observable effect
244
+ * as calling once. Safe to retry on transport failure.
245
+ */
246
+ idempotent?: boolean;
247
+ /**
248
+ * Effects of this method are reversible — the caller (or operator)
249
+ * can undo them with a follow-up call. Implies the method is not
250
+ * `dangerous`.
251
+ */
252
+ reversible?: boolean;
253
+ /**
254
+ * Calling this method is expensive (slow, costly, or rate-limited).
255
+ * Callers should avoid unnecessary invocations and may want to
256
+ * confirm / batch.
257
+ */
258
+ expensive?: boolean;
259
+ /**
260
+ * Method has irreversible or destructive effects (data loss, money
261
+ * spent, message sent, etc.). UIs should require confirmation.
262
+ */
263
+ dangerous?: boolean;
264
+ }
265
+ interface ErrorSchema {
266
+ /** JSON-RPC error code. -32768..-32000 are reserved. */
267
+ code: number;
268
+ message: string;
269
+ /** Optional schema describing the shape of `error.data`. */
270
+ data?: LinkRpcJsonSchema;
271
+ }
272
+ //#endregion
273
+ //#region src/schema/memberTypes.d.ts
274
+ /**
275
+ * The schema type linkrpc accepts everywhere: the zod *core* base shared by
276
+ * both classic `zod` and `zod/mini`. Typing against it (instead of classic
277
+ * `z.ZodType`) lets callers author interfaces with either flavour — classic
278
+ * for ergonomics, mini for minimal bundle size — while linkrpc's own internal
279
+ * interfaces use mini. `O` is the validated output type.
280
+ */
281
+ type Schema<O = unknown> = $ZodType<O>;
282
+ /**
283
+ * Marker base for a typed method member. Carries enough metadata to:
284
+ * - validate / parse params at runtime (via the zod schemas),
285
+ * - emit a JSON schema for reflection,
286
+ * - propagate TS types up to the interface definition.
287
+ */
288
+ type MemberType = RequestType<any, any, any, any, any> | NotificationType<any>;
289
+ /**
290
+ * Optional documentation for a method member.
291
+ *
292
+ * - `description` is the **normative** contract of the method (included in the
293
+ * interface hash — changing it changes `schemaHash`).
294
+ * - `comment` is non-normative implementation notes (stripped from the hash).
295
+ * - `annotations` are normative behavioral claims (e.g. `readOnly`,
296
+ * `idempotent`); included in the hash.
297
+ */
298
+ interface MemberDocs {
299
+ description?: string;
300
+ comment?: string;
301
+ annotations?: MemberAnnotations;
302
+ }
303
+ declare class RequestType<TParams = unknown, TResult = void, TError = void, TClientStream = never, TServerStream = never> {
304
+ readonly paramsSchema: Schema<TParams>;
305
+ readonly resultSchema: Schema<TResult>;
306
+ readonly errorSchema: Schema<TError>;
307
+ readonly docs: MemberDocs;
308
+ /**
309
+ * Schema for stream messages the **client** may emit on an
310
+ * in-flight call (e.g. cancellation, input). `undefined` means
311
+ * the client may not stream on this method.
312
+ */
313
+ readonly clientStreamSchema?: Schema<TClientStream> | undefined;
314
+ /**
315
+ * Schema for stream messages the **server** may emit while
316
+ * handling an in-flight call (e.g. progress, partial results).
317
+ * `undefined` means the server may not stream on this method.
318
+ */
319
+ readonly serverStreamSchema?: Schema<TServerStream> | undefined;
320
+ readonly kind: "request";
321
+ constructor(paramsSchema: Schema<TParams>, resultSchema: Schema<TResult>, errorSchema: Schema<TError>, docs?: MemberDocs,
322
+ /**
323
+ * Schema for stream messages the **client** may emit on an
324
+ * in-flight call (e.g. cancellation, input). `undefined` means
325
+ * the client may not stream on this method.
326
+ */
327
+ clientStreamSchema?: Schema<TClientStream> | undefined,
328
+ /**
329
+ * Schema for stream messages the **server** may emit while
330
+ * handling an in-flight call (e.g. progress, partial results).
331
+ * `undefined` means the server may not stream on this method.
332
+ */
333
+ serverStreamSchema?: Schema<TServerStream> | undefined);
334
+ /** Phantom field — typed-only, do not access at runtime. */
335
+ readonly _params: TParams;
336
+ readonly _result: TResult;
337
+ readonly _error: TError;
338
+ readonly _clientStream: TClientStream;
339
+ readonly _serverStream: TServerStream;
340
+ /**
341
+ * Return a copy of this request type with stream payload schemas
342
+ * attached. Pass `undefined` for either direction to leave it
343
+ * closed.
344
+ */
345
+ withStream<TClient = TClientStream, TServer = TServerStream>(opts: {
346
+ client?: Schema<TClient>;
347
+ server?: Schema<TServer>;
348
+ }): RequestType<TParams, TResult, TError, TClient, TServer>;
349
+ }
350
+ declare class NotificationType<TParams = unknown> {
351
+ readonly paramsSchema: Schema<TParams>;
352
+ readonly docs: MemberDocs;
353
+ readonly kind: "notification";
354
+ constructor(paramsSchema: Schema<TParams>, docs?: MemberDocs);
355
+ readonly _params: TParams;
356
+ }
357
+ /**
358
+ * Define a request method.
359
+ *
360
+ * @example
361
+ * bar: requestType(z.object({ to: z.string() }), z.string(), {
362
+ * description: "MUST resolve before the next call from the same caller.",
363
+ * })
364
+ */
365
+ declare function requestType<TParams, TResult = void, TError = void>(params: Schema<TParams>, result?: Schema<TResult>, docsOrError?: MemberDocs | Schema<TError>, maybeDocs?: MemberDocs): RequestType<TParams, TResult, TError>;
366
+ /**
367
+ * Define a notification method.
368
+ *
369
+ * @example
370
+ * foo: notificationType(z.object({ message: z.string() }))
371
+ */
372
+ declare function notificationType<TParams>(params: Schema<TParams>, docs?: MemberDocs): NotificationType<TParams>;
373
+ interface ZodToSvcJsonSchemaOptions {
374
+ readonly methodName: string;
375
+ readonly schemaPosition: string;
376
+ readonly components: Record<string, LinkRpcJsonSchema>;
377
+ }
378
+ /** Convert a zod schema to our restricted SvcJsonSchema subset. */
379
+ declare function zodToSvcJsonSchema(schema: Schema, options?: ZodToSvcJsonSchemaOptions): LinkRpcJsonSchema;
380
+ //#endregion
381
+ //#region src/connection/interfaceDefinition.d.ts
382
+ /**
383
+ * Per-call stream API handed to a request handler as its third argument.
384
+ * Allows the handler to consume {@link STREAM_METHOD} notifications
385
+ * emitted by the caller (`onMessage`) and emit stream notifications to
386
+ * the caller (`send`) while the request is in flight.
387
+ *
388
+ * Members are typed by the originating method's
389
+ * {@link RequestType.clientStreamSchema} / `serverStreamSchema`.
390
+ * Streams whose schema is `undefined` make the corresponding member
391
+ * effectively unusable: `send` is typed `(payload: never) => void` and
392
+ * the registered `onMessage` listener can never fire because the
393
+ * receiver-side validator rejects the wire payload.
394
+ */
395
+ interface StreamApi<TClient = unknown, TServer = unknown> {
396
+ /** Emit a server→client stream message. */
397
+ send(payload: TServer): Promise<void>;
398
+ /**
399
+ * Register a listener for client→server stream messages on this
400
+ * request. Calling twice replaces the previous listener.
401
+ */
402
+ onMessage(listener: (payload: TClient) => void): void;
403
+ /**
404
+ * Liveness probe toward the caller: resolves once the caller
405
+ * acknowledges with a matching pong, rejects if the call settles
406
+ * first. Independent of the channel's automatic keepalive ping.
407
+ */
408
+ ping(): Promise<void>;
409
+ /**
410
+ * Aborts when the caller cancels this in-flight request, or when the
411
+ * hub cancels it on the caller's behalf (caller disconnect / idle
412
+ * timeout). Observe it to stop work early and settle the request
413
+ * (e.g. `signal.throwIfAborted()`), which surfaces as a `cancelled`
414
+ * error to the caller.
415
+ */
416
+ readonly signal: AbortSignal;
417
+ }
418
+ interface InterfaceInfo {
419
+ id: string;
420
+ /**
421
+ * Normative description of the interface (markdown). Part of the
422
+ * interface hash — changing it is a contract change.
423
+ */
424
+ description?: string;
425
+ /** Non-normative implementation notes. Stripped from the hash. */
426
+ comment?: string;
427
+ /**
428
+ * Optional expected content hash (see `computeInterfaceHash`). When
429
+ * set, {@link InterfaceDefinition}'s constructor verifies that the
430
+ * computed {@link InterfaceDefinition.schemaHash} matches and throws
431
+ * otherwise — a guard against silent contract drift when the wire
432
+ * shape changes but a pinned hash was not updated.
433
+ */
434
+ hash?: string;
435
+ }
436
+ type MemberMap = Record<string, MemberType>;
437
+ /** Stable wire identity of one member in an interface definition. */
438
+ interface InterfaceMemberRef<TName extends string = string> {
439
+ readonly interfaceId: string;
440
+ readonly interfaceHash: string;
441
+ readonly member: TName;
442
+ }
443
+ type InterfaceMemberRefMap<TMembers extends MemberMap> = { readonly [K in keyof TMembers & string]: InterfaceMemberRef<K>; };
444
+ /**
445
+ * Per-call options accepted by a streaming-enabled client method. Currently
446
+ * only `onMessage` for consuming server→client stream notifications; the
447
+ * caller addresses client→server stream messages via the returned
448
+ * {@link StreamingCall}.
449
+ */
450
+ interface StreamCallOptions<TServer> {
451
+ /** Listener for server→client stream messages on this in-flight call. */
452
+ onMessage?: (payload: TServer) => void;
453
+ }
454
+ /**
455
+ * Return shape of a streaming-enabled client method. Behaves as a
456
+ * `Promise<TResult>` for the final response, and exposes `send` for
457
+ * emitting client→server stream messages on the in-flight call. The
458
+ * wire request id is also exposed (resolved once the request has
459
+ * been allocated).
460
+ *
461
+ * For methods whose interface schema declares no client stream
462
+ * (`TClient = never`), `send` is typed `(payload: never) => Promise<void>`
463
+ * and is effectively uncallable — matching the runtime behavior, where
464
+ * the receiver would drop client-emitted stream messages anyway.
465
+ */
466
+ interface StreamingCall<TResult, TClient> extends Promise<TResult> {
467
+ /** Resolves to the wire request id once the call has been sent. */
468
+ readonly requestId: Promise<RequestId>;
469
+ /** Emit a client→server stream message on this in-flight call. */
470
+ send(payload: TClient): Promise<void>;
471
+ /**
472
+ * Ask the callee to abort this in-flight call. Advisory: the call
473
+ * settles via its normal response (typically a `cancelled` error).
474
+ * `reason` is an open-set diagnostic string (see `StreamControlReason`).
475
+ */
476
+ cancel(reason?: string): Promise<void>;
477
+ /**
478
+ * Stop tracking this call locally. This does not notify the callee; call
479
+ * {@link cancel} first when remote work should also be cancelled.
480
+ */
481
+ dispose?(reason?: string): void;
482
+ /**
483
+ * Liveness probe toward the callee: resolves once the callee
484
+ * acknowledges with a matching pong, rejects if the call settles
485
+ * first. Independent of the channel's automatic keepalive ping.
486
+ */
487
+ ping(): Promise<void>;
488
+ }
489
+ /**
490
+ * `true` iff at least one stream direction is declared (either client or
491
+ * server stream schema present). Used by {@link InterfaceClient} to pick
492
+ * between the plain `Promise<R>` shape and the {@link StreamingCall}
493
+ * shape per method.
494
+ */
495
+ type _HasStream<TClient, TServer> = [TClient] extends [never] ? ([TServer] extends [never] ? false : true) : true;
496
+ /**
497
+ * Compile-time TypeScript shape of an interface — useful for typed
498
+ * client/server implementations on top of the runtime definition.
499
+ *
500
+ * Methods whose `RequestType` declares stream payloads via
501
+ * `.withStream({ client, server })` return a {@link StreamingCall}
502
+ * augmented with `send`; all others return a plain `Promise<TResult>`.
503
+ *
504
+ * @example
505
+ * type Client = InterfaceClient<typeof myInterface>;
506
+ * // => { bar(p: {...}): Promise<string>; foo(p: {...}): void; }
507
+ */
508
+ type InterfaceClientMember<TMember> = TMember extends RequestType<infer P, infer R, any, infer TC, infer TS> ? (_HasStream<TC, TS> extends true ? (params: P, opts?: StreamCallOptions<TS>) => StreamingCall<R, TC> : (params: P) => Promise<R>) : TMember extends NotificationType<infer P> ? (params: P) => void : never;
509
+ type InterfaceClient<TDef extends InterfaceDefinition<any>> = { [K in keyof TDef['members']]: InterfaceClientMember<TDef['members'][K]>; };
510
+ /**
511
+ * Compile-time shape of a server implementation for an interface — used by
512
+ * `LinkRpcConnection.register`. Request handlers may return synchronously or
513
+ * via a promise; notification handlers return void.
514
+ *
515
+ * `TCtx` is the call-context type carried by the hosting connection — see
516
+ * `LinkRpcConnection<TCtx>`. For the default connection (`TCtx = undefined`)
517
+ * handlers may take a single params arg; for ctx-aware connections (e.g.
518
+ * the hub's self connection) they may take a second `ctx` arg of the
519
+ * concrete type. A 1-arg handler remains assignable where a 2-arg handler
520
+ * is expected, so existing handlers compile unchanged.
521
+ */
522
+ type InterfaceHandler<TMember, TCtx> = TMember extends RequestType<infer P, infer R, any, infer TC, infer TS> ? (params: P, ctx: TCtx, stream: StreamApi<TC, TS>) => R | Promise<R> : TMember extends NotificationType<infer P> ? (params: P, ctx: TCtx) => void | Promise<void> : never;
523
+ type InterfaceHandlers<TDef extends InterfaceDefinition<any>, TCtx = undefined> = { [K in keyof TDef['members']]: InterfaceHandler<TDef['members'][K], TCtx>; };
524
+ /**
525
+ * Options accepted by {@link InterfaceDefinition}'s constructor.
526
+ *
527
+ * `frozenSchema` lets callers supply an externally-authored
528
+ * `LinkRpcInterfaceSchema` (e.g. produced by codegen or, in the faker, by an
529
+ * LLM at runtime) verbatim. When set, `toSchema()` returns that document
530
+ * (with `hash` overlaid) and `schemaHash` is computed from it — the
531
+ * `members` map is used only for runtime dispatch (param/result
532
+ * validation, stream routing) and is no longer the source of truth for
533
+ * the wire shape.
534
+ */
535
+ interface InterfaceDefinitionOpts {
536
+ frozenSchema?: LinkRpcInterfaceSchema;
537
+ }
538
+ declare class InterfaceDefinition<TMembers extends MemberMap> {
539
+ readonly info: InterfaceInfo;
540
+ readonly members: TMembers;
541
+ /** Typed wire references for capability and access-request construction. */
542
+ readonly ref: InterfaceMemberRefMap<TMembers>;
543
+ constructor(info: InterfaceInfo, members: TMembers, opts?: InterfaceDefinitionOpts);
544
+ /** Content hash of this interface (see `computeInterfaceHash`). */
545
+ get schemaHash(): string;
546
+ /** Lower the definition to a wire-format `LinkRpcInterfaceSchema`, hash filled in. */
547
+ toSchema(): LinkRpcInterfaceSchema;
548
+ }
549
+ /**
550
+ * Convenient builder for an interface definition. Tracks TypeScript types
551
+ * through `requestType` / `notificationType` so client and server code can
552
+ * derive their shapes from the definition.
553
+ *
554
+ * @example
555
+ * const myInterface = defineInterface(
556
+ * { id: "de.hediet.notification-target" },
557
+ * {
558
+ * send: requestType(z.object({ to: z.string() }), z.string()),
559
+ * notify: notificationType(z.object({ message: z.string() })),
560
+ * },
561
+ * );
562
+ */
563
+ declare function defineInterface<TMembers extends MemberMap>(info: InterfaceInfo, members: TMembers): InterfaceDefinition<TMembers>;
564
+ /**
565
+ * Build a runtime {@link InterfaceDefinition} from a previously-published
566
+ * {@link LinkRpcInterfaceSchema} — typically one received over the wire (e.g.
567
+ * from `hubrpc.schemas::get`) or generated at runtime by tooling that does
568
+ * not have the original zod sources at hand (codegen, faker / mock
569
+ * services, dynamic gateways).
570
+ *
571
+ * The original schema is kept verbatim: `toSchema()` returns it (with
572
+ * `hash` overlaid) and `schemaHash` is computed from it, so reflection
573
+ * consumers see the real wire contract. Member-level params / results /
574
+ * streams use `z.any()` because no zod source is available — call-site
575
+ * validation is therefore a no-op and the caller is responsible for
576
+ * shape-checking inputs and outputs.
577
+ *
578
+ * Methods with no `result` descriptor become notifications; methods with
579
+ * `clientStream` / `serverStream` get pass-through stream payload
580
+ * schemas attached.
581
+ */
582
+ declare function interfaceFromSchema(schema: LinkRpcInterfaceSchema): InterfaceDefinition<MemberMap>;
583
+ //#endregion
584
+ //#region src/schema/hash.d.ts
585
+ /**
586
+ * Compute the interface hash: SHA-256 of the canonicalized schema, truncated
587
+ * to 16 hex chars (64 bits of collision budget per id).
588
+ *
589
+ * Canonicalization strips the schema down to its **normative wire-contract
590
+ * projection** before hashing, so a single interface document can carry richer
591
+ * non-normative material (codegen hints, safety expressions, notes) without
592
+ * changing identity:
593
+ *
594
+ * 1. Normalize every JSON-Schema position (`params`, `result`, streams, and
595
+ * `components.schemas`) onto the decidable linkrpc subset.
596
+ * 2. Strip every `comment` field (non-normative — must not affect identity).
597
+ * `description` is NORMATIVE and kept in the hash.
598
+ * 3. Strip every **specification-extension** field — any object key whose name
599
+ * begins with `x-` — at every level of the document (see
600
+ * {@link EXTENSION_PREFIX}). This is the minimal, explicit "one document,
601
+ * two views" mechanism: the stored document keeps the rich `x-…`
602
+ * expressions; identity hashes only the simple contract. It mirrors
603
+ * OpenRPC/OpenAPI specification extensions (this schema format is a subset
604
+ * of OpenRPC 1.x). Editing an `x-…` value never changes the hash; changing
605
+ * a wire field (`params`, `result`, member names, `type`, `required`,
606
+ * `description`, `annotations`, …) does.
607
+ * 4. Omit the top-level `hash` field itself.
608
+ * 5. RFC 8785 JCS encode (recursive key sort, no whitespace) via {@link jcsCanonicalize}.
609
+ *
610
+ * Because no interface schema uses `x-…` keys today, this preserves every
611
+ * existing hash: stripping a set of keys that are always absent is a no-op.
612
+ *
613
+ * > Reservation. `x-…` is reserved for non-normative extensions at every level.
614
+ * > Member names cannot collide (they are alphanumeric per chapter 01 §2), and
615
+ * > object property names in the JSON Schema subset MUST NOT begin with `x-`.
616
+ */
617
+ declare function computeInterfaceHash(schema: LinkRpcInterfaceSchema): string;
618
+ /**
619
+ * Prefix marking a non-normative **specification-extension** key. Any object
620
+ * key beginning with this prefix is stripped before hashing (at every level),
621
+ * exactly like `comment`. Reserved for rich, identity-neutral material such as
622
+ * codegen directives, richer validation/safety expressions, or tooling hints.
623
+ */
624
+ declare const EXTENSION_PREFIX = "x-";
625
+ //#endregion
626
+ //#region src/schema/normalize.d.ts
627
+ /**
628
+ * Normalize raw JSON Schema output (e.g. from `z.toJSONSchema`) into the
629
+ * SvcJsonSchema subset:
630
+ *
631
+ * - drop annotation keys (`examples`, `default`, `$comment`, `readOnly`, ...)
632
+ * - drop out-of-subset refinements (`pattern`, `minimum`, `multipleOf`,
633
+ * `allOf`, `oneOf`, `if/then/else`, `patternProperties`, ...)
634
+ * - empty schema `{}` ⇒ `true` (top)
635
+ * - `{"not":{}}` ⇒ `false` (bottom); any other `not` is stripped
636
+ * - `type:"object"` without `additionalProperties` ⇒ closed (`false`),
637
+ * matching linkrpc's stricter contract
638
+ *
639
+ * The output is canonical: structurally equal inputs produce structurally
640
+ * equal outputs, which is what `computeInterfaceHash` relies on.
641
+ */
642
+ declare function normalizeJsonSchema(raw: unknown): LinkRpcJsonSchema;
643
+ //#endregion
644
+ //#region src/schema/assignability.d.ts
645
+ /**
646
+ * Structural subtype check: returns `true` iff every JSON value matching
647
+ * `sub` also matches `sup`, over the SvcJsonSchema subset.
648
+ *
649
+ * Cycles introduced by `$ref` are broken by assuming the recursive case
650
+ * holds (standard coinductive subtyping). This is sound for productive
651
+ * (non-degenerate) schemas; pathological inputs are out of scope.
652
+ */
653
+ declare function isAssignable(sub: LinkRpcJsonSchema, sup: LinkRpcJsonSchema, components?: Components): boolean;
654
+ interface Components {
655
+ schemas?: Record<string, LinkRpcJsonSchema>;
656
+ }
657
+ //#endregion
658
+ //#region src/schema/assertSchemaReferences.d.ts
659
+ declare function componentSchemaRef(name: string): string;
660
+ declare function componentSchemaName(ref: string): string;
661
+ /**
662
+ * Check the finite schema graph without interpreting JSON literal payloads.
663
+ * A reference/union-only cycle is invalid; descending into an object member
664
+ * or an array item guards a cycle, but does not imply the schema is nonempty.
665
+ */
666
+ declare function assertSchemaReferences(roots: Iterable<LinkRpcJsonSchema>, components?: Record<string, LinkRpcJsonSchema>): void;
667
+ //#endregion
668
+ //#region src/schema/materializeJsonSchema.d.ts
669
+ interface MaterializedJsonSchema {
670
+ $schema: "https://json-schema.org/draft/2020-12/schema";
671
+ $defs?: Record<string, unknown>;
672
+ [key: string]: unknown;
673
+ }
674
+ /**
675
+ * Export a LinkRPC schema and its components as standalone JSON Schema
676
+ * draft 2020-12. Node-local `x-json-schema` constraints are conjoined via
677
+ * `allOf`, so a refinement cannot accidentally override the wire contract.
678
+ *
679
+ * References are rewritten rather than dereferenced. Consequently recursive
680
+ * and mutually-recursive component graphs are materialized in finite time.
681
+ */
682
+ declare function materializeJsonSchema(root: LinkRpcJsonSchema, components?: Record<string, LinkRpcJsonSchema>): MaterializedJsonSchema;
683
+ //#endregion
684
+ //#region src/schema/schemaToZod.d.ts
685
+ interface SchemaToZodContext {
686
+ readonly toZod: (schema: LinkRpcJsonSchema) => z.ZodType<unknown>;
687
+ }
688
+ /**
689
+ * Create a recursive LinkRPC-schema validator materializer. Component
690
+ * references are lazy, so self and mutual recursion remain guarded.
691
+ */
692
+ declare function createSchemaToZod(components?: Record<string, LinkRpcJsonSchema>): SchemaToZodContext;
693
+ declare function schemaToZod(schema: LinkRpcJsonSchema, components?: Record<string, LinkRpcJsonSchema>): z.ZodType<unknown>;
694
+ //#endregion
695
+ //#region src/schema/codegen/generateTsInterface.d.ts
696
+ interface GenerateInterfaceOptions {
697
+ /**
698
+ * Module specifier from which `defineInterface`, `requestType`,
699
+ * `notificationType` are imported. Defaults to `@hediet/linkrpc`.
700
+ */
701
+ linkRpcImport?: string;
702
+ /**
703
+ * Identifier for the exported `InterfaceDefinition` const. Defaults to
704
+ * a sanitized form of the interface id with an `Interface` suffix
705
+ * (e.g. `hubrpc.directory` → `linkRpcDirectoryInterface`).
706
+ */
707
+ exportName?: string;
708
+ /**
709
+ * Preserve the supplied wire schema verbatim instead of reconstructing it
710
+ * from the generated Zod schemas. This permits type-safe generation for
711
+ * wire shapes that Zod represents differently, such as untagged `oneOf`.
712
+ */
713
+ preserveWireSchema?: boolean;
714
+ /**
715
+ * Also export a metadata-free target for `connection.get(target)`.
716
+ * The interface definition remains a separate export.
717
+ */
718
+ bareTarget?: {
719
+ exportName: string;
720
+ prefix: string;
721
+ };
722
+ }
723
+ /**
724
+ * Render a {@link LinkRpcInterfaceSchema} as a stand-alone TypeScript source
725
+ * file that, when evaluated, reproduces the same canonical schema (and
726
+ * therefore the same `schemaHash`).
727
+ *
728
+ * Components in `components.schemas` are emitted as named `const`
729
+ * declarations referenced from the bodies via `$ref`. Only recursive
730
+ * components receive explicit payload types; other types remain Zod-inferred.
731
+ */
732
+ declare function generateTsInterface(schema: LinkRpcInterfaceSchema, options?: GenerateInterfaceOptions): string;
733
+ //#endregion
734
+ //#region src/inspection/inspection.interfaces.d.ts
735
+ declare const zTopologyPort: import("zod/mini").ZodMiniObject<{
736
+ portId: import("zod/mini").ZodMiniString<string>;
737
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
738
+ }, import("zod/v4/core").$strip>;
739
+ declare const zParticipantDescriptor: import("zod/mini").ZodMiniObject<{
740
+ type: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
741
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
742
+ processId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
743
+ processType: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
744
+ nodeStatusServiceId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
745
+ metadata: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniRecord<import("zod/mini").ZodMiniString<string>, import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniString<string>, import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniBoolean<boolean>]>>>;
746
+ }, import("zod/v4/core").$strip>;
747
+ declare const zParticipantDescriptorSource: import("zod/mini").ZodMiniObject<{
748
+ source: import("zod/mini").ZodMiniEnum<{
749
+ self: "self";
750
+ attacher: "attacher";
751
+ }>;
752
+ descriptor: import("zod/mini").ZodMiniObject<{
753
+ type: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
754
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
755
+ processId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
756
+ processType: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
757
+ nodeStatusServiceId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
758
+ metadata: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniRecord<import("zod/mini").ZodMiniString<string>, import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniString<string>, import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniBoolean<boolean>]>>>;
759
+ }, import("zod/v4/core").$strip>;
760
+ }, import("zod/v4/core").$strip>;
761
+ declare const zTopologyNode: import("zod/mini").ZodMiniObject<{
762
+ nodeId: import("zod/mini").ZodMiniString<string>;
763
+ kind: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniEnum<{
764
+ endpoint: "endpoint";
765
+ hub: "hub";
766
+ }>>;
767
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
768
+ descriptors: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
769
+ source: import("zod/mini").ZodMiniEnum<{
770
+ self: "self";
771
+ attacher: "attacher";
772
+ }>;
773
+ descriptor: import("zod/mini").ZodMiniObject<{
774
+ type: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
775
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
776
+ processId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
777
+ processType: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
778
+ nodeStatusServiceId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
779
+ metadata: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniRecord<import("zod/mini").ZodMiniString<string>, import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniString<string>, import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniBoolean<boolean>]>>>;
780
+ }, import("zod/v4/core").$strip>;
781
+ }, import("zod/v4/core").$strip>>>;
782
+ ports: import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
783
+ portId: import("zod/mini").ZodMiniString<string>;
784
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
785
+ }, import("zod/v4/core").$strip>>;
786
+ }, import("zod/v4/core").$strip>;
787
+ declare const zTopologyLinkEndpoint: import("zod/mini").ZodMiniObject<{
788
+ nodeId: import("zod/mini").ZodMiniString<string>;
789
+ portId: import("zod/mini").ZodMiniString<string>;
790
+ }, import("zod/v4/core").$strip>;
791
+ declare const zTopologyTransportEndpoint: import("zod/mini").ZodMiniObject<{
792
+ address: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
793
+ port: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
794
+ }, import("zod/v4/core").$strip>;
795
+ /**
796
+ * Transport details as observed at a topology link. `local` corresponds to the
797
+ * link's `from` endpoint and `remote` to its `to` endpoint.
798
+ */
799
+ declare const zTopologyTransportInfo: import("zod/mini").ZodMiniObject<{
800
+ type: import("zod/mini").ZodMiniString<string>;
801
+ local: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
802
+ address: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
803
+ port: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
804
+ }, import("zod/v4/core").$strip>>;
805
+ remote: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
806
+ address: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
807
+ port: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
808
+ }, import("zod/v4/core").$strip>>;
809
+ path: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
810
+ metadata: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniRecord<import("zod/mini").ZodMiniString<string>, import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniString<string>, import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniBoolean<boolean>]>>>;
811
+ }, import("zod/v4/core").$strip>;
812
+ declare const zTopologyLink: import("zod/mini").ZodMiniObject<{
813
+ from: import("zod/mini").ZodMiniObject<{
814
+ nodeId: import("zod/mini").ZodMiniString<string>;
815
+ portId: import("zod/mini").ZodMiniString<string>;
816
+ }, import("zod/v4/core").$strip>;
817
+ to: import("zod/mini").ZodMiniObject<{
818
+ nodeId: import("zod/mini").ZodMiniString<string>;
819
+ portId: import("zod/mini").ZodMiniString<string>;
820
+ }, import("zod/v4/core").$strip>;
821
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
822
+ peerState: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniEnum<{
823
+ identified: "identified";
824
+ pending: "pending";
825
+ unsupported: "unsupported";
826
+ error: "error";
827
+ }>>;
828
+ transport: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
829
+ type: import("zod/mini").ZodMiniString<string>;
830
+ local: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
831
+ address: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
832
+ port: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
833
+ }, import("zod/v4/core").$strip>>;
834
+ remote: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
835
+ address: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
836
+ port: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
837
+ }, import("zod/v4/core").$strip>>;
838
+ path: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
839
+ metadata: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniRecord<import("zod/mini").ZodMiniString<string>, import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniString<string>, import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniBoolean<boolean>]>>>;
840
+ }, import("zod/v4/core").$strip>>;
841
+ }, import("zod/v4/core").$strip>;
842
+ declare const zRouteClaim: import("zod/mini").ZodMiniObject<{
843
+ serviceId: import("zod/mini").ZodMiniString<string>;
844
+ nodeId: import("zod/mini").ZodMiniString<string>;
845
+ portId: import("zod/mini").ZodMiniString<string>;
846
+ match: import("zod/mini").ZodMiniEnum<{
847
+ exact: "exact";
848
+ prefix: "prefix";
849
+ }>;
850
+ }, import("zod/v4/core").$strip>;
851
+ declare const zTopologyGraph: import("zod/mini").ZodMiniObject<{
852
+ observerServiceId: import("zod/mini").ZodMiniString<string>;
853
+ entryNodeId: import("zod/mini").ZodMiniString<string>;
854
+ nodes: import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
855
+ nodeId: import("zod/mini").ZodMiniString<string>;
856
+ kind: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniEnum<{
857
+ endpoint: "endpoint";
858
+ hub: "hub";
859
+ }>>;
860
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
861
+ descriptors: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
862
+ source: import("zod/mini").ZodMiniEnum<{
863
+ self: "self";
864
+ attacher: "attacher";
865
+ }>;
866
+ descriptor: import("zod/mini").ZodMiniObject<{
867
+ type: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
868
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
869
+ processId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
870
+ processType: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
871
+ nodeStatusServiceId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
872
+ metadata: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniRecord<import("zod/mini").ZodMiniString<string>, import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniString<string>, import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniBoolean<boolean>]>>>;
873
+ }, import("zod/v4/core").$strip>;
874
+ }, import("zod/v4/core").$strip>>>;
875
+ ports: import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
876
+ portId: import("zod/mini").ZodMiniString<string>;
877
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
878
+ }, import("zod/v4/core").$strip>>;
879
+ }, import("zod/v4/core").$strip>>;
880
+ links: import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
881
+ from: import("zod/mini").ZodMiniObject<{
882
+ nodeId: import("zod/mini").ZodMiniString<string>;
883
+ portId: import("zod/mini").ZodMiniString<string>;
884
+ }, import("zod/v4/core").$strip>;
885
+ to: import("zod/mini").ZodMiniObject<{
886
+ nodeId: import("zod/mini").ZodMiniString<string>;
887
+ portId: import("zod/mini").ZodMiniString<string>;
888
+ }, import("zod/v4/core").$strip>;
889
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
890
+ peerState: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniEnum<{
891
+ identified: "identified";
892
+ pending: "pending";
893
+ unsupported: "unsupported";
894
+ error: "error";
895
+ }>>;
896
+ transport: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
897
+ type: import("zod/mini").ZodMiniString<string>;
898
+ local: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
899
+ address: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
900
+ port: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
901
+ }, import("zod/v4/core").$strip>>;
902
+ remote: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
903
+ address: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
904
+ port: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
905
+ }, import("zod/v4/core").$strip>>;
906
+ path: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
907
+ metadata: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniRecord<import("zod/mini").ZodMiniString<string>, import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniString<string>, import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniBoolean<boolean>]>>>;
908
+ }, import("zod/v4/core").$strip>>;
909
+ }, import("zod/v4/core").$strip>>;
910
+ routes: import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
911
+ serviceId: import("zod/mini").ZodMiniString<string>;
912
+ nodeId: import("zod/mini").ZodMiniString<string>;
913
+ portId: import("zod/mini").ZodMiniString<string>;
914
+ match: import("zod/mini").ZodMiniEnum<{
915
+ exact: "exact";
916
+ prefix: "prefix";
917
+ }>;
918
+ }, import("zod/v4/core").$strip>>;
919
+ }, import("zod/v4/core").$strip>;
920
+ type TopologyPort = output<typeof zTopologyPort>;
921
+ type ParticipantDescriptor = output<typeof zParticipantDescriptor>;
922
+ type ParticipantDescriptorSource = output<typeof zParticipantDescriptorSource>;
923
+ type TopologyNode = output<typeof zTopologyNode>;
924
+ type TopologyLinkEndpoint = output<typeof zTopologyLinkEndpoint>;
925
+ type TopologyTransportEndpoint = output<typeof zTopologyTransportEndpoint>;
926
+ type TopologyTransportInfo = output<typeof zTopologyTransportInfo>;
927
+ type TopologyLink = output<typeof zTopologyLink>;
928
+ type RouteClaim = output<typeof zRouteClaim>;
929
+ type TopologyGraph = output<typeof zTopologyGraph>;
930
+ declare const topologyInterface: InterfaceDefinition<{
931
+ getGraph: RequestType<Record<string, never>, {
932
+ observerServiceId: string;
933
+ entryNodeId: string;
934
+ nodes: {
935
+ nodeId: string;
936
+ ports: {
937
+ portId: string;
938
+ label?: string | undefined;
939
+ }[];
940
+ kind?: "endpoint" | "hub" | undefined;
941
+ label?: string | undefined;
942
+ descriptors?: {
943
+ source: "self" | "attacher";
944
+ descriptor: {
945
+ type?: string | undefined;
946
+ label?: string | undefined;
947
+ processId?: number | undefined;
948
+ processType?: string | undefined;
949
+ nodeStatusServiceId?: string | undefined;
950
+ metadata?: Record<string, string | number | boolean> | undefined;
951
+ };
952
+ }[] | undefined;
953
+ }[];
954
+ links: {
955
+ from: {
956
+ nodeId: string;
957
+ portId: string;
958
+ };
959
+ to: {
960
+ nodeId: string;
961
+ portId: string;
962
+ };
963
+ label?: string | undefined;
964
+ peerState?: "identified" | "pending" | "unsupported" | "error" | undefined;
965
+ transport?: {
966
+ type: string;
967
+ local?: {
968
+ address?: string | undefined;
969
+ port?: number | undefined;
970
+ } | undefined;
971
+ remote?: {
972
+ address?: string | undefined;
973
+ port?: number | undefined;
974
+ } | undefined;
975
+ path?: string | undefined;
976
+ metadata?: Record<string, string | number | boolean> | undefined;
977
+ } | undefined;
978
+ }[];
979
+ routes: {
980
+ serviceId: string;
981
+ nodeId: string;
982
+ portId: string;
983
+ match: "exact" | "prefix";
984
+ }[];
985
+ }, void, Record<string, never>, any>;
986
+ watchGraph: RequestType<Record<string, never>, Record<string, never>, void, any, Record<string, never>>;
987
+ }>;
988
+ declare const zTrafficTransitEndpoint: import("zod/mini").ZodMiniObject<{
989
+ edgeId: import("zod/mini").ZodMiniString<string>;
990
+ portId: import("zod/mini").ZodMiniString<string>;
991
+ requestId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniString<string>]>>;
992
+ }, import("zod/v4/core").$strip>;
993
+ declare const zTrafficTransitEvent: import("zod/mini").ZodMiniObject<{
994
+ type: import("zod/mini").ZodMiniLiteral<"transit">;
995
+ timeMs: import("zod/mini").ZodMiniNumber<number>;
996
+ nodeId: import("zod/mini").ZodMiniString<string>;
997
+ in: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
998
+ edgeId: import("zod/mini").ZodMiniString<string>;
999
+ portId: import("zod/mini").ZodMiniString<string>;
1000
+ requestId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniString<string>]>>;
1001
+ }, import("zod/v4/core").$strip>>;
1002
+ out: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
1003
+ edgeId: import("zod/mini").ZodMiniString<string>;
1004
+ portId: import("zod/mini").ZodMiniString<string>;
1005
+ requestId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniString<string>]>>;
1006
+ }, import("zod/v4/core").$strip>>;
1007
+ disposition: import("zod/mini").ZodMiniEnum<{
1008
+ forwarded: "forwarded";
1009
+ consumed: "consumed";
1010
+ dropped: "dropped";
1011
+ unroutable: "unroutable";
1012
+ }>;
1013
+ kind: import("zod/mini").ZodMiniEnum<{
1014
+ request: "request";
1015
+ notification: "notification";
1016
+ response: "response";
1017
+ stream: "stream";
1018
+ }>;
1019
+ method: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
1020
+ params: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnknown>;
1021
+ result: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnknown>;
1022
+ error: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
1023
+ code: import("zod/mini").ZodMiniNumber<number>;
1024
+ message: import("zod/mini").ZodMiniString<string>;
1025
+ data: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnknown>;
1026
+ }, import("zod/v4/core").$strip>>;
1027
+ }, import("zod/v4/core").$strip>;
1028
+ declare const zTrafficOverflowEvent: import("zod/mini").ZodMiniObject<{
1029
+ type: import("zod/mini").ZodMiniLiteral<"overflow">;
1030
+ dropped: import("zod/mini").ZodMiniNumber<number>;
1031
+ }, import("zod/v4/core").$strip>;
1032
+ declare const zTrafficEvent: import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniObject<{
1033
+ type: import("zod/mini").ZodMiniLiteral<"transit">;
1034
+ timeMs: import("zod/mini").ZodMiniNumber<number>;
1035
+ nodeId: import("zod/mini").ZodMiniString<string>;
1036
+ in: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
1037
+ edgeId: import("zod/mini").ZodMiniString<string>;
1038
+ portId: import("zod/mini").ZodMiniString<string>;
1039
+ requestId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniString<string>]>>;
1040
+ }, import("zod/v4/core").$strip>>;
1041
+ out: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
1042
+ edgeId: import("zod/mini").ZodMiniString<string>;
1043
+ portId: import("zod/mini").ZodMiniString<string>;
1044
+ requestId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniString<string>]>>;
1045
+ }, import("zod/v4/core").$strip>>;
1046
+ disposition: import("zod/mini").ZodMiniEnum<{
1047
+ forwarded: "forwarded";
1048
+ consumed: "consumed";
1049
+ dropped: "dropped";
1050
+ unroutable: "unroutable";
1051
+ }>;
1052
+ kind: import("zod/mini").ZodMiniEnum<{
1053
+ request: "request";
1054
+ notification: "notification";
1055
+ response: "response";
1056
+ stream: "stream";
1057
+ }>;
1058
+ method: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
1059
+ params: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnknown>;
1060
+ result: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnknown>;
1061
+ error: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
1062
+ code: import("zod/mini").ZodMiniNumber<number>;
1063
+ message: import("zod/mini").ZodMiniString<string>;
1064
+ data: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnknown>;
1065
+ }, import("zod/v4/core").$strip>>;
1066
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
1067
+ type: import("zod/mini").ZodMiniLiteral<"overflow">;
1068
+ dropped: import("zod/mini").ZodMiniNumber<number>;
1069
+ }, import("zod/v4/core").$strip>]>;
1070
+ type TrafficTransitEndpoint = output<typeof zTrafficTransitEndpoint>;
1071
+ type TrafficTransitEvent = output<typeof zTrafficTransitEvent>;
1072
+ type TrafficOverflowEvent = output<typeof zTrafficOverflowEvent>;
1073
+ type TrafficEvent = output<typeof zTrafficEvent>;
1074
+ declare const zTrafficWatchResult: import("zod/mini").ZodMiniObject<{
1075
+ delivered: import("zod/mini").ZodMiniNumber<number>;
1076
+ dropped: import("zod/mini").ZodMiniNumber<number>;
1077
+ }, import("zod/v4/core").$strip>;
1078
+ type TrafficWatchResult = output<typeof zTrafficWatchResult>;
1079
+ /**
1080
+ * Observe raw message transits at the node hosting the addressed service.
1081
+ * Consumers may correlate adjacent transits by shared `(portId, requestId)`.
1082
+ */
1083
+ declare const trafficInterface: InterfaceDefinition<{
1084
+ watch: RequestType<{
1085
+ methodPrefix?: string | undefined;
1086
+ trafficIgnoreKey?: string | undefined;
1087
+ focusRequest?: {
1088
+ portId: string;
1089
+ requestId: string | number;
1090
+ } | undefined;
1091
+ }, {
1092
+ delivered: number;
1093
+ dropped: number;
1094
+ }, void, any, {
1095
+ type: "transit";
1096
+ timeMs: number;
1097
+ nodeId: string;
1098
+ disposition: "forwarded" | "consumed" | "dropped" | "unroutable";
1099
+ kind: "request" | "notification" | "response" | "stream";
1100
+ in?: {
1101
+ edgeId: string;
1102
+ portId: string;
1103
+ requestId?: string | number | undefined;
1104
+ } | undefined;
1105
+ out?: {
1106
+ edgeId: string;
1107
+ portId: string;
1108
+ requestId?: string | number | undefined;
1109
+ } | undefined;
1110
+ method?: string | undefined;
1111
+ params?: unknown;
1112
+ result?: unknown;
1113
+ error?: {
1114
+ code: number;
1115
+ message: string;
1116
+ data?: unknown;
1117
+ } | undefined;
1118
+ } | {
1119
+ type: "overflow";
1120
+ dropped: number;
1121
+ }>;
1122
+ watchWithPayloads: RequestType<{
1123
+ maxPayloadBytes: number;
1124
+ methodPrefix?: string | undefined;
1125
+ trafficIgnoreKey?: string | undefined;
1126
+ focusRequest?: {
1127
+ portId: string;
1128
+ requestId: string | number;
1129
+ } | undefined;
1130
+ }, {
1131
+ delivered: number;
1132
+ dropped: number;
1133
+ }, void, any, {
1134
+ type: "transit";
1135
+ timeMs: number;
1136
+ nodeId: string;
1137
+ disposition: "forwarded" | "consumed" | "dropped" | "unroutable";
1138
+ kind: "request" | "notification" | "response" | "stream";
1139
+ in?: {
1140
+ edgeId: string;
1141
+ portId: string;
1142
+ requestId?: string | number | undefined;
1143
+ } | undefined;
1144
+ out?: {
1145
+ edgeId: string;
1146
+ portId: string;
1147
+ requestId?: string | number | undefined;
1148
+ } | undefined;
1149
+ method?: string | undefined;
1150
+ params?: unknown;
1151
+ result?: unknown;
1152
+ error?: {
1153
+ code: number;
1154
+ message: string;
1155
+ data?: unknown;
1156
+ } | undefined;
1157
+ } | {
1158
+ type: "overflow";
1159
+ dropped: number;
1160
+ }>;
1161
+ }>;
1162
+ //#endregion
1163
+ //#region src/inspection/node.interfaces.d.ts
1164
+ declare const zNodeInfo: import("zod/mini").ZodMiniObject<{
1165
+ nodeId: import("zod/mini").ZodMiniString<string>;
1166
+ portId: import("zod/mini").ZodMiniString<string>;
1167
+ descriptors: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
1168
+ source: import("zod/mini").ZodMiniEnum<{
1169
+ self: "self";
1170
+ attacher: "attacher";
1171
+ }>;
1172
+ descriptor: import("zod/mini").ZodMiniObject<{
1173
+ type: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
1174
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
1175
+ processId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
1176
+ processType: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
1177
+ nodeStatusServiceId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
1178
+ metadata: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniRecord<import("zod/mini").ZodMiniString<string>, import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniString<string>, import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniBoolean<boolean>]>>>;
1179
+ }, import("zod/v4/core").$strip>;
1180
+ }, import("zod/v4/core").$strip>>>;
1181
+ }, import("zod/v4/core").$strip>;
1182
+ type NodeInfo = output<typeof zNodeInfo>;
1183
+ /**
1184
+ * Generates unique topology-correlation labels, not security identities.
1185
+ * Custom generators must avoid collisions across nodes and ports. Tests can
1186
+ * supply an independent deterministic sequence for each participant.
1187
+ */
1188
+ type TopologyIdGenerator = (kind: 'node' | 'port') => string;
1189
+ /**
1190
+ * Minimal root service for aligning the independently observed topologies at
1191
+ * both ends of a connection.
1192
+ */
1193
+ declare const nodeInterface: InterfaceDefinition<{
1194
+ getNodeId: RequestType<Record<string, never>, {
1195
+ nodeId: string;
1196
+ portId: string;
1197
+ descriptors?: {
1198
+ source: "self" | "attacher";
1199
+ descriptor: {
1200
+ type?: string | undefined;
1201
+ label?: string | undefined;
1202
+ processId?: number | undefined;
1203
+ processType?: string | undefined;
1204
+ nodeStatusServiceId?: string | undefined;
1205
+ metadata?: Record<string, string | number | boolean> | undefined;
1206
+ };
1207
+ }[] | undefined;
1208
+ }, any, never, never>;
1209
+ }>;
1210
+ //#endregion
1211
+ //#region src/connection/streaming.d.ts
1212
+ /**
1213
+ * Direction a {@link STREAM_METHOD} message travels, relative to the
1214
+ * request it is correlated with. Made explicit on the wire so that a
1215
+ * middlebox (the hub) can *author* a stream message — e.g. inject a
1216
+ * cancel when a caller disconnects — without an inbound message whose
1217
+ * arrival link it could infer the direction from.
1218
+ */
1219
+ declare const StreamDir: {
1220
+ /** callee → caller: progress, partial results. Routes like a response. */
1221
+ readonly toCaller: "toCaller";
1222
+ /** caller → callee: input, cancellation, keepalive ping. */
1223
+ readonly toCallee: "toCallee";
1224
+ };
1225
+ type StreamDir = (typeof StreamDir)[keyof typeof StreamDir];
1226
+ /**
1227
+ * Reserved control verbs. A control message carries no app `payload`; it
1228
+ * is interpreted by the runtime / hub itself, independently of the
1229
+ * originating method's stream schemas, so *any* request is cancellable
1230
+ * and keep-alive-able even when it declares no app stream.
1231
+ */
1232
+ declare const StreamControlType: {
1233
+ /**
1234
+ * Ask the callee to abort the in-flight request. Always {@link
1235
+ * StreamDir.toCallee}. The callee surfaces this as an `AbortSignal`
1236
+ * and is expected to settle the request (typically with a
1237
+ * `cancelled` error response).
1238
+ */
1239
+ readonly cancel: "cancel";
1240
+ /**
1241
+ * Keepalive / liveness probe. Resets the hub's per-request idle timer
1242
+ * so a long-running call is not reaped, and lets either side actively
1243
+ * probe the peer. Carries a `nonce` the peer echoes in its {@link
1244
+ * StreamControlType.pong}. May travel in either direction. Emitted
1245
+ * automatically (without awaiting a pong) by the channel for streaming
1246
+ * calls; see {@link STREAM_METHOD}.
1247
+ */
1248
+ readonly ping: "ping";
1249
+ /**
1250
+ * Reply to a {@link StreamControlType.ping}, echoing the ping's
1251
+ * `nonce` so the prober can correlate it. Travels opposite the ping.
1252
+ * Carries no app effect — purely a liveness acknowledgement.
1253
+ */
1254
+ readonly pong: "pong";
1255
+ };
1256
+ type StreamControlType = (typeof StreamControlType)[keyof typeof StreamControlType];
1257
+ /**
1258
+ * Well-known `control.reason` strings. The set is **open** — any string
1259
+ * is valid on the wire; these are the reasons linkrpc itself emits.
1260
+ */
1261
+ declare const StreamControlReason: {
1262
+ /**
1263
+ * The caller's transport dropped while the request was in flight; the
1264
+ * hub cancels the callee's now-orphaned work.
1265
+ */
1266
+ readonly clientDisconnected: "clientDisconnected";
1267
+ /**
1268
+ * The request exceeded the hub's idle timeout with no stream activity
1269
+ * (no ping, no stream message). See {@link STREAM_METHOD} docs.
1270
+ */
1271
+ readonly idleTimeout: "idleTimeout";
1272
+ };
1273
+ type StreamControlReason = (typeof StreamControlReason)[keyof typeof StreamControlReason];
1274
+ /**
1275
+ * Streaming sub-protocol. Long-running requests can emit additional
1276
+ * notifications correlated with the original call in either direction
1277
+ * (callee → caller progress, caller → callee input / cancellation /
1278
+ * keepalive).
1279
+ *
1280
+ * Wire form: a JSON-RPC notification whose method is
1281
+ * `${streamInterface.info.id}::send` and whose params match
1282
+ * `streamInterface.members.send.paramsSchema`. The hub routes purely on
1283
+ * `requestId` (following the originating request's established path, like
1284
+ * a response); the originating request's capability authorization covers
1285
+ * its full stream lifetime, so stream notifications carry no method /
1286
+ * interface namespace of their own. App `payload` contents are typed per
1287
+ * request via the originating method's
1288
+ * `RequestType.clientStreamSchema` / `serverStreamSchema`; reserved
1289
+ * `control` messages are schema-independent.
1290
+ *
1291
+ * Idle timeout: a request that never streams (no `control` ping, no
1292
+ * stream message) is subject to the hub's per-request idle timeout
1293
+ * (default 30 minutes) — at which point it is cancelled and its caller
1294
+ * gets a `requestTimeout` error. This bounds the hub's pending-request
1295
+ * table, which is also what protects it from a slow-loris / DDoS that
1296
+ * opens requests and never completes them. Streaming-enabled calls keep
1297
+ * themselves alive by emitting a periodic {@link StreamControlType.ping}.
1298
+ *
1299
+ * The interface is declarative: nobody calls
1300
+ * `LinkRpcConnection.register(streamInterface, ...)`. The channel and the
1301
+ * hub intercept `$stream::send` directly. The definition exists so
1302
+ * reflection / consent UIs can describe the wire shape and so all wire
1303
+ * constants derive from one source.
1304
+ */
1305
+ declare const streamInterface: InterfaceDefinition<{
1306
+ send: NotificationType<{
1307
+ requestId: string | number;
1308
+ dir: "toCaller" | "toCallee";
1309
+ control?: {
1310
+ type: "cancel" | "ping" | "pong";
1311
+ reason?: string | undefined;
1312
+ nonce?: string | undefined;
1313
+ } | undefined;
1314
+ payload?: unknown;
1315
+ }>;
1316
+ }>;
1317
+ /**
1318
+ * Full wire method name for stream notifications. Pulled from the
1319
+ * interface object so we have a single source of truth.
1320
+ */
1321
+ declare const STREAM_METHOD: `${string}::send`;
1322
+ /** Wire-level shape carried on `params` of {@link STREAM_METHOD}. */
1323
+ type StreamSendParams = output<typeof streamInterface.members.send.paramsSchema>;
1324
+ //#endregion
1325
+ //#region src/protocol/jcs.d.ts
1326
+ /**
1327
+ * RFC 8785 JSON Canonicalization Scheme (JCS).
1328
+ *
1329
+ * Used as the byte-deterministic encoding under every linkrpc signature
1330
+ * (RPC calls, capabilities, hub-signed previews). Both signer and verifier
1331
+ * canonicalize the same value object and obtain byte-identical UTF-8 bytes.
1332
+ *
1333
+ * Implementation inlined from the `canonicalize` npm package (Apache-2.0,
1334
+ * https://github.com/erdtman/canonicalize) so this module stays
1335
+ * zero-dependency for browser bundlers that don't resolve transitive
1336
+ * npm specifiers (e.g. the in-house app-bundler).
1337
+ */
1338
+ /** RFC 8785 canonical JSON string for `value`. */
1339
+ declare function jcsCanonicalize(value: unknown): string;
1340
+ /** UTF-8 bytes of the RFC 8785 canonical JSON for `value`. The thing actually signed / hashed. */
1341
+ declare function jcsCanonicalizeBytes(value: unknown): Uint8Array;
1342
+ //#endregion
1343
+ //#region src/crypto/cryptoProvider.d.ts
1344
+ /**
1345
+ * Identity primitives. linkrpc itself is identity-agnostic; this module
1346
+ * defines the shared types. No crypto code lives here — the crypto API is
1347
+ * `./crypto` (backed by the Web Crypto implementation in
1348
+ * `./ed25519CryptoProvider`).
1349
+ */
1350
+ /** Raw Ed25519 public key (32 bytes). */
1351
+ type PublicKey = Uint8Array;
1352
+ /** Raw Ed25519 private key (32 bytes — seed form). */
1353
+ type PrivateKey = Uint8Array;
1354
+ /** Raw Ed25519 signature (64 bytes). */
1355
+ type Signature = Uint8Array;
1356
+ /**
1357
+ * A **principal**: an identity's stable, opaque name. In Phase 1 every
1358
+ * principal is *perpetual* and self-describing — its genesis signing key is
1359
+ * embedded verbatim:
1360
+ *
1361
+ * principal = "id:" + keyId (e.g. "id:key:<b64url(pubKey)>")
1362
+ *
1363
+ * So the genesis check is pure string equality (`"id:" + keyId === principal`)
1364
+ * and no key-binding records are ever needed. Treat as opaque; construct via
1365
+ * {@link principalForPublicKey} and resolve a verifying key via
1366
+ * {@link resolveSigningKey}.
1367
+ */
1368
+ type PrincipalId = string;
1369
+ /**
1370
+ * A **keyId**: names the signing key that produced a signature. In Phase 1 the
1371
+ * only form is an *inline* key — the public key encoded verbatim:
1372
+ *
1373
+ * keyId = "key:" + b64url(pubKey)
1374
+ *
1375
+ * (Future forms, e.g. `"keydoc:" + b64url(sha256(jcs(doc)))`, are resolved
1376
+ * through bindings — see the design doc — but Phase 1 needs none.)
1377
+ */
1378
+ type KeyId = string;
1379
+ interface Keypair {
1380
+ readonly publicKey: PublicKey;
1381
+ readonly privateKey: PrivateKey;
1382
+ }
1383
+ /** Raw X25519 keypair. Both halves are 32 bytes. */
1384
+ interface X25519Keypair {
1385
+ readonly publicKey: Uint8Array;
1386
+ readonly privateKey: Uint8Array;
1387
+ }
1388
+ declare function bytesToBase64Url(bytes: Uint8Array): string;
1389
+ declare function base64UrlToBytes(s: string): Uint8Array;
1390
+ /** Role-tag prefix on a {@link KeyId}'s inline-key form. */
1391
+ declare const KEY_ID_PREFIX = "key:";
1392
+ /** Role-tag prefix that wraps a genesis {@link KeyId} into a {@link PrincipalId}. */
1393
+ declare const PRINCIPAL_PREFIX = "id:";
1394
+ /** The inline {@link KeyId} for a raw public key: `"key:" + b64url(pk)`. */
1395
+ declare function keyIdForPublicKey(pk: PublicKey): KeyId;
1396
+ /** The perpetual {@link PrincipalId} for a raw public key: `"id:key:" + b64url(pk)`. */
1397
+ declare function principalForPublicKey(pk: PublicKey): PrincipalId;
1398
+ /**
1399
+ * The genesis {@link KeyId} embedded in a perpetual {@link PrincipalId}
1400
+ * (`"id:" + keyId`). Throws if `principal` is not a well-formed `id:` name.
1401
+ */
1402
+ declare function keyIdForPrincipal(principal: PrincipalId): KeyId;
1403
+ /**
1404
+ * The raw public key carried inline by a `"key:"` {@link KeyId}. Throws on a
1405
+ * missing prefix or malformed base64url.
1406
+ */
1407
+ declare function publicKeyForKeyId(keyId: KeyId): PublicKey;
1408
+ /** Arguments to {@link resolveSigningKey}. */
1409
+ interface ResolveSigningKeyArgs {
1410
+ /** The identity the signature claims to be from. */
1411
+ readonly principal: PrincipalId;
1412
+ /** Which key (per `$hubrpcSignature[domain].keyId`) is claimed to have signed. */
1413
+ readonly keyId: KeyId;
1414
+ /** Presented key-binding records. Unused in Phase 1 (perpetual ids need none). */
1415
+ readonly bindings?: Record<KeyId, unknown>;
1416
+ /** Time the signature was made (e.g. `signedAtMs`). Unused in Phase 1. */
1417
+ readonly timeMs?: number;
1418
+ }
1419
+ /**
1420
+ * Resolve the verifying public key for `(principal, keyId)`, or `undefined`
1421
+ * to **reject** (fail closed). This is the single seam every verifier goes
1422
+ * through, replacing the old "the id *is* the key" decode.
1423
+ *
1424
+ * Phase 1 supports only inline genesis keys: the `keyId` must be a `"key:"`
1425
+ * form and the principal must be exactly `"id:" + keyId` (genesis
1426
+ * self-certification by string equality). `keydoc:`/rotation forms resolve
1427
+ * through `bindings`/`timeMs` later and are intentionally not handled here.
1428
+ */
1429
+ declare function resolveSigningKey(args: ResolveSigningKeyArgs): {
1430
+ publicKey: PublicKey;
1431
+ } | undefined;
1432
+ //#endregion
1433
+ //#region src/protocol/signedObject.d.ts
1434
+ /** An open signature domain. Each gets a distinct {@link signingDomainValue}. */
1435
+ type SignDomain = string;
1436
+ /** Reserved wire-key: the signature map `{ [domain]: SignatureEnvelope }`. */
1437
+ declare const HUBRPC_SIGNATURE_KEY = "$hubrpcSignature";
1438
+ /** Reserved wire-key: extrinsic unsigned attachments (e.g. the capability bag). */
1439
+ declare const HUBRPC_UNSIGNED_KEY = "$hubrpcUnsigned";
1440
+ /** Reserved wire-key: signed call meta, present only on calls (dodges the JSON-RPC param namespace). */
1441
+ declare const HUBRPC_META_KEY = "$hubrpc";
1442
+ /** @deprecated Use {@link HUBRPC_SIGNATURE_KEY}. */
1443
+ declare const LINKRPC_SIGNATURE_KEY = "$hubrpcSignature";
1444
+ /** @deprecated Use {@link HUBRPC_UNSIGNED_KEY}. */
1445
+ declare const LINKRPC_UNSIGNED_KEY = "$hubrpcUnsigned";
1446
+ /** @deprecated Use {@link HUBRPC_META_KEY}. */
1447
+ declare const LINKRPC_META_KEY = "$hubrpc";
1448
+ /**
1449
+ * One domain's signature on the wire: which key signed ({@link KeyId}, an
1450
+ * **unsigned** routing hint) plus the raw `base64url(sig)`. Lying about
1451
+ * `keyId` only makes verification fail (the resolver rejects or the key
1452
+ * mismatches), so it carries no integrity claim and is excluded from the
1453
+ * signed bytes along with the rest of `$hubrpcSignature`.
1454
+ */
1455
+ interface SignatureEnvelope {
1456
+ /** The key the signer used (`"key:..."`). Resolved against the principal. */
1457
+ readonly keyId: KeyId;
1458
+ /** `base64url` of the raw signature over {@link signingInput}. */
1459
+ readonly sig: string;
1460
+ }
1461
+ /** Per-domain signature map carried under {@link HUBRPC_SIGNATURE_KEY}. */
1462
+ type Signatures = { readonly [D in SignDomain]?: SignatureEnvelope; };
1463
+ /** Documentary brand for `base64url(sha256(signingInput(domain, T)))`. */
1464
+ type Base64Sha256<T = unknown> = string & {
1465
+ readonly __sha256Of?: T;
1466
+ };
1467
+ /**
1468
+ * The domain-separation key. It includes the frozen signature-suite version
1469
+ * and becomes the sole key of the object passed to JCS.
1470
+ */
1471
+ declare function signingDomainValue(domain: SignDomain): string;
1472
+ /**
1473
+ * THE bytes a signature commits to (and a content hash hashes) for `obj` in
1474
+ * `domain`: `jcs({ [domainValue(domain)]: obj minus the two reserved keys })`.
1475
+ */
1476
+ declare function signingInput(domain: SignDomain, obj: object): Uint8Array;
1477
+ /**
1478
+ * Content identity of a signed object: `base64url(sha256(signingInput(...)))`.
1479
+ * The single operation behind both a capability's `callBind.payloadHash`
1480
+ * (domain `"call"`) and a child capability's `parentHash` (domain
1481
+ * `"capability"`).
1482
+ */
1483
+ declare function signedHash<T extends object>(domain: SignDomain, obj: T): Base64Sha256<T>;
1484
+ /** Read the signature envelope for `domain` off an object's `$hubrpcSignature` map. */
1485
+ declare function readSignature(obj: object, domain: SignDomain): SignatureEnvelope | undefined;
1486
+ /** The {@link KeyId} the signer used for `domain` (the unsigned routing hint), if any. */
1487
+ declare function getKeyId(obj: object, domain: SignDomain): KeyId | undefined;
1488
+ /**
1489
+ * Return a copy of `obj` with `$hubrpcSignature[domain]` set to `envelope`,
1490
+ * preserving any sibling-domain signatures already present.
1491
+ */
1492
+ declare function withSignature<T extends object>(obj: T, domain: SignDomain, envelope: SignatureEnvelope): T & {
1493
+ $hubrpcSignature: Record<string, SignatureEnvelope>;
1494
+ };
1495
+ //#endregion
1496
+ //#region src/protocol/capability.d.ts
1497
+ /**
1498
+ * A single axis matcher. Empty prefix matches anything. Non-empty prefix `p`
1499
+ * matches `value` iff:
1500
+ * - `value === p`, OR
1501
+ * - `value` starts with `p + delimiter` (delimiter depends on the axis).
1502
+ *
1503
+ * For axes without a delimiter (`member`), prefix degrades to `startsWith`.
1504
+ */
1505
+ type Pattern = {
1506
+ exact: string;
1507
+ } | {
1508
+ prefix: string;
1509
+ };
1510
+ /**
1511
+ * Per-field matcher used by {@link Permission.params}. The set of declared
1512
+ * keys is a strict allowlist — a call whose params carry an undeclared key
1513
+ * is rejected, so the only way to permit a free value is to say
1514
+ * `{ any: true }` explicitly. Values are compared via canonical-JSON
1515
+ * equality, so anything JSON-serializable is acceptable.
1516
+ *
1517
+ * - `exact` — canonical-JSON equality against a single value.
1518
+ * - `enum` — canonical-JSON equality against any value in the list.
1519
+ * - `prefix` — value MUST be a string and `startsWith(prefix)`. Used to
1520
+ * pin e.g. a URL to a base-path subtree.
1521
+ * - `subsetOf` — value MUST be a `string[]` whose every element is in this
1522
+ * set. Order-independent; the empty array is a valid subset.
1523
+ * Used to bound a requested scope set.
1524
+ * - `any` — matches anything (the explicit wildcard).
1525
+ */
1526
+ type ParamMatcher = {
1527
+ exact: unknown;
1528
+ } | {
1529
+ enum: unknown[];
1530
+ } | {
1531
+ prefix: string;
1532
+ } | {
1533
+ subsetOf: string[];
1534
+ } | {
1535
+ any: true;
1536
+ };
1537
+ /**
1538
+ * The exact, point-precision narrowing of a {@link Permission}: it admits
1539
+ * **one** signed RPC call — the one whose call content-hash
1540
+ * ({@link import("./signedObject").signedHash}`("call", signedCall)`, i.e.
1541
+ * `base64url(sha256(jcs({ "hubrpc-sig/v1/call": userParams + $hubrpc })))`)
1542
+ * equals `payloadHash`. No field-by-field comparison; pure hash equality.
1543
+ * This is the *same bytes the call signature commits to*, so the host can
1544
+ * pre-compute it at consent time exactly as the consumer will sign.
1545
+ *
1546
+ * Because it binds the entire signed payload, `callBind` pins **every**
1547
+ * signed field at once — method, user params, `nonce`, `signedAtMs`,
1548
+ * `signer`, and `interfaceHash?`. Since the bound bytes include the
1549
+ * per-request `nonce`, a `callBind` grant is intrinsically single-use:
1550
+ * the request-nonce ledger rejects any replay of the one call it names.
1551
+ *
1552
+ * Used for "Allow once" flows where the user approved a single concrete call.
1553
+ */
1554
+ interface CallBind {
1555
+ /** Hash algorithm. Currently always "sha256". */
1556
+ alg: "sha256";
1557
+ /**
1558
+ * `signedHash("call", signedCall)` — the SHA-256 of exactly the bytes the
1559
+ * RPC signature commits to, for the one call this permission is bound to.
1560
+ */
1561
+ payloadHash: Base64Sha256;
1562
+ }
1563
+ /**
1564
+ * The address of a class of calls, expressed as patterns. A
1565
+ * {@link CallTarget} is admitted iff every axis pattern admits it.
1566
+ */
1567
+ interface TargetPattern {
1568
+ /** Delimiter `/`. `"github"` matches `"github/repos"` but not `"githubclone"`. */
1569
+ serviceId: Pattern;
1570
+ /** Delimiter `.`. `"linkrpc"` matches `"hubrpc.directory"` but not `"linkrpcx.foo"`. */
1571
+ interfaceId: Pattern;
1572
+ /**
1573
+ * Optional schema-version pin. When set, the call's asserted
1574
+ * `interfaceHash` (carried in `$hubrpc.interfaceHash`) must equal this
1575
+ * string. Omit to accept any version.
1576
+ */
1577
+ interfaceHash?: string;
1578
+ /**
1579
+ * Any-of: the call's member must match at least one pattern. Empty
1580
+ * list matches nothing. `[{ prefix: "" }]` is the universal wildcard.
1581
+ */
1582
+ members: Pattern[];
1583
+ }
1584
+ /**
1585
+ * One grant clause of a {@link Capability}. Denotes a set of calls the
1586
+ * holder may make, described at up to three zoom levels (coarse → exact):
1587
+ *
1588
+ * - `target` — *which endpoint* (always present);
1589
+ * - `params` — *which argument values* (optional value allowlist);
1590
+ * - `callBind` — *which exact call* (optional collapse to a single call).
1591
+ *
1592
+ * The {@link canInvoke}/{@link canDelegate} flags say what the holder may
1593
+ * *do* with that set: invoke calls in it, and/or delegate (re-issue a
1594
+ * narrowed grant) onward. Both default to `false` (fail closed) — a
1595
+ * permission that grants neither admits nothing.
1596
+ */
1597
+ interface Permission {
1598
+ /** Which endpoints this clause talks about. */
1599
+ target: TargetPattern;
1600
+ /** The holder may invoke calls in the set. Default `false`. */
1601
+ canInvoke?: boolean;
1602
+ /** The holder may delegate (re-issue a narrowed grant) of the set. Default `false`. */
1603
+ canDelegate?: boolean;
1604
+ /**
1605
+ * Optional value-level narrowing. Strict allowlist by top-level param
1606
+ * key: the call's param key-set must equal the declared set; each value
1607
+ * must satisfy its matcher. Omit to accept any params.
1608
+ */
1609
+ params?: Record<string, ParamMatcher>;
1610
+ /** Optional collapse to a single exact signed call. See {@link CallBind}. */
1611
+ callBind?: CallBind;
1612
+ }
1613
+ interface Capability {
1614
+ /** Issuer principal (signer of this cap). */
1615
+ issuer: PrincipalId;
1616
+ /** Audience principal (holder allowed to wield it). */
1617
+ audience: PrincipalId;
1618
+ /** What the holder may do. A call is permitted by the cap iff it is permitted by **any** permission. */
1619
+ permissions: Permission[];
1620
+ /** Unix milliseconds. Absent = never expires. */
1621
+ expiresAtMs?: number;
1622
+ /**
1623
+ * The single parent this cap delegates from, referenced by its content
1624
+ * hash (`signedHash("capability", parent)`). Linearized — at most one
1625
+ * parent. The parent itself travels out-of-band in the call's
1626
+ * `$hubrpcUnsigned.capabilities` bag and is resolved by this hash.
1627
+ * Effective authority is the intersection over the chain: a call must be
1628
+ * permitted by every link. Absent = this cap is a root.
1629
+ */
1630
+ parentHash?: Base64Sha256<Capability>;
1631
+ /** Per-cap distinguisher (base64url). Identifies the capability for audit/logging. */
1632
+ nonce: string;
1633
+ }
1634
+ /**
1635
+ * A capability with its issuer's signature attached under
1636
+ * `$hubrpcSignature.capability`. It IS a {@link Capability} (the fields are
1637
+ * top-level) plus the signature map — no separate wrapper object. The
1638
+ * signature commits to `signingInput("capability", cap)`, i.e. the cap with
1639
+ * `$hubrpcSignature`/`$hubrpcUnsigned` stripped.
1640
+ */
1641
+ type SignedCapability = Capability & {
1642
+ readonly [HUBRPC_SIGNATURE_KEY]: Signatures;
1643
+ };
1644
+ /**
1645
+ * Structural wire-shape check for an untrusted signed capability. This does
1646
+ * not establish authenticity; callers must still verify its signature and
1647
+ * delegation chain.
1648
+ */
1649
+ declare function hasSignedCapabilityShape(value: unknown): value is SignedCapability;
1650
+ /**
1651
+ * The address of a concrete call — *which endpoint*, with no arguments.
1652
+ * This is what {@link TargetPattern} matches against. The full concrete
1653
+ * call (with params/nonce/signer/bytes) is `Call` in `identity/capability`.
1654
+ */
1655
+ interface CallTarget {
1656
+ serviceId: string;
1657
+ interfaceId: string;
1658
+ member: string;
1659
+ /**
1660
+ * Schema-version assertion the caller stamps from its compile-time
1661
+ * knowledge of the interface (typed clients use `iface.schemaHash`).
1662
+ * Compared against `TargetPattern.interfaceHash` by the matcher. Absent
1663
+ * means the caller didn't pin a version — the matcher then requires
1664
+ * `target.interfaceHash` to also be absent.
1665
+ */
1666
+ interfaceHash?: string;
1667
+ }
1668
+ /**
1669
+ * Addressing match for a single permission: do its
1670
+ * `serviceId`/`interfaceId`/`interfaceHash`/`members` patterns admit
1671
+ * `target`?
1672
+ */
1673
+ declare function permissionMatchesTarget(target: CallTarget, perm: Permission): boolean;
1674
+ /**
1675
+ * Strict allowlist match for {@link Permission.params}. The set of
1676
+ * top-level keys in the call MUST equal the declared set; values must
1677
+ * satisfy their matchers. Nested objects/arrays are compared as opaque
1678
+ * JSON values via canonical-JSON equality. Pure (no crypto).
1679
+ */
1680
+ declare function matchParams(declared: Record<string, ParamMatcher>, actualParams: unknown): {
1681
+ ok: true;
1682
+ } | {
1683
+ ok: false;
1684
+ reason: string;
1685
+ };
1686
+ /** What a holder may do with a permission's call-set. */
1687
+ type Ability = "invoke" | "delegate";
1688
+ /**
1689
+ * A concrete, authenticated RPC call — the thing {@link permits} judges.
1690
+ * It is the call's {@link CallTarget} (which endpoint) plus the arguments
1691
+ * and the authenticated request metadata. Built by `verifyCall` from a
1692
+ * signed wire envelope.
1693
+ */
1694
+ interface Call {
1695
+ /** Which endpoint is being called. */
1696
+ target: CallTarget;
1697
+ /** User params with identity envelopes stripped. */
1698
+ params: unknown;
1699
+ /** Per-request replay nonce (the unit the gate dedups on). */
1700
+ nonce: string;
1701
+ /** Unix milliseconds the call was signed. */
1702
+ signedAtMs: number;
1703
+ /** The authenticated signer — must equal the leaf capability's audience. */
1704
+ signer: PrincipalId;
1705
+ /** The call's content hash (`signedHash("call", signedCall)`) — what `callBind` compares against. */
1706
+ callHash: Base64Sha256;
1707
+ }
1708
+ type Verdict = {
1709
+ ok: true;
1710
+ } | {
1711
+ ok: false;
1712
+ reason: string;
1713
+ };
1714
+ /**
1715
+ * Does `permission` admit `call` for the given `ability`? Checks, in
1716
+ * order: the ability flag (`canInvoke`/`canDelegate`, both default
1717
+ * `false`), the target address, the optional `params` allowlist, and the
1718
+ * optional `callBind` hash-binding. Pure.
1719
+ */
1720
+ declare function permissionPermits(call: Call, permission: Permission, ability: Ability): Verdict;
1721
+ /**
1722
+ * Does `cap` admit `call` for the given `ability`? True iff **any** of its
1723
+ * permissions does (the union over permissions). This is one *link's*
1724
+ * judgment; chain intersection is enforced by {@link verifyChain}.
1725
+ */
1726
+ declare function capabilityPermits(call: Call, cap: Capability, ability: Ability): Verdict;
1727
+ //#endregion
1728
+ //#region src/protocol/methodName.d.ts
1729
+ /**
1730
+ * Parsed JSON-RPC method string. The linkrpc dialect uses `::` to
1731
+ * separate up to three segments:
1732
+ *
1733
+ * - `"member"` — bare (preset-bound dispatch)
1734
+ * - `"interfaceId::member"` — interface form (root service)
1735
+ * - `"::interfaceId::member"` — explicit root form
1736
+ * - `"serviceId::interfaceId::member"` — fully-qualified form
1737
+ *
1738
+ * The hub does not accept the `bare` form (it has no interface context
1739
+ * to route on). Connection-level dispatch accepts all three.
1740
+ */
1741
+ type ParsedMethodName = {
1742
+ kind: "bare";
1743
+ member: string;
1744
+ } | {
1745
+ kind: "interface";
1746
+ interfaceId: string;
1747
+ member: string;
1748
+ } | {
1749
+ kind: "full";
1750
+ serviceId: string;
1751
+ interfaceId: string;
1752
+ member: string;
1753
+ };
1754
+ /**
1755
+ * Parse a JSON-RPC method string. Returns `undefined` if any segment is
1756
+ * empty or the segment count is out of range.
1757
+ */
1758
+ declare function parseMethodName(method: string): ParsedMethodName | undefined;
1759
+ /**
1760
+ * Convert a parsed method string to a {@link CallTarget} for capability
1761
+ * matching. Interface-form calls are addressed to the root service —
1762
+ * represented as an empty `serviceId`. Throws on `bare` form (no
1763
+ * interface context) and on malformed input.
1764
+ */
1765
+ declare function methodNameToTarget(method: string): CallTarget;
1766
+ //#endregion
1767
+ //#region src/protocol/linkRpcEnvelope.d.ts
1768
+ /**
1769
+ * Signed call meta. Lives under `params.$hubrpc` so it can't collide with
1770
+ * the user's top-level param keys. Present on signed AND unsigned calls
1771
+ * (the latter omit {@link CallMeta.principal} and carry no `$hubrpcSignature`).
1772
+ *
1773
+ * Included verbatim in the bytes a call signature commits to — the
1774
+ * signature covers `signingInput("call", { ...userParams, $hubrpc })`.
1775
+ */
1776
+ interface CallMeta {
1777
+ /** Fully-qualified wire method. The verifier asserts it equals the JSON-RPC `method`. */
1778
+ readonly method: string;
1779
+ /** Replay-protection nonce (base64url). The gate dedups on this. */
1780
+ readonly nonce: string;
1781
+ /** Unix milliseconds. Skew window enforced by the verifier. */
1782
+ readonly signedAtMs: number;
1783
+ /** Identity wielding the call. Present iff signed; equals the audience of every presented cap. */
1784
+ readonly principal?: PrincipalId;
1785
+ /** Optional schema hash assertion. Matched against `TargetPattern.interfaceHash`. */
1786
+ readonly interfaceHash?: string;
1787
+ }
1788
+ /**
1789
+ * Extrinsic, unsigned attachments carried under `params.$hubrpcUnsigned`.
1790
+ * Not covered by the call signature (they aren't authored by the signer).
1791
+ */
1792
+ interface LinkRpcUnsigned {
1793
+ /** Caller's presented capability bag. Parents are resolved out of this by hash. */
1794
+ readonly capabilities?: readonly SignedCapability[];
1795
+ }
1796
+ /** Reserved wire-key meta carried on a linkrpc call's params object. */
1797
+ interface LinkRpcWireMeta {
1798
+ readonly [HUBRPC_META_KEY]?: CallMeta;
1799
+ readonly [HUBRPC_SIGNATURE_KEY]?: Signatures;
1800
+ readonly [HUBRPC_UNSIGNED_KEY]?: LinkRpcUnsigned;
1801
+ }
1802
+ /**
1803
+ * Wire shape of `params` on a linkrpc JSON-RPC call.
1804
+ *
1805
+ * The user's params object (if any) is spread as-is, with the
1806
+ * {@link LinkRpcWireMeta} keys attached on top. `TUserParams` carries the
1807
+ * user-visible param shape; defaults to an open object. User params MUST be
1808
+ * a plain object — enforced at signing/verification via
1809
+ * {@link requireObjectParams}.
1810
+ */
1811
+ type LinkRpcWireParams<TUserParams extends {
1812
+ [key: string]: JsonValue | undefined;
1813
+ } = {
1814
+ [key: string]: JsonValue | undefined;
1815
+ }> = TUserParams & LinkRpcWireMeta;
1816
+ /** JSON-RPC request whose `params` carry the linkrpc wire meta. */
1817
+ type LinkRpcJsonRpcRequest<TUserParams extends {
1818
+ [key: string]: JsonValue | undefined;
1819
+ } = {
1820
+ [key: string]: JsonValue | undefined;
1821
+ }> = JsonRpcRequest<LinkRpcWireParams<TUserParams>>;
1822
+ /** JSON-RPC notification whose `params` carry the linkrpc wire meta. */
1823
+ type LinkRpcJsonRpcNotification<TUserParams extends {
1824
+ [key: string]: JsonValue | undefined;
1825
+ } = {
1826
+ [key: string]: JsonValue | undefined;
1827
+ }> = JsonRpcNotification<LinkRpcWireParams<TUserParams>>;
1828
+ /** Either of the two linkrpc-bearing JSON-RPC message shapes. */
1829
+ type LinkRpcJsonRpcMessage<TUserParams extends {
1830
+ [key: string]: JsonValue | undefined;
1831
+ } = {
1832
+ [key: string]: JsonValue | undefined;
1833
+ }> = LinkRpcJsonRpcRequest<TUserParams> | LinkRpcJsonRpcNotification<TUserParams>;
1834
+ /**
1835
+ * The linkrpc signing/cap system accepts only plain-object user params (or
1836
+ * none). Reject arrays/primitives at the boundary so "strip `$hubrpc*`, the
1837
+ * rest is the signed user params" stays unambiguous.
1838
+ */
1839
+ declare function requireObjectParams(userParams: JsonValue | undefined): Record<string, JsonValue | undefined>;
1840
+ /**
1841
+ * Return the application-authored portion of a LinkRPC params value.
1842
+ *
1843
+ * Routing and gate layers must continue forwarding the original wire params so
1844
+ * every chained hub can independently verify the envelope. Terminal dispatch
1845
+ * may use this derived value for application-schema validation without mutating
1846
+ * or replacing the wire message.
1847
+ */
1848
+ declare function stripLinkRpcWireMeta(wireParams: unknown): JsonValue | undefined;
1849
+ //#endregion
1850
+ //#region src/disposable.d.ts
1851
+ /** Minimal disposable handle; calling `dispose` releases the resource. */
1852
+ interface IDisposable {
1853
+ dispose(): void;
1854
+ }
1855
+ //#endregion
1856
+ //#region src/transport/messageTransport.d.ts
1857
+ interface IMessageTransport<TIncoming = JsonRpcMessage, TOutgoing = JsonRpcMessage> {
1858
+ send(message: TOutgoing): void | Promise<void>;
1859
+ /**
1860
+ * Sets the listener for incoming messages. Setting `undefined` detaches.
1861
+ * The transport buffers messages received before a listener is attached
1862
+ * and delivers them the next tick when one is set.
1863
+ * Forgetting to set a listener will cause the queue to leak.
1864
+ */
1865
+ setListener(listener: ((message: TIncoming) => void) | undefined): void;
1866
+ dispose(): void;
1867
+ }
1868
+ type MessageWithContext<TCtx> = JsonRpcMessage & {
1869
+ context: TCtx;
1870
+ };
1871
+ type MessageTransportWithContext<TCtx> = IMessageTransport<JsonRpcMessage, MessageWithContext<TCtx>>;
1872
+ type MessageTransportDirection = 'send' | 'receive';
1873
+ type MessageTransportTrace = (direction: MessageTransportDirection, message: JsonRpcMessage) => void;
1874
+ /**
1875
+ * Observe every message crossing a transport without changing its buffering or
1876
+ * lifecycle behavior.
1877
+ */
1878
+ declare function traceMessageTransport(transport: IMessageTransport, trace: MessageTransportTrace): IMessageTransport;
1879
+ /**
1880
+ * Pipe two transports together: every message one receives is forwarded to
1881
+ * the other's `send`. Returns a disposable that detaches both listeners.
1882
+ *
1883
+ * Neither transport is disposed — the caller owns their lifecycle. This is
1884
+ * the building block for relays (e.g. bridging a `WindowMessageTransport`
1885
+ * for an iframe to a multiplexer channel).
1886
+ */
1887
+ declare function connectTransports<T extends JsonRpcMessage>(a: IMessageTransport<T>, b: IMessageTransport<T>): IDisposable;
1888
+ /**
1889
+ * Two in-memory transports wired back-to-back. Useful for tests and for
1890
+ * same-process bridges.
1891
+ *
1892
+ * Generic in the per-direction payload type so asymmetric pairs (e.g. one
1893
+ * side sends plain `JsonRpcMessage`, the other side sends
1894
+ * `JsonRpcMessage & { context: Participant }`) are expressible at the type
1895
+ * level. At runtime both halves just hand objects through by reference.
1896
+ */
1897
+ declare class TransportPair<TFromA = JsonRpcMessage, TFromB = JsonRpcMessage> {
1898
+ readonly a: IMessageTransport<TFromB, TFromA>;
1899
+ readonly b: IMessageTransport<TFromA, TFromB>;
1900
+ constructor();
1901
+ }
1902
+ //#endregion
1903
+ //#region src/transport/multiplexedTransport.d.ts
1904
+ interface MuxEnvelope {
1905
+ readonly $mux: "v1";
1906
+ readonly ch: string;
1907
+ readonly m: JsonRpcMessage;
1908
+ }
1909
+ declare class MultiplexedTransport<TChannels extends Record<string, string>> implements IDisposable {
1910
+ static create<TChannels extends Record<string, string>>(base: IMessageTransport<MuxEnvelope, MuxEnvelope>, channels: TChannels): MultiplexedTransport<TChannels>;
1911
+ /** Logical transports keyed by the friendly channel names. */
1912
+ readonly transports: { readonly [K in keyof TChannels]: IMessageTransport; };
1913
+ private readonly _base;
1914
+ private readonly _byId;
1915
+ private readonly _usedIds;
1916
+ private _disposed;
1917
+ constructor(base: IMessageTransport<MuxEnvelope, MuxEnvelope>, channels: TChannels);
1918
+ /**
1919
+ * Add a logical channel after the multiplexer has started.
1920
+ *
1921
+ * Channel ids are permanently retired when disposed. This prevents a late
1922
+ * envelope for an old iframe from being delivered to a replacement iframe.
1923
+ */
1924
+ addChannel(id: string): IMessageTransport;
1925
+ dispose(): void;
1926
+ private _createChannel;
1927
+ }
1928
+ //#endregion
1929
+ //#region src/connection/channel.d.ts
1930
+ declare class Channel<TInCtx = undefined, TOutCtx = undefined> {
1931
+ readonly sender: IRequestSender<TOutCtx>;
1932
+ private readonly _setHandler;
1933
+ private readonly _setWireObserver?;
1934
+ constructor(sender: IRequestSender<TOutCtx>, _setHandler: (h: IRequestHandler<TInCtx> | undefined) => void, _setWireObserver?: ((observer: WireMessageObserver | undefined) => void) | undefined);
1935
+ /** Bind the inbound request/notification handler. May be called before or after construction of {@link LinkRpcConnection}. */
1936
+ setRequestHandler(handler: IRequestHandler<TInCtx> | undefined): void;
1937
+ /**
1938
+ * Install the endpoint inspection observer at the JSON-RPC wire boundary.
1939
+ * Intended for {@link LinkRpcConnection}; ordinary consumers should use the
1940
+ * public `hubrpc.traffic` service instead.
1941
+ */
1942
+ setWireMessageObserver(observer: WireMessageObserver | undefined): void;
1943
+ /**
1944
+ * Compose this channel with a sender-side decorator (typically the
1945
+ * signing layer). The decorator wraps {@link sender} only; the
1946
+ * {@link setRequestHandler} binding is shared with the original channel
1947
+ * so the receive side is bound exactly once regardless of decoration depth.
1948
+ */
1949
+ withSender<TNewOutCtx>(decorate: (raw: IRequestSender<TOutCtx>) => IRequestSender<TNewOutCtx>): Channel<TInCtx, TNewOutCtx>;
1950
+ }
1951
+ type WireMessageDirection = 'inbound' | 'outbound';
1952
+ type WireMessageObserver = (direction: WireMessageDirection, message: JsonRpcMessage) => void;
1953
+ interface IRequestHandler<TInCtx = undefined> {
1954
+ handleRequest(call: IncomingCall<TInCtx>): Promise<Result>;
1955
+ handleNotification(call: IncomingCall<TInCtx>): void;
1956
+ }
1957
+ /**
1958
+ * Inbound call observed by an {@link IRequestHandler}. `TInCtx` is the
1959
+ * per-call out-of-band context the transport attached on the receiving
1960
+ * side (e.g. the hub stamps `Participant` on overlay-bound messages).
1961
+ * For wire transports it's `undefined`.
1962
+ */
1963
+ interface IncomingCall<TInCtx = undefined> {
1964
+ method: string;
1965
+ params: JsonValue | undefined;
1966
+ /** Out-of-band context attached by the transport, if any. */
1967
+ context: TInCtx;
1968
+ /**
1969
+ * Per-call streaming handle. Both directions live on this object,
1970
+ * scoped to the request's lifetime. The inbound listener is auto-
1971
+ * detached when the handler's response settles. For notifications
1972
+ * (no request id) the handle is a no-op stub.
1973
+ */
1974
+ stream: IncomingStream;
1975
+ /**
1976
+ * Aborts when the caller cancels this in-flight request (a
1977
+ * `toCallee` `cancel` control), or when the hub cancels it on the
1978
+ * caller's behalf (caller disconnect / idle timeout). The handler
1979
+ * should observe this and settle promptly — typically by throwing,
1980
+ * which surfaces as a `cancelled` error response. For notifications
1981
+ * this never aborts.
1982
+ */
1983
+ signal: AbortSignal;
1984
+ }
1985
+ /**
1986
+ * Per-call streaming handle attached to {@link IncomingCall.stream}.
1987
+ * Scoped to a single in-flight request; the channel automatically
1988
+ * detaches the inbound listener when the handler's response settles.
1989
+ *
1990
+ * For notifications (which have no request id), `requestId` is
1991
+ * `undefined`, `send` is a no-op, and `onMessage` is a no-op.
1992
+ */
1993
+ interface IncomingStream {
1994
+ /** Emit a server→client stream notification correlated with this call. */
1995
+ send(payload: JsonValue): Promise<void>;
1996
+ /**
1997
+ * Register a listener for client→server stream messages correlated
1998
+ * with this call. Pass `undefined` to detach. Replaces any prior
1999
+ * listener. The channel detaches the listener automatically when
2000
+ * the handler's response settles.
2001
+ */
2002
+ onMessage(listener: ((payload: JsonValue) => void) | undefined): void;
2003
+ /**
2004
+ * Liveness probe toward the caller: emit a `toCaller` ping and
2005
+ * resolve once the caller's `pong` (matching nonce) returns. Rejects
2006
+ * if the request settles first. Independent of the channel's
2007
+ * automatic keepalive ping.
2008
+ */
2009
+ ping(): Promise<void>;
2010
+ }
2011
+ type Result = {
2012
+ result: JsonValue;
2013
+ } | {
2014
+ error: {
2015
+ code: number;
2016
+ message: string;
2017
+ data?: JsonValue;
2018
+ };
2019
+ };
2020
+ /**
2021
+ * What callers use to send. The {@link Channel} factory binds an
2022
+ * {@link IRequestHandler} at construction (immutable for the channel's
2023
+ * lifetime) and hands the caller back an `IRequestSender`.
2024
+ *
2025
+ * `TOutCtx` is the per-call context bag this sender understands. For
2026
+ * the base {@link JsonRpcChannel} it's `undefined` (the channel
2027
+ * doesn't read any overrides). Decorators like `SigningSender`
2028
+ * parametrise it on their own ctx shape.
2029
+ */
2030
+ interface IRequestSender<TOutCtx = undefined> {
2031
+ sendRequest(method: string, params: JsonValue | undefined, opts?: SendOpts<TOutCtx>): Promise<JsonValue>;
2032
+ sendNotification(method: string, params: JsonValue | undefined, opts?: SendOpts<TOutCtx>): Promise<void>;
2033
+ /**
2034
+ * Issue a request that participates in the streaming sub-protocol.
2035
+ * Returns synchronously with the wire request id, the result
2036
+ * promise, and a `send` for emitting client→server stream messages.
2037
+ */
2038
+ sendRequestWithStream(method: string, params: JsonValue | undefined, opts?: StreamSendOpts<TOutCtx>): RawStreamingCall;
2039
+ close(): void;
2040
+ }
2041
+ /**
2042
+ * Handle for a request issued via
2043
+ * {@link IRequestSender.sendRequestWithStream}. `send` emits
2044
+ * client→server stream messages correlated with this call. `result`
2045
+ * resolves with the call's response.
2046
+ */
2047
+ interface RawStreamingCall {
2048
+ readonly result: Promise<JsonValue>;
2049
+ /** Emit a client→server (`toCallee`) stream message correlated with this call. */
2050
+ send(payload: JsonValue): void;
2051
+ /**
2052
+ * Ask the callee to abort this in-flight request (a `toCallee`
2053
+ * `cancel` control). Advisory: the request settles via its normal
2054
+ * response (typically a `cancelled` error). `reason` is an open-set
2055
+ * diagnostic string (see `StreamControlReason`).
2056
+ */
2057
+ cancel(reason?: string): void;
2058
+ /**
2059
+ * Stop tracking this request locally and reject {@link result}. This does
2060
+ * not notify the callee; call {@link cancel} first when remote work should
2061
+ * also be cancelled. Safe to call after the request has already settled.
2062
+ */
2063
+ dispose?(reason?: string): void;
2064
+ /**
2065
+ * Liveness probe toward the callee: emit a `toCallee` ping and
2066
+ * resolve once the callee's `pong` (matching nonce) returns. Rejects
2067
+ * if the request settles first. Independent of the channel's
2068
+ * automatic keepalive ping.
2069
+ */
2070
+ ping(): Promise<void>;
2071
+ }
2072
+ /**
2073
+ * Per-send options.
2074
+ *
2075
+ * `interfaceHash` is interface-level call metadata: the schema hash of
2076
+ * the interface a typed proxy is calling. It is independent of
2077
+ * `TOutCtx` — the connection stamps it from the interface definition,
2078
+ * the base {@link JsonRpcChannel} ignores it, and signing decorators
2079
+ * bake it into the `$hubrpc` envelope.
2080
+ *
2081
+ * `ctx` is the sender's `TOutCtx`-typed override / extension bag for
2082
+ * per-call decorator overrides (e.g. `signerOverride`, `capsOverride`).
2083
+ * The base {@link JsonRpcChannel} ignores `ctx` entirely; decorators
2084
+ * like `SigningSender` interpret it.
2085
+ */
2086
+ interface SendOpts<TOutCtx = undefined> {
2087
+ readonly ctx?: TOutCtx;
2088
+ /** Interface schema hash for this call (interface-level metadata). */
2089
+ readonly interfaceHash?: string;
2090
+ }
2091
+ interface StreamSendOpts<TOutCtx = undefined> extends SendOpts<TOutCtx> {
2092
+ readonly onStreamMessage?: (payload: JsonValue) => void;
2093
+ }
2094
+ /**
2095
+ * Convenience: the transport type a {@link JsonRpcChannel} expects.
2096
+ * Outbound is plain `JsonRpcMessage` — the base channel does not
2097
+ * attach context to outgoing wire messages.
2098
+ */
2099
+ type ChannelTransport<TInCtx = undefined> = IMessageTransport<MessageWithCtx<TInCtx>>;
2100
+ /**
2101
+ * Type of incoming messages on the channel's transport. With
2102
+ * `TInCtx = undefined` (default) this is just `JsonRpcMessage`. With a
2103
+ * concrete `TInCtx`, the transport carries a `context` field alongside
2104
+ * the message — out-of-band, never sent over a wire, set by the
2105
+ * in-process producer.
2106
+ */
2107
+ type MessageWithCtx<TInCtx> = [TInCtx] extends [undefined] ? JsonRpcMessage : JsonRpcMessage & {
2108
+ context: TInCtx;
2109
+ };
2110
+ declare class RpcError extends Error {
2111
+ readonly code: number;
2112
+ readonly data?: JsonValue | undefined;
2113
+ constructor(message: string, code: number, data?: JsonValue | undefined);
2114
+ }
2115
+ //#endregion
2116
+ //#region src/connection/bareInterfaceTarget.d.ts
2117
+ /** A metadata-free foreign-protocol interface and its wire-method prefix. */
2118
+ interface BareInterfaceTarget<TDef extends InterfaceDefinition<any>> {
2119
+ readonly mode: 'bare';
2120
+ readonly interface: TDef;
2121
+ readonly prefix: string;
2122
+ }
2123
+ /**
2124
+ * Bundle an interface definition with metadata-free foreign-protocol
2125
+ * addressing for use with `connection.get(target)`.
2126
+ */
2127
+ declare function bareInterfaceTarget<TDef extends InterfaceDefinition<any>>(iface: TDef, options?: {
2128
+ readonly prefix?: string;
2129
+ }): BareInterfaceTarget<TDef>;
2130
+ //#endregion
2131
+ //#region src/connection/channelConnector.d.ts
2132
+ /**
2133
+ * A raw channel that signals when it closes (and, when possible, can be torn
2134
+ * down). Both {@link openHubChannel}'s `HubChannel` and `openStdioChannel`'s
2135
+ * `StdioChannel` satisfy this shape.
2136
+ */
2137
+ type ConnectableChannel = Channel<undefined, unknown> & {
2138
+ /**
2139
+ * Fires once when the channel closes. Returns a disposable to unsubscribe.
2140
+ *
2141
+ * Ordering contract: when a close causes a sending method (e.g. a request
2142
+ * or notification) to reject/throw, {@link onClose} must fire *before* that
2143
+ * rejection surfaces to the caller. This lets consumers reliably tell a
2144
+ * close-induced failure (the channel is already observably closed) apart
2145
+ * from a genuine error (the channel is still open). See
2146
+ * {@link ChannelConnector.keepConnected}.
2147
+ */
2148
+ onClose(listener: () => void): IDisposable;
2149
+ /** Tear the channel down. Optional — stdio channels have no explicit close. */
2150
+ close?(): void;
2151
+ };
2152
+ /** Handle returned by {@link ChannelConnector.keepConnected}. */
2153
+ interface KeepConnectedHandle {
2154
+ /**
2155
+ * Resolves when the loop exits: the channel closed and the connector does
2156
+ * not redial, or {@link stop} (or the supplied signal) fired.
2157
+ */
2158
+ readonly done: Promise<void>;
2159
+ /** Stop redialing and close the current channel (if any). */
2160
+ stop(): void;
2161
+ }
2162
+ /** Callback run on every (re)connect. The channel is the raw, unsigned channel. */
2163
+ type OnChannelConnect<T extends ConnectableChannel> = (ctx: {
2164
+ channel: T;
2165
+ }) => void | Promise<void>;
2166
+ interface ExpBackoffOptions {
2167
+ readonly initialBackoffMs?: number;
2168
+ readonly maxBackoffMs?: number;
2169
+ }
2170
+ /**
2171
+ * Drives a connect / (re)connect loop over a raw {@link ConnectableChannel}.
2172
+ *
2173
+ * Unlike connection-level helpers, this works at the channel layer: the
2174
+ * caller composes identity / signing on top of the channel handed to
2175
+ * {@link keepConnected} (e.g. `SigningSender.wrapChannel(channel, { principal })`).
2176
+ *
2177
+ * Construct via {@link ChannelConnector.once} (a single, already-open channel
2178
+ * that never redials) or {@link ChannelConnector.expBackoff} (re-open via a
2179
+ * factory with exponential backoff after each close).
2180
+ */
2181
+ declare class ChannelConnector<T extends ConnectableChannel> {
2182
+ private readonly _open;
2183
+ private readonly _redial;
2184
+ private readonly _initialBackoffMs;
2185
+ private readonly _maxBackoffMs;
2186
+ private constructor();
2187
+ /**
2188
+ * A connector over a single channel (or a promise of one). Never redials;
2189
+ * the loop ends when the channel closes or {@link KeepConnectedHandle.stop}
2190
+ * fires.
2191
+ */
2192
+ static once<T extends ConnectableChannel>(channel: T | Promise<T>): ChannelConnector<T>;
2193
+ /**
2194
+ * A redialing connector: `open` is called once per attempt, and the loop
2195
+ * reconnects with exponential backoff after each close (or failed open).
2196
+ */
2197
+ static expBackoff<T extends ConnectableChannel>(open: () => Promise<T>, opts?: ExpBackoffOptions): ChannelConnector<T>;
2198
+ /**
2199
+ * Run `onConnect` on every (re)connect with the freshly opened channel.
2200
+ * The callback typically wraps the channel with signing and registers
2201
+ * handlers. Returns once the loop exits (see {@link KeepConnectedHandle}).
2202
+ */
2203
+ keepConnected(onConnect: OnChannelConnect<T>, opts?: {
2204
+ signal?: AbortSignal;
2205
+ }): KeepConnectedHandle;
2206
+ }
2207
+ //#endregion
2208
+ //#region src/connection/jsonRpcChannel.d.ts
2209
+ /**
2210
+ * Minimal JSON-RPC 2.0 channel: correlates requests with responses,
2211
+ * dispatches incoming requests/notifications to a handler.
2212
+ *
2213
+ * Construct via {@link JsonRpcChannel.create}: it returns a
2214
+ * {@link Channel} factory which materialises the live channel once a
2215
+ * handler is supplied via `.connect(handler)`. The handler is fixed for
2216
+ * the channel's lifetime — no setter, no mid-flight swap.
2217
+ *
2218
+ * The outbound `TOutCtx` of the produced sender is `unknown` — this
2219
+ * channel ignores per-call ctx entirely. Decorators (e.g.
2220
+ * `SigningSender`) lift it to a concrete shape.
2221
+ */
2222
+ declare class JsonRpcChannel<TInCtx = undefined> implements IRequestSender<unknown> {
2223
+ private readonly _transport;
2224
+ /**
2225
+ * Wrap a transport in a {@link Channel}. The channel's sender is live
2226
+ * immediately; call {@link Channel.setRequestHandler} (or pass the channel
2227
+ * to {@link LinkRpcConnection}) to bind the inbound handler.
2228
+ */
2229
+ static create<TInCtx = undefined>(transport: ChannelTransport<TInCtx>): Channel<TInCtx, unknown>;
2230
+ /** Wrap a transport and retain an explicit lifecycle hook for its owner. */
2231
+ static createWithClose<TInCtx = undefined>(transport: ChannelTransport<TInCtx>): {
2232
+ channel: Channel<TInCtx, unknown>;
2233
+ close: () => void;
2234
+ };
2235
+ private _nextId;
2236
+ private readonly _pending;
2237
+ /**
2238
+ * Per-request callbacks invoked when a {@link STREAM_METHOD}
2239
+ * notification arrives with a matching `requestId`. Used in both
2240
+ * directions: outgoing-request callers register here keyed by the
2241
+ * id they sent; per-call incoming-request stream handles register
2242
+ * keyed by the id they observed. Entries are removed when the
2243
+ * corresponding request completes (response received for outgoing,
2244
+ * response sent for incoming).
2245
+ */
2246
+ private readonly _streamListeners;
2247
+ /**
2248
+ * Per-incoming-request handlers for reserved `control` messages
2249
+ * (cancel / ping / pong) arriving as stream notifications. Keyed
2250
+ * by the id observed; removed when the request settles.
2251
+ */
2252
+ private readonly _streamControl;
2253
+ private readonly _incomingAborts;
2254
+ private _handler;
2255
+ private _wireObserver;
2256
+ private _closeError;
2257
+ setRequestHandler(handler: IRequestHandler<TInCtx> | undefined): void;
2258
+ setWireMessageObserver(observer: WireMessageObserver | undefined): void;
2259
+ private constructor();
2260
+ sendRequest(method: string, params: JsonValue | undefined, opts?: SendOpts<unknown>): Promise<JsonValue>;
2261
+ sendNotification(method: string, params: JsonValue | undefined, opts?: SendOpts<unknown>): Promise<void>;
2262
+ sendRequestWithStream(method: string, params: JsonValue | undefined, opts?: StreamSendOpts<unknown>): RawStreamingCall;
2263
+ /**
2264
+ * Build the symmetric ping/pong machinery for one in-flight request.
2265
+ *
2266
+ * `outboundDir` is the direction *this* side emits controls in
2267
+ * (`toCallee` for the caller, `toCaller` for the callee). A received
2268
+ * ping is answered with a pong in that same direction, echoing the
2269
+ * ping's nonce; a received pong resolves the matching outstanding
2270
+ * {@link ping} probe.
2271
+ */
2272
+ private _makePinger;
2273
+ /**
2274
+ * Emit a stream notification ({@link STREAM_METHOD}) associated with
2275
+ * an in-flight request. Internal: outgoing-side callers reach this
2276
+ * via {@link RawStreamingCall.send} / `cancel`; incoming-side handlers
2277
+ * reach it via {@link IncomingStream.send}.
2278
+ */
2279
+ private _sendStream;
2280
+ close(): void;
2281
+ private _throwIfClosed;
2282
+ private _onMessage;
2283
+ private _handleStreamNotification;
2284
+ private _handleRequest;
2285
+ private _handleNotification;
2286
+ private _observeInbound;
2287
+ private _observeOutbound;
2288
+ private _observeSendFailure;
2289
+ }
2290
+ //#endregion
2291
+ //#region src/connection/requestTimeout.d.ts
2292
+ declare const DEFAULT_RPC_TIMEOUT_MS = 5000;
2293
+ interface CancellableRequest<T> extends Promise<T> {
2294
+ cancel(reason?: string): void | Promise<void>;
2295
+ dispose?(reason?: string): void;
2296
+ }
2297
+ declare function withRpcTimeout<T>(request: CancellableRequest<T>, target: string, timeoutMs?: number): Promise<T>;
2298
+ //#endregion
2299
+ //#region src/connection/endpointUri.d.ts
2300
+ /**
2301
+ * A strict, RFC-3986 URI vocabulary for "where the linkrpc server lives, and
2302
+ * how to reach (or start) it". Every endpoint round-trips through
2303
+ * {@link parseEndpointUri} / {@link formatEndpointUri} and is a valid `new URL()`
2304
+ * — safe to put in env vars, logs, and config.
2305
+ *
2306
+ * Supported schemes:
2307
+ * - `unix:/path/to.sock?token=…` → {@link SocketEndpoint}
2308
+ * - `npipe://./pipe/name?token=…` → {@link SocketEndpoint} (Windows)
2309
+ * - `ws://host:port?token=…` / `wss:…` → {@link WsEndpoint} (LinkRPC handshake)
2310
+ * - `ws-no-init://host:port?…` → {@link WsNoInitEndpoint}
2311
+ * - `cmd-stdio:?command=…` / `…?argv=…` → {@link CmdStdioEndpoint}
2312
+ * - `cmd:?command=…` / `…?argv=…` → {@link CmdEnvEndpoint}
2313
+ *
2314
+ * The command payload is `{ command: string } | { argv: string[] }`:
2315
+ * - `?command=node%20server.js` — one verbatim string, split by the OS shell.
2316
+ * - `?argv=node&argv=server.js` — repeated `argv` params, structure-preserving.
2317
+ *
2318
+ * A bare string with no scheme (legacy `LINKRPC_ENDPOINT`) is auto-detected: a
2319
+ * `ws://`/`wss://` URL stays WebSocket, anything else is a socket path.
2320
+ */
2321
+ /** Verbatim command line (`{ command }`) or pre-split argv (`{ argv }`). */
2322
+ type EndpointCommand = {
2323
+ readonly command: string;
2324
+ } | {
2325
+ readonly argv: readonly string[];
2326
+ };
2327
+ /** Named pipe / unix-domain-socket the server already listens on. */
2328
+ interface SocketEndpoint {
2329
+ readonly kind: 'socket';
2330
+ readonly path: string;
2331
+ readonly token?: string;
2332
+ /**
2333
+ * Present on sockets created by `hub connect`. Local framing still uses the
2334
+ * LinkRPC transport handshake; this describes whether forwarded application
2335
+ * calls target a LinkRPC or plain JSON-RPC peer.
2336
+ */
2337
+ readonly brokerMode?: 'linkrpc' | 'raw';
2338
+ }
2339
+ /** A running WebSocket hub; `token` rides in the `hubrpc::initialize` handshake. */
2340
+ interface WsEndpoint {
2341
+ readonly kind: 'ws';
2342
+ readonly url: string;
2343
+ readonly token?: string;
2344
+ }
2345
+ /**
2346
+ * A running plain-JSON-RPC WebSocket endpoint. Unlike {@link WsEndpoint}, CLI
2347
+ * consumers use it without the `hubrpc::initialize` handshake or LinkRPC signing.
2348
+ * Query parameters are preserved verbatim for protocols that authenticate
2349
+ * during the WebSocket upgrade (for example AHP's `tkn` parameter).
2350
+ */
2351
+ interface WsNoInitEndpoint {
2352
+ readonly kind: 'ws-no-init';
2353
+ /** Actual `ws://` URL passed to the WebSocket constructor. */
2354
+ readonly url: string;
2355
+ }
2356
+ /** Spawn a child and talk linkrpc over its stdin/stdout. */
2357
+ interface CmdStdioEndpoint {
2358
+ readonly kind: 'cmd-stdio';
2359
+ readonly command: EndpointCommand;
2360
+ /** Extra environment variables injected into the spawned child. */
2361
+ readonly env?: Readonly<Record<string, string>>;
2362
+ /** Working directory for the spawned child. */
2363
+ readonly cwd?: string;
2364
+ }
2365
+ /**
2366
+ * Spawn a child against a freshly-started *local hub*: the parent listens on a
2367
+ * private socket, hands the child its address + token via `LINKRPC_ENDPOINT` /
2368
+ * `LINKRPC_TOKEN`, and the child dials in as a hub participant (registering its
2369
+ * services), exactly as it would against a remote hub.
2370
+ */
2371
+ interface CmdEnvEndpoint {
2372
+ readonly kind: 'cmd-env';
2373
+ readonly command: EndpointCommand;
2374
+ /**
2375
+ * When set, the local hub provisions (or reuses) a *persistent* managed
2376
+ * identity under this slot id, so the child's HPKE wrap/unwrap keys survive
2377
+ * across runs (sealed archives re-open).
2378
+ */
2379
+ readonly provisionSlot?: string;
2380
+ /** Extra environment variables injected into the spawned child. */
2381
+ readonly env?: Readonly<Record<string, string>>;
2382
+ /** Working directory for the spawned child. */
2383
+ readonly cwd?: string;
2384
+ }
2385
+ type ResolvedEndpoint = SocketEndpoint | WsEndpoint | WsNoInitEndpoint | CmdStdioEndpoint | CmdEnvEndpoint;
2386
+ /**
2387
+ * Parse a strict endpoint URI into an {@link ResolvedEndpoint}. Throws on an
2388
+ * unknown scheme or a malformed command endpoint. A bare (scheme-less) string
2389
+ * is auto-detected as `ws`/`wss` URL or a socket path.
2390
+ */
2391
+ declare function parseEndpointUri(uri: string): ResolvedEndpoint;
2392
+ interface FormatEndpointOptions {
2393
+ /** Emit the real token instead of redacting it. Default: redact. */
2394
+ readonly revealToken?: boolean;
2395
+ }
2396
+ /**
2397
+ * Render an {@link ResolvedEndpoint} back to a canonical strict URI. The token is
2398
+ * redacted (`***`) unless `revealToken` is set, so the result is paste-safe for
2399
+ * logs. Round-trips with {@link parseEndpointUri} when `revealToken` is true.
2400
+ */
2401
+ declare function formatEndpointUri(spec: ResolvedEndpoint, options?: FormatEndpointOptions): string;
2402
+ /** True for endpoints that connect to existing, possibly-remote infrastructure. */
2403
+ declare function isHubEndpoint(spec: ResolvedEndpoint): spec is SocketEndpoint | WsEndpoint;
2404
+ //#endregion
2405
+ //#region src/identity/identity.d.ts
2406
+ /** JSON-serializable form of a {@link KeypairSigningIdentity} (base64url keys). */
2407
+ interface SerializedKeypairSigningIdentity {
2408
+ readonly privateKey: string;
2409
+ readonly publicKey: string;
2410
+ }
2411
+ /**
2412
+ * The public face of a signing identity: its stable {@link PrincipalId} name
2413
+ * and the {@link KeyId} its signatures are stamped with. In Phase 1 (perpetual
2414
+ * identities) the keyId is the genesis key embedded in the principal, so it is
2415
+ * derived by stripping the `id:` prefix.
2416
+ */
2417
+ declare class PublicSigningIdentity {
2418
+ readonly principal: PrincipalId;
2419
+ constructor(principal: PrincipalId);
2420
+ /** The {@link KeyId} this identity signs with (its genesis key, in Phase 1). */
2421
+ get keyId(): KeyId;
2422
+ }
2423
+ interface SigningIdentity {
2424
+ readonly publicSigningIdentity: PublicSigningIdentity;
2425
+ sign(bytes: Uint8Array): Promise<Uint8Array>;
2426
+ }
2427
+ /**
2428
+ * {@link SigningIdentity} backed by an in-process keypair. For the common
2429
+ * case where the signing material lives in memory. For external HSM-style
2430
+ * backends, implement {@link SigningIdentity} directly.
2431
+ */
2432
+ declare class KeypairSigningIdentity implements SigningIdentity {
2433
+ private readonly _privateKey;
2434
+ readonly publicSigningIdentity: PublicSigningIdentity;
2435
+ constructor(principal: PrincipalId, _privateKey: PrivateKey);
2436
+ sign(message: Uint8Array): Promise<Signature>;
2437
+ static fromKeypair(keypair: Keypair): KeypairSigningIdentity;
2438
+ /** Generate a fresh signing identity (Ed25519 keypair). */
2439
+ static generateNew(): Promise<KeypairSigningIdentity>;
2440
+ /** Restore an identity from its {@link toJson} form. */
2441
+ static fromJson(json: SerializedKeypairSigningIdentity): KeypairSigningIdentity;
2442
+ /** Serialize the keypair to a JSON-friendly form (base64url keys). */
2443
+ toJson(): SerializedKeypairSigningIdentity;
2444
+ }
2445
+ declare class PublicWrappingIdentity {
2446
+ readonly wrapPublicKey: Uint8Array;
2447
+ constructor(wrapPublicKey: Uint8Array);
2448
+ }
2449
+ interface WrappingIdentity {
2450
+ readonly publicWrappingIdentity: PublicWrappingIdentity;
2451
+ wrap(domain: string, bytes: Uint8Array): Promise<Uint8Array>;
2452
+ unwrap(domain: string, blob: Uint8Array): Promise<Uint8Array>;
2453
+ }
2454
+ interface Identity extends SigningIdentity, WrappingIdentity {
2455
+ /** The identity's stable {@link PrincipalId} name. */
2456
+ readonly principal: PrincipalId;
2457
+ /** @deprecated */
2458
+ readonly wrapPublicKey: Uint8Array;
2459
+ }
2460
+ /**
2461
+ * Full {@link Identity} backed by in-process Ed25519 (signing) and X25519
2462
+ * (wrapping) keypairs. The local counterpart to a keystore/executor-backed
2463
+ * identity — used by self-managed principals that hold their own key
2464
+ * material (e.g. loaded from disk). For external HSM-style backends,
2465
+ * implement {@link Identity} directly.
2466
+ */
2467
+ declare class KeypairIdentity implements Identity {
2468
+ private readonly _privateKey;
2469
+ private readonly _wrap;
2470
+ readonly principal: PrincipalId;
2471
+ readonly wrapPublicKey: Uint8Array;
2472
+ readonly publicSigningIdentity: PublicSigningIdentity;
2473
+ readonly publicWrappingIdentity: PublicWrappingIdentity;
2474
+ constructor(principal: PrincipalId, _privateKey: PrivateKey, _wrap: X25519Keypair);
2475
+ sign(message: Uint8Array): Promise<Signature>;
2476
+ wrap(domain: string, bytes: Uint8Array): Promise<Uint8Array>;
2477
+ unwrap(domain: string, blob: Uint8Array): Promise<Uint8Array>;
2478
+ /** Generate a fresh identity (Ed25519 + X25519 keypairs). */
2479
+ static generate(): Promise<KeypairIdentity>;
2480
+ }
2481
+ //#endregion
2482
+ //#region src/identity/capability.d.ts
2483
+ /**
2484
+ * Pure freshness check for a single capability link: `true` when the cap never
2485
+ * expires, or its `expiresAtMs` is still in the future at `now + marginMs`.
2486
+ *
2487
+ * Mirrors the gate's expiry rule in {@link verifyChain}'s link check
2488
+ * (`expiresAtMs < nowMs` ⇒ expired) so a producer can decide, *before signing*,
2489
+ * whether to re-acquire a cap rather than attach one the gate will reject as
2490
+ * `expired`. The `marginMs` safety window absorbs in-flight transit time and
2491
+ * client/hub clock skew — pass the call's `signedAtMs` as `now` so the check
2492
+ * evaluates expiry against the same instant baked into the envelope.
2493
+ *
2494
+ * This checks ONE link. Effective authority requires every link in a
2495
+ * delegation chain to be unexpired, so a producer attaching a bag should apply
2496
+ * this to every cap it would attach (see {@link capBagFreshAt}).
2497
+ */
2498
+ declare function capabilityFreshAt(cap: Capability, now: number, marginMs?: number): boolean;
2499
+ /**
2500
+ * Freshness over a whole presented bag: `true` only when every cap is fresh at
2501
+ * `now + marginMs` (see {@link capabilityFreshAt}). An empty bag is trivially
2502
+ * fresh. Use this at the cap-production point to decide whether to re-acquire.
2503
+ */
2504
+ declare function capBagFreshAt(caps: readonly Capability[], now: number, marginMs?: number): boolean;
2505
+ type PermitResult = {
2506
+ ok: true;
2507
+ capabilityNonce: string;
2508
+ rootIssuer: PrincipalId;
2509
+ } | {
2510
+ ok: false;
2511
+ reason: string;
2512
+ };
2513
+ /**
2514
+ * A trust anchor accepted as a capability-chain root, plus whether it may be
2515
+ * named in authorization error messages.
2516
+ */
2517
+ interface AcceptedRootIssuer {
2518
+ /** The principal accepted as a chain root for the queried service. */
2519
+ principal: PrincipalId;
2520
+ /**
2521
+ * Whether this issuer may be disclosed in `permits` rejection reasons.
2522
+ * Public anchors (e.g. a hub's well-known admin identity) are surfaced to
2523
+ * help diagnose "wrong root" failures; private ones are withheld so the
2524
+ * error never leaks the set of trusted issuers.
2525
+ */
2526
+ isPublic: boolean;
2527
+ }
2528
+ /**
2529
+ * **The** authorization predicate. A call is permitted iff some presented
2530
+ * capability (1) addresses the call, (2) has a genuine, well-delegated
2531
+ * chain whose leaf audience is the caller (`call.signer`), and (3) roots
2532
+ * at an issuer the verifier accepts **for the call's service**.
2533
+ *
2534
+ * Pure: it reports the verdict (and the `capabilityNonce` / `rootIssuer`
2535
+ * for audit) but performs no consumption. Replay is the caller's job — the
2536
+ * gate dedups `call.nonce`, so `callBind` grants are single-use for free.
2537
+ *
2538
+ * `acceptedRootIssuers` is consulted with the call's `serviceId` and returns
2539
+ * the accepted {@link AcceptedRootIssuer} anchors; an empty result rejects
2540
+ * every capability (fail closed) — trust is the verifier's, never the
2541
+ * token's. Anchors flagged `isPublic` are named in the rejection reason when
2542
+ * a chain roots at an unaccepted issuer.
2543
+ */
2544
+ declare function permits(call: Call, capabilities: readonly SignedCapability[], acceptedRootIssuers: (serviceId: string) => readonly AcceptedRootIssuer[], nowMs: number, opts?: {
2545
+ maxDepth?: number;
2546
+ }): Promise<PermitResult>;
2547
+ /**
2548
+ * Sign a `Capability` with a {@link SigningIdentity}. The private key never
2549
+ * leaves the identity. The result verifies via {@link verifyChain}.
2550
+ */
2551
+ declare function signCapability(capability: Capability, issuer: SigningIdentity): Promise<SignedCapability>;
2552
+ interface IssueCapabilityOptions {
2553
+ /** Identity allowed to present the capability. */
2554
+ readonly audience: PublicSigningIdentity;
2555
+ /** Authority granted to the audience. */
2556
+ readonly permissions: readonly Permission[];
2557
+ /** Optional expiration time as Unix milliseconds. */
2558
+ readonly expiresAtMs?: number;
2559
+ /** Optional parent whose authority this capability narrows. */
2560
+ readonly parent?: SignedCapability;
2561
+ }
2562
+ /**
2563
+ * Issue and sign a capability, deriving its issuer, nonce, and optional parent
2564
+ * hash. The result is plain JSON data and survives a JSON stringify/parse
2565
+ * round-trip without reconstruction.
2566
+ */
2567
+ declare function issueCapability(issuer: SigningIdentity, options: IssueCapabilityOptions): Promise<SignedCapability>;
2568
+ type ParamMatcherFor<T> = {
2569
+ exact: T;
2570
+ } | {
2571
+ enum: T[];
2572
+ } | {
2573
+ any: true;
2574
+ } | (T extends string ? {
2575
+ prefix: string;
2576
+ } : never) | (T extends readonly string[] ? {
2577
+ subsetOf: string[];
2578
+ } : never);
2579
+ /** Type-safe top-level parameter matchers for one interface member. */
2580
+ type ParamMatchers<T> = T extends Record<string, unknown> ? { [K in keyof T]: ParamMatcherFor<Exclude<T[K], undefined>>; } : never;
2581
+ type RequestMemberName<TMembers extends MemberMap> = { [K in keyof TMembers]: TMembers[K] extends RequestType<any, any, any, any, any> ? K : never; }[keyof TMembers] & string;
2582
+ type RequestParams<TMember> = TMember extends RequestType<infer TParams, any, any, any, any> ? TParams : never;
2583
+ /** Match a string parameter by prefix. */
2584
+ declare function prefix(value: string): {
2585
+ prefix: string;
2586
+ };
2587
+ /**
2588
+ * Build an invoke permission from a typed interface member. The helper derives
2589
+ * the interface id and schema hash and type-checks parameter matcher names and
2590
+ * values against the member's params.
2591
+ */
2592
+ declare function invoke<TMembers extends MemberMap, TMember extends RequestMemberName<TMembers>>(serviceId: string, iface: InterfaceDefinition<TMembers>, member: TMember, params?: ParamMatchers<RequestParams<TMembers[TMember]>>): Permission;
2593
+ //#endregion
2594
+ //#region src/identity/managedIdentity.d.ts
2595
+ /**
2596
+ * Executor-side backing for `identity.storage::*`. Lifecycle tied to a
2597
+ * single managed-identity slot; the executor decides where bytes are
2598
+ * stored.
2599
+ */
2600
+ interface ManagedIdentityStorageBackend {
2601
+ get(key: string): Promise<unknown | undefined>;
2602
+ set(key: string, value: unknown): Promise<void>;
2603
+ /** Returns `true` iff the key existed before this call. */
2604
+ delete(key: string): Promise<boolean>;
2605
+ list(prefix?: string): Promise<string[]>;
2606
+ }
2607
+ /**
2608
+ * In-process storage backend. Used by tests and by any executor that
2609
+ * doesn't need at-rest persistence.
2610
+ */
2611
+ declare class InMemoryManagedIdentityStorage implements ManagedIdentityStorageBackend {
2612
+ private readonly _data;
2613
+ get(key: string): Promise<unknown | undefined>;
2614
+ set(key: string, value: unknown): Promise<void>;
2615
+ delete(key: string): Promise<boolean>;
2616
+ list(prefix?: string): Promise<string[]>;
2617
+ }
2618
+ /**
2619
+ * In-process `ManagedIdentity` that holds the private key in memory and
2620
+ * uses the package crypto API. Useful for tests and for hub-side features
2621
+ * that want a short-lived identity without touching disk.
2622
+ */
2623
+ declare class InMemoryManagedIdentity implements Identity {
2624
+ private readonly _ed;
2625
+ private readonly _wrap;
2626
+ readonly principal: PrincipalId;
2627
+ readonly wrapPublicKey: Uint8Array;
2628
+ constructor(_ed: Keypair, _wrap: X25519Keypair);
2629
+ get publicSigningIdentity(): PublicSigningIdentity;
2630
+ get publicWrappingIdentity(): PublicWrappingIdentity;
2631
+ sign(bytes: Uint8Array): Promise<Signature>;
2632
+ wrap(domain: string, bytes: Uint8Array): Promise<Uint8Array>;
2633
+ unwrap(domain: string, blob: Uint8Array): Promise<Uint8Array>;
2634
+ /** Generate a fresh in-memory identity (Ed25519 + X25519 keypairs). */
2635
+ static generate(): Promise<InMemoryManagedIdentity>;
2636
+ }
2637
+ /**
2638
+ * Register the `identity` interface on `overlay` so the bound participant
2639
+ * can call `identity::sign` etc. on its root overlay. The overlay is
2640
+ * private to one participant — no other peer can reach these methods.
2641
+ *
2642
+ * When `storage` is supplied, the `identity.storage` interface is
2643
+ * registered alongside `identity::*`. Lifetime/scope of the backend is
2644
+ * the executor's responsibility — for keystore-backed identities the
2645
+ * backend lives as long as the identity slot does.
2646
+ *
2647
+ * Typical caller: the executor (e.g. the VS Code extension), right after
2648
+ * `Hub.attachParticipant`, on the `rootOverlay` returned from the attach
2649
+ * handle.
2650
+ */
2651
+ declare function registerIdentityOnOverlay(overlay: LinkRpcConnection, identity: Identity, storage?: ManagedIdentityStorageBackend): void;
2652
+ /**
2653
+ * Like {@link registerIdentityOnOverlay}, but resolves the identity lazily on
2654
+ * first use via `resolveIdentity`. The identity is materialized only when the
2655
+ * bound participant actually calls `identity::*` — registering the overlay
2656
+ * does NOT create or load any identity.
2657
+ *
2658
+ * This is essential for the consent model: a host can serve `identity::*` on a
2659
+ * keystore slot without making the slot privileged (`hasState`) until the app
2660
+ * genuinely opts into an identity. `resolveIdentity` is expected to be cheap on
2661
+ * repeat calls (the keystore caches in memory), and to reflect lifecycle
2662
+ * changes — e.g. after a slot is wiped and re-created ("Reset Identity"), the
2663
+ * next call resolves the fresh identity.
2664
+ *
2665
+ * `storage` is registered eagerly because reading/writing storage is itself
2666
+ * the privileged act the app must perform to gain state — exposing the
2667
+ * interface costs nothing until used.
2668
+ */
2669
+ declare function registerLazyIdentityOnOverlay(overlay: LinkRpcConnection<unknown>, resolveIdentity: () => Promise<Identity>, storage?: ManagedIdentityStorageBackend): void;
2670
+ /**
2671
+ * Client-side proxy for `identity.storage::*`. Methods round-trip through
2672
+ * the participant's root overlay; the executor enforces key-shape rules
2673
+ * server-side.
2674
+ *
2675
+ * Calls are unsigned (same recursion-guard rationale as
2676
+ * {@link createManagedIdentity} — the overlay is private to one
2677
+ * participant, so transport-level routing already authenticates).
2678
+ */
2679
+ interface ManagedIdentityStorage {
2680
+ get<T = unknown>(key: string): Promise<T | undefined>;
2681
+ set(key: string, value: unknown): Promise<void>;
2682
+ delete(key: string): Promise<boolean>;
2683
+ list(prefix?: string): Promise<string[]>;
2684
+ }
2685
+ /**
2686
+ * A managed identity resolved from an executor's `identity::*` overlay: a
2687
+ * full {@link Identity} (signing + HPKE wrap/unwrap, all round-tripping
2688
+ * through the executor — private keys never leave it) plus the
2689
+ * per-identity {@link ManagedIdentityStorage}.
2690
+ */
2691
+ interface ManagedIdentity extends Identity {
2692
+ /**
2693
+ * Per-identity persistent key/value store. Backed by the executor's
2694
+ * `identity.storage::*` overlay; calls throw when the executor did not
2695
+ * register storage for this slot (e.g. an in-process identity for tests).
2696
+ */
2697
+ readonly storage: ManagedIdentityStorage;
2698
+ }
2699
+ /**
2700
+ * Bootstrap a {@link ManagedIdentity} from a sender (typically the raw
2701
+ * unsigned sender obtained via `channel.sender` before wrapping with
2702
+ * {@link SigningSender}). Makes `identity::*` calls unsigned — the
2703
+ * executor's overlay is private to one participant so routing already
2704
+ * identifies the caller, preventing signing recursion.
2705
+ *
2706
+ * The returned identity signs / wraps / unwraps by round-tripping through
2707
+ * the executor's `identity::*` overlay; the caller wires it into their
2708
+ * {@link SigningSender} configuration (e.g. as a {@link Principal}). No
2709
+ * side effects on any existing connection or holder.
2710
+ */
2711
+ declare function createManagedIdentity(sender: IRequestSender<unknown>): Promise<ManagedIdentity>;
2712
+ //#endregion
2713
+ //#region src/identity/capBag.d.ts
2714
+ interface CapBagOptions {
2715
+ /**
2716
+ * Per-identity persistent storage (e.g.
2717
+ * {@link ManagedIdentityHandle.storage}). Omit for a memory-only bag
2718
+ * that forgets its caps when the process exits.
2719
+ */
2720
+ readonly storage?: ManagedIdentityStorage;
2721
+ /** Storage key. Defaults to `hubrpc.caps.v1`. */
2722
+ readonly storageKey?: string;
2723
+ /** Optional sink for non-fatal storage warnings. */
2724
+ readonly onWarn?: (message: string) => void;
2725
+ }
2726
+ /**
2727
+ * A process-lifetime bag of hub-issued capabilities. Plug
2728
+ * {@link CapBag.provider} straight into a connection's cap provider so every
2729
+ * outbound signed call carries whatever caps have been granted so far. The
2730
+ * hub picks whichever cap matches the call per dispatch.
2731
+ *
2732
+ * When constructed with {@link CapBagOptions.storage} the bag hydrates from
2733
+ * (and persists to) storage, so the next process spawn for the same identity
2734
+ * reuses its grants without re-prompting.
2735
+ */
2736
+ declare class CapBag {
2737
+ /** Create a bag, hydrating from storage when one was supplied. */
2738
+ static load(options?: CapBagOptions): Promise<CapBag>;
2739
+ private readonly _caps;
2740
+ private readonly _storage?;
2741
+ private readonly _storageKey;
2742
+ private readonly _onWarn;
2743
+ private constructor();
2744
+ get capabilities(): readonly SignedCapability[];
2745
+ /**
2746
+ * A {@link CapProvider} reflecting the bag at call-time. Assign it to
2747
+ * `HubClientHandle.signing.capProvider` or pass it through
2748
+ * `SigningSenderConfig.capProvider`.
2749
+ */
2750
+ readonly provider: CapProvider;
2751
+ /** Append capabilities and persist (when backed by storage). */
2752
+ add(...caps: readonly SignedCapability[]): Promise<void>;
2753
+ /** Drop all capabilities and persist the empty bag. */
2754
+ clear(): Promise<void>;
2755
+ private _hydrate;
2756
+ private _persist;
2757
+ }
2758
+ //#endregion
2759
+ //#region src/identity/principal.d.ts
2760
+ /**
2761
+ * A signing identity bundled with its durable capability set. The
2762
+ * {@link SigningIdentity} is fixed for the life of the principal; the
2763
+ * {@link CapBag} is mutable and extensible — caps accumulate as the peer grants
2764
+ * them.
2765
+ *
2766
+ * Transient, per-call (one-shot) grants are deliberately NOT part of a
2767
+ * principal: that is a separate policy, see `OneShotCapStaging`.
2768
+ *
2769
+ * Lives in its own module (rather than alongside `SigningSender`) so the
2770
+ * `SigningSender` ⇄ `createManagedPrincipal` factory cycle does not run through
2771
+ * a top-level `class … extends Principal`: such a cycle would hit a TDZ
2772
+ * ("Class extends value undefined") depending on module evaluation order.
2773
+ */
2774
+ declare class Principal {
2775
+ readonly identity: SigningIdentity;
2776
+ readonly capBag: CapBag;
2777
+ static create(identity: SigningIdentity, capabilities?: readonly SignedCapability[]): Promise<Principal>;
2778
+ constructor(identity: SigningIdentity, capBag: CapBag);
2779
+ get id(): PrincipalId;
2780
+ }
2781
+ //#endregion
2782
+ //#region src/identity/managedPrincipal.d.ts
2783
+ /**
2784
+ * A {@link Principal} that also exposes the executor-backed per-identity
2785
+ * {@link ManagedIdentityStorage}. Returned by {@link createManagedPrincipal}
2786
+ * so callers can persist their own app state (e.g. a resolved serviceId)
2787
+ * alongside the granted capabilities, using the very same durable store the
2788
+ * {@link CapBag} hydrates from — no second storage wiring required.
2789
+ */
2790
+ declare class PrincipalWithStore extends Principal {
2791
+ readonly store: ManagedIdentityStorage;
2792
+ readonly identity: Identity;
2793
+ constructor(identity: Identity, capBag: CapBag, store: ManagedIdentityStorage);
2794
+ }
2795
+ /**
2796
+ * Executor-managed principal: the peer signs for us through its
2797
+ * `identity::sign` overlay (we never hold a private key). Bootstrapped purely
2798
+ * from the outbound `sender` — no side effects on any connection — and caps
2799
+ * persist in the executor-backed per-identity storage. Works over any
2800
+ * transport whose peer serves the identity overlay (hub *or* stdio).
2801
+ *
2802
+ * Call this exactly once per channel: it performs the `identity::*` handshake
2803
+ * and hydrates the {@link CapBag} from storage. The returned
2804
+ * {@link PrincipalWithStore} additionally surfaces that same durable
2805
+ * {@link ManagedIdentityStorage} as `store`.
2806
+ */
2807
+ declare function createManagedPrincipal(sender: IRequestSender<unknown>): Promise<PrincipalWithStore>;
2808
+ //#endregion
2809
+ //#region src/identity/signingSender.d.ts
2810
+ /**
2811
+ * Per-outbound-call hook. Sees every signed call this sender makes,
2812
+ * and gets a chance to:
2813
+ * - attach capabilities (the common case),
2814
+ * - override `method` / `params` / `interfaceHash` (rewriting,
2815
+ * auditing, schema-pinning),
2816
+ * - advance `signedAtMs` (e.g. after a slow consent prompt that needs
2817
+ * to issue a cap bound to a fresher timestamp than the sender's
2818
+ * initial wall-clock).
2819
+ *
2820
+ * `signer` and `nonce` are NOT overridable. `signer` is the call's
2821
+ * identity; `nonce` ties any cap to this specific call attempt and must
2822
+ * not drift between the cap-issuance request and the call itself.
2823
+ */
2824
+ type CapProvider = (req: {
2825
+ readonly method: string;
2826
+ readonly params: JsonValue | undefined;
2827
+ readonly signer: PrincipalId;
2828
+ readonly nonce: string;
2829
+ readonly signedAtMs: number;
2830
+ readonly interfaceHash?: string;
2831
+ }) => Promise<CapProviderResult>;
2832
+ interface CapProviderResult {
2833
+ readonly capabilities?: readonly SignedCapability[];
2834
+ /** Override the wire method this sender signs. Default: the original. */
2835
+ readonly method?: string;
2836
+ /** Override the params this sender signs. Default: the original. */
2837
+ readonly params?: JsonValue;
2838
+ /** Override the interfaceHash baked into the signed envelope. */
2839
+ readonly interfaceHash?: string;
2840
+ /** Advance the Unix-ms timestamp baked into the signed envelope. */
2841
+ readonly signedAtMs?: number;
2842
+ }
2843
+ /**
2844
+ * Per-call ctx the {@link SigningSender} consumes. All fields are
2845
+ * optional; the sender's persistent {@link SigningSenderConfig.principal} is
2846
+ * the default.
2847
+ *
2848
+ * To install a signer after the sender is already constructed (e.g. a
2849
+ * managed-identity bootstrap), mutate the caller-owned config object — it is
2850
+ * read fresh on every call. No setter on the sender itself.
2851
+ */
2852
+ interface SigningCallCtx {
2853
+ /**
2854
+ * Override the signer for this call only. Pass `null` to skip
2855
+ * signing entirely (plain unsigned JSON-RPC). Bootstrap flows that
2856
+ * must talk to `identity::*` before a managed signer is available
2857
+ * use `signerOverride: null` for those calls.
2858
+ */
2859
+ readonly signerOverride?: SigningIdentity | null;
2860
+ /**
2861
+ * Replace whatever caps the persistent cap provider would attach.
2862
+ * Skips the persistent provider for this call.
2863
+ */
2864
+ readonly capsOverride?: readonly SignedCapability[];
2865
+ /**
2866
+ * Reserved for the perm-denied / consent retry path. Currently a
2867
+ * passthrough — sender does not act on it yet.
2868
+ */
2869
+ readonly requestPermissionWhenDenied?: boolean;
2870
+ }
2871
+ /**
2872
+ * Persistent config for a {@link SigningSender}.
2873
+ *
2874
+ * `principal` is the call identity plus its durable, extensible capability
2875
+ * set. `oneShotCaps` is an optional side-policy that may stage a single-use
2876
+ * capability onto the very next call without touching the principal. Both
2877
+ * fields are read fresh on every call, so callers may install or swap them
2878
+ * after the sender has been constructed.
2879
+ *
2880
+ * A missing `principal` means "no signing / no caps" for that call, unless
2881
+ * overridden via {@link SigningCallCtx}.
2882
+ */
2883
+ interface SigningSenderConfig {
2884
+ /** Identity + persistent (extensible) capabilities. */
2885
+ readonly principal?: Principal;
2886
+ /**
2887
+ * Optional per-call capability provider. Runs at sign-time with the
2888
+ * concrete method/params/nonce/timestamp and may return caps and/or
2889
+ * signing overrides.
2890
+ */
2891
+ readonly capProvider?: CapProvider;
2892
+ /**
2893
+ * Optional one-shot capability staging policy. Independent of the
2894
+ * principal; drained per outbound signed call.
2895
+ */
2896
+ readonly oneShotCaps?: OneShotCapStaging;
2897
+ }
2898
+ /**
2899
+ * Side-policy for staging *one-shot* capabilities onto the next outbound
2900
+ * signed call, independent of any {@link Principal}. The {@link SigningSender}
2901
+ * drains the staged caps after attaching them once, so a spent cap never
2902
+ * leaks into a later call.
2903
+ *
2904
+ * Requesting the one-shot grant (prompting the user / hub) lives next to —
2905
+ * not inside — the principal: the principal owns identity and durable
2906
+ * capabilities; this owns the transient per-call grant.
2907
+ */
2908
+ declare class OneShotCapStaging {
2909
+ private _staged;
2910
+ /** Stage caps for the next signed call. Replaces any still-pending caps. */
2911
+ stage(caps: readonly SignedCapability[]): void;
2912
+ /**
2913
+ * Take (and clear) the staged caps. Called by {@link SigningSender} once
2914
+ * per outbound signed call.
2915
+ */
2916
+ take(): readonly SignedCapability[];
2917
+ }
2918
+ /**
2919
+ * Outbound sender decorator that wraps every call in a `$hubrpc` signed
2920
+ * envelope and (optionally) attaches capabilities. Stateless w.r.t. signing
2921
+ * config — the {@link Principal} and {@link OneShotCapStaging} are resolved
2922
+ * per-call from {@link SigningSenderConfig}, so the caller can install or
2923
+ * swap them after construction by mutating that object.
2924
+ */
2925
+ /**
2926
+ * The result of {@link SigningSender.fromChannelWithManagedPrincipal} /
2927
+ * {@link SigningSender.fromTransportWithManagedPrincipal}: a signing
2928
+ * {@link Channel} ready for `LinkRpcConnection`, plus the executor-managed
2929
+ * {@link PrincipalWithStore} that drives it (caps, per-identity storage, nodeId).
2930
+ */
2931
+ interface ManagedSigningChannel<TInCtx = undefined> {
2932
+ readonly channel: Channel<TInCtx, SigningCallCtx>;
2933
+ readonly principal: PrincipalWithStore;
2934
+ }
2935
+ declare class SigningSender<TInCtx = unknown> implements IRequestSender<SigningCallCtx> {
2936
+ private readonly _inner;
2937
+ private readonly _config;
2938
+ /**
2939
+ * Wrap an inner channel with signing. Composes via {@link Channel.withSender}
2940
+ * so the resulting `Channel<TInCtx, SigningCallCtx>` plugs into
2941
+ * `LinkRpcConnection`.
2942
+ */
2943
+ static wrapChannel<TInCtx>(inner: Channel<TInCtx, unknown>, config: SigningSenderConfig): Channel<TInCtx, SigningCallCtx>;
2944
+ /**
2945
+ * Bootstrap an executor-managed {@link Principal} over the **unsigned**
2946
+ * `channel`, then wrap that same channel with signing driven by it.
2947
+ *
2948
+ * Crucially, the `identity::*` handshake that mints the managed principal
2949
+ * rides the *raw* channel (`channel.sender`), so those bootstrap calls are
2950
+ * themselves never signed — there is no "sign the sign call" recursion and
2951
+ * no reliance on threading `signerOverride: null` through every transport
2952
+ * layer. The returned signing {@link Channel} is what callers hand to
2953
+ * `LinkRpcConnection`; the {@link PrincipalWithStore} is returned alongside
2954
+ * for caps / per-identity storage / nodeId.
2955
+ */
2956
+ static fromChannelWithManagedPrincipal<TInCtx>(channel: Channel<TInCtx, unknown>, config?: Omit<SigningSenderConfig, 'principal'>): Promise<ManagedSigningChannel<TInCtx>>;
2957
+ /**
2958
+ * Convenience over {@link fromChannelWithManagedPrincipal}: build the
2959
+ * unsigned {@link JsonRpcChannel} from `transport` first. The common entry
2960
+ * point for app hosts / services that own a raw {@link IMessageTransport}.
2961
+ */
2962
+ static fromTransportWithManagedPrincipal(transport: IMessageTransport, config?: Omit<SigningSenderConfig, 'principal'>): Promise<ManagedSigningChannel<undefined>>;
2963
+ constructor(_inner: IRequestSender<unknown>, _config: SigningSenderConfig);
2964
+ sendRequest(method: string, params: JsonValue | undefined, opts?: SendOpts<SigningCallCtx>): Promise<JsonValue>;
2965
+ sendNotification(method: string, params: JsonValue | undefined, opts?: SendOpts<SigningCallCtx>): Promise<void>;
2966
+ sendRequestWithStream(method: string, params: JsonValue | undefined, opts?: StreamSendOpts<SigningCallCtx>): RawStreamingCall;
2967
+ close(): void;
2968
+ private _prepareOutbound;
2969
+ private _resolveSigner;
2970
+ private _createSigningCoordinates;
2971
+ private _resolveIntentAndCapabilities;
2972
+ private _signPreparedCall;
2973
+ }
2974
+ declare namespace crypto_d_exports {
2975
+ export { generateKeypair, generateX25519Keypair, hpkeOpen, hpkeSeal, keypairFromSeed, sha256, sign, verify, x25519KeypairFromSeed };
2976
+ }
2977
+ /** Generate a fresh Ed25519 keypair (raw 32-byte seed + 32-byte public key). */
2978
+ declare function generateKeypair(): Promise<Keypair>;
2979
+ /**
2980
+ * Deterministically derive an Ed25519 keypair from a raw 32-byte seed. For
2981
+ * tests / reproducible identities only — production keys must be random
2982
+ * (use {@link generateKeypair}).
2983
+ */
2984
+ declare function keypairFromSeed(seed: Uint8Array): Promise<Keypair>;
2985
+ /**
2986
+ * Deterministically derive an X25519 keypair from a raw 32-byte scalar. For
2987
+ * tests / reproducible identities only.
2988
+ */
2989
+ declare function x25519KeypairFromSeed(seed: Uint8Array): Promise<X25519Keypair>;
2990
+ /** Ed25519 sign `message` with a raw 32-byte seed private key. */
2991
+ declare function sign(privateKey: PrivateKey, message: Uint8Array): Promise<Signature>;
2992
+ /** Ed25519 verify. Returns `false` (never throws) on malformed input. */
2993
+ declare function verify(publicKey: PublicKey, message: Uint8Array, sig: Signature): Promise<boolean>;
2994
+ /** Generate a fresh X25519 keypair (raw 32-byte scalar + 32-byte public key). */
2995
+ declare function generateX25519Keypair(): Promise<X25519Keypair>;
2996
+ /**
2997
+ * HPKE-base-mode single-shot seal. Output blob layout is
2998
+ * `enc (32 B) || ciphertext || tag (16 B)`; `domain` is bound into both the
2999
+ * HPKE `info` parameter and the AEAD AAD.
3000
+ */
3001
+ declare function hpkeSeal(args: {
3002
+ readonly recipientPublicKey: Uint8Array;
3003
+ readonly domain: Uint8Array;
3004
+ readonly plaintext: Uint8Array;
3005
+ }): Promise<Uint8Array>;
3006
+ /**
3007
+ * HPKE-base-mode single-shot open. Throws on any tag failure (wrong domain,
3008
+ * wrong recipient key, or tampered blob); the error deliberately does NOT
3009
+ * distinguish these cases.
3010
+ */
3011
+ declare function hpkeOpen(args: {
3012
+ readonly recipientPrivateKey: Uint8Array;
3013
+ readonly domain: Uint8Array;
3014
+ readonly blob: Uint8Array;
3015
+ }): Promise<Uint8Array>;
3016
+ /** SHA-256 digest (synchronous, dependency-free). */
3017
+ declare function sha256(bytes: Uint8Array): Uint8Array;
3018
+ //#endregion
3019
+ //#region src/identity/identity.interfaces.d.ts
3020
+ /**
3021
+ * Per-participant key oracle. Reached on the participant's root overlay
3022
+ * (form-2 method names like `identity::sign`). Private key material lives
3023
+ * in the executor; the participant only sees the operations.
3024
+ *
3025
+ * Wire shape:
3026
+ * sign / wrap / unwrap all take and return base64url-encoded bytes.
3027
+ * `domain` is a caller-chosen string bound into HPKE info and the AEAD
3028
+ * AAD. `unwrap` succeeds only when invoked with the exact `domain` that
3029
+ * `wrap` was called with. Use a stable, namespaced string (e.g.
3030
+ * `secrets.vault.master-key.v1`).
3031
+ */
3032
+ declare const identityInterface: InterfaceDefinition<{
3033
+ getPrincipal: RequestType<Record<string, never>, {
3034
+ principal: string;
3035
+ }, any, never, never>;
3036
+ getWrapPublicKey: RequestType<Record<string, never>, {
3037
+ wrapPublicKey: string;
3038
+ }, any, never, never>;
3039
+ sign: RequestType<{
3040
+ bytes: string;
3041
+ }, {
3042
+ signature: string;
3043
+ }, any, never, never>;
3044
+ wrap: RequestType<{
3045
+ domain: string;
3046
+ bytes: string;
3047
+ }, {
3048
+ blob: string;
3049
+ }, any, never, never>;
3050
+ unwrap: RequestType<{
3051
+ domain: string;
3052
+ blob: string;
3053
+ }, {
3054
+ bytes: string;
3055
+ }, any, never, never>;
3056
+ }>;
3057
+ /**
3058
+ * Per-identity persistent key/value store. Reached on the participant's
3059
+ * root overlay as `identity.storage::get` etc. — same overlay that serves
3060
+ * `identity::*`, same single-participant addressability.
3061
+ *
3062
+ * Storage scope is the executor's managed-identity slot (e.g.
3063
+ * `service:demo`). Lifecycle is bound to the identity: when the executor
3064
+ * deletes the identity for a slot, the storage for that slot is wiped in
3065
+ * the same operation. New identity issued for the same slot starts empty.
3066
+ *
3067
+ * The executor encrypts the backing file at rest with the same secret it
3068
+ * uses for identity files — see {@link IdentityKeystore} in
3069
+ * `@hediet/linkrpc/node`.
3070
+ *
3071
+ * Keys must match `^[A-Za-z0-9._/-]{1,256}$`. `/` is conventional for
3072
+ * namespacing (`caps.v1`, `prefs/foo`) and `list({ prefix })` honours
3073
+ * that. Values are arbitrary JSON.
3074
+ */
3075
+ declare const identityStorageInterface: InterfaceDefinition<{
3076
+ get: RequestType<{
3077
+ key: string;
3078
+ }, {
3079
+ value?: unknown;
3080
+ }, any, never, never>;
3081
+ set: RequestType<{
3082
+ key: string;
3083
+ value: unknown;
3084
+ }, Record<string, never>, any, never, never>;
3085
+ delete: RequestType<{
3086
+ key: string;
3087
+ }, {
3088
+ existed: boolean;
3089
+ }, any, never, never>;
3090
+ list: RequestType<{
3091
+ prefix?: string | undefined;
3092
+ }, {
3093
+ keys: string[];
3094
+ }, any, never, never>;
3095
+ }>;
3096
+ //#endregion
3097
+ //#region src/identity/signedRpcEnvelope.d.ts
3098
+ interface SignRpcCallOptions {
3099
+ readonly method: string;
3100
+ /** The user's params. Must be a plain JSON object or `undefined` (else throws). */
3101
+ readonly params?: JsonValue;
3102
+ /** Identity that produces the signature. */
3103
+ readonly signingIdentity: SigningIdentity;
3104
+ /** Unix milliseconds. Defaults to `Date.now()`. */
3105
+ readonly nowMs?: number;
3106
+ /** Override the random nonce (testing). */
3107
+ readonly nonce?: Uint8Array;
3108
+ /** Optional schema hash assertion. */
3109
+ readonly interfaceHash?: string;
3110
+ }
3111
+ interface SignedRpcCall {
3112
+ /**
3113
+ * Wire params for the JSON-RPC request: the user's params merged with
3114
+ * `$hubrpc` (signed meta) and `$hubrpcSignature` (the `call` signature).
3115
+ * Capabilities are attached separately via {@link attachCapabilities}
3116
+ * since they are unsigned authority hints, not part of what the
3117
+ * signature commits to.
3118
+ */
3119
+ readonly wireParams: LinkRpcWireParams;
3120
+ /** The signed call meta embedded under `$hubrpc`. */
3121
+ readonly callMeta: CallMeta;
3122
+ /** The call's content hash (`signedHash("call", signedParams)`) — what `callBind` binds to. */
3123
+ readonly callHash: Base64Sha256;
3124
+ }
3125
+ /**
3126
+ * Sign a single JSON-RPC call. Produces the wire-form params with the
3127
+ * `$hubrpc` (signed meta) and `$hubrpcSignature.call` envelopes attached,
3128
+ * plus the call content hash.
3129
+ */
3130
+ declare function signRpcCall(opts: SignRpcCallOptions): Promise<SignedRpcCall>;
3131
+ /**
3132
+ * Attach capabilities to a {@link SignedRpcCall.wireParams}. Capabilities
3133
+ * ride in `$hubrpcUnsigned.capabilities` — they are NOT part of what the
3134
+ * signature commits to (which is why this is a separate step). Returns a
3135
+ * new wireParams object; the input is not mutated.
3136
+ */
3137
+ declare function attachCapabilities(wireParams: LinkRpcWireParams, capabilities: readonly SignedCapability[]): LinkRpcWireParams;
3138
+ interface VerifyRpcCallOptions {
3139
+ readonly wireMethod: string;
3140
+ /** Raw params object received on the wire. */
3141
+ readonly wireParams: unknown;
3142
+ /** Defaults to `Date.now()`. */
3143
+ readonly nowMs?: number;
3144
+ /** Max clock skew in milliseconds. Default 300000 (5 min). */
3145
+ readonly maxSkewMs?: number;
3146
+ /** When `true`, reject calls lacking a signed envelope + signature. */
3147
+ readonly requireSigned?: boolean;
3148
+ }
3149
+ type VerifyRpcCallResult = {
3150
+ readonly ok: true;
3151
+ /** `undefined` when the call had no signed (`$hubrpc` + `$hubrpcSignature.call`) envelope. */
3152
+ readonly identity: undefined | {
3153
+ readonly callMeta: CallMeta;
3154
+ /** The authenticated principal (`callMeta.principal`). */
3155
+ readonly signer: PrincipalId;
3156
+ /** The call's content hash — input to `callBind.payloadHash`. */
3157
+ readonly callHash: Base64Sha256;
3158
+ readonly capabilities: SignedCapability[];
3159
+ };
3160
+ /** Params the handler should see (user params with the reserved keys stripped). */
3161
+ readonly params: JsonValue | undefined;
3162
+ } | {
3163
+ readonly ok: false;
3164
+ readonly reason: string;
3165
+ };
3166
+ /**
3167
+ * Verify the identity envelope on a JSON-RPC call. Does **not** evaluate
3168
+ * capability chains or caveats — that is the hub / authoriser's job.
3169
+ *
3170
+ * A signed call carries `$hubrpc` (with `principal`) and a `call` signature
3171
+ * under `$hubrpcSignature`. The signature is checked against
3172
+ * `signingInput("call", wireParams)` (the reserved keys are stripped by the
3173
+ * signed-object standard). Bare/unsigned calls return `identity: undefined`.
3174
+ */
3175
+ declare function verifyRpcCall(opts: VerifyRpcCallOptions): Promise<VerifyRpcCallResult>;
3176
+ //#endregion
3177
+ //#region src/identity/metaEnvelope.d.ts
3178
+ /** Plain JSON object with optional values — the wire shape JSON-RPC params take. */
3179
+ type JsonObject = {
3180
+ [key: string]: JsonValue | undefined;
3181
+ };
3182
+ interface SignParamsOptions {
3183
+ method: string;
3184
+ /** Caller-supplied params (without identity envelopes). Must be an object or undefined. */
3185
+ params: JsonObject | undefined;
3186
+ /** Identity that produces the signature. */
3187
+ signingIdentity: SigningIdentity;
3188
+ /**
3189
+ * Caps to attach. They are NOT signed — they ride in `$hubrpcUnsigned`.
3190
+ */
3191
+ capabilities?: readonly SignedCapability[];
3192
+ /** Unix milliseconds; defaults to `Date.now()`. */
3193
+ nowMs?: number;
3194
+ /** Override nonce (testing); otherwise 16 random bytes. */
3195
+ nonce?: Uint8Array;
3196
+ /** Stamped into the signed envelope as `interfaceHash`. */
3197
+ interfaceHash?: string;
3198
+ }
3199
+ /**
3200
+ * Returns a wire-form params object carrying the `$hubrpc` envelope, the
3201
+ * `call` signature under `$hubrpcSignature`, and (optionally) capabilities
3202
+ * under `$hubrpcUnsigned`.
3203
+ */
3204
+ declare function signParams(opts: SignParamsOptions): Promise<JsonObject>;
3205
+ interface VerifyCallOptions {
3206
+ method: string;
3207
+ /** Raw params as received on the wire. Carries `$hubrpc` + `$hubrpcSignature` when signed. */
3208
+ params: unknown;
3209
+ /** Decode the method string into the call's target address. */
3210
+ parseMethod: (method: string) => CallTarget;
3211
+ nowMs?: number;
3212
+ /** Max clock skew in milliseconds. Default 300000 (±5min). */
3213
+ maxSkewMs?: number;
3214
+ /** Reject if no capability is presented. */
3215
+ requireCapability?: boolean;
3216
+ }
3217
+ type VerifyResult = {
3218
+ ok: true;
3219
+ signer: PrincipalId;
3220
+ /**
3221
+ * The resolved, authenticated call — the unit `permits()` judges.
3222
+ * Authorization is intentionally NOT done here; the gate owns it
3223
+ * (and the replay ledger).
3224
+ */
3225
+ call: Call;
3226
+ /** Params with the reserved keys stripped — pass this to the actual handler. */
3227
+ strippedParams: Record<string, unknown> | undefined;
3228
+ /** Leaf + parent capabilities to hand to `permits()`. */
3229
+ capabilities: SignedCapability[];
3230
+ /** Per-call nonce extracted from the envelope (for replay-protection ledgers). */
3231
+ nonce: string;
3232
+ /** The call's content hash — input to `callBind.payloadHash`. */
3233
+ callHash: Base64Sha256;
3234
+ /** The `$hubrpc` envelope as received. */
3235
+ callMeta: CallMeta;
3236
+ /** Schema-version assertion the caller stamped. */
3237
+ interfaceHash: string | undefined;
3238
+ } | {
3239
+ ok: false;
3240
+ /**
3241
+ * Failure category:
3242
+ * - `"capability"` — the call shape was fine; the caller needs to
3243
+ * acquire (or present) a capability. Hub should surface this as
3244
+ * `permissionRequired` so consumers know to negotiate access.
3245
+ * - `"envelope"` — anything else (missing/bad signature, replay,
3246
+ * malformed nonce, etc). Hub should surface as `invalidRequest`.
3247
+ */
3248
+ kind: "capability" | "envelope";
3249
+ reason: string;
3250
+ };
3251
+ declare function verifyCall(opts: VerifyCallOptions): Promise<VerifyResult>;
3252
+ //#endregion
3253
+ //#region src/identity/seededPrincipal.d.ts
3254
+ interface SeededPrincipalOptions {
3255
+ /** Numeric seed; the same value always yields the same identity / principal. */
3256
+ readonly seed: number;
3257
+ }
3258
+ /**
3259
+ * Build a **random**, in-memory {@link Principal}: a fresh Ed25519 signing
3260
+ * identity + X25519 wrapping key, paired with an empty memory-only
3261
+ * {@link CapBag}. Full-entropy (unlike {@link createSeededMemoryPrincipal}), so
3262
+ * it is safe to sign trusted calls — e.g. an in-process "agent" identity a hub
3263
+ * admin delegates read authority to (via a minted capability) for directory
3264
+ * discovery. The identity is ephemeral: it vanishes with the process.
3265
+ */
3266
+ declare function createMemoryPrincipal(): Promise<Principal>;
3267
+ /**
3268
+ * Build a deterministic {@link Principal} from a numeric seed: a reproducible
3269
+ * Ed25519 signing identity (so the nodeId is stable across runs) plus a matching
3270
+ * X25519 wrapping key, paired with an empty, memory-only {@link CapBag}.
3271
+ *
3272
+ * For tests and reproducible local setups ONLY — the key material is derived
3273
+ * from a low-entropy seed and must never be used to sign anything trusted.
3274
+ */
3275
+ declare function createSeededMemoryPrincipal(opts: SeededPrincipalOptions): Promise<Principal>;
3276
+ /**
3277
+ * Derive a deterministic {@link KeypairSigningIdentity} from a numeric seed: a
3278
+ * reproducible Ed25519 signing identity (so the nodeId is stable across runs),
3279
+ * with no wrapping key. Use it where only signing/issuing is needed — e.g. a
3280
+ * hub admin `issuer` that mints capabilities in tests.
3281
+ *
3282
+ * For tests and reproducible local setups ONLY — the key material is derived
3283
+ * from a low-entropy seed and must never be used to sign anything trusted.
3284
+ */
3285
+ declare function createSeededSigningIdentity(opts: SeededPrincipalOptions): Promise<KeypairSigningIdentity>;
3286
+ //#endregion
3287
+ //#region src/hub/common/reflection.interfaces.d.ts
3288
+ declare const defaultsInterface: InterfaceDefinition<{
3289
+ get: RequestType<Record<string, never>, {
3290
+ serviceId?: string | undefined;
3291
+ interfaceId?: string | undefined;
3292
+ interfaceHash?: string | undefined;
3293
+ }, any, never, never>;
3294
+ listBindings: RequestType<Record<string, never>, {
3295
+ bindings: {
3296
+ prefix: string;
3297
+ interfaceId: string;
3298
+ interfaceHash: string;
3299
+ serviceId?: string | undefined;
3300
+ }[];
3301
+ }, any, never, never>;
3302
+ }>;
3303
+ /**
3304
+ * A single root-principal requirement. `transitive: true` means the requirement
3305
+ * also applies to every service reachable *through* this one — i.e. when this
3306
+ * listing is a `hubrpc.directory` reference, everything it lists inherits the
3307
+ * requirement (also as transitive).
3308
+ */
3309
+ declare const zRootPrincipalReq: import("zod/mini").ZodMiniObject<{
3310
+ principal: import("zod/mini").ZodMiniString<string>;
3311
+ transitive: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniBoolean<boolean>>;
3312
+ }, import("zod/v4/core").$strip>;
3313
+ /** One OR-set. The set is satisfied by holding *any one* of its principals. */
3314
+ declare const zRootPrincipalSet: import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
3315
+ principal: import("zod/mini").ZodMiniString<string>;
3316
+ transitive: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniBoolean<boolean>>;
3317
+ }, import("zod/v4/core").$strip>>;
3318
+ type RootPrincipalReq = output<typeof zRootPrincipalReq>;
3319
+ type RootPrincipalSet = output<typeof zRootPrincipalSet>;
3320
+ declare const zServiceIdPattern: import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniObject<{
3321
+ exact: import("zod/mini").ZodMiniString<string>;
3322
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
3323
+ prefix: import("zod/mini").ZodMiniString<string>;
3324
+ }, import("zod/v4/core").$strip>]>;
3325
+ type ServiceIdPattern = output<typeof zServiceIdPattern>;
3326
+ declare const directoryInterface: InterfaceDefinition<{
3327
+ list: RequestType<{
3328
+ interfaceId?: string | undefined;
3329
+ interfaceIdPrefix?: string | undefined;
3330
+ serviceId?: string | undefined;
3331
+ serviceIdScopes?: ({
3332
+ exact: string;
3333
+ } | {
3334
+ prefix: string;
3335
+ })[] | undefined;
3336
+ cursor?: string | undefined;
3337
+ limit?: number | undefined;
3338
+ timeoutMs?: number | undefined;
3339
+ }, {
3340
+ items: {
3341
+ serviceId: string;
3342
+ interfaceId: string;
3343
+ interfaceHash: string;
3344
+ serviceDescription?: string | undefined;
3345
+ rootPrincipalSets?: {
3346
+ principal: string;
3347
+ transitive?: boolean | undefined;
3348
+ }[][] | undefined;
3349
+ reachableServiceIds?: ({
3350
+ exact: string;
3351
+ } | {
3352
+ prefix: string;
3353
+ })[] | undefined;
3354
+ }[];
3355
+ nextCursor?: string | undefined;
3356
+ truncated?: boolean | undefined;
3357
+ }, any, never, never>;
3358
+ /**
3359
+ * Coarse change tap on the directory.
3360
+ *
3361
+ * `watch` is a long-lived streaming request that emits an **empty tick**
3362
+ * whenever the (optionally filtered) directory *might* have changed. The
3363
+ * tick carries no delta and no payload — its only meaning is "re-`list`
3364
+ * now". The consumer reconciles against its own last snapshot.
3365
+ *
3366
+ * This keeps the server stateless: it never computes or replays
3367
+ * per-item deltas, never does an initial-sync replay. Over-emission is
3368
+ * allowed (the consumer re-lists and finds nothing new); under-emission
3369
+ * is not. Ticks are coalesced. The `interfaceId` / `serviceId` filters
3370
+ * mirror `list` and are a relevance hint, not a guarantee.
3371
+ *
3372
+ * The request resolves when the caller cancels (or the connection
3373
+ * drops); the runtime auto-detaches the stream when it settles.
3374
+ */
3375
+ watch: RequestType<{
3376
+ interfaceId?: string | undefined;
3377
+ interfaceIdPrefix?: string | undefined;
3378
+ serviceId?: string | undefined;
3379
+ serviceIdScopes?: ({
3380
+ exact: string;
3381
+ } | {
3382
+ prefix: string;
3383
+ })[] | undefined;
3384
+ }, Record<string, never>, void, any, Record<string, never>>;
3385
+ }>;
3386
+ /**
3387
+ * A `directoryInterface.watch` handler for a **static** directory. It opens the
3388
+ * stream, never ticks, and resolves when the caller cancels. Dynamic providers,
3389
+ * including {@link LinkRpcConnection.enableReflection}, use a change-emitting
3390
+ * implementation instead.
3391
+ */
3392
+ declare function directoryWatchNever(_params: {
3393
+ interfaceId?: string;
3394
+ interfaceIdPrefix?: string;
3395
+ serviceId?: string;
3396
+ serviceIdScopes?: ServiceIdPattern[];
3397
+ }, _ctx: unknown, stream: StreamApi<unknown, Record<string, never>>): Promise<Record<string, never>>;
3398
+ declare const schemasInterface: InterfaceDefinition<{
3399
+ get: RequestType<{
3400
+ interfaceId: string;
3401
+ hash?: string | undefined;
3402
+ }, {
3403
+ schema: unknown;
3404
+ }, any, never, never>;
3405
+ }>;
3406
+ //#endregion
3407
+ //#region src/connection/linkRpcConnection.d.ts
3408
+ interface LinkRpcConnectionOptions {
3409
+ /** Topology node/port ID generator. Defaults to cryptographic randomness. */
3410
+ readonly generateTopologyId?: TopologyIdGenerator;
3411
+ /**
3412
+ * Validate parameters passed through typed interface clients before sending
3413
+ * them. Enabled by default. Disable only when interoperating with a peer
3414
+ * whose accepted wire shape intentionally differs from the local schema.
3415
+ */
3416
+ readonly validateOutboundParams?: boolean;
3417
+ }
3418
+ /**
3419
+ * High-level linkrpc connection. Layers method-name routing and zod-driven
3420
+ * validation on top of a plain JSON-RPC channel.
3421
+ *
3422
+ * Typed proxies built by this class merely forward each call's
3423
+ * `interfaceHash` hint to the channel so the signer stamps it into the
3424
+ * `$hubrpc` envelope.
3425
+ *
3426
+ * `TInCtx` is the per-call out-of-band context the connection's transport
3427
+ * carries. Default `undefined` covers cross-process and ordinary in-process
3428
+ * transports. The hub's self/overlay connections instantiate with a
3429
+ * concrete `TInCtx` (e.g. `Participant`) so handlers can see who originated
3430
+ * the call.
3431
+ *
3432
+ * `TOutCtx` is the per-call override / extension bag the outbound sender
3433
+ * understands (see {@link SendOpts.ctx}). It only ever flows into the
3434
+ * sender as input, so it is a contravariant type parameter. Default `any`
3435
+ * keeps the bare `LinkRpcConnection` a valid supertype for holders that do
3436
+ * not care about the outbound ctx; pass a concrete shape (e.g.
3437
+ * `SigningCallCtx`) to get precise {@link get} typing. The connection
3438
+ * itself is agnostic to its contents — it merely forwards the `ctx`
3439
+ * defaults supplied to {@link get}.
3440
+ */
3441
+ declare class LinkRpcConnection<TInCtx = any, TOutCtx = any> {
3442
+ /**
3443
+ * Convenience: build a {@link JsonRpcChannel} `Channel` from the
3444
+ * given transport and wrap it in an `LinkRpcConnection`. Use this
3445
+ * when you have a transport at hand and don't need a decorator
3446
+ * stack (e.g. signing).
3447
+ */
3448
+ static fromTransport<TInCtx = undefined>(transport: IMessageTransport<MessageWithCtx<TInCtx>, JsonRpcMessage>, options?: LinkRpcConnectionOptions): LinkRpcConnection<TInCtx>;
3449
+ /** Underlying JSON-RPC sender — useful for callers that need raw access (e.g. to call hub-served methods that bypass the interface registry). */
3450
+ readonly channel: IRequestSender<TOutCtx>;
3451
+ /** key = `${serviceId ?? ""}::${interfaceId}` */
3452
+ private readonly _registry;
3453
+ /** Descriptions for services that have been registered with a `serviceDescription`. */
3454
+ private readonly _serviceDescriptions;
3455
+ /** Root-node-id requirement sets recorded per serviceId. */
3456
+ private readonly _serviceRootPrincipalSets;
3457
+ private readonly _directoryWatchers;
3458
+ private readonly _directoryListeners;
3459
+ private _inspection;
3460
+ private _trafficInspector;
3461
+ private readonly _serviceInspectionRegistrations;
3462
+ private readonly _wireChannel;
3463
+ private readonly _validateOutboundParams;
3464
+ /** Bare-method bindings, keyed by their exact wire prefix. */
3465
+ private readonly _bareBindings;
3466
+ private readonly _generateTopologyId;
3467
+ /**
3468
+ * Construct from a {@link Channel} (binds the inbound handler and uses
3469
+ * `channel.sender` for outbound calls) or from a bare
3470
+ * {@link IRequestSender} (send-only — no inbound handler is registered,
3471
+ * useful for bootstrap flows like `createManagedIdentity`).
3472
+ */
3473
+ constructor(channel: Channel<TInCtx, TOutCtx> | IRequestSender<TOutCtx>, options?: LinkRpcConnectionOptions);
3474
+ /** Get a typed metadata-free client for a bundled bare interface target. */
3475
+ get<TDef extends InterfaceDefinition<any>>(target: BareInterfaceTarget<TDef>): InterfaceClient<TDef>;
3476
+ /** Get a typed client for `iface`, routed to the implicit (root) service. */
3477
+ get<TDef extends InterfaceDefinition<any>>(iface: TDef, opts?: GetOptions<TOutCtx>): InterfaceClient<TDef>;
3478
+ /**
3479
+ * Get a typed client that emits foreign-protocol bare method names.
3480
+ * Unlike {@link get}, these calls carry no LinkRPC interface metadata.
3481
+ */
3482
+ getBare<TDef extends InterfaceDefinition<any>>(iface: TDef, opts?: BareGetOptions): InterfaceClient<TDef>;
3483
+ /** Get a service-scoped handle; all interfaces obtained from it route via `serviceId` (form 3). */
3484
+ service(serviceId: string): ServiceHandle<TInCtx, TOutCtx>;
3485
+ /** Register handlers for an interface on this connection's server side. */
3486
+ register<TDef extends InterfaceDefinition<any>>(iface: TDef, handlers: InterfaceHandlers<TDef, TInCtx>, opts?: RegisterOptions): InterfaceRegistration;
3487
+ private _register;
3488
+ /**
3489
+ * Declare the preset interface for form-1 (bare-method) dispatch. The
3490
+ * interface must already be registered under the root (no serviceId).
3491
+ * Surfaced via `hubrpc.defaults::get`.
3492
+ */
3493
+ setPreset(iface: InterfaceDefinition<any>): void;
3494
+ /**
3495
+ * Bind foreign-protocol bare methods to an already registered interface.
3496
+ * Matching uses the longest prefix; once selected, a missing member does
3497
+ * not fall through to a shorter binding.
3498
+ */
3499
+ bindBare(iface: InterfaceDefinition<any>, opts: {
3500
+ prefix: string;
3501
+ serviceId?: string;
3502
+ }): InterfaceRegistration;
3503
+ /** Snapshot of every interface currently registered on this connection. */
3504
+ listRegisteredInterfaces(): readonly {
3505
+ readonly serviceId: string;
3506
+ readonly interfaceId: string;
3507
+ readonly interfaceHash: string;
3508
+ readonly serviceDescription?: string;
3509
+ readonly rootPrincipalSets?: readonly RootPrincipalSet[];
3510
+ }[];
3511
+ /** Subscribe to coarse local directory changes; listeners must re-list. */
3512
+ onDidChangeDirectory(listener: () => void): () => void;
3513
+ /**
3514
+ * Look up a registered interface definition by id (and optional content
3515
+ * hash). Returns `undefined` if no registered interface matches.
3516
+ */
3517
+ findRegisteredInterface(interfaceId: string, hash?: string): InterfaceDefinition<any> | undefined;
3518
+ /**
3519
+ * Register the three linkrpc reflection interfaces (`defaults`,
3520
+ * `directory`, `schemas`), backed by this connection's live registry.
3521
+ *
3522
+ * By default they live under the root service (form-2 reachable as
3523
+ * `hubrpc.directory::list`). Pass `serviceId` to additionally mount
3524
+ * them under a specific service — useful for participants that live
3525
+ * behind a hub, so callers can reach reflection via form-3
3526
+ * `<serviceId>::hubrpc.directory::list`.
3527
+ *
3528
+ * Idempotent: re-registering the same `(serviceId, interfaceId)` pair
3529
+ * is a no-op.
3530
+ */
3531
+ enableReflection(opts?: {
3532
+ serviceId?: string;
3533
+ }): InterfaceRegistration;
3534
+ private _notifyDirectoryWatchers;
3535
+ /**
3536
+ * Enable the root `hubrpc.node::getNodeId` topology-bootstrap service.
3537
+ *
3538
+ * The generated ids are stable while this registration is active. They are
3539
+ * unauthenticated correlation labels only; callers must not use them for
3540
+ * identity, capability, or authorization decisions.
3541
+ */
3542
+ enableInspection(descriptors?: readonly ParticipantDescriptorSource[]): InspectionRegistration;
3543
+ /** Number of active endpoint traffic stream subscribers. */
3544
+ get trafficObserverCount(): number;
3545
+ close(): void;
3546
+ private _buildClient;
3547
+ private _validateOutboundParamsFor;
3548
+ private _handleRequest;
3549
+ private _buildStreamApi;
3550
+ private _handleNotification;
3551
+ private _parseRouted;
3552
+ private _installServiceInspection;
3553
+ private _removeServiceInspection;
3554
+ private _hasBusinessServiceRegistration;
3555
+ private _endpointGraph;
3556
+ private _watchTraffic;
3557
+ }
3558
+ /**
3559
+ * Options when obtaining a typed client for an interface.
3560
+ *
3561
+ * - `serviceId`: route to a specific service (form 3). Omit for form 2
3562
+ * (implicit / root service on the connection).
3563
+ * - any `TOutCtx` property: a per-client default merged into the `ctx`
3564
+ * of every call issued through the returned proxy (e.g.
3565
+ * `signerOverride`, `capsOverride` for a signing channel). The
3566
+ * connection forwards these verbatim; it does not interpret them.
3567
+ *
3568
+ * Schema-version pinning travels as interface-level call metadata
3569
+ * ({@link SendOpts.interfaceHash}); the typed proxy stamps
3570
+ * `iface.schemaHash` automatically, independent of `TOutCtx`.
3571
+ */
3572
+ type GetOptions<TOutCtx = undefined> = {
3573
+ serviceId?: string;
3574
+ } & Partial<TOutCtx>;
3575
+ /** Options for a metadata-free, bare-method typed client. */
3576
+ interface BareGetOptions {
3577
+ prefix?: string;
3578
+ }
3579
+ interface RegisterOptions {
3580
+ /**
3581
+ * If set, this interface is mounted under this service id (form 3).
3582
+ */
3583
+ serviceId?: string;
3584
+ /**
3585
+ * Optional human description recorded for `serviceId` and surfaced
3586
+ * through `hubrpc.directory::list`. Requires `serviceId`. The first
3587
+ * registration's description wins; any later registration that
3588
+ * supplies a *different* non-undefined description throws.
3589
+ */
3590
+ serviceDescription?: string;
3591
+ /**
3592
+ * Root node ids required to access `serviceId`, in CNF (AND of OR-sets):
3593
+ * the caller must satisfy **every** set, and a set is satisfied by **any
3594
+ * one** of its node ids. Surfaced through `hubrpc.directory::list`.
3595
+ * Requires `serviceId`. Recorded per service; a later registration that
3596
+ * supplies a *different* value for the same `serviceId` throws.
3597
+ */
3598
+ rootPrincipalSets?: readonly RootPrincipalSet[];
3599
+ }
3600
+ /** A live interface registration. Disposing it removes dispatch and reflection state. */
3601
+ interface InterfaceRegistration {
3602
+ /** Remove this exact registration. Idempotent. */
3603
+ dispose(): void;
3604
+ }
3605
+ /** Generated topology identity and its live root-interface registration. */
3606
+ interface InspectionRegistration extends InterfaceRegistration, NodeInfo {
3607
+ /**
3608
+ * Observe this endpoint's full-payload traffic in-process. Wire observation
3609
+ * remains disabled until either this or an RPC traffic watch is active.
3610
+ */
3611
+ observeTraffic(observer: (transit: TrafficTransitEvent) => void): InterfaceRegistration;
3612
+ }
3613
+ /** Service-scoped handle returned by `connection.service(id)`. */
3614
+ declare class ServiceHandle<TInCtx = undefined, TOutCtx = undefined> {
3615
+ private readonly _connection;
3616
+ private readonly _serviceId;
3617
+ constructor(_connection: LinkRpcConnection<TInCtx, TOutCtx>, _serviceId: string);
3618
+ get<TDef extends InterfaceDefinition<any>>(iface: TDef, opts?: Partial<TOutCtx>): InterfaceClient<TDef>;
3619
+ register<TDef extends InterfaceDefinition<any>>(iface: TDef, handlers: InterfaceHandlers<TDef, TInCtx>, opts?: Omit<RegisterOptions, 'serviceId'>): InterfaceRegistration;
3620
+ }
3621
+ //#endregion
3622
+ export { ManagedIdentityStorageBackend as $, DiscriminatorSchema as $i, signedHash as $n, zTopologyLinkEndpoint as $r, Result as $t, VerifyRpcCallResult as A, InterfaceMemberRefMap as Ai, Capability as An, nodeInterface as Ar, WsNoInitEndpoint as At, OneShotCapStaging as B, RequestType as Bi, permissionPermits as Bn, TopologyTransportInfo as Br, ExpBackoffOptions as Bt, VerifyCallOptions as C, JsonValue as Ca, computeInterfaceHash as Ci, ParsedMethodName as Cn, StreamControlReason as Cr, CmdEnvEndpoint as Ct, SignRpcCallOptions as D, InterfaceHandlers as Di, Call as Dn, streamInterface as Dr, ResolvedEndpoint as Dt, verifyCall as E, InterfaceDefinitionOpts as Ei, Ability as En, StreamSendParams as Er, FormatEndpointOptions as Et, identityStorageInterface as F, defineInterface as Fi, TargetPattern as Fn, TopologyLink as Fr, DEFAULT_RPC_TIMEOUT_MS as Ft, createManagedPrincipal as G, zodToSvcJsonSchema as Gi, LINKRPC_META_KEY as Gn, TrafficWatchResult as Gr, Channel as Gt, SigningSender as H, ZodToSvcJsonSchemaOptions as Hi, HUBRPC_META_KEY as Hn, TrafficOverflowEvent as Hr, OnChannelConnect as Ht, crypto_d_exports as I, interfaceFromSchema as Ii, capabilityPermits as In, TopologyLinkEndpoint as Ir, withRpcTimeout as It, CapBagOptions as J, MemberAnnotations as Ji, SignDomain as Jn, zParticipantDescriptor as Jr, IRequestSender as Jt, Principal as K, ErrorSchema as Ki, LINKRPC_SIGNATURE_KEY as Kn, topologyInterface as Kr, ChannelTransport as Kt, CapProvider as L, MemberDocs as Li, hasSignedCapabilityShape as Ln, TopologyNode as Lr, JsonRpcChannel as Lt, signRpcCall as M, StreamApi as Mi, Pattern as Mn, ParticipantDescriptorSource as Mr, isHubEndpoint as Mt, verifyRpcCall as N, StreamCallOptions as Ni, Permission as Nn, RouteClaim as Nr, parseEndpointUri as Nt, SignedRpcCall as O, InterfaceInfo as Oi, CallBind as On, NodeInfo as Or, SocketEndpoint as Ot, identityInterface as P, StreamingCall as Pi, SignedCapability as Pn, TopologyGraph as Pr, CancellableRequest as Pt, ManagedIdentityStorage as Q, ConstSchema as Qi, readSignature as Qn, zTopologyLink as Qr, RawStreamingCall as Qt, CapProviderResult as R, MemberType as Ri, matchParams as Rn, TopologyPort as Rr, ChannelConnector as Rt, SignParamsOptions as S, isResponse as Sa, EXTENSION_PREFIX as Si, stripLinkRpcWireMeta as Sn, STREAM_METHOD as Sr, WrappingIdentity as St, signParams as T, InterfaceDefinition as Ti, parseMethodName as Tn, StreamDir as Tr, EndpointCommand as Tt, SigningSenderConfig as U, notificationType as Ui, HUBRPC_SIGNATURE_KEY as Un, TrafficTransitEndpoint as Ur, BareInterfaceTarget as Ut, SigningCallCtx as V, Schema as Vi, Base64Sha256 as Vn, TrafficEvent as Vr, KeepConnectedHandle as Vt, PrincipalWithStore as W, requestType as Wi, HUBRPC_UNSIGNED_KEY as Wn, TrafficTransitEvent as Wr, bareInterfaceTarget as Wt, InMemoryManagedIdentityStorage as X, ArraySchema as Xi, Signatures as Xn, zRouteClaim as Xr, IncomingStream as Xt, InMemoryManagedIdentity as Y, MethodSchema as Yi, SignatureEnvelope as Yn, zParticipantDescriptorSource as Yr, IncomingCall as Yt, ManagedIdentity as Z, BooleanSchema as Zi, getKeyId as Zn, zTopologyGraph as Zr, MessageWithCtx as Zt, SeededPrincipalOptions as _, JsonRpcResponse as _a, componentSchemaName as _i, LinkRpcJsonRpcRequest as _n, principalForPublicKey as _r, KeypairSigningIdentity as _t, LinkRpcConnection as a, ObjectSchema as aa, zTrafficOverflowEvent as ai, IMessageTransport as an, Keypair as ar, ParamMatcherFor as at, createSeededSigningIdentity as b, isNotification as ba, isAssignable as bi, LinkRpcWireParams as bn, jcsCanonicalize as br, SerializedKeypairSigningIdentity as bt, ServiceHandle as c, SchemaBase as ca, zTrafficWatchResult as ci, MessageTransportWithContext as cn, PrivateKey as cr, capBagFreshAt as ct, ServiceIdPattern as d, UnionSchema as da, SchemaToZodContext as di, connectTransports as dn, Signature as dr, issueCapability as dt, EnumSchema as ea, zTopologyNode as ei, RpcError as en, signingDomainValue as er, createManagedIdentity as et, defaultsInterface as f, ErrorCode as fa, createSchemaToZod as fi, traceMessageTransport as fn, X25519Keypair as fr, permits as ft, zServiceIdPattern as g, JsonRpcRequest as ga, assertSchemaReferences as gi, LinkRpcJsonRpcNotification as gn, keyIdForPublicKey as gr, KeypairIdentity as gt, schemasInterface as h, JsonRpcNotification as ha, materializeJsonSchema as hi, LinkRpcJsonRpcMessage as hn, keyIdForPrincipal as hr, Identity as ht, InterfaceRegistration as i, NumberSchema as ia, zTrafficEvent as ii, MuxEnvelope as in, KeyId as ir, IssueCapabilityOptions as it, attachCapabilities as j, MemberMap as ji, ParamMatcher as jn, ParticipantDescriptor as jr, formatEndpointUri as jt, VerifyRpcCallOptions as k, InterfaceMemberRef as ki, CallTarget as kn, TopologyIdGenerator as kr, WsEndpoint as kt, RootPrincipalReq as l, StringSchema as la, GenerateInterfaceOptions as li, MessageWithContext as ln, PublicKey as lr, capabilityFreshAt as lt, directoryWatchNever as m, JsonRpcMessage as ma, MaterializedJsonSchema as mi, CallMeta as mn, bytesToBase64Url as mr, signCapability as mt, GetOptions as n, LinkRpcJsonSchema as na, zTopologyTransportEndpoint as ni, StreamSendOpts as nn, withSignature as nr, registerLazyIdentityOnOverlay as nt, LinkRpcConnectionOptions as o, OneOfSchema as oa, zTrafficTransitEndpoint as oi, MessageTransportDirection as on, PRINCIPAL_PREFIX as or, ParamMatchers as ot, directoryInterface as p, JsonRpcError as pa, schemaToZod as pi, IDisposable as pn, base64UrlToBytes as pr, prefix as pt, CapBag as q, LinkRpcInterfaceSchema as qi, LINKRPC_UNSIGNED_KEY as qn, trafficInterface as qr, IRequestHandler as qt, InspectionRegistration as r, NullSchema as ra, zTopologyTransportInfo as ri, MultiplexedTransport as rn, KEY_ID_PREFIX as rr, AcceptedRootIssuer as rt, RegisterOptions as s, RefSchema as sa, zTrafficTransitEvent as si, MessageTransportTrace as sn, PrincipalId as sr, PermitResult as st, BareGetOptions as t, IntegerSchema as ta, zTopologyPort as ti, SendOpts as tn, signingInput as tr, registerIdentityOnOverlay as tt, RootPrincipalSet as u, TupleSchema as ua, generateTsInterface as ui, TransportPair as un, ResolveSigningKeyArgs as ur, invoke as ut, createMemoryPrincipal as v, JsonRpcSuccess as va, componentSchemaRef as vi, LinkRpcUnsigned as vn, publicKeyForKeyId as vr, PublicSigningIdentity as vt, VerifyResult as w, InterfaceClient as wi, methodNameToTarget as wn, StreamControlType as wr, CmdStdioEndpoint as wt, JsonObject as x, isRequest as xa, normalizeJsonSchema as xi, requireObjectParams as xn, jcsCanonicalizeBytes as xr, SigningIdentity as xt, createSeededMemoryPrincipal as y, RequestId as ya, Components as yi, LinkRpcWireMeta as yn, resolveSigningKey as yr, PublicWrappingIdentity as yt, ManagedSigningChannel as z, NotificationType as zi, permissionMatchesTarget as zn, TopologyTransportEndpoint as zr, ConnectableChannel as zt };
3623
+ //# sourceMappingURL=linkRpcConnection-CtlQmetO.d.ts.map