@hediet/linkrpc 0.0.2 → 0.0.3-next.20260922.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 (33) hide show
  1. package/README.md +266 -31
  2. package/dist/chunks/{hub.interfaces-Bf4VfWNX.js → hub.interfaces-Deslgtgr.js} +2 -2
  3. package/dist/chunks/{hub.interfaces-Bf4VfWNX.js.map → hub.interfaces-Deslgtgr.js.map} +1 -1
  4. package/dist/chunks/{hubAccess-C06qAKao.d.ts → hubAccess-BmPvNNaM.d.ts} +2 -2
  5. package/dist/chunks/{hubAccess-C06qAKao.d.ts.map → hubAccess-BmPvNNaM.d.ts.map} +1 -1
  6. package/dist/chunks/{hubFacade-BIB9CoAv.js → hubFacade-BKTQXCdF.js} +2 -2
  7. package/dist/chunks/{hubFacade-BIB9CoAv.js.map → hubFacade-BKTQXCdF.js.map} +1 -1
  8. package/dist/chunks/{hubFacade-DtQpGpUy.d.ts → hubFacade-Bmh-SFWd.d.ts} +2 -2
  9. package/dist/chunks/{hubFacade-DtQpGpUy.d.ts.map → hubFacade-Bmh-SFWd.d.ts.map} +1 -1
  10. package/dist/chunks/{boundedTrafficSubscription-XZ1KwXZC.js → inspectionHost-BIkLKvr1.js} +1014 -32
  11. package/dist/chunks/inspectionHost-BIkLKvr1.js.map +1 -0
  12. package/dist/chunks/{linkRpcConnection-BadD37ok.d.ts → linkRpcConnection-Bbq20hQG.d.ts} +2215 -1699
  13. package/dist/chunks/linkRpcConnection-Bbq20hQG.d.ts.map +1 -0
  14. package/dist/chunks/{src-CAhXne71.js → src-DKjTceek.js} +1975 -2051
  15. package/dist/chunks/src-DKjTceek.js.map +1 -0
  16. package/dist/hub/client/index.d.ts +3 -3
  17. package/dist/hub/client/index.js +3 -3
  18. package/dist/hub/common/index.d.ts +2 -325
  19. package/dist/hub/common/index.d.ts.map +1 -1
  20. package/dist/hub/common/index.js +2 -2
  21. package/dist/index.d.ts +2 -2
  22. package/dist/index.js +3 -3
  23. package/dist/inspection/index.d.ts +87 -2
  24. package/dist/inspection/index.d.ts.map +1 -1
  25. package/dist/inspection/index.js +2 -2
  26. package/dist/node.d.ts +3 -3
  27. package/dist/node.js +4 -4
  28. package/dist/web.d.ts +2 -2
  29. package/dist/web.js +3 -3
  30. package/package.json +7 -2
  31. package/dist/chunks/boundedTrafficSubscription-XZ1KwXZC.js.map +0 -1
  32. package/dist/chunks/linkRpcConnection-BadD37ok.d.ts.map +0 -1
  33. package/dist/chunks/src-CAhXne71.js.map +0 -1
@@ -42,6 +42,8 @@ interface JsonRpcError {
42
42
  type JsonRpcResponse = JsonRpcSuccess | JsonRpcError;
43
43
  type JsonRpcMessage = JsonRpcRequest | JsonRpcNotification | JsonRpcResponse;
44
44
  declare const ErrorCode: {
45
+ /** Default code for named LinkRPC application errors. */
46
+ readonly applicationError: 1;
45
47
  readonly parseError: -32700;
46
48
  readonly invalidRequest: -32600;
47
49
  readonly methodNotFound: -32601;
@@ -204,7 +206,7 @@ interface MethodSchema {
204
206
  * may not stream on this method.
205
207
  */
206
208
  serverStream?: LinkRpcJsonSchema;
207
- /** Application-level errors. Codes MUST be unique. */
209
+ /** Raw codes are exclusive; named and legacy declarations may form a union per code. */
208
210
  errors?: ErrorSchema[];
209
211
  summary?: string;
210
212
  /**
@@ -262,14 +264,41 @@ interface MemberAnnotations {
262
264
  */
263
265
  dangerous?: boolean;
264
266
  }
265
- interface ErrorSchema {
267
+ type ErrorSchema = LegacyErrorSchema | RawErrorSchema;
268
+ interface RawErrorSchema {
269
+ code: number;
270
+ /** Schema of the wire body { message, data? }, excluding the outer code. */
271
+ schema: LinkRpcJsonSchema;
272
+ type?: never;
273
+ message?: never;
274
+ data?: never;
275
+ }
276
+ interface LegacyErrorSchema {
277
+ schema?: never;
278
+ /** Named error discriminator in `error.data.type`. Absent for legacy numeric errors. */
279
+ type?: string;
266
280
  /** JSON-RPC error code. -32768..-32000 and LinkRPC cancellation code -32800 are reserved. */
267
281
  code: number;
268
282
  message: string;
269
- /** Optional schema describing the shape of `error.data`. */
283
+ /** Payload schema: `error.data.data` for named errors, `error.data` for legacy errors. */
270
284
  data?: LinkRpcJsonSchema;
271
285
  }
272
286
  //#endregion
287
+ //#region src/connection/rpcFailure.d.ts
288
+ declare const rpcFailureBrand: unique symbol;
289
+ /** A nominal failure wrapper: successful application objects can never collide with it. */
290
+ declare class RpcFailure<E> {
291
+ readonly error: E;
292
+ readonly [rpcFailureBrand] = true;
293
+ constructor(error: E);
294
+ }
295
+ type Result$1<T, E = never> = T | RpcFailure<E>;
296
+ declare function isRpcFailure<T, E>(value: Result$1<T, E>): value is RpcFailure<E>;
297
+ declare function isRpcFailure(value: unknown): value is RpcFailure<unknown>;
298
+ //#endregion
299
+ //#region src/schema/applicationErrorBrand.d.ts
300
+ declare const applicationErrorBrand: unique symbol;
301
+ //#endregion
273
302
  //#region src/schema/memberTypes.d.ts
274
303
  /**
275
304
  * The schema type linkrpc accepts everywhere: the zod *core* base shared by
@@ -286,8 +315,7 @@ type Schema<O = unknown> = $ZodType<O>;
286
315
  * - propagate TS types up to the interface definition.
287
316
  */
288
317
  type MemberType = RequestType<any, any, any, any, any, any, any> | NotificationType<any>;
289
- declare const applicationErrorBrand: unique symbol;
290
- type ApplicationErrorValue<TCode extends number = number, TMessage extends string = string, TData = never> = {
318
+ type ApplicationErrorValue<TCode extends number = number, TMessage extends string = string, TData = never, TType extends string | undefined = undefined> = {
291
319
  readonly kind: 'application';
292
320
  readonly code: TCode;
293
321
  readonly message: TMessage;
@@ -295,33 +323,104 @@ type ApplicationErrorValue<TCode extends number = number, TMessage extends strin
295
323
  readonly data?: never;
296
324
  } : {
297
325
  readonly data: TData;
326
+ }) & (TType extends string ? {
327
+ readonly type: TType;
328
+ } : {
329
+ readonly type?: never;
298
330
  });
299
- type CreatedApplicationErrorValue<TCode extends number = number, TMessage extends string = string, TData = never> = ApplicationErrorValue<TCode, TMessage, TData> & {
331
+ type CreatedApplicationErrorValue<TCode extends number = number, TMessage extends string = string, TData = never, TType extends string | undefined = undefined> = ApplicationErrorValue<TCode, TMessage, TData, TType> & {
300
332
  readonly [applicationErrorBrand]: true;
301
333
  };
302
- interface ApplicationErrorDescriptor<TCode extends number = number, TMessage extends string = string, TData = never> {
334
+ interface ApplicationErrorDescriptor<TCode extends number = number, TMessage extends string = string, TData = never, TType extends string | undefined = undefined> {
303
335
  readonly code: TCode;
304
336
  readonly message: TMessage;
305
337
  readonly dataSchema?: Schema<TData>;
306
- readonly create: [TData] extends [never] ? () => CreatedApplicationErrorValue<TCode, TMessage, TData> : (data: TData) => CreatedApplicationErrorValue<TCode, TMessage, TData>;
338
+ readonly type: TType;
339
+ /** Match a validated application payload or its failure wrapper. */
340
+ is(value: RpcFailure<unknown>): value is RpcFailure<ApplicationErrorValue<TCode, string, TData, TType>>;
341
+ is(value: {
342
+ readonly kind: 'application';
343
+ }): value is ApplicationErrorValue<TCode, string, TData, TType>;
344
+ is(value: unknown): value is ApplicationErrorValue<TCode, string, TData, TType> | RpcFailure<ApplicationErrorValue<TCode, string, TData, TType>>;
345
+ readonly create: [TData] extends [never] ? () => CreatedApplicationErrorValue<TCode, TMessage, TData, TType> : (data: TData) => CreatedApplicationErrorValue<TCode, TMessage, TData, TType>;
307
346
  }
308
347
  interface ApplicationErrorDescriptorBase {
348
+ readonly type?: string;
309
349
  readonly code: number;
310
- readonly message: string;
350
+ readonly message?: string;
351
+ readonly bodySchema?: Schema;
311
352
  readonly dataSchema?: Schema<any>;
312
353
  readonly create: (...args: any[]) => {
313
354
  readonly kind: 'application';
314
355
  readonly code: number;
315
356
  readonly message: string;
316
357
  readonly data?: unknown;
358
+ readonly type?: string;
317
359
  readonly [applicationErrorBrand]: true;
318
360
  };
319
361
  }
320
- type ApplicationErrorOf<T> = T extends ApplicationErrorDescriptor<infer C, infer M, infer D> ? CreatedApplicationErrorValue<C, M, D> : never;
321
- type PublicApplicationErrorOf<T> = 0 extends (1 & T) ? never : T extends CreatedApplicationErrorValue<infer C, infer M, infer D> ? ApplicationErrorValue<C, M, D> : never;
362
+ type ApplicationErrorOf<T> = T extends RpcErrorDescriptor<infer C, infer B> ? CreatedRpcErrorValue<C, B> : T extends ApplicationErrorDescriptor<infer C, infer M, infer D, infer N> ? CreatedApplicationErrorValue<C, M, D, N> : never;
363
+ type PublicApplicationErrorOf<T> = 0 extends (1 & T) ? never : T extends {
364
+ readonly [rawErrorBrand]: true;
365
+ } ? Omit<T, typeof applicationErrorBrand | typeof rawErrorBrand> : T extends CreatedApplicationErrorValue<infer C, infer M, infer D, infer N> ? ApplicationErrorValue<C, N extends string ? string : M, D, N> : never;
322
366
  type DeclaredApplicationErrorOf<T> = 0 extends (1 & T) ? never : Extract<T, ReturnType<ApplicationErrorDescriptorBase['create']>>;
323
367
  type ApplicationErrorsOf<T extends readonly ApplicationErrorDescriptorBase[]> = ApplicationErrorOf<T[number]>;
368
+ declare const rawErrorBrand: unique symbol;
369
+ type RpcErrorBody = {
370
+ readonly message: string;
371
+ readonly data?: unknown;
372
+ };
373
+ type RpcErrorValue<C extends number, B extends RpcErrorBody> = B & {
374
+ readonly kind: 'application';
375
+ readonly code: C;
376
+ readonly type?: never;
377
+ };
378
+ type CreatedRpcErrorValue<C extends number, B extends RpcErrorBody> = RpcErrorValue<C, B> & {
379
+ readonly [applicationErrorBrand]: true;
380
+ readonly [rawErrorBrand]: true;
381
+ };
382
+ interface RpcErrorDescriptor<C extends number = number, B extends RpcErrorBody = RpcErrorBody> {
383
+ readonly code: C;
384
+ readonly bodySchema: Schema<B>;
385
+ readonly type?: never;
386
+ readonly message?: never;
387
+ readonly dataSchema?: never;
388
+ create(body: B): CreatedRpcErrorValue<C, B>;
389
+ is(value: RpcFailure<unknown>): value is RpcFailure<RpcErrorValue<C, B>>;
390
+ is(value: {
391
+ readonly kind: 'application';
392
+ }): value is RpcErrorValue<C, B>;
393
+ is(value: unknown): value is RpcErrorValue<C, B> | RpcFailure<RpcErrorValue<C, B>>;
394
+ }
395
+ type RawBody<M extends string, D extends Schema> = {
396
+ message: M;
397
+ } & (D['_zod']['optout'] extends 'optional' ? {
398
+ data?: output<D>;
399
+ } : {
400
+ data: output<D>;
401
+ });
402
+ /** Declare an error selected by numeric code; its schema validates the body afterwards. */
403
+ declare function rpcError<const C extends number, B>(code: C, schema: Schema<B>): RpcErrorDescriptor<C, unknown extends B ? RpcErrorBody : B & RpcErrorBody>;
404
+ declare function rpcError<const C extends number, M extends string = string, D extends Schema = Schema>(code: C, shape: {
405
+ message?: Schema<M>;
406
+ data: D;
407
+ }): RpcErrorDescriptor<C, RawBody<M, D>>;
408
+ declare function rpcError<const C extends number, M extends string = string>(code: C, shape: {
409
+ message?: Schema<M>;
410
+ }): RpcErrorDescriptor<C, {
411
+ message: M;
412
+ data?: never;
413
+ }>;
324
414
  /** Declare one checked application error for use with {@link RequestType.withErrors}. */
415
+ declare function applicationError<const TType extends string, TData, const TCode extends number = typeof ErrorCode.applicationError>(type: TType, options: {
416
+ message?: string;
417
+ data: Schema<TData>;
418
+ code?: TCode;
419
+ }): ApplicationErrorDescriptor<TCode, string, TData, TType>;
420
+ declare function applicationError<const TType extends string, const TCode extends number = typeof ErrorCode.applicationError>(type: TType, options?: {
421
+ message?: string;
422
+ code?: TCode;
423
+ }): ApplicationErrorDescriptor<TCode, string, never, TType>;
325
424
  declare function applicationError<const TCode extends number, const TMessage extends string>(code: TCode, message: TMessage): ApplicationErrorDescriptor<TCode, TMessage, never>;
326
425
  declare function applicationError<const TCode extends number, const TMessage extends string, TData>(code: TCode, message: TMessage, data: Schema<TData>): ApplicationErrorDescriptor<TCode, TMessage, TData>;
327
426
  /** Runtime nominal check for values produced by an application-error descriptor. */
@@ -432,6 +531,22 @@ interface ZodToSvcJsonSchemaOptions {
432
531
  /** Convert a zod schema to our restricted SvcJsonSchema subset. */
433
532
  declare function zodToSvcJsonSchema(schema: Schema, options?: ZodToSvcJsonSchemaOptions): LinkRpcJsonSchema;
434
533
  //#endregion
534
+ //#region src/schema/validationIssue.d.ts
535
+ interface JsonSchemaValidationIssue {
536
+ readonly path: string;
537
+ readonly message: string;
538
+ }
539
+ //#endregion
540
+ //#region src/connection/nonCompliantServerError.d.ts
541
+ /** JSON Pointer diagnostics relative to the original wire error. */
542
+ type RpcValidationIssue = JsonSchemaValidationIssue;
543
+ declare class NonCompliantServerError extends Error {
544
+ readonly original: JsonRpcError['error'];
545
+ readonly issues: readonly RpcValidationIssue[];
546
+ readonly kind: "nonCompliantServer";
547
+ constructor(original: JsonRpcError['error'], issues: readonly RpcValidationIssue[]);
548
+ }
549
+ //#endregion
435
550
  //#region src/connection/interfaceDefinition.d.ts
436
551
  /**
437
552
  * Per-call stream API handed to a request handler as its third argument.
@@ -550,17 +665,28 @@ interface LocalRpcError {
550
665
  readonly kind: 'local';
551
666
  readonly cause: unknown;
552
667
  }
668
+ interface TransportRpcError {
669
+ readonly kind: 'transport';
670
+ readonly cause: unknown;
671
+ }
672
+ type GenericRpcError = RemoteRpcError | LocalRpcError | TransportRpcError | NonCompliantServerError;
673
+ type RpcCallError<E = never> = {
674
+ readonly kind: 'application';
675
+ readonly error: E;
676
+ } | {
677
+ readonly kind: 'generic';
678
+ readonly error: GenericRpcError;
679
+ };
553
680
  type CheckedCallResult<TResult, TApplicationError = never> = {
554
681
  readonly ok: true;
555
682
  readonly value: TResult;
556
683
  } | {
557
684
  readonly ok: false;
558
- readonly error: TApplicationError | RemoteRpcError | LocalRpcError;
685
+ readonly error: TApplicationError | GenericRpcError;
559
686
  };
560
- interface CheckedCall<TResult, TApplicationError = never> extends Promise<TResult> {
687
+ interface CheckedCall<TResult, TApplicationError = never> extends Promise<Result$1<TResult, TApplicationError>> {
561
688
  /**
562
- * Settle without throwing. Only an exact code/message/data-schema match is
563
- * promoted to a typed application error.
689
+ * @deprecated Use getResultClient() for values that include generic errors.
564
690
  */
565
691
  result(): Promise<CheckedCallResult<TResult, TApplicationError>>;
566
692
  }
@@ -572,6 +698,7 @@ interface CheckedCall<TResult, TApplicationError = never> extends Promise<TResul
572
698
  */
573
699
  type _HasStream<TClient, TServer> = [TClient] extends [never] ? ([TServer] extends [never] ? false : true) : true;
574
700
  type ClientCall<TResult, TApplicationError> = [TApplicationError] extends [never] ? Promise<TResult> : CheckedCall<TResult, TApplicationError>;
701
+ type ClientResult<R, E> = [E] extends [never] ? R : Result$1<R, E>;
575
702
  /**
576
703
  * Compile-time TypeScript shape of an interface — useful for typed
577
704
  * client/server implementations on top of the runtime definition.
@@ -584,8 +711,10 @@ type ClientCall<TResult, TApplicationError> = [TApplicationError] extends [never
584
711
  * type Client = InterfaceClient<typeof myInterface>;
585
712
  * // => { bar(p: {...}): Promise<string>; foo(p: {...}): void; }
586
713
  */
587
- type InterfaceClientMember<TMember> = TMember extends RequestType<infer P, infer R, infer E, infer TC, infer TS, any, any> ? (_HasStream<TC, TS> extends true ? (params: P, opts?: StreamCallOptions<TS>) => StreamingCall<R, TC> & ClientCall<R, PublicApplicationErrorOf<E>> : (params: P) => ClientCall<R, PublicApplicationErrorOf<E>>) : TMember extends NotificationType<infer P> ? (params: P) => void : never;
714
+ type InterfaceClientMember<TMember> = TMember extends RequestType<infer P, infer R, infer E, infer TC, infer TS, any, any> ? (_HasStream<TC, TS> extends true ? (params: P, opts?: StreamCallOptions<TS>) => StreamingCall<ClientResult<R, PublicApplicationErrorOf<E>>, TC> & ClientCall<R, PublicApplicationErrorOf<E>> : (params: P) => ClientCall<R, PublicApplicationErrorOf<E>>) : TMember extends NotificationType<infer P> ? (params: P) => void : never;
588
715
  type InterfaceClient<TDef extends InterfaceDefinition<any>> = { [K in keyof TDef['members']]: InterfaceClientMember<TDef['members'][K]>; };
716
+ /** Every request returns failures as values, including methods with no declared errors. */
717
+ type InterfaceResultClient<TDef extends InterfaceDefinition<any>> = { [K in keyof TDef['members']]: TDef['members'][K] extends RequestType<infer P, infer R, infer E, infer TC, infer TS, any, any> ? _HasStream<TC, TS> extends true ? (params: P, opts?: StreamCallOptions<TS>) => StreamingCall<Result$1<R, RpcCallError<PublicApplicationErrorOf<E>>>, TC> : (params: P) => Promise<Result$1<R, RpcCallError<PublicApplicationErrorOf<E>>>> : TDef['members'][K] extends NotificationType<infer P> ? (params: P) => void : never; };
589
718
  /**
590
719
  * Compile-time shape of a server implementation for an interface — used by
591
720
  * `LinkRpcConnection.register`. Request handlers may return synchronously or
@@ -653,8 +782,8 @@ declare function defineInterface<TMembers extends MemberMap>(info: InterfaceInfo
653
782
  * streams use `z.any()` because no zod source is available — call-site
654
783
  * validation is therefore a no-op and the caller is responsible for
655
784
  * shape-checking inputs and outputs. Declared application-error payloads
656
- * are materialized and validated because recognizing a typed error must
657
- * never rely on its code alone.
785
+ * are materialized and validated after code selection. A known code whose
786
+ * body fails all declared branches is a noncompliant-server failure.
658
787
  *
659
788
  * Methods with no `result` descriptor become notifications; methods with
660
789
  * `clientStream` / `serverStream` get pass-through stream payload
@@ -737,6 +866,7 @@ interface Components {
737
866
  }
738
867
  /** Match one JSON value against the structural LinkRPC subset without transforming it. */
739
868
  declare function matchesJsonSchema(value: JsonValue, schema: LinkRpcJsonSchema, components?: Components): boolean;
869
+ declare function validateJsonSchema(value: JsonValue, schema: LinkRpcJsonSchema, components?: Components): readonly JsonSchemaValidationIssue[];
740
870
  //#endregion
741
871
  //#region src/schema/assertSchemaReferences.d.ts
742
872
  declare function componentSchemaRef(name: string): string;
@@ -777,6 +907,8 @@ declare function schemaToZod(schema: LinkRpcJsonSchema, components?: Record<stri
777
907
  //#endregion
778
908
  //#region src/schema/codegen/generateTsInterface.d.ts
779
909
  interface GenerateInterfaceOptions {
910
+ /** Omit imports when composing definitions inside a generated module. */
911
+ omitImports?: boolean;
780
912
  /**
781
913
  * Module specifier from which `defineInterface`, `requestType`,
782
914
  * `notificationType` are imported. Defaults to `@hediet/linkrpc`.
@@ -814,614 +946,283 @@ interface GenerateInterfaceOptions {
814
946
  */
815
947
  declare function generateTsInterface(schema: LinkRpcInterfaceSchema, options?: GenerateInterfaceOptions): string;
816
948
  //#endregion
817
- //#region src/inspection/inspection.interfaces.d.ts
818
- declare const zTopologyPort: import("zod/mini").ZodMiniObject<{
819
- portId: import("zod/mini").ZodMiniString<string>;
820
- label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
821
- }, import("zod/v4/core").$strip>;
822
- declare const zParticipantDescriptor: import("zod/mini").ZodMiniObject<{
823
- type: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
824
- label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
825
- processId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
826
- processType: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
827
- nodeStatusServiceId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
828
- 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>]>>>;
829
- }, import("zod/v4/core").$strip>;
830
- declare const zParticipantDescriptorSource: import("zod/mini").ZodMiniObject<{
831
- source: import("zod/mini").ZodMiniEnum<{
832
- self: "self";
833
- attacher: "attacher";
834
- }>;
835
- descriptor: import("zod/mini").ZodMiniObject<{
836
- type: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
837
- label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
838
- processId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
839
- processType: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
840
- nodeStatusServiceId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
841
- 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>]>>>;
842
- }, import("zod/v4/core").$strip>;
843
- }, import("zod/v4/core").$strip>;
844
- declare const zTopologyNode: import("zod/mini").ZodMiniObject<{
845
- nodeId: import("zod/mini").ZodMiniString<string>;
846
- kind: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniEnum<{
847
- endpoint: "endpoint";
848
- hub: "hub";
849
- }>>;
850
- label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
851
- descriptors: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
852
- source: import("zod/mini").ZodMiniEnum<{
853
- self: "self";
854
- attacher: "attacher";
855
- }>;
856
- descriptor: import("zod/mini").ZodMiniObject<{
857
- type: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
858
- label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
859
- processId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
860
- processType: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
861
- nodeStatusServiceId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
862
- 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>]>>>;
863
- }, import("zod/v4/core").$strip>;
864
- }, import("zod/v4/core").$strip>>>;
865
- ports: import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
866
- portId: import("zod/mini").ZodMiniString<string>;
867
- label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
868
- }, import("zod/v4/core").$strip>>;
869
- }, import("zod/v4/core").$strip>;
870
- declare const zTopologyLinkEndpoint: import("zod/mini").ZodMiniObject<{
871
- nodeId: import("zod/mini").ZodMiniString<string>;
872
- portId: import("zod/mini").ZodMiniString<string>;
873
- }, import("zod/v4/core").$strip>;
874
- declare const zTopologyTransportEndpoint: import("zod/mini").ZodMiniObject<{
875
- address: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
876
- port: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
877
- }, import("zod/v4/core").$strip>;
949
+ //#region src/schema/staticHubSchema.d.ts
950
+ interface InterfaceRef {
951
+ interfaceId: string;
952
+ interfaceHash: string;
953
+ }
954
+ type StaticInterfaceReference = InterfaceRef;
955
+ interface StaticService {
956
+ serviceId: string;
957
+ interfaces: StaticInterfaceReference[];
958
+ }
959
+ interface StaticHubSchemaDocument {
960
+ services?: StaticService[];
961
+ defaultInterface?: StaticInterfaceReference;
962
+ bareInterfaces?: {
963
+ interface: InterfaceRef;
964
+ prefix: string;
965
+ }[];
966
+ interfaceSchemas: LinkRpcInterfaceSchema[];
967
+ }
968
+ type StaticHubSchema = StaticHubSchemaDocument;
969
+ declare function parseStaticHubSchema(value: unknown): StaticHubSchema;
970
+ //#endregion
971
+ //#region src/schema/codegen/generateTsContract.d.ts
972
+ interface GenerateContractOptions {
973
+ linkRpcImport?: string;
974
+ /** Exact `interfaceId@interfaceHash` keys; required when derived names collide. */
975
+ interfaceNames?: Readonly<Record<string, string>>;
976
+ /** Keys: `root:id@hash`, `service:serviceId:id@hash`, `default`, or `bare:prefix`. */
977
+ bindingNames?: Readonly<Record<string, string>>;
978
+ }
979
+ /** Generate one reusable definition per schema and immutable, typed route descriptors. */
980
+ declare function generateTsContract(document: StaticHubSchemaDocument, options?: GenerateContractOptions): string;
981
+ //#endregion
982
+ //#region src/disposable.d.ts
983
+ /** Minimal disposable handle; calling `dispose` releases the resource. */
984
+ interface IDisposable {
985
+ dispose(): void;
986
+ }
987
+ //#endregion
988
+ //#region src/transport/messageTransport.d.ts
989
+ interface IMessageTransport<TIncoming = JsonRpcMessage, TOutgoing = JsonRpcMessage> {
990
+ send(message: TOutgoing): void | Promise<void>;
991
+ /**
992
+ * Sets the listener for incoming messages. Setting `undefined` detaches.
993
+ * The transport buffers messages received before a listener is attached
994
+ * and delivers them the next tick when one is set.
995
+ * Forgetting to set a listener will cause the queue to leak.
996
+ */
997
+ setListener(listener: ((message: TIncoming) => void) | undefined): void;
998
+ dispose(): void;
999
+ }
1000
+ type MessageWithContext<TCtx> = JsonRpcMessage & {
1001
+ context: TCtx;
1002
+ };
1003
+ type MessageTransportWithContext<TCtx> = IMessageTransport<JsonRpcMessage, MessageWithContext<TCtx>>;
1004
+ type MessageTransportDirection = 'send' | 'receive';
1005
+ type MessageTransportTrace = (direction: MessageTransportDirection, message: JsonRpcMessage) => void;
878
1006
  /**
879
- * Transport details as observed at a topology link. `local` corresponds to the
880
- * link's `from` endpoint and `remote` to its `to` endpoint.
1007
+ * Observe every message crossing a transport without changing its buffering or
1008
+ * lifecycle behavior.
881
1009
  */
882
- declare const zTopologyTransportInfo: import("zod/mini").ZodMiniObject<{
883
- type: import("zod/mini").ZodMiniString<string>;
884
- local: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
885
- address: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
886
- port: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
887
- }, import("zod/v4/core").$strip>>;
888
- remote: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
889
- address: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
890
- port: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
891
- }, import("zod/v4/core").$strip>>;
892
- path: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
893
- 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>]>>>;
894
- }, import("zod/v4/core").$strip>;
895
- declare const zTopologyLink: import("zod/mini").ZodMiniObject<{
896
- from: import("zod/mini").ZodMiniObject<{
897
- nodeId: import("zod/mini").ZodMiniString<string>;
898
- portId: import("zod/mini").ZodMiniString<string>;
899
- }, import("zod/v4/core").$strip>;
900
- to: import("zod/mini").ZodMiniObject<{
901
- nodeId: import("zod/mini").ZodMiniString<string>;
902
- portId: import("zod/mini").ZodMiniString<string>;
903
- }, import("zod/v4/core").$strip>;
904
- label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
905
- peerState: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniEnum<{
906
- identified: "identified";
907
- pending: "pending";
908
- unsupported: "unsupported";
909
- error: "error";
910
- }>>;
911
- transport: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
912
- type: import("zod/mini").ZodMiniString<string>;
913
- local: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
914
- address: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
915
- port: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
916
- }, import("zod/v4/core").$strip>>;
917
- remote: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
918
- address: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
919
- port: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
920
- }, import("zod/v4/core").$strip>>;
921
- path: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
922
- 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>]>>>;
923
- }, import("zod/v4/core").$strip>>;
924
- }, import("zod/v4/core").$strip>;
925
- declare const zRouteClaim: import("zod/mini").ZodMiniObject<{
926
- serviceId: import("zod/mini").ZodMiniString<string>;
927
- nodeId: import("zod/mini").ZodMiniString<string>;
928
- portId: import("zod/mini").ZodMiniString<string>;
929
- match: import("zod/mini").ZodMiniEnum<{
930
- exact: "exact";
931
- prefix: "prefix";
932
- }>;
933
- }, import("zod/v4/core").$strip>;
934
- declare const zTopologyGraph: import("zod/mini").ZodMiniObject<{
935
- observerServiceId: import("zod/mini").ZodMiniString<string>;
936
- entryNodeId: import("zod/mini").ZodMiniString<string>;
937
- nodes: import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
938
- nodeId: import("zod/mini").ZodMiniString<string>;
939
- kind: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniEnum<{
940
- endpoint: "endpoint";
941
- hub: "hub";
942
- }>>;
943
- label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
944
- descriptors: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
945
- source: import("zod/mini").ZodMiniEnum<{
946
- self: "self";
947
- attacher: "attacher";
948
- }>;
949
- descriptor: import("zod/mini").ZodMiniObject<{
950
- type: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
951
- label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
952
- processId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
953
- processType: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
954
- nodeStatusServiceId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
955
- 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>]>>>;
956
- }, import("zod/v4/core").$strip>;
957
- }, import("zod/v4/core").$strip>>>;
958
- ports: import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
959
- portId: import("zod/mini").ZodMiniString<string>;
960
- label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
961
- }, import("zod/v4/core").$strip>>;
962
- }, import("zod/v4/core").$strip>>;
963
- links: import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
964
- from: import("zod/mini").ZodMiniObject<{
965
- nodeId: import("zod/mini").ZodMiniString<string>;
966
- portId: import("zod/mini").ZodMiniString<string>;
967
- }, import("zod/v4/core").$strip>;
968
- to: import("zod/mini").ZodMiniObject<{
969
- nodeId: import("zod/mini").ZodMiniString<string>;
970
- portId: import("zod/mini").ZodMiniString<string>;
971
- }, import("zod/v4/core").$strip>;
972
- label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
973
- peerState: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniEnum<{
974
- identified: "identified";
975
- pending: "pending";
976
- unsupported: "unsupported";
977
- error: "error";
978
- }>>;
979
- transport: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
980
- type: import("zod/mini").ZodMiniString<string>;
981
- local: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
982
- address: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
983
- port: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
984
- }, import("zod/v4/core").$strip>>;
985
- remote: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
986
- address: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
987
- port: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
988
- }, import("zod/v4/core").$strip>>;
989
- path: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
990
- 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>]>>>;
991
- }, import("zod/v4/core").$strip>>;
992
- }, import("zod/v4/core").$strip>>;
993
- routes: import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
994
- serviceId: import("zod/mini").ZodMiniString<string>;
995
- nodeId: import("zod/mini").ZodMiniString<string>;
996
- portId: import("zod/mini").ZodMiniString<string>;
997
- match: import("zod/mini").ZodMiniEnum<{
998
- exact: "exact";
999
- prefix: "prefix";
1000
- }>;
1001
- }, import("zod/v4/core").$strip>>;
1002
- }, import("zod/v4/core").$strip>;
1003
- type TopologyPort = output<typeof zTopologyPort>;
1004
- type ParticipantDescriptor = output<typeof zParticipantDescriptor>;
1005
- type ParticipantDescriptorSource = output<typeof zParticipantDescriptorSource>;
1006
- type TopologyNode = output<typeof zTopologyNode>;
1007
- type TopologyLinkEndpoint = output<typeof zTopologyLinkEndpoint>;
1008
- type TopologyTransportEndpoint = output<typeof zTopologyTransportEndpoint>;
1009
- type TopologyTransportInfo = output<typeof zTopologyTransportInfo>;
1010
- type TopologyLink = output<typeof zTopologyLink>;
1011
- type RouteClaim = output<typeof zRouteClaim>;
1012
- type TopologyGraph = output<typeof zTopologyGraph>;
1013
- declare const topologyInterface: InterfaceDefinition<{
1014
- getGraph: RequestType<Record<string, never>, {
1015
- observerServiceId: string;
1016
- entryNodeId: string;
1017
- nodes: {
1018
- nodeId: string;
1019
- ports: {
1020
- portId: string;
1021
- label?: string | undefined;
1022
- }[];
1023
- kind?: "endpoint" | "hub" | undefined;
1024
- label?: string | undefined;
1025
- descriptors?: {
1026
- source: "self" | "attacher";
1027
- descriptor: {
1028
- type?: string | undefined;
1029
- label?: string | undefined;
1030
- processId?: number | undefined;
1031
- processType?: string | undefined;
1032
- nodeStatusServiceId?: string | undefined;
1033
- metadata?: Record<string, string | number | boolean> | undefined;
1034
- };
1035
- }[] | undefined;
1036
- }[];
1037
- links: {
1038
- from: {
1039
- nodeId: string;
1040
- portId: string;
1041
- };
1042
- to: {
1043
- nodeId: string;
1044
- portId: string;
1045
- };
1046
- label?: string | undefined;
1047
- peerState?: "identified" | "pending" | "unsupported" | "error" | undefined;
1048
- transport?: {
1049
- type: string;
1050
- local?: {
1051
- address?: string | undefined;
1052
- port?: number | undefined;
1053
- } | undefined;
1054
- remote?: {
1055
- address?: string | undefined;
1056
- port?: number | undefined;
1057
- } | undefined;
1058
- path?: string | undefined;
1059
- metadata?: Record<string, string | number | boolean> | undefined;
1060
- } | undefined;
1061
- }[];
1062
- routes: {
1063
- serviceId: string;
1064
- nodeId: string;
1065
- portId: string;
1066
- match: "exact" | "prefix";
1067
- }[];
1068
- }, void, NoInfer<Record<string, never>>, never, readonly ApplicationErrorDescriptorBase[], void>;
1069
- watchGraph: RequestType<Record<string, never>, Record<string, never>, void, never, NoInfer<Record<string, never>>, readonly ApplicationErrorDescriptorBase[], void>;
1070
- }>;
1071
- declare const zTrafficTransitEndpoint: import("zod/mini").ZodMiniObject<{
1072
- edgeId: import("zod/mini").ZodMiniString<string>;
1073
- portId: import("zod/mini").ZodMiniString<string>;
1074
- requestId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniString<string>]>>;
1075
- }, import("zod/v4/core").$strip>;
1076
- declare const zTrafficTransitEvent: import("zod/mini").ZodMiniObject<{
1077
- type: import("zod/mini").ZodMiniLiteral<"transit">;
1078
- timeMs: import("zod/mini").ZodMiniNumber<number>;
1079
- nodeId: import("zod/mini").ZodMiniString<string>;
1080
- in: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
1081
- edgeId: import("zod/mini").ZodMiniString<string>;
1082
- portId: import("zod/mini").ZodMiniString<string>;
1083
- requestId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniString<string>]>>;
1084
- }, import("zod/v4/core").$strip>>;
1085
- out: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
1086
- edgeId: import("zod/mini").ZodMiniString<string>;
1087
- portId: import("zod/mini").ZodMiniString<string>;
1088
- requestId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniString<string>]>>;
1089
- }, import("zod/v4/core").$strip>>;
1090
- disposition: import("zod/mini").ZodMiniEnum<{
1091
- forwarded: "forwarded";
1092
- consumed: "consumed";
1093
- dropped: "dropped";
1094
- unroutable: "unroutable";
1095
- }>;
1096
- kind: import("zod/mini").ZodMiniEnum<{
1097
- request: "request";
1098
- notification: "notification";
1099
- response: "response";
1100
- stream: "stream";
1101
- }>;
1102
- method: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
1103
- params: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnknown>;
1104
- result: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnknown>;
1105
- error: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
1106
- code: import("zod/mini").ZodMiniNumber<number>;
1107
- message: import("zod/mini").ZodMiniString<string>;
1108
- data: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnknown>;
1109
- }, import("zod/v4/core").$strip>>;
1110
- }, import("zod/v4/core").$strip>;
1111
- declare const zTrafficOverflowEvent: import("zod/mini").ZodMiniObject<{
1112
- type: import("zod/mini").ZodMiniLiteral<"overflow">;
1113
- dropped: import("zod/mini").ZodMiniNumber<number>;
1114
- }, import("zod/v4/core").$strip>;
1115
- declare const zTrafficEvent: import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniObject<{
1116
- type: import("zod/mini").ZodMiniLiteral<"transit">;
1117
- timeMs: import("zod/mini").ZodMiniNumber<number>;
1118
- nodeId: import("zod/mini").ZodMiniString<string>;
1119
- in: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
1120
- edgeId: import("zod/mini").ZodMiniString<string>;
1121
- portId: import("zod/mini").ZodMiniString<string>;
1122
- requestId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniString<string>]>>;
1123
- }, import("zod/v4/core").$strip>>;
1124
- out: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
1125
- edgeId: import("zod/mini").ZodMiniString<string>;
1126
- portId: import("zod/mini").ZodMiniString<string>;
1127
- requestId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniString<string>]>>;
1128
- }, import("zod/v4/core").$strip>>;
1129
- disposition: import("zod/mini").ZodMiniEnum<{
1130
- forwarded: "forwarded";
1131
- consumed: "consumed";
1132
- dropped: "dropped";
1133
- unroutable: "unroutable";
1134
- }>;
1135
- kind: import("zod/mini").ZodMiniEnum<{
1136
- request: "request";
1137
- notification: "notification";
1138
- response: "response";
1139
- stream: "stream";
1140
- }>;
1141
- method: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
1142
- params: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnknown>;
1143
- result: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnknown>;
1144
- error: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
1145
- code: import("zod/mini").ZodMiniNumber<number>;
1146
- message: import("zod/mini").ZodMiniString<string>;
1147
- data: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnknown>;
1148
- }, import("zod/v4/core").$strip>>;
1149
- }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
1150
- type: import("zod/mini").ZodMiniLiteral<"overflow">;
1151
- dropped: import("zod/mini").ZodMiniNumber<number>;
1152
- }, import("zod/v4/core").$strip>]>;
1153
- type TrafficTransitEndpoint = output<typeof zTrafficTransitEndpoint>;
1154
- type TrafficTransitEvent = output<typeof zTrafficTransitEvent>;
1155
- type TrafficOverflowEvent = output<typeof zTrafficOverflowEvent>;
1156
- type TrafficEvent = output<typeof zTrafficEvent>;
1157
- declare const zTrafficWatchResult: import("zod/mini").ZodMiniObject<{
1158
- delivered: import("zod/mini").ZodMiniNumber<number>;
1159
- dropped: import("zod/mini").ZodMiniNumber<number>;
1160
- }, import("zod/v4/core").$strip>;
1161
- type TrafficWatchResult = output<typeof zTrafficWatchResult>;
1010
+ declare function traceMessageTransport(transport: IMessageTransport, trace: MessageTransportTrace): IMessageTransport;
1162
1011
  /**
1163
- * Observe raw message transits at the node hosting the addressed service.
1164
- * Consumers may correlate adjacent transits by shared `(portId, requestId)`.
1012
+ * Pipe two transports together: every message one receives is forwarded to
1013
+ * the other's `send`. Returns a disposable that detaches both listeners.
1014
+ *
1015
+ * Neither transport is disposed — the caller owns their lifecycle. This is
1016
+ * the building block for relays (e.g. bridging a `WindowMessageTransport`
1017
+ * for an iframe to a multiplexer channel).
1165
1018
  */
1166
- declare const trafficInterface: InterfaceDefinition<{
1167
- watch: RequestType<{
1168
- methodPrefix?: string | undefined;
1169
- trafficIgnoreKey?: string | undefined;
1170
- focusRequest?: {
1171
- portId: string;
1172
- requestId: string | number;
1173
- } | undefined;
1174
- }, {
1175
- delivered: number;
1176
- dropped: number;
1177
- }, void, never, NoInfer<{
1178
- type: "transit";
1179
- timeMs: number;
1180
- nodeId: string;
1181
- disposition: "forwarded" | "consumed" | "dropped" | "unroutable";
1182
- kind: "request" | "notification" | "response" | "stream";
1183
- in?: {
1184
- edgeId: string;
1185
- portId: string;
1186
- requestId?: string | number | undefined;
1187
- } | undefined;
1188
- out?: {
1189
- edgeId: string;
1190
- portId: string;
1191
- requestId?: string | number | undefined;
1192
- } | undefined;
1193
- method?: string | undefined;
1194
- params?: unknown;
1195
- result?: unknown;
1196
- error?: {
1197
- code: number;
1198
- message: string;
1199
- data?: unknown;
1200
- } | undefined;
1201
- } | {
1202
- type: "overflow";
1203
- dropped: number;
1204
- }>, readonly ApplicationErrorDescriptorBase[], void>;
1205
- watchWithPayloads: RequestType<{
1206
- maxPayloadBytes: number;
1207
- methodPrefix?: string | undefined;
1208
- trafficIgnoreKey?: string | undefined;
1209
- focusRequest?: {
1210
- portId: string;
1211
- requestId: string | number;
1212
- } | undefined;
1213
- }, {
1214
- delivered: number;
1215
- dropped: number;
1216
- }, void, never, NoInfer<{
1217
- type: "transit";
1218
- timeMs: number;
1219
- nodeId: string;
1220
- disposition: "forwarded" | "consumed" | "dropped" | "unroutable";
1221
- kind: "request" | "notification" | "response" | "stream";
1222
- in?: {
1223
- edgeId: string;
1224
- portId: string;
1225
- requestId?: string | number | undefined;
1226
- } | undefined;
1227
- out?: {
1228
- edgeId: string;
1229
- portId: string;
1230
- requestId?: string | number | undefined;
1231
- } | undefined;
1232
- method?: string | undefined;
1233
- params?: unknown;
1234
- result?: unknown;
1235
- error?: {
1236
- code: number;
1237
- message: string;
1238
- data?: unknown;
1239
- } | undefined;
1240
- } | {
1241
- type: "overflow";
1242
- dropped: number;
1243
- }>, readonly ApplicationErrorDescriptorBase[], void>;
1244
- }>;
1245
- //#endregion
1246
- //#region src/inspection/node.interfaces.d.ts
1247
- declare const zNodeInfo: import("zod/mini").ZodMiniObject<{
1248
- nodeId: import("zod/mini").ZodMiniString<string>;
1249
- portId: import("zod/mini").ZodMiniString<string>;
1250
- descriptors: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
1251
- source: import("zod/mini").ZodMiniEnum<{
1252
- self: "self";
1253
- attacher: "attacher";
1254
- }>;
1255
- descriptor: import("zod/mini").ZodMiniObject<{
1256
- type: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
1257
- label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
1258
- processId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
1259
- processType: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
1260
- nodeStatusServiceId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
1261
- 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>]>>>;
1262
- }, import("zod/v4/core").$strip>;
1263
- }, import("zod/v4/core").$strip>>>;
1264
- }, import("zod/v4/core").$strip>;
1265
- type NodeInfo = output<typeof zNodeInfo>;
1266
- /**
1267
- * Generates unique topology-correlation labels, not security identities.
1268
- * Custom generators must avoid collisions across nodes and ports. Tests can
1269
- * supply an independent deterministic sequence for each participant.
1270
- */
1271
- type TopologyIdGenerator = (kind: 'node' | 'port') => string;
1019
+ declare function connectTransports<T extends JsonRpcMessage>(a: IMessageTransport<T>, b: IMessageTransport<T>): IDisposable;
1272
1020
  /**
1273
- * Minimal root service for aligning the independently observed topologies at
1274
- * both ends of a connection.
1021
+ * Two in-memory transports wired back-to-back. Useful for tests and for
1022
+ * same-process bridges.
1023
+ *
1024
+ * Generic in the per-direction payload type so asymmetric pairs (e.g. one
1025
+ * side sends plain `JsonRpcMessage`, the other side sends
1026
+ * `JsonRpcMessage & { context: Participant }`) are expressible at the type
1027
+ * level. At runtime both halves just hand objects through by reference.
1275
1028
  */
1276
- declare const nodeInterface: InterfaceDefinition<{
1277
- getNodeId: RequestType<Record<string, never>, {
1278
- nodeId: string;
1279
- portId: string;
1280
- descriptors?: {
1281
- source: "self" | "attacher";
1282
- descriptor: {
1283
- type?: string | undefined;
1284
- label?: string | undefined;
1285
- processId?: number | undefined;
1286
- processType?: string | undefined;
1287
- nodeStatusServiceId?: string | undefined;
1288
- metadata?: Record<string, string | number | boolean> | undefined;
1289
- };
1290
- }[] | undefined;
1291
- }, any, never, never, readonly ApplicationErrorDescriptorBase[], any>;
1292
- }>;
1029
+ declare class TransportPair<TFromA = JsonRpcMessage, TFromB = JsonRpcMessage> {
1030
+ readonly a: IMessageTransport<TFromB, TFromA>;
1031
+ readonly b: IMessageTransport<TFromA, TFromB>;
1032
+ constructor();
1033
+ }
1293
1034
  //#endregion
1294
- //#region src/connection/streaming.d.ts
1035
+ //#region src/connection/channel.d.ts
1036
+ declare class Channel<TInCtx = undefined, TOutCtx = undefined> {
1037
+ readonly sender: IRequestSender<TOutCtx>;
1038
+ private readonly _setHandler;
1039
+ private readonly _setWireObserver?;
1040
+ constructor(sender: IRequestSender<TOutCtx>, _setHandler: (h: IRequestHandler<TInCtx> | undefined) => void, _setWireObserver?: ((observer: WireMessageObserver | undefined) => void) | undefined);
1041
+ /** Bind the inbound request/notification handler. May be called before or after construction of {@link LinkRpcConnection}. */
1042
+ setRequestHandler(handler: IRequestHandler<TInCtx> | undefined): void;
1043
+ /**
1044
+ * Install the endpoint inspection observer at the JSON-RPC wire boundary.
1045
+ * Intended for {@link LinkRpcConnection}; ordinary consumers should use the
1046
+ * public `hubrpc.traffic` service instead.
1047
+ */
1048
+ setWireMessageObserver(observer: WireMessageObserver | undefined): void;
1049
+ /**
1050
+ * Compose this channel with a sender-side decorator (typically the
1051
+ * signing layer). The decorator wraps {@link sender} only; the
1052
+ * {@link setRequestHandler} binding is shared with the original channel
1053
+ * so the receive side is bound exactly once regardless of decoration depth.
1054
+ */
1055
+ withSender<TNewOutCtx>(decorate: (raw: IRequestSender<TOutCtx>) => IRequestSender<TNewOutCtx>): Channel<TInCtx, TNewOutCtx>;
1056
+ }
1057
+ type WireMessageDirection = 'inbound' | 'outbound';
1058
+ type WireMessageObserver = (direction: WireMessageDirection, message: JsonRpcMessage) => void;
1059
+ interface IRequestHandler<TInCtx = undefined> {
1060
+ handleRequest(call: IncomingCall<TInCtx>): Promise<Result>;
1061
+ handleNotification(call: IncomingCall<TInCtx>): void;
1062
+ }
1295
1063
  /**
1296
- * Direction a {@link STREAM_METHOD} message travels, relative to the
1297
- * request it is correlated with. Made explicit on the wire so that a
1298
- * middlebox (the hub) can *author* a stream message — e.g. inject a
1299
- * cancel when a caller disconnects — without an inbound message whose
1300
- * arrival link it could infer the direction from.
1064
+ * Inbound call observed by an {@link IRequestHandler}. `TInCtx` is the
1065
+ * per-call out-of-band context the transport attached on the receiving
1066
+ * side (e.g. the hub stamps `Participant` on overlay-bound messages).
1067
+ * For wire transports it's `undefined`.
1301
1068
  */
1302
- declare const StreamDir: {
1303
- /** callee → caller: progress, partial results. Routes like a response. */
1304
- readonly toCaller: "toCaller";
1305
- /** caller → callee: input, cancellation, keepalive ping. */
1306
- readonly toCallee: "toCallee";
1307
- };
1308
- type StreamDir = (typeof StreamDir)[keyof typeof StreamDir];
1069
+ interface IncomingCall<TInCtx = undefined> {
1070
+ method: string;
1071
+ params: JsonValue | undefined;
1072
+ /** Out-of-band context attached by the transport, if any. */
1073
+ context: TInCtx;
1074
+ /**
1075
+ * Per-call streaming handle. Both directions live on this object,
1076
+ * scoped to the request's lifetime. The inbound listener is auto-
1077
+ * detached when the handler's response settles. For notifications
1078
+ * (no request id) the handle is a no-op stub.
1079
+ */
1080
+ stream: IncomingStream;
1081
+ /**
1082
+ * Aborts when the caller cancels this in-flight request (a
1083
+ * `toCallee` `cancel` control), or when the hub cancels it on the
1084
+ * caller's behalf (caller disconnect / idle timeout). The handler
1085
+ * should observe this and settle promptly — typically by throwing,
1086
+ * which surfaces as a `cancelled` error response. For notifications
1087
+ * this never aborts.
1088
+ */
1089
+ signal: AbortSignal;
1090
+ }
1309
1091
  /**
1310
- * Reserved control verbs. A control message carries no app `payload`; it
1311
- * is interpreted by the runtime / hub itself, independently of the
1312
- * originating method's stream schemas, so *any* request is cancellable
1313
- * and keep-alive-able even when it declares no app stream.
1092
+ * Per-call streaming handle attached to {@link IncomingCall.stream}.
1093
+ * Scoped to a single in-flight request; the channel automatically
1094
+ * detaches the inbound listener when the handler's response settles.
1095
+ *
1096
+ * For notifications (which have no request id), `requestId` is
1097
+ * `undefined`, `send` is a no-op, and `onMessage` is a no-op.
1314
1098
  */
1315
- declare const StreamControlType: {
1099
+ interface IncomingStream {
1100
+ /** Emit a server→client stream notification correlated with this call. */
1101
+ send(payload: JsonValue): Promise<void>;
1316
1102
  /**
1317
- * Ask the callee to abort the in-flight request. Always {@link
1318
- * StreamDir.toCallee}. The callee surfaces this as an `AbortSignal`
1319
- * and is expected to settle the request (typically with a
1320
- * `cancelled` error response).
1103
+ * Register a listener for client→server stream messages correlated
1104
+ * with this call. Pass `undefined` to detach. Replaces any prior
1105
+ * listener. The channel detaches the listener automatically when
1106
+ * the handler's response settles.
1321
1107
  */
1322
- readonly cancel: "cancel";
1108
+ onMessage(listener: ((payload: JsonValue) => void) | undefined): void;
1323
1109
  /**
1324
- * Keepalive / liveness probe. Resets the hub's per-request idle timer
1325
- * so a long-running call is not reaped, and lets either side actively
1326
- * probe the peer. Carries a `nonce` the peer echoes in its {@link
1327
- * StreamControlType.pong}. May travel in either direction. Emitted
1328
- * automatically (without awaiting a pong) by the channel for streaming
1329
- * calls; see {@link STREAM_METHOD}.
1110
+ * Liveness probe toward the caller: emit a `toCaller` ping and
1111
+ * resolve once the caller's `pong` (matching nonce) returns. Rejects
1112
+ * if the request settles first. Independent of the channel's
1113
+ * automatic keepalive ping.
1330
1114
  */
1331
- readonly ping: "ping";
1115
+ ping(): Promise<void>;
1116
+ }
1117
+ type Result = {
1118
+ result: JsonValue;
1119
+ } | {
1120
+ error: {
1121
+ code: number;
1122
+ message: string;
1123
+ data?: JsonValue;
1124
+ };
1125
+ };
1126
+ /**
1127
+ * What callers use to send. The {@link Channel} factory binds an
1128
+ * {@link IRequestHandler} at construction (immutable for the channel's
1129
+ * lifetime) and hands the caller back an `IRequestSender`.
1130
+ *
1131
+ * `TOutCtx` is the per-call context bag this sender understands. For
1132
+ * the base {@link JsonRpcChannel} it's `undefined` (the channel
1133
+ * doesn't read any overrides). Decorators like `SigningSender`
1134
+ * parametrise it on their own ctx shape.
1135
+ */
1136
+ interface IRequestSender<TOutCtx = undefined> {
1137
+ sendRequest(method: string, params: JsonValue | undefined, opts?: SendOpts<TOutCtx>): Promise<JsonValue>;
1138
+ sendNotification(method: string, params: JsonValue | undefined, opts?: SendOpts<TOutCtx>): Promise<void>;
1332
1139
  /**
1333
- * Reply to a {@link StreamControlType.ping}, echoing the ping's
1334
- * `nonce` so the prober can correlate it. Travels opposite the ping.
1335
- * Carries no app effect — purely a liveness acknowledgement.
1140
+ * Issue a request that participates in the streaming sub-protocol.
1141
+ * Returns synchronously with the wire request id, the result
1142
+ * promise, and a `send` for emitting client→server stream messages.
1336
1143
  */
1337
- readonly pong: "pong";
1338
- };
1339
- type StreamControlType = (typeof StreamControlType)[keyof typeof StreamControlType];
1144
+ sendRequestWithStream(method: string, params: JsonValue | undefined, opts?: StreamSendOpts<TOutCtx>): RawStreamingCall;
1145
+ close(): void;
1146
+ }
1340
1147
  /**
1341
- * Well-known `control.reason` strings. The set is **open** — any string
1342
- * is valid on the wire; these are the reasons linkrpc itself emits.
1148
+ * Handle for a request issued via
1149
+ * {@link IRequestSender.sendRequestWithStream}. `send` emits
1150
+ * client→server stream messages correlated with this call. `result`
1151
+ * resolves with the call's response.
1343
1152
  */
1344
- declare const StreamControlReason: {
1153
+ interface RawStreamingCall {
1154
+ readonly result: Promise<JsonValue>;
1155
+ /** Emit a client→server (`toCallee`) stream message correlated with this call. */
1156
+ send(payload: JsonValue): void;
1345
1157
  /**
1346
- * The caller's transport dropped while the request was in flight; the
1347
- * hub cancels the callee's now-orphaned work.
1158
+ * Ask the callee to abort this in-flight request (a `toCallee`
1159
+ * `cancel` control). Advisory: the request settles via its normal
1160
+ * response (typically a `cancelled` error). `reason` is an open-set
1161
+ * diagnostic string (see `StreamControlReason`).
1348
1162
  */
1349
- readonly clientDisconnected: "clientDisconnected";
1163
+ cancel(reason?: string): void;
1350
1164
  /**
1351
- * The request exceeded the hub's idle timeout with no stream activity
1352
- * (no ping, no stream message). See {@link STREAM_METHOD} docs.
1165
+ * Stop tracking this request locally and reject {@link result}. This does
1166
+ * not notify the callee; call {@link cancel} first when remote work should
1167
+ * also be cancelled. Safe to call after the request has already settled.
1353
1168
  */
1354
- readonly idleTimeout: "idleTimeout";
1355
- };
1356
- type StreamControlReason = (typeof StreamControlReason)[keyof typeof StreamControlReason];
1169
+ dispose?(reason?: string): void;
1170
+ /**
1171
+ * Liveness probe toward the callee: emit a `toCallee` ping and
1172
+ * resolve once the callee's `pong` (matching nonce) returns. Rejects
1173
+ * if the request settles first. Independent of the channel's
1174
+ * automatic keepalive ping.
1175
+ */
1176
+ ping(): Promise<void>;
1177
+ }
1357
1178
  /**
1358
- * Streaming sub-protocol. Long-running requests can emit additional
1359
- * notifications correlated with the original call in either direction
1360
- * (callee → caller progress, caller → callee input / cancellation /
1361
- * keepalive).
1362
- *
1363
- * Wire form: a JSON-RPC notification whose method is
1364
- * `${streamInterface.info.id}::send` and whose params match
1365
- * `streamInterface.members.send.paramsSchema`. The hub routes purely on
1366
- * `requestId` (following the originating request's established path, like
1367
- * a response); the originating request's capability authorization covers
1368
- * its full stream lifetime, so stream notifications carry no method /
1369
- * interface namespace of their own. App `payload` contents are typed per
1370
- * request via the originating method's
1371
- * `RequestType.clientStreamSchema` / `serverStreamSchema`; reserved
1372
- * `control` messages are schema-independent.
1179
+ * Per-send options.
1373
1180
  *
1374
- * Idle timeout: a request that never streams (no `control` ping, no
1375
- * stream message) is subject to the hub's per-request idle timeout
1376
- * (default 30 minutes) — at which point it is cancelled and its caller
1377
- * gets a `requestTimeout` error. This bounds the hub's pending-request
1378
- * table, which is also what protects it from a slow-loris / DDoS that
1379
- * opens requests and never completes them. Streaming-enabled calls keep
1380
- * themselves alive by emitting a periodic {@link StreamControlType.ping}.
1181
+ * `interfaceHash` is interface-level call metadata: the schema hash of
1182
+ * the interface a typed proxy is calling. It is independent of
1183
+ * `TOutCtx` — the connection stamps it from the interface definition,
1184
+ * the base {@link JsonRpcChannel} ignores it, and signing decorators
1185
+ * bake it into the `$hubrpc` envelope.
1381
1186
  *
1382
- * The interface is declarative: nobody calls
1383
- * `LinkRpcConnection.register(streamInterface, ...)`. The channel and the
1384
- * hub intercept `$stream::send` directly. The definition exists so
1385
- * reflection / consent UIs can describe the wire shape and so all wire
1386
- * constants derive from one source.
1387
- */
1388
- declare const streamInterface: InterfaceDefinition<{
1389
- send: NotificationType<{
1390
- requestId: string | number;
1391
- dir: "toCaller" | "toCallee";
1392
- control?: {
1393
- type: "cancel" | "ping" | "pong";
1394
- reason?: string | undefined;
1395
- nonce?: string | undefined;
1396
- } | undefined;
1397
- payload?: unknown;
1398
- }>;
1399
- }>;
1187
+ * `ctx` is the sender's `TOutCtx`-typed override / extension bag for
1188
+ * per-call decorator overrides (e.g. `signerOverride`, `capsOverride`).
1189
+ * The base {@link JsonRpcChannel} ignores `ctx` entirely; decorators
1190
+ * like `SigningSender` interpret it.
1191
+ */
1192
+ interface SendOpts<TOutCtx = undefined> {
1193
+ readonly ctx?: TOutCtx;
1194
+ /** Interface schema hash for this call (interface-level metadata). */
1195
+ readonly interfaceHash?: string;
1196
+ }
1197
+ interface StreamSendOpts<TOutCtx = undefined> extends SendOpts<TOutCtx> {
1198
+ readonly onStreamMessage?: (payload: JsonValue) => void;
1199
+ }
1400
1200
  /**
1401
- * Full wire method name for stream notifications. Pulled from the
1402
- * interface object so we have a single source of truth.
1201
+ * Convenience: the transport type a {@link JsonRpcChannel} expects.
1202
+ * Outbound is plain `JsonRpcMessage` — the base channel does not
1203
+ * attach context to outgoing wire messages.
1403
1204
  */
1404
- declare const STREAM_METHOD: `${string}::send`;
1405
- /** Wire-level shape carried on `params` of {@link STREAM_METHOD}. */
1406
- type StreamSendParams = output<typeof streamInterface.members.send.paramsSchema>;
1407
- //#endregion
1408
- //#region src/protocol/jcs.d.ts
1205
+ type ChannelTransport<TInCtx = undefined> = IMessageTransport<MessageWithCtx<TInCtx>>;
1409
1206
  /**
1410
- * RFC 8785 JSON Canonicalization Scheme (JCS).
1411
- *
1412
- * Used as the byte-deterministic encoding under every linkrpc signature
1413
- * (RPC calls, capabilities, hub-signed previews). Both signer and verifier
1414
- * canonicalize the same value object and obtain byte-identical UTF-8 bytes.
1415
- *
1416
- * Implementation inlined from the `canonicalize` npm package (Apache-2.0,
1417
- * https://github.com/erdtman/canonicalize) so this module stays
1418
- * zero-dependency for browser bundlers that don't resolve transitive
1419
- * npm specifiers (e.g. the in-house app-bundler).
1207
+ * Type of incoming messages on the channel's transport. With
1208
+ * `TInCtx = undefined` (default) this is just `JsonRpcMessage`. With a
1209
+ * concrete `TInCtx`, the transport carries a `context` field alongside
1210
+ * the message — out-of-band, never sent over a wire, set by the
1211
+ * in-process producer.
1420
1212
  */
1421
- /** RFC 8785 canonical JSON string for `value`. */
1422
- declare function jcsCanonicalize(value: unknown): string;
1423
- /** UTF-8 bytes of the RFC 8785 canonical JSON for `value`. The thing actually signed / hashed. */
1424
- declare function jcsCanonicalizeBytes(value: unknown): Uint8Array;
1213
+ type MessageWithCtx<TInCtx> = [TInCtx] extends [undefined] ? JsonRpcMessage : JsonRpcMessage & {
1214
+ context: TInCtx;
1215
+ };
1216
+ declare class RpcError extends Error {
1217
+ readonly code: number;
1218
+ /** Whether this error was decoded from a peer response. */
1219
+ readonly origin: 'local' | 'remote' | 'transport';
1220
+ readonly data?: JsonValue;
1221
+ readonly hasData: boolean;
1222
+ constructor(message: string, code: number, data?: JsonValue,
1223
+ /** Whether this error was decoded from a peer response. */
1224
+ origin?: 'local' | 'remote' | 'transport', hasData?: boolean);
1225
+ }
1425
1226
  //#endregion
1426
1227
  //#region src/crypto/cryptoProvider.d.ts
1427
1228
  /**
@@ -1808,1257 +1609,1974 @@ declare function permissionPermits(call: Call, permission: Permission, ability:
1808
1609
  */
1809
1610
  declare function capabilityPermits(call: Call, cap: Capability, ability: Ability): Verdict;
1810
1611
  //#endregion
1811
- //#region src/protocol/methodName.d.ts
1612
+ //#region src/identity/identity.d.ts
1613
+ /** JSON-serializable form of a {@link KeypairSigningIdentity} (base64url keys). */
1614
+ interface SerializedKeypairSigningIdentity {
1615
+ readonly privateKey: string;
1616
+ readonly publicKey: string;
1617
+ }
1812
1618
  /**
1813
- * Parsed JSON-RPC method string. The linkrpc dialect uses `::` to
1814
- * separate up to three segments:
1815
- *
1816
- * - `"member"` — bare (preset-bound dispatch)
1817
- * - `"interfaceId::member"` — interface form (root service)
1818
- * - `"::interfaceId::member"` — explicit root form
1819
- * - `"serviceId::interfaceId::member"` — fully-qualified form
1820
- *
1821
- * The hub does not accept the `bare` form (it has no interface context
1822
- * to route on). Connection-level dispatch accepts all three.
1619
+ * The public face of a signing identity: its stable {@link PrincipalId} name
1620
+ * and the {@link KeyId} its signatures are stamped with. In Phase 1 (perpetual
1621
+ * identities) the keyId is the genesis key embedded in the principal, so it is
1622
+ * derived by stripping the `id:` prefix.
1823
1623
  */
1824
- type ParsedMethodName = {
1825
- kind: "bare";
1826
- member: string;
1827
- } | {
1828
- kind: "interface";
1829
- interfaceId: string;
1830
- member: string;
1831
- } | {
1832
- kind: "full";
1833
- serviceId: string;
1834
- interfaceId: string;
1835
- member: string;
1836
- };
1624
+ declare class PublicSigningIdentity {
1625
+ readonly principal: PrincipalId;
1626
+ constructor(principal: PrincipalId);
1627
+ /** The {@link KeyId} this identity signs with (its genesis key, in Phase 1). */
1628
+ get keyId(): KeyId;
1629
+ }
1630
+ interface SigningIdentity {
1631
+ readonly publicSigningIdentity: PublicSigningIdentity;
1632
+ sign(bytes: Uint8Array): Promise<Uint8Array>;
1633
+ }
1837
1634
  /**
1838
- * Parse a JSON-RPC method string. Returns `undefined` if any segment is
1839
- * empty or the segment count is out of range.
1635
+ * {@link SigningIdentity} backed by an in-process keypair. For the common
1636
+ * case where the signing material lives in memory. For external HSM-style
1637
+ * backends, implement {@link SigningIdentity} directly.
1840
1638
  */
1841
- declare function parseMethodName(method: string): ParsedMethodName | undefined;
1639
+ declare class KeypairSigningIdentity implements SigningIdentity {
1640
+ private readonly _privateKey;
1641
+ readonly publicSigningIdentity: PublicSigningIdentity;
1642
+ constructor(principal: PrincipalId, _privateKey: PrivateKey);
1643
+ sign(message: Uint8Array): Promise<Signature>;
1644
+ static fromKeypair(keypair: Keypair): KeypairSigningIdentity;
1645
+ /** Generate a fresh signing identity (Ed25519 keypair). */
1646
+ static generateNew(): Promise<KeypairSigningIdentity>;
1647
+ /** Restore an identity from its {@link toJson} form. */
1648
+ static fromJson(json: SerializedKeypairSigningIdentity): KeypairSigningIdentity;
1649
+ /** Serialize the keypair to a JSON-friendly form (base64url keys). */
1650
+ toJson(): SerializedKeypairSigningIdentity;
1651
+ }
1652
+ declare class PublicWrappingIdentity {
1653
+ readonly wrapPublicKey: Uint8Array;
1654
+ constructor(wrapPublicKey: Uint8Array);
1655
+ }
1656
+ interface WrappingIdentity {
1657
+ readonly publicWrappingIdentity: PublicWrappingIdentity;
1658
+ wrap(domain: string, bytes: Uint8Array): Promise<Uint8Array>;
1659
+ unwrap(domain: string, blob: Uint8Array): Promise<Uint8Array>;
1660
+ }
1661
+ interface Identity extends SigningIdentity, WrappingIdentity {
1662
+ /** The identity's stable {@link PrincipalId} name. */
1663
+ readonly principal: PrincipalId;
1664
+ /** @deprecated */
1665
+ readonly wrapPublicKey: Uint8Array;
1666
+ }
1842
1667
  /**
1843
- * Convert a parsed method string to a {@link CallTarget} for capability
1844
- * matching. Interface-form calls are addressed to the root service —
1845
- * represented as an empty `serviceId`. Throws on `bare` form (no
1846
- * interface context) and on malformed input.
1668
+ * Full {@link Identity} backed by in-process Ed25519 (signing) and X25519
1669
+ * (wrapping) keypairs. The local counterpart to a keystore/executor-backed
1670
+ * identity — used by self-managed principals that hold their own key
1671
+ * material (e.g. loaded from disk). For external HSM-style backends,
1672
+ * implement {@link Identity} directly.
1847
1673
  */
1848
- declare function methodNameToTarget(method: string): CallTarget;
1674
+ declare class KeypairIdentity implements Identity {
1675
+ private readonly _privateKey;
1676
+ private readonly _wrap;
1677
+ readonly principal: PrincipalId;
1678
+ readonly wrapPublicKey: Uint8Array;
1679
+ readonly publicSigningIdentity: PublicSigningIdentity;
1680
+ readonly publicWrappingIdentity: PublicWrappingIdentity;
1681
+ constructor(principal: PrincipalId, _privateKey: PrivateKey, _wrap: X25519Keypair);
1682
+ sign(message: Uint8Array): Promise<Signature>;
1683
+ wrap(domain: string, bytes: Uint8Array): Promise<Uint8Array>;
1684
+ unwrap(domain: string, blob: Uint8Array): Promise<Uint8Array>;
1685
+ /** Generate a fresh identity (Ed25519 + X25519 keypairs). */
1686
+ static generate(): Promise<KeypairIdentity>;
1687
+ }
1849
1688
  //#endregion
1850
- //#region src/protocol/linkRpcEnvelope.d.ts
1689
+ //#region src/identity/capability.d.ts
1851
1690
  /**
1852
- * Signed call meta. Lives under `params.$hubrpc` so it can't collide with
1853
- * the user's top-level param keys. Present on signed AND unsigned calls
1854
- * (the latter omit {@link CallMeta.principal} and carry no `$hubrpcSignature`).
1691
+ * Pure freshness check for a single capability link: `true` when the cap never
1692
+ * expires, or its `expiresAtMs` is still in the future at `now + marginMs`.
1855
1693
  *
1856
- * Included verbatim in the bytes a call signature commits to — the
1857
- * signature covers `signingInput("call", { ...userParams, $hubrpc })`.
1694
+ * Mirrors the gate's expiry rule in {@link verifyChain}'s link check
1695
+ * (`expiresAtMs < nowMs` ⇒ expired) so a producer can decide, *before signing*,
1696
+ * whether to re-acquire a cap rather than attach one the gate will reject as
1697
+ * `expired`. The `marginMs` safety window absorbs in-flight transit time and
1698
+ * client/hub clock skew — pass the call's `signedAtMs` as `now` so the check
1699
+ * evaluates expiry against the same instant baked into the envelope.
1700
+ *
1701
+ * This checks ONE link. Effective authority requires every link in a
1702
+ * delegation chain to be unexpired, so a producer attaching a bag should apply
1703
+ * this to every cap it would attach (see {@link capBagFreshAt}).
1858
1704
  */
1859
- interface CallMeta {
1860
- /** Fully-qualified wire method. The verifier asserts it equals the JSON-RPC `method`. */
1861
- readonly method: string;
1862
- /** Replay-protection nonce (base64url). The gate dedups on this. */
1863
- readonly nonce: string;
1864
- /** Unix milliseconds. Skew window enforced by the verifier. */
1865
- readonly signedAtMs: number;
1866
- /** Identity wielding the call. Present iff signed; equals the audience of every presented cap. */
1867
- readonly principal?: PrincipalId;
1868
- /** Optional schema hash assertion. Matched against `TargetPattern.interfaceHash`. */
1869
- readonly interfaceHash?: string;
1870
- }
1705
+ declare function capabilityFreshAt(cap: Capability, now: number, marginMs?: number): boolean;
1871
1706
  /**
1872
- * Extrinsic, unsigned attachments carried under `params.$hubrpcUnsigned`.
1873
- * Not covered by the call signature (they aren't authored by the signer).
1707
+ * Freshness over a whole presented bag: `true` only when every cap is fresh at
1708
+ * `now + marginMs` (see {@link capabilityFreshAt}). An empty bag is trivially
1709
+ * fresh. Use this at the cap-production point to decide whether to re-acquire.
1874
1710
  */
1875
- interface LinkRpcUnsigned {
1876
- /** Caller's presented capability bag. Parents are resolved out of this by hash. */
1877
- readonly capabilities?: readonly SignedCapability[];
1878
- }
1879
- /** Reserved wire-key meta carried on a linkrpc call's params object. */
1880
- interface LinkRpcWireMeta {
1881
- readonly [HUBRPC_META_KEY]?: CallMeta;
1882
- readonly [HUBRPC_SIGNATURE_KEY]?: Signatures;
1883
- readonly [HUBRPC_UNSIGNED_KEY]?: LinkRpcUnsigned;
1711
+ declare function capBagFreshAt(caps: readonly Capability[], now: number, marginMs?: number): boolean;
1712
+ type PermitResult = {
1713
+ ok: true;
1714
+ capabilityNonce: string;
1715
+ rootIssuer: PrincipalId;
1716
+ } | {
1717
+ ok: false;
1718
+ reason: string;
1719
+ };
1720
+ /**
1721
+ * A trust anchor accepted as a capability-chain root, plus whether it may be
1722
+ * named in authorization error messages.
1723
+ */
1724
+ interface AcceptedRootIssuer {
1725
+ /** The principal accepted as a chain root for the queried service. */
1726
+ principal: PrincipalId;
1727
+ /**
1728
+ * Whether this issuer may be disclosed in `permits` rejection reasons.
1729
+ * Public anchors (e.g. a hub's well-known admin identity) are surfaced to
1730
+ * help diagnose "wrong root" failures; private ones are withheld so the
1731
+ * error never leaks the set of trusted issuers.
1732
+ */
1733
+ isPublic: boolean;
1884
1734
  }
1885
1735
  /**
1886
- * Wire shape of `params` on a linkrpc JSON-RPC call.
1736
+ * **The** authorization predicate. A call is permitted iff some presented
1737
+ * capability (1) addresses the call, (2) has a genuine, well-delegated
1738
+ * chain whose leaf audience is the caller (`call.signer`), and (3) roots
1739
+ * at an issuer the verifier accepts **for the call's service**.
1887
1740
  *
1888
- * The user's params object (if any) is spread as-is, with the
1889
- * {@link LinkRpcWireMeta} keys attached on top. `TUserParams` carries the
1890
- * user-visible param shape; defaults to an open object. User params MUST be
1891
- * a plain object — enforced at signing/verification via
1892
- * {@link requireObjectParams}.
1741
+ * Pure: it reports the verdict (and the `capabilityNonce` / `rootIssuer`
1742
+ * for audit) but performs no consumption. Replay is the caller's job — the
1743
+ * gate dedups `call.nonce`, so `callBind` grants are single-use for free.
1744
+ *
1745
+ * `acceptedRootIssuers` is consulted with the call's `serviceId` and returns
1746
+ * the accepted {@link AcceptedRootIssuer} anchors; an empty result rejects
1747
+ * every capability (fail closed) — trust is the verifier's, never the
1748
+ * token's. Anchors flagged `isPublic` are named in the rejection reason when
1749
+ * a chain roots at an unaccepted issuer.
1893
1750
  */
1894
- type LinkRpcWireParams<TUserParams extends {
1895
- [key: string]: JsonValue | undefined;
1896
- } = {
1897
- [key: string]: JsonValue | undefined;
1898
- }> = TUserParams & LinkRpcWireMeta;
1899
- /** JSON-RPC request whose `params` carry the linkrpc wire meta. */
1900
- type LinkRpcJsonRpcRequest<TUserParams extends {
1901
- [key: string]: JsonValue | undefined;
1902
- } = {
1903
- [key: string]: JsonValue | undefined;
1904
- }> = JsonRpcRequest<LinkRpcWireParams<TUserParams>>;
1905
- /** JSON-RPC notification whose `params` carry the linkrpc wire meta. */
1906
- type LinkRpcJsonRpcNotification<TUserParams extends {
1907
- [key: string]: JsonValue | undefined;
1908
- } = {
1909
- [key: string]: JsonValue | undefined;
1910
- }> = JsonRpcNotification<LinkRpcWireParams<TUserParams>>;
1911
- /** Either of the two linkrpc-bearing JSON-RPC message shapes. */
1912
- type LinkRpcJsonRpcMessage<TUserParams extends {
1913
- [key: string]: JsonValue | undefined;
1914
- } = {
1915
- [key: string]: JsonValue | undefined;
1916
- }> = LinkRpcJsonRpcRequest<TUserParams> | LinkRpcJsonRpcNotification<TUserParams>;
1751
+ declare function permits(call: Call, capabilities: readonly SignedCapability[], acceptedRootIssuers: (serviceId: string) => readonly AcceptedRootIssuer[], nowMs: number, opts?: {
1752
+ maxDepth?: number;
1753
+ }): Promise<PermitResult>;
1917
1754
  /**
1918
- * The linkrpc signing/cap system accepts only plain-object user params (or
1919
- * none). Reject arrays/primitives at the boundary so "strip `$hubrpc*`, the
1920
- * rest is the signed user params" stays unambiguous.
1755
+ * Sign a `Capability` with a {@link SigningIdentity}. The private key never
1756
+ * leaves the identity. The result verifies via {@link verifyChain}.
1921
1757
  */
1922
- declare function requireObjectParams(userParams: JsonValue | undefined): Record<string, JsonValue | undefined>;
1758
+ declare function signCapability(capability: Capability, issuer: SigningIdentity): Promise<SignedCapability>;
1759
+ interface IssueCapabilityOptions {
1760
+ /** Identity allowed to present the capability. */
1761
+ readonly audience: PublicSigningIdentity;
1762
+ /** Authority granted to the audience. */
1763
+ readonly permissions: readonly Permission[];
1764
+ /** Optional expiration time as Unix milliseconds. */
1765
+ readonly expiresAtMs?: number;
1766
+ /** Optional parent whose authority this capability narrows. */
1767
+ readonly parent?: SignedCapability;
1768
+ }
1923
1769
  /**
1924
- * Return the application-authored portion of a LinkRPC params value.
1925
- *
1926
- * Routing and gate layers must continue forwarding the original wire params so
1927
- * every chained hub can independently verify the envelope. Terminal dispatch
1928
- * may use this derived value for application-schema validation without mutating
1929
- * or replacing the wire message.
1770
+ * Issue and sign a capability, deriving its issuer, nonce, and optional parent
1771
+ * hash. The result is plain JSON data and survives a JSON stringify/parse
1772
+ * round-trip without reconstruction.
1930
1773
  */
1931
- declare function stripLinkRpcWireMeta(wireParams: unknown): JsonValue | undefined;
1932
- //#endregion
1933
- //#region src/disposable.d.ts
1934
- /** Minimal disposable handle; calling `dispose` releases the resource. */
1935
- interface IDisposable {
1936
- dispose(): void;
1937
- }
1938
- //#endregion
1939
- //#region src/transport/messageTransport.d.ts
1940
- interface IMessageTransport<TIncoming = JsonRpcMessage, TOutgoing = JsonRpcMessage> {
1941
- send(message: TOutgoing): void | Promise<void>;
1942
- /**
1943
- * Sets the listener for incoming messages. Setting `undefined` detaches.
1944
- * The transport buffers messages received before a listener is attached
1945
- * and delivers them the next tick when one is set.
1946
- * Forgetting to set a listener will cause the queue to leak.
1947
- */
1948
- setListener(listener: ((message: TIncoming) => void) | undefined): void;
1949
- dispose(): void;
1950
- }
1951
- type MessageWithContext<TCtx> = JsonRpcMessage & {
1952
- context: TCtx;
1774
+ declare function issueCapability(issuer: SigningIdentity, options: IssueCapabilityOptions): Promise<SignedCapability>;
1775
+ type ParamMatcherFor<T> = {
1776
+ exact: T;
1777
+ } | {
1778
+ enum: T[];
1779
+ } | {
1780
+ any: true;
1781
+ } | (T extends string ? {
1782
+ prefix: string;
1783
+ } : never) | (T extends readonly string[] ? {
1784
+ subsetOf: string[];
1785
+ } : never);
1786
+ /** Type-safe top-level parameter matchers for one interface member. */
1787
+ type ParamMatchers<T> = T extends Record<string, unknown> ? { [K in keyof T]: ParamMatcherFor<Exclude<T[K], undefined>>; } : never;
1788
+ type RequestMemberName<TMembers extends MemberMap> = { [K in keyof TMembers]: TMembers[K] extends RequestType<any, any, any, any, any, any, any> ? K : never; }[keyof TMembers] & string;
1789
+ type RequestParams<TMember> = TMember extends RequestType<infer TParams, any, any, any, any, any, any> ? TParams : never;
1790
+ /** Match a string parameter by prefix. */
1791
+ declare function prefix(value: string): {
1792
+ prefix: string;
1953
1793
  };
1954
- type MessageTransportWithContext<TCtx> = IMessageTransport<JsonRpcMessage, MessageWithContext<TCtx>>;
1955
- type MessageTransportDirection = 'send' | 'receive';
1956
- type MessageTransportTrace = (direction: MessageTransportDirection, message: JsonRpcMessage) => void;
1957
1794
  /**
1958
- * Observe every message crossing a transport without changing its buffering or
1959
- * lifecycle behavior.
1795
+ * Build an invoke permission from a typed interface member. The helper derives
1796
+ * the interface id and schema hash and type-checks parameter matcher names and
1797
+ * values against the member's params.
1960
1798
  */
1961
- declare function traceMessageTransport(transport: IMessageTransport, trace: MessageTransportTrace): IMessageTransport;
1799
+ declare function invoke<TMembers extends MemberMap, TMember extends RequestMemberName<TMembers>>(serviceId: string, iface: InterfaceDefinition<TMembers>, member: TMember, params?: ParamMatchers<RequestParams<TMembers[TMember]>>): Permission;
1800
+ //#endregion
1801
+ //#region src/connection/jsonRpcChannel.d.ts
1962
1802
  /**
1963
- * Pipe two transports together: every message one receives is forwarded to
1964
- * the other's `send`. Returns a disposable that detaches both listeners.
1803
+ * Minimal JSON-RPC 2.0 channel: correlates requests with responses,
1804
+ * dispatches incoming requests/notifications to a handler.
1965
1805
  *
1966
- * Neither transport is disposed — the caller owns their lifecycle. This is
1967
- * the building block for relays (e.g. bridging a `WindowMessageTransport`
1968
- * for an iframe to a multiplexer channel).
1969
- */
1970
- declare function connectTransports<T extends JsonRpcMessage>(a: IMessageTransport<T>, b: IMessageTransport<T>): IDisposable;
1971
- /**
1972
- * Two in-memory transports wired back-to-back. Useful for tests and for
1973
- * same-process bridges.
1806
+ * Construct via {@link JsonRpcChannel.create}: it returns a
1807
+ * {@link Channel} factory which materialises the live channel once a
1808
+ * handler is supplied via `.connect(handler)`. The handler is fixed for
1809
+ * the channel's lifetime — no setter, no mid-flight swap.
1974
1810
  *
1975
- * Generic in the per-direction payload type so asymmetric pairs (e.g. one
1976
- * side sends plain `JsonRpcMessage`, the other side sends
1977
- * `JsonRpcMessage & { context: Participant }`) are expressible at the type
1978
- * level. At runtime both halves just hand objects through by reference.
1811
+ * The outbound `TOutCtx` of the produced sender is `unknown` — this
1812
+ * channel ignores per-call ctx entirely. Decorators (e.g.
1813
+ * `SigningSender`) lift it to a concrete shape.
1979
1814
  */
1980
- declare class TransportPair<TFromA = JsonRpcMessage, TFromB = JsonRpcMessage> {
1981
- readonly a: IMessageTransport<TFromB, TFromA>;
1982
- readonly b: IMessageTransport<TFromA, TFromB>;
1983
- constructor();
1984
- }
1985
- //#endregion
1986
- //#region src/transport/multiplexedTransport.d.ts
1987
- interface MuxEnvelope {
1988
- readonly $mux: "v1";
1989
- readonly ch: string;
1990
- readonly m: JsonRpcMessage;
1991
- }
1992
- declare class MultiplexedTransport<TChannels extends Record<string, string>> implements IDisposable {
1993
- static create<TChannels extends Record<string, string>>(base: IMessageTransport<MuxEnvelope, MuxEnvelope>, channels: TChannels): MultiplexedTransport<TChannels>;
1994
- /** Logical transports keyed by the friendly channel names. */
1995
- readonly transports: { readonly [K in keyof TChannels]: IMessageTransport; };
1996
- private readonly _base;
1997
- private readonly _byId;
1998
- private readonly _usedIds;
1999
- private _disposed;
2000
- constructor(base: IMessageTransport<MuxEnvelope, MuxEnvelope>, channels: TChannels);
1815
+ declare class JsonRpcChannel<TInCtx = undefined> implements IRequestSender<unknown> {
1816
+ private readonly _transport;
2001
1817
  /**
2002
- * Add a logical channel after the multiplexer has started.
2003
- *
2004
- * Channel ids are permanently retired when disposed. This prevents a late
2005
- * envelope for an old iframe from being delivered to a replacement iframe.
1818
+ * Wrap a transport in a {@link Channel}. The channel's sender is live
1819
+ * immediately; call {@link Channel.setRequestHandler} (or pass the channel
1820
+ * to {@link LinkRpcConnection}) to bind the inbound handler.
2006
1821
  */
2007
- addChannel(id: string): IMessageTransport;
2008
- dispose(): void;
2009
- private _createChannel;
2010
- }
2011
- //#endregion
2012
- //#region src/connection/channel.d.ts
2013
- declare class Channel<TInCtx = undefined, TOutCtx = undefined> {
2014
- readonly sender: IRequestSender<TOutCtx>;
2015
- private readonly _setHandler;
2016
- private readonly _setWireObserver?;
2017
- constructor(sender: IRequestSender<TOutCtx>, _setHandler: (h: IRequestHandler<TInCtx> | undefined) => void, _setWireObserver?: ((observer: WireMessageObserver | undefined) => void) | undefined);
2018
- /** Bind the inbound request/notification handler. May be called before or after construction of {@link LinkRpcConnection}. */
2019
- setRequestHandler(handler: IRequestHandler<TInCtx> | undefined): void;
1822
+ static create<TInCtx = undefined>(transport: ChannelTransport<TInCtx>): Channel<TInCtx, unknown>;
1823
+ /** Wrap a transport and retain an explicit lifecycle hook for its owner. */
1824
+ static createWithClose<TInCtx = undefined>(transport: ChannelTransport<TInCtx>): {
1825
+ channel: Channel<TInCtx, unknown>;
1826
+ close: () => void;
1827
+ };
1828
+ private _nextId;
1829
+ private readonly _pending;
2020
1830
  /**
2021
- * Install the endpoint inspection observer at the JSON-RPC wire boundary.
2022
- * Intended for {@link LinkRpcConnection}; ordinary consumers should use the
2023
- * public `hubrpc.traffic` service instead.
1831
+ * Per-request callbacks invoked when a {@link STREAM_METHOD}
1832
+ * notification arrives with a matching `requestId`. Used in both
1833
+ * directions: outgoing-request callers register here keyed by the
1834
+ * id they sent; per-call incoming-request stream handles register
1835
+ * keyed by the id they observed. Entries are removed when the
1836
+ * corresponding request completes (response received for outgoing,
1837
+ * response sent for incoming).
2024
1838
  */
2025
- setWireMessageObserver(observer: WireMessageObserver | undefined): void;
1839
+ private readonly _streamListeners;
2026
1840
  /**
2027
- * Compose this channel with a sender-side decorator (typically the
2028
- * signing layer). The decorator wraps {@link sender} only; the
2029
- * {@link setRequestHandler} binding is shared with the original channel
2030
- * so the receive side is bound exactly once regardless of decoration depth.
1841
+ * Per-incoming-request handlers for reserved `control` messages
1842
+ * (cancel / ping / pong) arriving as stream notifications. Keyed
1843
+ * by the id observed; removed when the request settles.
2031
1844
  */
2032
- withSender<TNewOutCtx>(decorate: (raw: IRequestSender<TOutCtx>) => IRequestSender<TNewOutCtx>): Channel<TInCtx, TNewOutCtx>;
2033
- }
2034
- type WireMessageDirection = 'inbound' | 'outbound';
2035
- type WireMessageObserver = (direction: WireMessageDirection, message: JsonRpcMessage) => void;
2036
- interface IRequestHandler<TInCtx = undefined> {
2037
- handleRequest(call: IncomingCall<TInCtx>): Promise<Result>;
2038
- handleNotification(call: IncomingCall<TInCtx>): void;
2039
- }
2040
- /**
2041
- * Inbound call observed by an {@link IRequestHandler}. `TInCtx` is the
2042
- * per-call out-of-band context the transport attached on the receiving
2043
- * side (e.g. the hub stamps `Participant` on overlay-bound messages).
2044
- * For wire transports it's `undefined`.
2045
- */
2046
- interface IncomingCall<TInCtx = undefined> {
2047
- method: string;
2048
- params: JsonValue | undefined;
2049
- /** Out-of-band context attached by the transport, if any. */
2050
- context: TInCtx;
1845
+ private readonly _streamControl;
1846
+ private readonly _incomingAborts;
1847
+ private _handler;
1848
+ private _wireObserver;
1849
+ private _closeError;
1850
+ setRequestHandler(handler: IRequestHandler<TInCtx> | undefined): void;
1851
+ setWireMessageObserver(observer: WireMessageObserver | undefined): void;
1852
+ private constructor();
1853
+ sendRequest(method: string, params: JsonValue | undefined, opts?: SendOpts<unknown>): Promise<JsonValue>;
1854
+ sendNotification(method: string, params: JsonValue | undefined, opts?: SendOpts<unknown>): Promise<void>;
1855
+ sendRequestWithStream(method: string, params: JsonValue | undefined, opts?: StreamSendOpts<unknown>): RawStreamingCall;
2051
1856
  /**
2052
- * Per-call streaming handle. Both directions live on this object,
2053
- * scoped to the request's lifetime. The inbound listener is auto-
2054
- * detached when the handler's response settles. For notifications
2055
- * (no request id) the handle is a no-op stub.
1857
+ * Build the symmetric ping/pong machinery for one in-flight request.
1858
+ *
1859
+ * `outboundDir` is the direction *this* side emits controls in
1860
+ * (`toCallee` for the caller, `toCaller` for the callee). A received
1861
+ * ping is answered with a pong in that same direction, echoing the
1862
+ * ping's nonce; a received pong resolves the matching outstanding
1863
+ * {@link ping} probe.
2056
1864
  */
2057
- stream: IncomingStream;
1865
+ private _makePinger;
2058
1866
  /**
2059
- * Aborts when the caller cancels this in-flight request (a
2060
- * `toCallee` `cancel` control), or when the hub cancels it on the
2061
- * caller's behalf (caller disconnect / idle timeout). The handler
2062
- * should observe this and settle promptly — typically by throwing,
2063
- * which surfaces as a `cancelled` error response. For notifications
2064
- * this never aborts.
1867
+ * Emit a stream notification ({@link STREAM_METHOD}) associated with
1868
+ * an in-flight request. Internal: outgoing-side callers reach this
1869
+ * via {@link RawStreamingCall.send} / `cancel`; incoming-side handlers
1870
+ * reach it via {@link IncomingStream.send}.
2065
1871
  */
2066
- signal: AbortSignal;
2067
- }
2068
- /**
2069
- * Per-call streaming handle attached to {@link IncomingCall.stream}.
2070
- * Scoped to a single in-flight request; the channel automatically
2071
- * detaches the inbound listener when the handler's response settles.
2072
- *
2073
- * For notifications (which have no request id), `requestId` is
2074
- * `undefined`, `send` is a no-op, and `onMessage` is a no-op.
1872
+ private _sendStream;
1873
+ close(): void;
1874
+ private _throwIfClosed;
1875
+ private _onMessage;
1876
+ private _handleStreamNotification;
1877
+ private _handleRequest;
1878
+ private _handleNotification;
1879
+ private _observeInbound;
1880
+ private _observeOutbound;
1881
+ private _observeSendFailure;
1882
+ }
1883
+ //#endregion
1884
+ //#region src/identity/managedIdentity.d.ts
1885
+ /**
1886
+ * Executor-side backing for `identity.storage::*`. Lifecycle tied to a
1887
+ * single managed-identity slot; the executor decides where bytes are
1888
+ * stored.
2075
1889
  */
2076
- interface IncomingStream {
2077
- /** Emit a server→client stream notification correlated with this call. */
2078
- send(payload: JsonValue): Promise<void>;
2079
- /**
2080
- * Register a listener for client→server stream messages correlated
2081
- * with this call. Pass `undefined` to detach. Replaces any prior
2082
- * listener. The channel detaches the listener automatically when
2083
- * the handler's response settles.
2084
- */
2085
- onMessage(listener: ((payload: JsonValue) => void) | undefined): void;
2086
- /**
2087
- * Liveness probe toward the caller: emit a `toCaller` ping and
2088
- * resolve once the caller's `pong` (matching nonce) returns. Rejects
2089
- * if the request settles first. Independent of the channel's
2090
- * automatic keepalive ping.
2091
- */
2092
- ping(): Promise<void>;
1890
+ interface ManagedIdentityStorageBackend {
1891
+ get(key: string): Promise<unknown | undefined>;
1892
+ set(key: string, value: unknown): Promise<void>;
1893
+ /** Returns `true` iff the key existed before this call. */
1894
+ delete(key: string): Promise<boolean>;
1895
+ list(prefix?: string): Promise<string[]>;
2093
1896
  }
2094
- type Result = {
2095
- result: JsonValue;
2096
- } | {
2097
- error: {
2098
- code: number;
2099
- message: string;
2100
- data?: JsonValue;
2101
- };
2102
- };
2103
1897
  /**
2104
- * What callers use to send. The {@link Channel} factory binds an
2105
- * {@link IRequestHandler} at construction (immutable for the channel's
2106
- * lifetime) and hands the caller back an `IRequestSender`.
2107
- *
2108
- * `TOutCtx` is the per-call context bag this sender understands. For
2109
- * the base {@link JsonRpcChannel} it's `undefined` (the channel
2110
- * doesn't read any overrides). Decorators like `SigningSender`
2111
- * parametrise it on their own ctx shape.
1898
+ * In-process storage backend. Used by tests and by any executor that
1899
+ * doesn't need at-rest persistence.
2112
1900
  */
2113
- interface IRequestSender<TOutCtx = undefined> {
2114
- sendRequest(method: string, params: JsonValue | undefined, opts?: SendOpts<TOutCtx>): Promise<JsonValue>;
2115
- sendNotification(method: string, params: JsonValue | undefined, opts?: SendOpts<TOutCtx>): Promise<void>;
2116
- /**
2117
- * Issue a request that participates in the streaming sub-protocol.
2118
- * Returns synchronously with the wire request id, the result
2119
- * promise, and a `send` for emitting client→server stream messages.
2120
- */
2121
- sendRequestWithStream(method: string, params: JsonValue | undefined, opts?: StreamSendOpts<TOutCtx>): RawStreamingCall;
2122
- close(): void;
1901
+ declare class InMemoryManagedIdentityStorage implements ManagedIdentityStorageBackend {
1902
+ private readonly _data;
1903
+ get(key: string): Promise<unknown | undefined>;
1904
+ set(key: string, value: unknown): Promise<void>;
1905
+ delete(key: string): Promise<boolean>;
1906
+ list(prefix?: string): Promise<string[]>;
2123
1907
  }
2124
1908
  /**
2125
- * Handle for a request issued via
2126
- * {@link IRequestSender.sendRequestWithStream}. `send` emits
2127
- * client→server stream messages correlated with this call. `result`
2128
- * resolves with the call's response.
1909
+ * In-process `ManagedIdentity` that holds the private key in memory and
1910
+ * uses the package crypto API. Useful for tests and for hub-side features
1911
+ * that want a short-lived identity without touching disk.
2129
1912
  */
2130
- interface RawStreamingCall {
2131
- readonly result: Promise<JsonValue>;
2132
- /** Emit a client→server (`toCallee`) stream message correlated with this call. */
2133
- send(payload: JsonValue): void;
2134
- /**
2135
- * Ask the callee to abort this in-flight request (a `toCallee`
2136
- * `cancel` control). Advisory: the request settles via its normal
2137
- * response (typically a `cancelled` error). `reason` is an open-set
2138
- * diagnostic string (see `StreamControlReason`).
2139
- */
2140
- cancel(reason?: string): void;
2141
- /**
2142
- * Stop tracking this request locally and reject {@link result}. This does
2143
- * not notify the callee; call {@link cancel} first when remote work should
2144
- * also be cancelled. Safe to call after the request has already settled.
2145
- */
2146
- dispose?(reason?: string): void;
2147
- /**
2148
- * Liveness probe toward the callee: emit a `toCallee` ping and
2149
- * resolve once the callee's `pong` (matching nonce) returns. Rejects
2150
- * if the request settles first. Independent of the channel's
2151
- * automatic keepalive ping.
2152
- */
2153
- ping(): Promise<void>;
1913
+ declare class InMemoryManagedIdentity implements Identity {
1914
+ private readonly _ed;
1915
+ private readonly _wrap;
1916
+ readonly principal: PrincipalId;
1917
+ readonly wrapPublicKey: Uint8Array;
1918
+ constructor(_ed: Keypair, _wrap: X25519Keypair);
1919
+ get publicSigningIdentity(): PublicSigningIdentity;
1920
+ get publicWrappingIdentity(): PublicWrappingIdentity;
1921
+ sign(bytes: Uint8Array): Promise<Signature>;
1922
+ wrap(domain: string, bytes: Uint8Array): Promise<Uint8Array>;
1923
+ unwrap(domain: string, blob: Uint8Array): Promise<Uint8Array>;
1924
+ /** Generate a fresh in-memory identity (Ed25519 + X25519 keypairs). */
1925
+ static generate(): Promise<InMemoryManagedIdentity>;
2154
1926
  }
2155
1927
  /**
2156
- * Per-send options.
1928
+ * Register the `identity` interface on `overlay` so the bound participant
1929
+ * can call `identity::sign` etc. on its root overlay. The overlay is
1930
+ * private to one participant — no other peer can reach these methods.
2157
1931
  *
2158
- * `interfaceHash` is interface-level call metadata: the schema hash of
2159
- * the interface a typed proxy is calling. It is independent of
2160
- * `TOutCtx` — the connection stamps it from the interface definition,
2161
- * the base {@link JsonRpcChannel} ignores it, and signing decorators
2162
- * bake it into the `$hubrpc` envelope.
1932
+ * When `storage` is supplied, the `identity.storage` interface is
1933
+ * registered alongside `identity::*`. Lifetime/scope of the backend is
1934
+ * the executor's responsibility — for keystore-backed identities the
1935
+ * backend lives as long as the identity slot does.
2163
1936
  *
2164
- * `ctx` is the sender's `TOutCtx`-typed override / extension bag for
2165
- * per-call decorator overrides (e.g. `signerOverride`, `capsOverride`).
2166
- * The base {@link JsonRpcChannel} ignores `ctx` entirely; decorators
2167
- * like `SigningSender` interpret it.
1937
+ * Typical caller: the executor (e.g. the VS Code extension), right after
1938
+ * `Hub.attachParticipant`, on the `rootOverlay` returned from the attach
1939
+ * handle.
2168
1940
  */
2169
- interface SendOpts<TOutCtx = undefined> {
2170
- readonly ctx?: TOutCtx;
2171
- /** Interface schema hash for this call (interface-level metadata). */
2172
- readonly interfaceHash?: string;
2173
- }
2174
- interface StreamSendOpts<TOutCtx = undefined> extends SendOpts<TOutCtx> {
2175
- readonly onStreamMessage?: (payload: JsonValue) => void;
2176
- }
1941
+ declare function registerIdentityOnOverlay(overlay: LinkRpcConnection, identity: Identity, storage?: ManagedIdentityStorageBackend): void;
2177
1942
  /**
2178
- * Convenience: the transport type a {@link JsonRpcChannel} expects.
2179
- * Outbound is plain `JsonRpcMessage` — the base channel does not
2180
- * attach context to outgoing wire messages.
1943
+ * Like {@link registerIdentityOnOverlay}, but resolves the identity lazily on
1944
+ * first use via `resolveIdentity`. The identity is materialized only when the
1945
+ * bound participant actually calls `identity::*` — registering the overlay
1946
+ * does NOT create or load any identity.
1947
+ *
1948
+ * This is essential for the consent model: a host can serve `identity::*` on a
1949
+ * keystore slot without making the slot privileged (`hasState`) until the app
1950
+ * genuinely opts into an identity. `resolveIdentity` is expected to be cheap on
1951
+ * repeat calls (the keystore caches in memory), and to reflect lifecycle
1952
+ * changes — e.g. after a slot is wiped and re-created ("Reset Identity"), the
1953
+ * next call resolves the fresh identity.
1954
+ *
1955
+ * `storage` is registered eagerly because reading/writing storage is itself
1956
+ * the privileged act the app must perform to gain state — exposing the
1957
+ * interface costs nothing until used.
2181
1958
  */
2182
- type ChannelTransport<TInCtx = undefined> = IMessageTransport<MessageWithCtx<TInCtx>>;
1959
+ declare function registerLazyIdentityOnOverlay(overlay: LinkRpcConnection<unknown>, resolveIdentity: () => Promise<Identity>, storage?: ManagedIdentityStorageBackend): void;
2183
1960
  /**
2184
- * Type of incoming messages on the channel's transport. With
2185
- * `TInCtx = undefined` (default) this is just `JsonRpcMessage`. With a
2186
- * concrete `TInCtx`, the transport carries a `context` field alongside
2187
- * the message — out-of-band, never sent over a wire, set by the
2188
- * in-process producer.
1961
+ * Client-side proxy for `identity.storage::*`. Methods round-trip through
1962
+ * the participant's root overlay; the executor enforces key-shape rules
1963
+ * server-side.
1964
+ *
1965
+ * Calls are unsigned (same recursion-guard rationale as
1966
+ * {@link createManagedIdentity} — the overlay is private to one
1967
+ * participant, so transport-level routing already authenticates).
2189
1968
  */
2190
- type MessageWithCtx<TInCtx> = [TInCtx] extends [undefined] ? JsonRpcMessage : JsonRpcMessage & {
2191
- context: TInCtx;
2192
- };
2193
- declare class RpcError extends Error {
2194
- readonly code: number;
2195
- /** Whether this error was decoded from a peer response. */
2196
- readonly origin: 'local' | 'remote';
2197
- readonly data?: JsonValue;
2198
- readonly hasData: boolean;
2199
- constructor(message: string, code: number, data?: JsonValue,
2200
- /** Whether this error was decoded from a peer response. */
2201
- origin?: 'local' | 'remote', hasData?: boolean);
2202
- }
2203
- //#endregion
2204
- //#region src/connection/bareInterfaceTarget.d.ts
2205
- /** A metadata-free foreign-protocol interface and its wire-method prefix. */
2206
- interface BareInterfaceTarget<TDef extends InterfaceDefinition<any>> {
2207
- readonly mode: 'bare';
2208
- readonly interface: TDef;
2209
- readonly prefix: string;
1969
+ interface ManagedIdentityStorage {
1970
+ get<T = unknown>(key: string): Promise<T | undefined>;
1971
+ set(key: string, value: unknown): Promise<void>;
1972
+ delete(key: string): Promise<boolean>;
1973
+ list(prefix?: string): Promise<string[]>;
2210
1974
  }
2211
1975
  /**
2212
- * Bundle an interface definition with metadata-free foreign-protocol
2213
- * addressing for use with `connection.get(target)`.
2214
- */
2215
- declare function bareInterfaceTarget<TDef extends InterfaceDefinition<any>>(iface: TDef, options?: {
2216
- readonly prefix?: string;
2217
- }): BareInterfaceTarget<TDef>;
2218
- //#endregion
2219
- //#region src/connection/channelConnector.d.ts
2220
- /**
2221
- * A raw channel that signals when it closes (and, when possible, can be torn
2222
- * down). Both {@link openHubChannel}'s `HubChannel` and `openStdioChannel`'s
2223
- * `StdioChannel` satisfy this shape.
1976
+ * A managed identity resolved from an executor's `identity::*` overlay: a
1977
+ * full {@link Identity} (signing + HPKE wrap/unwrap, all round-tripping
1978
+ * through the executor — private keys never leave it) plus the
1979
+ * per-identity {@link ManagedIdentityStorage}.
2224
1980
  */
2225
- type ConnectableChannel = Channel<undefined, unknown> & {
2226
- /**
2227
- * Fires once when the channel closes. Returns a disposable to unsubscribe.
2228
- *
2229
- * Ordering contract: when a close causes a sending method (e.g. a request
2230
- * or notification) to reject/throw, {@link onClose} must fire *before* that
2231
- * rejection surfaces to the caller. This lets consumers reliably tell a
2232
- * close-induced failure (the channel is already observably closed) apart
2233
- * from a genuine error (the channel is still open). See
2234
- * {@link ChannelConnector.keepConnected}.
2235
- */
2236
- onClose(listener: () => void): IDisposable;
2237
- /** Tear the channel down. Optional — stdio channels have no explicit close. */
2238
- close?(): void;
2239
- };
2240
- /** Handle returned by {@link ChannelConnector.keepConnected}. */
2241
- interface KeepConnectedHandle {
1981
+ interface ManagedIdentity extends Identity {
2242
1982
  /**
2243
- * Resolves when the loop exits: the channel closed and the connector does
2244
- * not redial, or {@link stop} (or the supplied signal) fired.
1983
+ * Per-identity persistent key/value store. Backed by the executor's
1984
+ * `identity.storage::*` overlay; calls throw when the executor did not
1985
+ * register storage for this slot (e.g. an in-process identity for tests).
2245
1986
  */
2246
- readonly done: Promise<void>;
2247
- /** Stop redialing and close the current channel (if any). */
2248
- stop(): void;
2249
- }
2250
- /** Callback run on every (re)connect. The channel is the raw, unsigned channel. */
2251
- type OnChannelConnect<T extends ConnectableChannel> = (ctx: {
2252
- channel: T;
2253
- }) => void | Promise<void>;
2254
- interface ExpBackoffOptions {
2255
- readonly initialBackoffMs?: number;
2256
- readonly maxBackoffMs?: number;
1987
+ readonly storage: ManagedIdentityStorage;
2257
1988
  }
2258
1989
  /**
2259
- * Drives a connect / (re)connect loop over a raw {@link ConnectableChannel}.
2260
- *
2261
- * Unlike connection-level helpers, this works at the channel layer: the
2262
- * caller composes identity / signing on top of the channel handed to
2263
- * {@link keepConnected} (e.g. `SigningSender.wrapChannel(channel, { principal })`).
1990
+ * Bootstrap a {@link ManagedIdentity} from a sender (typically the raw
1991
+ * unsigned sender obtained via `channel.sender` before wrapping with
1992
+ * {@link SigningSender}). Makes `identity::*` calls unsigned — the
1993
+ * executor's overlay is private to one participant so routing already
1994
+ * identifies the caller, preventing signing recursion.
2264
1995
  *
2265
- * Construct via {@link ChannelConnector.once} (a single, already-open channel
2266
- * that never redials) or {@link ChannelConnector.expBackoff} (re-open via a
2267
- * factory with exponential backoff after each close).
1996
+ * The returned identity signs / wraps / unwraps by round-tripping through
1997
+ * the executor's `identity::*` overlay; the caller wires it into their
1998
+ * {@link SigningSender} configuration (e.g. as a {@link Principal}). No
1999
+ * side effects on any existing connection or holder.
2268
2000
  */
2269
- declare class ChannelConnector<T extends ConnectableChannel> {
2270
- private readonly _open;
2271
- private readonly _redial;
2272
- private readonly _initialBackoffMs;
2273
- private readonly _maxBackoffMs;
2274
- private constructor();
2275
- /**
2276
- * A connector over a single channel (or a promise of one). Never redials;
2277
- * the loop ends when the channel closes or {@link KeepConnectedHandle.stop}
2278
- * fires.
2279
- */
2280
- static once<T extends ConnectableChannel>(channel: T | Promise<T>): ChannelConnector<T>;
2281
- /**
2282
- * A redialing connector: `open` is called once per attempt, and the loop
2283
- * reconnects with exponential backoff after each close (or failed open).
2284
- */
2285
- static expBackoff<T extends ConnectableChannel>(open: () => Promise<T>, opts?: ExpBackoffOptions): ChannelConnector<T>;
2001
+ declare function createManagedIdentity(sender: IRequestSender<unknown>): Promise<ManagedIdentity>;
2002
+ //#endregion
2003
+ //#region src/identity/capBag.d.ts
2004
+ interface CapBagOptions {
2286
2005
  /**
2287
- * Run `onConnect` on every (re)connect with the freshly opened channel.
2288
- * The callback typically wraps the channel with signing and registers
2289
- * handlers. Returns once the loop exits (see {@link KeepConnectedHandle}).
2006
+ * Per-identity persistent storage (e.g.
2007
+ * {@link ManagedIdentityHandle.storage}). Omit for a memory-only bag
2008
+ * that forgets its caps when the process exits.
2290
2009
  */
2291
- keepConnected(onConnect: OnChannelConnect<T>, opts?: {
2292
- signal?: AbortSignal;
2293
- }): KeepConnectedHandle;
2010
+ readonly storage?: ManagedIdentityStorage;
2011
+ /** Storage key. Defaults to `hubrpc.caps.v1`. */
2012
+ readonly storageKey?: string;
2013
+ /** Optional sink for non-fatal storage warnings. */
2014
+ readonly onWarn?: (message: string) => void;
2294
2015
  }
2295
- //#endregion
2296
- //#region src/connection/jsonRpcChannel.d.ts
2297
2016
  /**
2298
- * Minimal JSON-RPC 2.0 channel: correlates requests with responses,
2299
- * dispatches incoming requests/notifications to a handler.
2300
- *
2301
- * Construct via {@link JsonRpcChannel.create}: it returns a
2302
- * {@link Channel} factory which materialises the live channel once a
2303
- * handler is supplied via `.connect(handler)`. The handler is fixed for
2304
- * the channel's lifetime — no setter, no mid-flight swap.
2017
+ * A process-lifetime bag of hub-issued capabilities. Plug
2018
+ * {@link CapBag.provider} straight into a connection's cap provider so every
2019
+ * outbound signed call carries whatever caps have been granted so far. The
2020
+ * hub picks whichever cap matches the call per dispatch.
2305
2021
  *
2306
- * The outbound `TOutCtx` of the produced sender is `unknown` — this
2307
- * channel ignores per-call ctx entirely. Decorators (e.g.
2308
- * `SigningSender`) lift it to a concrete shape.
2022
+ * When constructed with {@link CapBagOptions.storage} the bag hydrates from
2023
+ * (and persists to) storage, so the next process spawn for the same identity
2024
+ * reuses its grants without re-prompting.
2309
2025
  */
2310
- declare class JsonRpcChannel<TInCtx = undefined> implements IRequestSender<unknown> {
2311
- private readonly _transport;
2312
- /**
2313
- * Wrap a transport in a {@link Channel}. The channel's sender is live
2314
- * immediately; call {@link Channel.setRequestHandler} (or pass the channel
2315
- * to {@link LinkRpcConnection}) to bind the inbound handler.
2316
- */
2317
- static create<TInCtx = undefined>(transport: ChannelTransport<TInCtx>): Channel<TInCtx, unknown>;
2318
- /** Wrap a transport and retain an explicit lifecycle hook for its owner. */
2319
- static createWithClose<TInCtx = undefined>(transport: ChannelTransport<TInCtx>): {
2320
- channel: Channel<TInCtx, unknown>;
2321
- close: () => void;
2322
- };
2323
- private _nextId;
2324
- private readonly _pending;
2325
- /**
2326
- * Per-request callbacks invoked when a {@link STREAM_METHOD}
2327
- * notification arrives with a matching `requestId`. Used in both
2328
- * directions: outgoing-request callers register here keyed by the
2329
- * id they sent; per-call incoming-request stream handles register
2330
- * keyed by the id they observed. Entries are removed when the
2331
- * corresponding request completes (response received for outgoing,
2332
- * response sent for incoming).
2333
- */
2334
- private readonly _streamListeners;
2335
- /**
2336
- * Per-incoming-request handlers for reserved `control` messages
2337
- * (cancel / ping / pong) arriving as stream notifications. Keyed
2338
- * by the id observed; removed when the request settles.
2339
- */
2340
- private readonly _streamControl;
2341
- private readonly _incomingAborts;
2342
- private _handler;
2343
- private _wireObserver;
2344
- private _closeError;
2345
- setRequestHandler(handler: IRequestHandler<TInCtx> | undefined): void;
2346
- setWireMessageObserver(observer: WireMessageObserver | undefined): void;
2026
+ declare class CapBag {
2027
+ /** Create a bag, hydrating from storage when one was supplied. */
2028
+ static load(options?: CapBagOptions): Promise<CapBag>;
2029
+ private readonly _caps;
2030
+ private readonly _storage?;
2031
+ private readonly _storageKey;
2032
+ private readonly _onWarn;
2347
2033
  private constructor();
2348
- sendRequest(method: string, params: JsonValue | undefined, opts?: SendOpts<unknown>): Promise<JsonValue>;
2349
- sendNotification(method: string, params: JsonValue | undefined, opts?: SendOpts<unknown>): Promise<void>;
2350
- sendRequestWithStream(method: string, params: JsonValue | undefined, opts?: StreamSendOpts<unknown>): RawStreamingCall;
2351
- /**
2352
- * Build the symmetric ping/pong machinery for one in-flight request.
2353
- *
2354
- * `outboundDir` is the direction *this* side emits controls in
2355
- * (`toCallee` for the caller, `toCaller` for the callee). A received
2356
- * ping is answered with a pong in that same direction, echoing the
2357
- * ping's nonce; a received pong resolves the matching outstanding
2358
- * {@link ping} probe.
2359
- */
2360
- private _makePinger;
2034
+ get capabilities(): readonly SignedCapability[];
2361
2035
  /**
2362
- * Emit a stream notification ({@link STREAM_METHOD}) associated with
2363
- * an in-flight request. Internal: outgoing-side callers reach this
2364
- * via {@link RawStreamingCall.send} / `cancel`; incoming-side handlers
2365
- * reach it via {@link IncomingStream.send}.
2036
+ * A {@link CapProvider} reflecting the bag at call-time. Assign it to
2037
+ * `HubClientHandle.signing.capProvider` or pass it through
2038
+ * `SigningSenderConfig.capProvider`.
2366
2039
  */
2367
- private _sendStream;
2368
- close(): void;
2369
- private _throwIfClosed;
2370
- private _onMessage;
2371
- private _handleStreamNotification;
2372
- private _handleRequest;
2373
- private _handleNotification;
2374
- private _observeInbound;
2375
- private _observeOutbound;
2376
- private _observeSendFailure;
2377
- }
2378
- //#endregion
2379
- //#region src/connection/requestTimeout.d.ts
2380
- declare const DEFAULT_RPC_TIMEOUT_MS = 5000;
2381
- interface CancellableRequest<T> extends Promise<T> {
2382
- cancel(reason?: string): void | Promise<void>;
2383
- dispose?(reason?: string): void;
2040
+ readonly provider: CapProvider;
2041
+ /** Append capabilities and persist (when backed by storage). */
2042
+ add(...caps: readonly SignedCapability[]): Promise<void>;
2043
+ /** Drop all capabilities and persist the empty bag. */
2044
+ clear(): Promise<void>;
2045
+ private _hydrate;
2046
+ private _persist;
2384
2047
  }
2385
- declare function withRpcTimeout<T>(request: CancellableRequest<T>, target: string, timeoutMs?: number): Promise<T>;
2386
2048
  //#endregion
2387
- //#region src/connection/endpointUri.d.ts
2049
+ //#region src/identity/principal.d.ts
2388
2050
  /**
2389
- * A strict, RFC-3986 URI vocabulary for "where the linkrpc server lives, and
2390
- * how to reach (or start) it". Every endpoint round-trips through
2391
- * {@link parseEndpointUri} / {@link formatEndpointUri} and is a valid `new URL()`
2392
- * — safe to put in env vars, logs, and config.
2393
- *
2394
- * Supported schemes:
2395
- * - `unix:/path/to.sock?token=…` → {@link SocketEndpoint}
2396
- * - `npipe://./pipe/name?token=…` → {@link SocketEndpoint} (Windows)
2397
- * - `ws://host:port?token=…` / `wss:…` → {@link WsEndpoint} (LinkRPC handshake)
2398
- * - `ws-no-init://host:port?…` → {@link WsNoInitEndpoint}
2399
- * - `cmd-stdio:?command=…` / `…?argv=…` → {@link CmdStdioEndpoint}
2400
- * - `cmd:?command=…` / `…?argv=…` → {@link CmdEnvEndpoint}
2051
+ * A signing identity bundled with its durable capability set. The
2052
+ * {@link SigningIdentity} is fixed for the life of the principal; the
2053
+ * {@link CapBag} is mutable and extensible — caps accumulate as the peer grants
2054
+ * them.
2401
2055
  *
2402
- * The command payload is `{ command: string } | { argv: string[] }`:
2403
- * - `?command=node%20server.js` — one verbatim string, split by the OS shell.
2404
- * - `?argv=node&argv=server.js` — repeated `argv` params, structure-preserving.
2056
+ * Transient, per-call (one-shot) grants are deliberately NOT part of a
2057
+ * principal: that is a separate policy, see `OneShotCapStaging`.
2405
2058
  *
2406
- * A bare string with no scheme (legacy `LINKRPC_ENDPOINT`) is auto-detected: a
2407
- * `ws://`/`wss://` URL stays WebSocket, anything else is a socket path.
2059
+ * Lives in its own module (rather than alongside `SigningSender`) so the
2060
+ * `SigningSender` ⇄ `createManagedPrincipal` factory cycle does not run through
2061
+ * a top-level `class … extends Principal`: such a cycle would hit a TDZ
2062
+ * ("Class extends value undefined") depending on module evaluation order.
2408
2063
  */
2409
- /** Verbatim command line (`{ command }`) or pre-split argv (`{ argv }`). */
2410
- type EndpointCommand = {
2411
- readonly command: string;
2412
- } | {
2413
- readonly argv: readonly string[];
2414
- };
2415
- /** Named pipe / unix-domain-socket the server already listens on. */
2416
- interface SocketEndpoint {
2417
- readonly kind: 'socket';
2418
- readonly path: string;
2419
- readonly token?: string;
2420
- /**
2421
- * Present on sockets created by `hub connect`. Local framing still uses the
2422
- * LinkRPC transport handshake; this describes whether forwarded application
2423
- * calls target a LinkRPC or plain JSON-RPC peer.
2424
- */
2425
- readonly brokerMode?: 'linkrpc' | 'raw';
2426
- }
2427
- /** A running WebSocket hub; `token` rides in the `hubrpc::initialize` handshake. */
2428
- interface WsEndpoint {
2429
- readonly kind: 'ws';
2430
- readonly url: string;
2431
- readonly token?: string;
2064
+ declare class Principal {
2065
+ readonly identity: SigningIdentity;
2066
+ readonly capBag: CapBag;
2067
+ static create(identity: SigningIdentity, capabilities?: readonly SignedCapability[]): Promise<Principal>;
2068
+ constructor(identity: SigningIdentity, capBag: CapBag);
2069
+ get id(): PrincipalId;
2432
2070
  }
2071
+ //#endregion
2072
+ //#region src/identity/managedPrincipal.d.ts
2433
2073
  /**
2434
- * A running plain-JSON-RPC WebSocket endpoint. Unlike {@link WsEndpoint}, CLI
2435
- * consumers use it without the `hubrpc::initialize` handshake or LinkRPC signing.
2436
- * Query parameters are preserved verbatim for protocols that authenticate
2437
- * during the WebSocket upgrade (for example AHP's `tkn` parameter).
2074
+ * A {@link Principal} that also exposes the executor-backed per-identity
2075
+ * {@link ManagedIdentityStorage}. Returned by {@link createManagedPrincipal}
2076
+ * so callers can persist their own app state (e.g. a resolved serviceId)
2077
+ * alongside the granted capabilities, using the very same durable store the
2078
+ * {@link CapBag} hydrates from — no second storage wiring required.
2438
2079
  */
2439
- interface WsNoInitEndpoint {
2440
- readonly kind: 'ws-no-init';
2441
- /** Actual `ws://` URL passed to the WebSocket constructor. */
2442
- readonly url: string;
2443
- }
2444
- /** Spawn a child and talk linkrpc over its stdin/stdout. */
2445
- interface CmdStdioEndpoint {
2446
- readonly kind: 'cmd-stdio';
2447
- readonly command: EndpointCommand;
2448
- /** Extra environment variables injected into the spawned child. */
2449
- readonly env?: Readonly<Record<string, string>>;
2450
- /** Working directory for the spawned child. */
2451
- readonly cwd?: string;
2080
+ declare class PrincipalWithStore extends Principal {
2081
+ readonly store: ManagedIdentityStorage;
2082
+ readonly identity: Identity;
2083
+ constructor(identity: Identity, capBag: CapBag, store: ManagedIdentityStorage);
2452
2084
  }
2453
2085
  /**
2454
- * Spawn a child against a freshly-started *local hub*: the parent listens on a
2455
- * private socket, hands the child its address + token via `LINKRPC_ENDPOINT` /
2456
- * `LINKRPC_TOKEN`, and the child dials in as a hub participant (registering its
2457
- * services), exactly as it would against a remote hub.
2458
- */
2459
- interface CmdEnvEndpoint {
2460
- readonly kind: 'cmd-env';
2461
- readonly command: EndpointCommand;
2462
- /**
2463
- * When set, the local hub provisions (or reuses) a *persistent* managed
2464
- * identity under this slot id, so the child's HPKE wrap/unwrap keys survive
2465
- * across runs (sealed archives re-open).
2086
+ * Executor-managed principal: the peer signs for us through its
2087
+ * `identity::sign` overlay (we never hold a private key). Bootstrapped purely
2088
+ * from the outbound `sender` — no side effects on any connection — and caps
2089
+ * persist in the executor-backed per-identity storage. Works over any
2090
+ * transport whose peer serves the identity overlay (hub *or* stdio).
2091
+ *
2092
+ * Call this exactly once per channel: it performs the `identity::*` handshake
2093
+ * and hydrates the {@link CapBag} from storage. The returned
2094
+ * {@link PrincipalWithStore} additionally surfaces that same durable
2095
+ * {@link ManagedIdentityStorage} as `store`.
2096
+ */
2097
+ declare function createManagedPrincipal(sender: IRequestSender<unknown>): Promise<PrincipalWithStore>;
2098
+ //#endregion
2099
+ //#region src/identity/signingSender.d.ts
2100
+ /**
2101
+ * Per-outbound-call hook. Sees every signed call this sender makes,
2102
+ * and gets a chance to:
2103
+ * - attach capabilities (the common case),
2104
+ * - override `method` / `params` / `interfaceHash` (rewriting,
2105
+ * auditing, schema-pinning),
2106
+ * - advance `signedAtMs` (e.g. after a slow consent prompt that needs
2107
+ * to issue a cap bound to a fresher timestamp than the sender's
2108
+ * initial wall-clock).
2109
+ *
2110
+ * `signer` and `nonce` are NOT overridable. `signer` is the call's
2111
+ * identity; `nonce` ties any cap to this specific call attempt and must
2112
+ * not drift between the cap-issuance request and the call itself.
2113
+ */
2114
+ type CapProvider = (req: {
2115
+ readonly method: string;
2116
+ readonly params: JsonValue | undefined;
2117
+ readonly signer: PrincipalId;
2118
+ readonly nonce: string;
2119
+ readonly signedAtMs: number;
2120
+ readonly interfaceHash?: string;
2121
+ }) => Promise<CapProviderResult>;
2122
+ interface CapProviderResult {
2123
+ readonly capabilities?: readonly SignedCapability[];
2124
+ /** Override the wire method this sender signs. Default: the original. */
2125
+ readonly method?: string;
2126
+ /** Override the params this sender signs. Default: the original. */
2127
+ readonly params?: JsonValue;
2128
+ /** Override the interfaceHash baked into the signed envelope. */
2129
+ readonly interfaceHash?: string;
2130
+ /** Advance the Unix-ms timestamp baked into the signed envelope. */
2131
+ readonly signedAtMs?: number;
2132
+ }
2133
+ /**
2134
+ * Per-call ctx the {@link SigningSender} consumes. All fields are
2135
+ * optional; the sender's persistent {@link SigningSenderConfig.principal} is
2136
+ * the default.
2137
+ *
2138
+ * To install a signer after the sender is already constructed (e.g. a
2139
+ * managed-identity bootstrap), mutate the caller-owned config object — it is
2140
+ * read fresh on every call. No setter on the sender itself.
2141
+ */
2142
+ interface SigningCallCtx {
2143
+ /**
2144
+ * Override the signer for this call only. Pass `null` to skip
2145
+ * signing entirely (plain unsigned JSON-RPC). Bootstrap flows that
2146
+ * must talk to `identity::*` before a managed signer is available
2147
+ * use `signerOverride: null` for those calls.
2466
2148
  */
2467
- readonly provisionSlot?: string;
2468
- /** Extra environment variables injected into the spawned child. */
2469
- readonly env?: Readonly<Record<string, string>>;
2470
- /** Working directory for the spawned child. */
2471
- readonly cwd?: string;
2149
+ readonly signerOverride?: SigningIdentity | null;
2150
+ /**
2151
+ * Replace whatever caps the persistent cap provider would attach.
2152
+ * Skips the persistent provider for this call.
2153
+ */
2154
+ readonly capsOverride?: readonly SignedCapability[];
2155
+ /**
2156
+ * Reserved for the perm-denied / consent retry path. Currently a
2157
+ * passthrough — sender does not act on it yet.
2158
+ */
2159
+ readonly requestPermissionWhenDenied?: boolean;
2472
2160
  }
2473
- type ResolvedEndpoint = SocketEndpoint | WsEndpoint | WsNoInitEndpoint | CmdStdioEndpoint | CmdEnvEndpoint;
2474
2161
  /**
2475
- * Parse a strict endpoint URI into an {@link ResolvedEndpoint}. Throws on an
2476
- * unknown scheme or a malformed command endpoint. A bare (scheme-less) string
2477
- * is auto-detected as `ws`/`wss` URL or a socket path.
2162
+ * Persistent config for a {@link SigningSender}.
2163
+ *
2164
+ * `principal` is the call identity plus its durable, extensible capability
2165
+ * set. `oneShotCaps` is an optional side-policy that may stage a single-use
2166
+ * capability onto the very next call without touching the principal. Both
2167
+ * fields are read fresh on every call, so callers may install or swap them
2168
+ * after the sender has been constructed.
2169
+ *
2170
+ * A missing `principal` means "no signing / no caps" for that call, unless
2171
+ * overridden via {@link SigningCallCtx}.
2478
2172
  */
2479
- declare function parseEndpointUri(uri: string): ResolvedEndpoint;
2480
- interface FormatEndpointOptions {
2481
- /** Emit the real token instead of redacting it. Default: redact. */
2482
- readonly revealToken?: boolean;
2173
+ interface SigningSenderConfig {
2174
+ /** Identity + persistent (extensible) capabilities. */
2175
+ readonly principal?: Principal;
2176
+ /**
2177
+ * Optional per-call capability provider. Runs at sign-time with the
2178
+ * concrete method/params/nonce/timestamp and may return caps and/or
2179
+ * signing overrides.
2180
+ */
2181
+ readonly capProvider?: CapProvider;
2182
+ /**
2183
+ * Optional one-shot capability staging policy. Independent of the
2184
+ * principal; drained per outbound signed call.
2185
+ */
2186
+ readonly oneShotCaps?: OneShotCapStaging;
2483
2187
  }
2484
2188
  /**
2485
- * Render an {@link ResolvedEndpoint} back to a canonical strict URI. The token is
2486
- * redacted (`***`) unless `revealToken` is set, so the result is paste-safe for
2487
- * logs. Round-trips with {@link parseEndpointUri} when `revealToken` is true.
2189
+ * Side-policy for staging *one-shot* capabilities onto the next outbound
2190
+ * signed call, independent of any {@link Principal}. The {@link SigningSender}
2191
+ * drains the staged caps after attaching them once, so a spent cap never
2192
+ * leaks into a later call.
2193
+ *
2194
+ * Requesting the one-shot grant (prompting the user / hub) lives next to —
2195
+ * not inside — the principal: the principal owns identity and durable
2196
+ * capabilities; this owns the transient per-call grant.
2488
2197
  */
2489
- declare function formatEndpointUri(spec: ResolvedEndpoint, options?: FormatEndpointOptions): string;
2490
- /** True for endpoints that connect to existing, possibly-remote infrastructure. */
2491
- declare function isHubEndpoint(spec: ResolvedEndpoint): spec is SocketEndpoint | WsEndpoint;
2492
- //#endregion
2493
- //#region src/identity/identity.d.ts
2494
- /** JSON-serializable form of a {@link KeypairSigningIdentity} (base64url keys). */
2495
- interface SerializedKeypairSigningIdentity {
2496
- readonly privateKey: string;
2497
- readonly publicKey: string;
2198
+ declare class OneShotCapStaging {
2199
+ private _staged;
2200
+ /** Stage caps for the next signed call. Replaces any still-pending caps. */
2201
+ stage(caps: readonly SignedCapability[]): void;
2202
+ /**
2203
+ * Take (and clear) the staged caps. Called by {@link SigningSender} once
2204
+ * per outbound signed call.
2205
+ */
2206
+ take(): readonly SignedCapability[];
2498
2207
  }
2499
2208
  /**
2500
- * The public face of a signing identity: its stable {@link PrincipalId} name
2501
- * and the {@link KeyId} its signatures are stamped with. In Phase 1 (perpetual
2502
- * identities) the keyId is the genesis key embedded in the principal, so it is
2503
- * derived by stripping the `id:` prefix.
2209
+ * Outbound sender decorator that wraps every call in a `$hubrpc` signed
2210
+ * envelope and (optionally) attaches capabilities. Stateless w.r.t. signing
2211
+ * config — the {@link Principal} and {@link OneShotCapStaging} are resolved
2212
+ * per-call from {@link SigningSenderConfig}, so the caller can install or
2213
+ * swap them after construction by mutating that object.
2504
2214
  */
2505
- declare class PublicSigningIdentity {
2506
- readonly principal: PrincipalId;
2507
- constructor(principal: PrincipalId);
2508
- /** The {@link KeyId} this identity signs with (its genesis key, in Phase 1). */
2509
- get keyId(): KeyId;
2215
+ /**
2216
+ * The result of {@link SigningSender.fromChannelWithManagedPrincipal} /
2217
+ * {@link SigningSender.fromTransportWithManagedPrincipal}: a signing
2218
+ * {@link Channel} ready for `LinkRpcConnection`, plus the executor-managed
2219
+ * {@link PrincipalWithStore} that drives it (caps, per-identity storage, nodeId).
2220
+ */
2221
+ interface ManagedSigningChannel<TInCtx = undefined> {
2222
+ readonly channel: Channel<TInCtx, SigningCallCtx>;
2223
+ readonly principal: PrincipalWithStore;
2510
2224
  }
2511
- interface SigningIdentity {
2512
- readonly publicSigningIdentity: PublicSigningIdentity;
2513
- sign(bytes: Uint8Array): Promise<Uint8Array>;
2225
+ declare class SigningSender<TInCtx = unknown> implements IRequestSender<SigningCallCtx> {
2226
+ private readonly _inner;
2227
+ private readonly _config;
2228
+ /**
2229
+ * Wrap an inner channel with signing. Composes via {@link Channel.withSender}
2230
+ * so the resulting `Channel<TInCtx, SigningCallCtx>` plugs into
2231
+ * `LinkRpcConnection`.
2232
+ */
2233
+ static wrapChannel<TInCtx>(inner: Channel<TInCtx, unknown>, config: SigningSenderConfig): Channel<TInCtx, SigningCallCtx>;
2234
+ /**
2235
+ * Bootstrap an executor-managed {@link Principal} over the **unsigned**
2236
+ * `channel`, then wrap that same channel with signing driven by it.
2237
+ *
2238
+ * Crucially, the `identity::*` handshake that mints the managed principal
2239
+ * rides the *raw* channel (`channel.sender`), so those bootstrap calls are
2240
+ * themselves never signed — there is no "sign the sign call" recursion and
2241
+ * no reliance on threading `signerOverride: null` through every transport
2242
+ * layer. The returned signing {@link Channel} is what callers hand to
2243
+ * `LinkRpcConnection`; the {@link PrincipalWithStore} is returned alongside
2244
+ * for caps / per-identity storage / nodeId.
2245
+ */
2246
+ static fromChannelWithManagedPrincipal<TInCtx>(channel: Channel<TInCtx, unknown>, config?: Omit<SigningSenderConfig, 'principal'>): Promise<ManagedSigningChannel<TInCtx>>;
2247
+ /**
2248
+ * Convenience over {@link fromChannelWithManagedPrincipal}: build the
2249
+ * unsigned {@link JsonRpcChannel} from `transport` first. The common entry
2250
+ * point for app hosts / services that own a raw {@link IMessageTransport}.
2251
+ */
2252
+ static fromTransportWithManagedPrincipal(transport: IMessageTransport, config?: Omit<SigningSenderConfig, 'principal'>): Promise<ManagedSigningChannel<undefined>>;
2253
+ constructor(_inner: IRequestSender<unknown>, _config: SigningSenderConfig);
2254
+ sendRequest(method: string, params: JsonValue | undefined, opts?: SendOpts<SigningCallCtx>): Promise<JsonValue>;
2255
+ sendNotification(method: string, params: JsonValue | undefined, opts?: SendOpts<SigningCallCtx>): Promise<void>;
2256
+ sendRequestWithStream(method: string, params: JsonValue | undefined, opts?: StreamSendOpts<SigningCallCtx>): RawStreamingCall;
2257
+ close(): void;
2258
+ private _prepareOutbound;
2259
+ private _resolveSigner;
2260
+ private _createSigningCoordinates;
2261
+ private _resolveIntentAndCapabilities;
2262
+ private _signPreparedCall;
2514
2263
  }
2264
+ //#endregion
2265
+ //#region src/hub/common/directoryWalk.d.ts
2515
2266
  /**
2516
- * {@link SigningIdentity} backed by an in-process keypair. For the common
2517
- * case where the signing material lives in memory. For external HSM-style
2518
- * backends, implement {@link SigningIdentity} directly.
2267
+ * Portable reflection walk over the `hubrpc.directory` referral tree.
2268
+ *
2269
+ * A directory may explicitly list other `hubrpc.directory` services as
2270
+ * referrals. Flattening that graph into an interface inventory is the
2271
+ * consumer's job. Routing state is deliberately not part of this contract.
2519
2272
  */
2520
- declare class KeypairSigningIdentity implements SigningIdentity {
2521
- private readonly _privateKey;
2522
- readonly publicSigningIdentity: PublicSigningIdentity;
2523
- constructor(principal: PrincipalId, _privateKey: PrivateKey);
2524
- sign(message: Uint8Array): Promise<Signature>;
2525
- static fromKeypair(keypair: Keypair): KeypairSigningIdentity;
2526
- /** Generate a fresh signing identity (Ed25519 keypair). */
2527
- static generateNew(): Promise<KeypairSigningIdentity>;
2528
- /** Restore an identity from its {@link toJson} form. */
2529
- static fromJson(json: SerializedKeypairSigningIdentity): KeypairSigningIdentity;
2530
- /** Serialize the keypair to a JSON-friendly form (base64url keys). */
2531
- toJson(): SerializedKeypairSigningIdentity;
2273
+ /**
2274
+ * The sender reflection helpers speak over: the signing decorator that wraps
2275
+ * the live channel. Decoupled from the concrete `JsonRpcChannel` so reconnect
2276
+ * can swap the underlying channel transparently.
2277
+ */
2278
+ type ReflectionChannel = IRequestSender<SigningCallCtx>;
2279
+ interface ServiceListing {
2280
+ readonly serviceId: string;
2281
+ readonly interfaceId: string;
2282
+ readonly hash: string;
2283
+ readonly path?: string;
2284
+ /** Optional non-normative description of the owning service. */
2285
+ readonly serviceDescription?: string;
2286
+ /**
2287
+ * Root node ids required to access the owning service, in CNF. Surfaced by
2288
+ * the directory; {@link walkHubDetailed} additionally folds transitive
2289
+ * requirements from ancestor directories onto descendants.
2290
+ */
2291
+ readonly rootPrincipalSets?: readonly RootPrincipalSet[];
2292
+ /** Scope carried by a directory referral; omitted means its service-id subtree. */
2293
+ readonly reachableServiceIds?: readonly ServiceIdPattern[];
2532
2294
  }
2533
- declare class PublicWrappingIdentity {
2534
- readonly wrapPublicKey: Uint8Array;
2535
- constructor(wrapPublicKey: Uint8Array);
2295
+ /**
2296
+ * A {@link ServiceListing} enriched with the service id of the directory that
2297
+ * reported it. This is provenance only: every listing is asserted reachable by
2298
+ * sending to the endpoint that answered the directory.
2299
+ */
2300
+ interface DiscoveredListing extends ServiceListing {
2301
+ readonly discoveredFrom: string;
2536
2302
  }
2537
- interface WrappingIdentity {
2538
- readonly publicWrappingIdentity: PublicWrappingIdentity;
2539
- wrap(domain: string, bytes: Uint8Array): Promise<Uint8Array>;
2540
- unwrap(domain: string, blob: Uint8Array): Promise<Uint8Array>;
2303
+ interface ListOptions {
2304
+ readonly interfaceId?: string;
2305
+ readonly interfaceIdPrefix?: string;
2306
+ readonly serviceId?: string;
2307
+ readonly serviceIdScopes?: readonly ServiceIdPattern[];
2308
+ readonly limit?: number;
2309
+ readonly timeoutMs?: number;
2310
+ /**
2311
+ * When set, send the reflection call to that service via form-3
2312
+ * (`<target>::hubrpc.directory::list`) instead of the implicit root
2313
+ * directory. Used when talking to a hub: the root directory is the hub
2314
+ * itself, but per-service reflection lives on each participant.
2315
+ */
2316
+ readonly target?: string;
2541
2317
  }
2542
- interface Identity extends SigningIdentity, WrappingIdentity {
2543
- /** The identity's stable {@link PrincipalId} name. */
2544
- readonly principal: PrincipalId;
2545
- /** @deprecated */
2546
- readonly wrapPublicKey: Uint8Array;
2318
+ declare function fetchDirectory(channel: ReflectionChannel, opts?: ListOptions): Promise<ServiceListing[]>;
2319
+ declare function fetchSchema(channel: ReflectionChannel, interfaceId: string, hash: string | undefined,
2320
+ /**
2321
+ * Optional routing target. When set, the schema request is addressed to
2322
+ * `<target>::hubrpc.schemas::get` (form-3) so it reaches the service that
2323
+ * actually hosts this interface — needed when talking to a hub and the
2324
+ * interface lives behind a participant.
2325
+ */
2326
+ target?: string): Promise<LinkRpcInterfaceSchema>;
2327
+ declare function findMethodInSchema(schema: LinkRpcInterfaceSchema, methodName: string): MethodSchema | undefined;
2328
+ /** Default recursion depth when walking the bus. */
2329
+ declare const DEFAULT_WALK_DEPTH = 5;
2330
+ /** Segment-aware service-id pattern matching (`foo` includes `foo/bar`, not `foobar`). */
2331
+ declare function serviceIdMatchesPattern(serviceId: string, pattern: ServiceIdPattern): boolean;
2332
+ /** Whether a service id is included by a union of patterns. `undefined` means unfiltered. */
2333
+ declare function serviceIdMatchesScopes(serviceId: string, scopes: readonly ServiceIdPattern[] | undefined): boolean;
2334
+ /** Canonicalize a pattern union by removing duplicates and contained patterns. */
2335
+ declare function normalizeServiceIdScopes(scopes: readonly ServiceIdPattern[]): ServiceIdPattern[];
2336
+ /** Pairwise intersection of two pattern unions. */
2337
+ declare function intersectServiceIdScopes(left: readonly ServiceIdPattern[], right: readonly ServiceIdPattern[]): ServiceIdPattern[];
2338
+ /**
2339
+ * A sub-directory the walk surfaced but could not enumerate — typically because
2340
+ * it is capability-gated (e.g. the `hub` directory, reachable only once the
2341
+ * connection holds a capability for it). The services it would have listed are
2342
+ * therefore absent from the walk; callers can surface `reason` to explain the
2343
+ * gap rather than silently dropping the branch.
2344
+ */
2345
+ interface InaccessibleDirectory {
2346
+ /** The directory target (serviceId) that could not be enumerated. */
2347
+ readonly serviceId: string;
2348
+ /** The error message from the denied directory lookup. */
2349
+ readonly reason: string;
2350
+ }
2351
+ interface WalkHubResult {
2352
+ /** Every interface reachable from the directories the walk could read. */
2353
+ readonly listings: DiscoveredListing[];
2354
+ /**
2355
+ * Sub-directories that were referenced but could not be enumerated (e.g.
2356
+ * capability-gated). Their services are not present in `listings`.
2357
+ */
2358
+ readonly inaccessible: InaccessibleDirectory[];
2547
2359
  }
2548
2360
  /**
2549
- * Full {@link Identity} backed by in-process Ed25519 (signing) and X25519
2550
- * (wrapping) keypairs. The local counterpart to a keystore/executor-backed
2551
- * identity — used by self-managed principals that hold their own key
2552
- * material (e.g. loaded from disk). For external HSM-style backends,
2553
- * implement {@link Identity} directly.
2361
+ * Recursive graph walk: list a directory, intersect the accumulated service-id
2362
+ * scope with every explicit `hubrpc.directory` referral, and recurse. Bounded
2363
+ * by `maxDepth`.
2364
+ *
2365
+ * Every listing is tagged with `discoveredFrom` — the serviceId of the
2366
+ * directory that produced it. When the same `(serviceId, interfaceId, hash)`
2367
+ * shows up via several directories (e.g. once forwarded by the hub, once
2368
+ * directly from the participant), we keep the one whose `discoveredFrom`
2369
+ * matches the item's `serviceId`, since that's the directory that
2370
+ * authoritatively knows about it.
2371
+ *
2372
+ * Transitive root-node-id requirements flow down the tree: when the walk
2373
+ * recurses into a directory whose own `rootPrincipalSets` include `transitive`
2374
+ * reqs, every interface discovered at or below that directory inherits them (as
2375
+ * singleton AND-sets, kept transitive so they keep flowing further down). This
2376
+ * replaces the hub-side `applyTransitiveReqs` fold that the v1 aggregating
2377
+ * directory performed.
2378
+ *
2379
+ * A sub-directory the walk cannot read is recorded in
2380
+ * {@link WalkHubResult.inaccessible} rather than silently dropped. A failure to
2381
+ * read the *root* directory is left silent — there is no sub-tree to explain —
2382
+ * and simply yields empty results.
2383
+ *
2384
+ * When {@link WalkHubOptions.unlockGatedDirectory} is supplied, each gated
2385
+ * sub-directory is offered to the hook; if it returns `true` (a capability was
2386
+ * granted), that directory is re-queued and the walk continues into it — a
2387
+ * fixpoint that keeps unlocking newly-revealed gated branches until nothing
2388
+ * more can be opened (still bounded by `maxDepth`).
2389
+ */
2390
+ interface WalkHubOptions {
2391
+ readonly maxDepth?: number;
2392
+ /** Hard deadline for each directory page request. Defaults to 5 seconds. */
2393
+ readonly timeoutMs?: number;
2394
+ /** Return only listings for this exact interface id after traversing directories. */
2395
+ readonly interfaceId?: string;
2396
+ /** Return only listings whose interface id starts with this prefix after traversal. */
2397
+ readonly interfaceIdPrefix?: string;
2398
+ /** Return only listings for this exact service id after traversal. */
2399
+ readonly serviceId?: string;
2400
+ /** Initial service-id scope. Defaults to the universal `{ prefix: "" }`. */
2401
+ readonly serviceIdScopes?: readonly ServiceIdPattern[];
2402
+ /**
2403
+ * The directory the walk starts from. Defaults to the implicit root
2404
+ * directory (form-2 `hubrpc.directory::list`). Pass a serviceId to start at
2405
+ * `<rootTarget>::hubrpc.directory::list` — e.g. the hub's own global
2406
+ * directory (`'hub'`) when walking from the hub's in-process connection.
2407
+ */
2408
+ readonly rootTarget?: string;
2409
+ /**
2410
+ * Invoked once per gated sub-directory the walk encounters. Return `true`
2411
+ * if a capability for its `hubrpc.directory::list` was granted and the
2412
+ * directory should be re-listed; `false` (or omitted hook) leaves it in
2413
+ * {@link WalkHubResult.inaccessible}. Called at most once per `serviceId`.
2414
+ */
2415
+ unlockGatedDirectory?: (serviceId: string) => Promise<boolean>;
2416
+ /** Optional diagnostic sink for inaccessible lists and ended watches. */
2417
+ readonly log?: (message: string) => void;
2418
+ }
2419
+ declare function walkHubDetailed(channel: ReflectionChannel, opts?: WalkHubOptions): Promise<WalkHubResult>;
2420
+ /**
2421
+ * Backward-compatible wrapper over {@link walkHubDetailed} that returns only the
2422
+ * reachable listings, dropping the inaccessible-directory report.
2423
+ */
2424
+ declare function walkHub(channel: ReflectionChannel, opts?: WalkHubOptions): Promise<DiscoveredListing[]>;
2425
+ interface HubDirectoryChange {
2426
+ /** Directory that emitted the tick. `undefined` denotes the connection root. */
2427
+ readonly target: string | undefined;
2428
+ readonly result: WalkHubResult;
2429
+ }
2430
+ type HubDirectoryGraphTarget = {
2431
+ readonly kind: 'root';
2432
+ readonly serviceId?: string;
2433
+ } | {
2434
+ readonly kind: 'addressed';
2435
+ readonly serviceId: string;
2436
+ };
2437
+ type HubDirectoryNodeState = 'unexplored' | 'loading' | 'loaded' | 'inaccessible';
2438
+ interface HubDirectoryParentReport {
2439
+ readonly target: HubDirectoryGraphTarget;
2440
+ readonly scopes: readonly ServiceIdPattern[];
2441
+ /** Resulting depth for this incoming parent path. */
2442
+ readonly depth: number;
2443
+ }
2444
+ /** Stable public report for one native directory response. */
2445
+ interface HubDirectoryNodeReport {
2446
+ readonly target: HubDirectoryGraphTarget;
2447
+ readonly state: HubDirectoryNodeState;
2448
+ readonly effectiveScopes: readonly ServiceIdPattern[];
2449
+ readonly depth: number;
2450
+ readonly parents: readonly HubDirectoryParentReport[];
2451
+ /** Per-directory listings, normalized to `ServiceListing`, before inherited metadata is folded. */
2452
+ readonly nativeListings: readonly ServiceListing[];
2453
+ readonly inaccessibleReason?: string;
2454
+ readonly watching: boolean;
2455
+ }
2456
+ /**
2457
+ * Complete point-in-time graph document. `root` exists from construction in
2458
+ * the `unexplored` state, so consumers can render before exploration starts.
2459
+ */
2460
+ interface HubDirectoryGraphSnapshot {
2461
+ readonly revision: number;
2462
+ readonly complete: boolean;
2463
+ readonly root: HubDirectoryNodeReport;
2464
+ readonly directories: readonly HubDirectoryNodeReport[];
2465
+ readonly result: WalkHubResult;
2466
+ }
2467
+ type HubDirectoryGraphEvent = {
2468
+ readonly type: 'snapshot';
2469
+ readonly reason: 'subscribed' | 'reconciliation-started' | 'reset';
2470
+ readonly snapshot: HubDirectoryGraphSnapshot;
2471
+ } | {
2472
+ readonly type: 'node-added';
2473
+ readonly reason: 'referral';
2474
+ readonly node: HubDirectoryNodeReport;
2475
+ readonly snapshot: HubDirectoryGraphSnapshot;
2476
+ } | {
2477
+ readonly type: 'node-updated';
2478
+ readonly reason: 'loading' | 'loaded' | 'inaccessible' | 'referral' | 'watch-started' | 'watch-stopped' | 'watch-ended' | 'reset';
2479
+ readonly previous: HubDirectoryNodeReport;
2480
+ readonly node: HubDirectoryNodeReport;
2481
+ readonly snapshot: HubDirectoryGraphSnapshot;
2482
+ } | {
2483
+ readonly type: 'node-removed';
2484
+ readonly reason: 'unreachable' | 'reset';
2485
+ readonly previous: HubDirectoryNodeReport;
2486
+ readonly snapshot: HubDirectoryGraphSnapshot;
2487
+ } | {
2488
+ readonly type: 'settled';
2489
+ readonly snapshot: HubDirectoryGraphSnapshot;
2490
+ };
2491
+ /**
2492
+ * Reusable directory graph explorer and watcher.
2493
+ *
2494
+ * The class keeps one native snapshot per directory target. A watch tick
2495
+ * re-lists only its source target; outgoing referral changes then propagate
2496
+ * through affected descendants. Unchanged siblings retain both their snapshot
2497
+ * and watch. Multi-parent targets are queried with the normalized union of all
2498
+ * incoming path scopes.
2499
+ */
2500
+ declare class HubDirectoryExplorer {
2501
+ private readonly _channel;
2502
+ private readonly _options;
2503
+ private readonly _maxDepth;
2504
+ private readonly _initialScopes;
2505
+ private readonly _nodes;
2506
+ private readonly _unlockAttempted;
2507
+ private readonly _listeners;
2508
+ private readonly _graphListeners;
2509
+ private readonly _pendingTicks;
2510
+ private readonly _watchRetryTimers;
2511
+ private readonly _watchRetryDelays;
2512
+ private _initialized;
2513
+ private _disposed;
2514
+ private _watching;
2515
+ private _complete;
2516
+ private _revision;
2517
+ private _work;
2518
+ private _explorePromise;
2519
+ constructor(_channel: ReflectionChannel, _options?: WalkHubOptions);
2520
+ /** Perform a fresh bounded exploration without starting watches. */
2521
+ explore(): Promise<WalkHubResult>;
2522
+ private _explore;
2523
+ /** Current deduplicated graph snapshot. */
2524
+ get result(): WalkHubResult;
2525
+ /** Current complete-or-progressive directory graph report. */
2526
+ get graphSnapshot(): HubDirectoryGraphSnapshot;
2527
+ /**
2528
+ * Subscribe to progressive graph reports. The listener is registered before
2529
+ * receiving a synchronous current snapshot, avoiding the subscribe/explore
2530
+ * race for both idle and already-running explorers.
2531
+ */
2532
+ subscribe(listener: (event: HubDirectoryGraphEvent) => void): () => void;
2533
+ /**
2534
+ * Explore once, then watch every reachable directory. Resolves after the
2535
+ * initial graph and watches are established.
2536
+ */
2537
+ watch(listener: (change: HubDirectoryChange) => void): Promise<() => void>;
2538
+ /** Wait until all currently queued watch reconciliation has settled. */
2539
+ whenIdle(): Promise<void>;
2540
+ dispose(): void;
2541
+ private _loadNode;
2542
+ private _tryUnlock;
2543
+ private _reconcileOutgoing;
2544
+ private _outgoingFor;
2545
+ private _createRootNode;
2546
+ private _createNode;
2547
+ private _updateNodeFromParents;
2548
+ private _deriveNodeFromParents;
2549
+ private _derivedNodeState;
2550
+ /**
2551
+ * Rebuild incoming contributions from the root seed. Starting with no
2552
+ * non-root contributions computes the least fixed point, so a disconnected
2553
+ * or narrowed cycle cannot keep scopes contributed by its previous state.
2554
+ */
2555
+ private _reconcileScopesFromRoot;
2556
+ private _computeScopeFixedPoint;
2557
+ private _pruneUnreachable;
2558
+ /**
2559
+ * Every changed watch scope uses list/watch/list: callers reach this method
2560
+ * only after a list under the current scope, then the replacement watch is
2561
+ * installed before a verification list. Either the verification sees a
2562
+ * handoff mutation or the new watch ticks for it.
2563
+ */
2564
+ private _synchronizeWatches;
2565
+ private _replaceWatch;
2566
+ private _queueTick;
2567
+ private _stopWatch;
2568
+ private _stopAllWatches;
2569
+ private _scheduleWatchRetry;
2570
+ private _clearWatchRetry;
2571
+ private _clearNodes;
2572
+ private _resetForExplore;
2573
+ private _updateNode;
2574
+ private _nodeReport;
2575
+ private _targetForKey;
2576
+ private _emitNodeAdded;
2577
+ private _emitNodeUpdated;
2578
+ private _emitNodeRemoved;
2579
+ private _startReconciliation;
2580
+ private _settle;
2581
+ private _emitSnapshot;
2582
+ private _emitGraphEvent;
2583
+ private _deliverGraphEvent;
2584
+ private _nodeKeyForTarget;
2585
+ private _throwIfDisposed;
2586
+ }
2587
+ //#endregion
2588
+ //#region src/schema/exportStaticHubSchema.d.ts
2589
+ interface ExportStaticHubSchemaOptions {
2590
+ /** Directory and default-binding reflection scope; omitted means the connection root. */
2591
+ serviceId?: string;
2592
+ maxDepth?: number;
2593
+ timeoutMs?: number;
2594
+ }
2595
+ /** Export a complete static contract, failing on missing reflection, schemas, or truncated discovery. */
2596
+ declare function exportStaticHubSchema(channel: ReflectionChannel, options?: ExportStaticHubSchemaOptions): Promise<StaticHubSchemaDocument>;
2597
+ //#endregion
2598
+ //#region src/inspection/inspection.interfaces.d.ts
2599
+ declare const zTopologyPort: import("zod/mini").ZodMiniObject<{
2600
+ portId: import("zod/mini").ZodMiniString<string>;
2601
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2602
+ }, import("zod/v4/core").$strip>;
2603
+ declare const zParticipantDescriptor: import("zod/mini").ZodMiniObject<{
2604
+ type: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2605
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2606
+ processId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
2607
+ processType: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2608
+ nodeStatusServiceId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2609
+ 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>]>>>;
2610
+ }, import("zod/v4/core").$strip>;
2611
+ declare const zParticipantDescriptorSource: import("zod/mini").ZodMiniObject<{
2612
+ source: import("zod/mini").ZodMiniEnum<{
2613
+ self: "self";
2614
+ attacher: "attacher";
2615
+ }>;
2616
+ descriptor: import("zod/mini").ZodMiniObject<{
2617
+ type: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2618
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2619
+ processId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
2620
+ processType: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2621
+ nodeStatusServiceId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2622
+ 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>]>>>;
2623
+ }, import("zod/v4/core").$strip>;
2624
+ }, import("zod/v4/core").$strip>;
2625
+ declare const zTopologyNode: import("zod/mini").ZodMiniObject<{
2626
+ nodeId: import("zod/mini").ZodMiniString<string>;
2627
+ kind: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniEnum<{
2628
+ endpoint: "endpoint";
2629
+ hub: "hub";
2630
+ }>>;
2631
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2632
+ descriptors: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
2633
+ source: import("zod/mini").ZodMiniEnum<{
2634
+ self: "self";
2635
+ attacher: "attacher";
2636
+ }>;
2637
+ descriptor: import("zod/mini").ZodMiniObject<{
2638
+ type: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2639
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2640
+ processId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
2641
+ processType: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2642
+ nodeStatusServiceId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2643
+ 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>]>>>;
2644
+ }, import("zod/v4/core").$strip>;
2645
+ }, import("zod/v4/core").$strip>>>;
2646
+ ports: import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
2647
+ portId: import("zod/mini").ZodMiniString<string>;
2648
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2649
+ }, import("zod/v4/core").$strip>>;
2650
+ }, import("zod/v4/core").$strip>;
2651
+ declare const zTopologyLinkEndpoint: import("zod/mini").ZodMiniObject<{
2652
+ nodeId: import("zod/mini").ZodMiniString<string>;
2653
+ portId: import("zod/mini").ZodMiniString<string>;
2654
+ }, import("zod/v4/core").$strip>;
2655
+ declare const zTopologyTransportEndpoint: import("zod/mini").ZodMiniObject<{
2656
+ address: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2657
+ port: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
2658
+ }, import("zod/v4/core").$strip>;
2659
+ /**
2660
+ * Transport details as observed at a topology link. `local` corresponds to the
2661
+ * link's `from` endpoint and `remote` to its `to` endpoint.
2662
+ */
2663
+ declare const zTopologyTransportInfo: import("zod/mini").ZodMiniObject<{
2664
+ type: import("zod/mini").ZodMiniString<string>;
2665
+ local: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
2666
+ address: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2667
+ port: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
2668
+ }, import("zod/v4/core").$strip>>;
2669
+ remote: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
2670
+ address: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2671
+ port: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
2672
+ }, import("zod/v4/core").$strip>>;
2673
+ path: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2674
+ 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>]>>>;
2675
+ }, import("zod/v4/core").$strip>;
2676
+ declare const zTopologyLink: import("zod/mini").ZodMiniObject<{
2677
+ from: import("zod/mini").ZodMiniObject<{
2678
+ nodeId: import("zod/mini").ZodMiniString<string>;
2679
+ portId: import("zod/mini").ZodMiniString<string>;
2680
+ }, import("zod/v4/core").$strip>;
2681
+ to: import("zod/mini").ZodMiniObject<{
2682
+ nodeId: import("zod/mini").ZodMiniString<string>;
2683
+ portId: import("zod/mini").ZodMiniString<string>;
2684
+ }, import("zod/v4/core").$strip>;
2685
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2686
+ peerState: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniEnum<{
2687
+ identified: "identified";
2688
+ pending: "pending";
2689
+ unsupported: "unsupported";
2690
+ error: "error";
2691
+ }>>;
2692
+ transport: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
2693
+ type: import("zod/mini").ZodMiniString<string>;
2694
+ local: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
2695
+ address: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2696
+ port: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
2697
+ }, import("zod/v4/core").$strip>>;
2698
+ remote: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
2699
+ address: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2700
+ port: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
2701
+ }, import("zod/v4/core").$strip>>;
2702
+ path: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2703
+ 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>]>>>;
2704
+ }, import("zod/v4/core").$strip>>;
2705
+ }, import("zod/v4/core").$strip>;
2706
+ declare const zRouteClaim: import("zod/mini").ZodMiniObject<{
2707
+ serviceId: import("zod/mini").ZodMiniString<string>;
2708
+ nodeId: import("zod/mini").ZodMiniString<string>;
2709
+ portId: import("zod/mini").ZodMiniString<string>;
2710
+ match: import("zod/mini").ZodMiniEnum<{
2711
+ exact: "exact";
2712
+ prefix: "prefix";
2713
+ }>;
2714
+ }, import("zod/v4/core").$strip>;
2715
+ declare const zTopologyGraph: import("zod/mini").ZodMiniObject<{
2716
+ observerServiceId: import("zod/mini").ZodMiniString<string>;
2717
+ entryNodeId: import("zod/mini").ZodMiniString<string>;
2718
+ nodes: import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
2719
+ nodeId: import("zod/mini").ZodMiniString<string>;
2720
+ kind: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniEnum<{
2721
+ endpoint: "endpoint";
2722
+ hub: "hub";
2723
+ }>>;
2724
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2725
+ descriptors: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
2726
+ source: import("zod/mini").ZodMiniEnum<{
2727
+ self: "self";
2728
+ attacher: "attacher";
2729
+ }>;
2730
+ descriptor: import("zod/mini").ZodMiniObject<{
2731
+ type: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2732
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2733
+ processId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
2734
+ processType: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2735
+ nodeStatusServiceId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2736
+ 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>]>>>;
2737
+ }, import("zod/v4/core").$strip>;
2738
+ }, import("zod/v4/core").$strip>>>;
2739
+ ports: import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
2740
+ portId: import("zod/mini").ZodMiniString<string>;
2741
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2742
+ }, import("zod/v4/core").$strip>>;
2743
+ }, import("zod/v4/core").$strip>>;
2744
+ links: import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
2745
+ from: import("zod/mini").ZodMiniObject<{
2746
+ nodeId: import("zod/mini").ZodMiniString<string>;
2747
+ portId: import("zod/mini").ZodMiniString<string>;
2748
+ }, import("zod/v4/core").$strip>;
2749
+ to: import("zod/mini").ZodMiniObject<{
2750
+ nodeId: import("zod/mini").ZodMiniString<string>;
2751
+ portId: import("zod/mini").ZodMiniString<string>;
2752
+ }, import("zod/v4/core").$strip>;
2753
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2754
+ peerState: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniEnum<{
2755
+ identified: "identified";
2756
+ pending: "pending";
2757
+ unsupported: "unsupported";
2758
+ error: "error";
2759
+ }>>;
2760
+ transport: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
2761
+ type: import("zod/mini").ZodMiniString<string>;
2762
+ local: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
2763
+ address: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2764
+ port: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
2765
+ }, import("zod/v4/core").$strip>>;
2766
+ remote: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
2767
+ address: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2768
+ port: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
2769
+ }, import("zod/v4/core").$strip>>;
2770
+ path: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2771
+ 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>]>>>;
2772
+ }, import("zod/v4/core").$strip>>;
2773
+ }, import("zod/v4/core").$strip>>;
2774
+ routes: import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
2775
+ serviceId: import("zod/mini").ZodMiniString<string>;
2776
+ nodeId: import("zod/mini").ZodMiniString<string>;
2777
+ portId: import("zod/mini").ZodMiniString<string>;
2778
+ match: import("zod/mini").ZodMiniEnum<{
2779
+ exact: "exact";
2780
+ prefix: "prefix";
2781
+ }>;
2782
+ }, import("zod/v4/core").$strip>>;
2783
+ }, import("zod/v4/core").$strip>;
2784
+ type TopologyPort = output<typeof zTopologyPort>;
2785
+ type ParticipantDescriptor = output<typeof zParticipantDescriptor>;
2786
+ type ParticipantDescriptorSource = output<typeof zParticipantDescriptorSource>;
2787
+ type TopologyNode = output<typeof zTopologyNode>;
2788
+ type TopologyLinkEndpoint = output<typeof zTopologyLinkEndpoint>;
2789
+ type TopologyTransportEndpoint = output<typeof zTopologyTransportEndpoint>;
2790
+ type TopologyTransportInfo = output<typeof zTopologyTransportInfo>;
2791
+ type TopologyLink = output<typeof zTopologyLink>;
2792
+ type RouteClaim = output<typeof zRouteClaim>;
2793
+ type TopologyGraph = output<typeof zTopologyGraph>;
2794
+ declare const topologyInterface: InterfaceDefinition<{
2795
+ getGraph: RequestType<Record<string, never>, {
2796
+ observerServiceId: string;
2797
+ entryNodeId: string;
2798
+ nodes: {
2799
+ nodeId: string;
2800
+ ports: {
2801
+ portId: string;
2802
+ label?: string | undefined;
2803
+ }[];
2804
+ kind?: "endpoint" | "hub" | undefined;
2805
+ label?: string | undefined;
2806
+ descriptors?: {
2807
+ source: "self" | "attacher";
2808
+ descriptor: {
2809
+ type?: string | undefined;
2810
+ label?: string | undefined;
2811
+ processId?: number | undefined;
2812
+ processType?: string | undefined;
2813
+ nodeStatusServiceId?: string | undefined;
2814
+ metadata?: Record<string, string | number | boolean> | undefined;
2815
+ };
2816
+ }[] | undefined;
2817
+ }[];
2818
+ links: {
2819
+ from: {
2820
+ nodeId: string;
2821
+ portId: string;
2822
+ };
2823
+ to: {
2824
+ nodeId: string;
2825
+ portId: string;
2826
+ };
2827
+ label?: string | undefined;
2828
+ peerState?: "identified" | "pending" | "unsupported" | "error" | undefined;
2829
+ transport?: {
2830
+ type: string;
2831
+ local?: {
2832
+ address?: string | undefined;
2833
+ port?: number | undefined;
2834
+ } | undefined;
2835
+ remote?: {
2836
+ address?: string | undefined;
2837
+ port?: number | undefined;
2838
+ } | undefined;
2839
+ path?: string | undefined;
2840
+ metadata?: Record<string, string | number | boolean> | undefined;
2841
+ } | undefined;
2842
+ }[];
2843
+ routes: {
2844
+ serviceId: string;
2845
+ nodeId: string;
2846
+ portId: string;
2847
+ match: "exact" | "prefix";
2848
+ }[];
2849
+ }, void, NoInfer<Record<string, never>>, never, readonly ApplicationErrorDescriptorBase[], void>;
2850
+ watchGraph: RequestType<Record<string, never>, Record<string, never>, void, never, NoInfer<Record<string, never>>, readonly ApplicationErrorDescriptorBase[], void>;
2851
+ }>;
2852
+ declare const zTrafficTransitEndpoint: import("zod/mini").ZodMiniObject<{
2853
+ edgeId: import("zod/mini").ZodMiniString<string>;
2854
+ portId: import("zod/mini").ZodMiniString<string>;
2855
+ requestId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniString<string>]>>;
2856
+ }, import("zod/v4/core").$strip>;
2857
+ declare const zTrafficTransitEvent: import("zod/mini").ZodMiniObject<{
2858
+ type: import("zod/mini").ZodMiniLiteral<"transit">;
2859
+ timeMs: import("zod/mini").ZodMiniNumber<number>;
2860
+ nodeId: import("zod/mini").ZodMiniString<string>;
2861
+ in: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
2862
+ edgeId: import("zod/mini").ZodMiniString<string>;
2863
+ portId: import("zod/mini").ZodMiniString<string>;
2864
+ requestId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniString<string>]>>;
2865
+ }, import("zod/v4/core").$strip>>;
2866
+ out: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
2867
+ edgeId: import("zod/mini").ZodMiniString<string>;
2868
+ portId: import("zod/mini").ZodMiniString<string>;
2869
+ requestId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniString<string>]>>;
2870
+ }, import("zod/v4/core").$strip>>;
2871
+ disposition: import("zod/mini").ZodMiniEnum<{
2872
+ forwarded: "forwarded";
2873
+ consumed: "consumed";
2874
+ dropped: "dropped";
2875
+ unroutable: "unroutable";
2876
+ }>;
2877
+ kind: import("zod/mini").ZodMiniEnum<{
2878
+ request: "request";
2879
+ notification: "notification";
2880
+ response: "response";
2881
+ stream: "stream";
2882
+ }>;
2883
+ method: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2884
+ params: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnknown>;
2885
+ result: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnknown>;
2886
+ error: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
2887
+ code: import("zod/mini").ZodMiniNumber<number>;
2888
+ message: import("zod/mini").ZodMiniString<string>;
2889
+ data: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnknown>;
2890
+ }, import("zod/v4/core").$strip>>;
2891
+ }, import("zod/v4/core").$strip>;
2892
+ declare const zTrafficOverflowEvent: import("zod/mini").ZodMiniObject<{
2893
+ type: import("zod/mini").ZodMiniLiteral<"overflow">;
2894
+ dropped: import("zod/mini").ZodMiniNumber<number>;
2895
+ }, import("zod/v4/core").$strip>;
2896
+ declare const zTrafficEvent: import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniObject<{
2897
+ type: import("zod/mini").ZodMiniLiteral<"transit">;
2898
+ timeMs: import("zod/mini").ZodMiniNumber<number>;
2899
+ nodeId: import("zod/mini").ZodMiniString<string>;
2900
+ in: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
2901
+ edgeId: import("zod/mini").ZodMiniString<string>;
2902
+ portId: import("zod/mini").ZodMiniString<string>;
2903
+ requestId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniString<string>]>>;
2904
+ }, import("zod/v4/core").$strip>>;
2905
+ out: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
2906
+ edgeId: import("zod/mini").ZodMiniString<string>;
2907
+ portId: import("zod/mini").ZodMiniString<string>;
2908
+ requestId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniNumber<number>, import("zod/mini").ZodMiniString<string>]>>;
2909
+ }, import("zod/v4/core").$strip>>;
2910
+ disposition: import("zod/mini").ZodMiniEnum<{
2911
+ forwarded: "forwarded";
2912
+ consumed: "consumed";
2913
+ dropped: "dropped";
2914
+ unroutable: "unroutable";
2915
+ }>;
2916
+ kind: import("zod/mini").ZodMiniEnum<{
2917
+ request: "request";
2918
+ notification: "notification";
2919
+ response: "response";
2920
+ stream: "stream";
2921
+ }>;
2922
+ method: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
2923
+ params: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnknown>;
2924
+ result: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnknown>;
2925
+ error: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniObject<{
2926
+ code: import("zod/mini").ZodMiniNumber<number>;
2927
+ message: import("zod/mini").ZodMiniString<string>;
2928
+ data: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnknown>;
2929
+ }, import("zod/v4/core").$strip>>;
2930
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
2931
+ type: import("zod/mini").ZodMiniLiteral<"overflow">;
2932
+ dropped: import("zod/mini").ZodMiniNumber<number>;
2933
+ }, import("zod/v4/core").$strip>]>;
2934
+ type TrafficTransitEndpoint = output<typeof zTrafficTransitEndpoint>;
2935
+ type TrafficTransitEvent = output<typeof zTrafficTransitEvent>;
2936
+ type TrafficOverflowEvent = output<typeof zTrafficOverflowEvent>;
2937
+ type TrafficEvent = output<typeof zTrafficEvent>;
2938
+ declare const zTrafficWatchResult: import("zod/mini").ZodMiniObject<{
2939
+ delivered: import("zod/mini").ZodMiniNumber<number>;
2940
+ dropped: import("zod/mini").ZodMiniNumber<number>;
2941
+ }, import("zod/v4/core").$strip>;
2942
+ type TrafficWatchResult = output<typeof zTrafficWatchResult>;
2943
+ /**
2944
+ * Observe raw message transits at the node hosting the addressed service.
2945
+ * Consumers may correlate adjacent transits by shared `(portId, requestId)`.
2554
2946
  */
2555
- declare class KeypairIdentity implements Identity {
2556
- private readonly _privateKey;
2557
- private readonly _wrap;
2558
- readonly principal: PrincipalId;
2559
- readonly wrapPublicKey: Uint8Array;
2560
- readonly publicSigningIdentity: PublicSigningIdentity;
2561
- readonly publicWrappingIdentity: PublicWrappingIdentity;
2562
- constructor(principal: PrincipalId, _privateKey: PrivateKey, _wrap: X25519Keypair);
2563
- sign(message: Uint8Array): Promise<Signature>;
2564
- wrap(domain: string, bytes: Uint8Array): Promise<Uint8Array>;
2565
- unwrap(domain: string, blob: Uint8Array): Promise<Uint8Array>;
2566
- /** Generate a fresh identity (Ed25519 + X25519 keypairs). */
2567
- static generate(): Promise<KeypairIdentity>;
2568
- }
2947
+ declare const trafficInterface: InterfaceDefinition<{
2948
+ watch: RequestType<{
2949
+ methodPrefix?: string | undefined;
2950
+ trafficIgnoreKey?: string | undefined;
2951
+ focusRequest?: {
2952
+ portId: string;
2953
+ requestId: string | number;
2954
+ } | undefined;
2955
+ }, {
2956
+ delivered: number;
2957
+ dropped: number;
2958
+ }, void, never, NoInfer<{
2959
+ type: "transit";
2960
+ timeMs: number;
2961
+ nodeId: string;
2962
+ disposition: "forwarded" | "consumed" | "dropped" | "unroutable";
2963
+ kind: "request" | "notification" | "response" | "stream";
2964
+ in?: {
2965
+ edgeId: string;
2966
+ portId: string;
2967
+ requestId?: string | number | undefined;
2968
+ } | undefined;
2969
+ out?: {
2970
+ edgeId: string;
2971
+ portId: string;
2972
+ requestId?: string | number | undefined;
2973
+ } | undefined;
2974
+ method?: string | undefined;
2975
+ params?: unknown;
2976
+ result?: unknown;
2977
+ error?: {
2978
+ code: number;
2979
+ message: string;
2980
+ data?: unknown;
2981
+ } | undefined;
2982
+ } | {
2983
+ type: "overflow";
2984
+ dropped: number;
2985
+ }>, readonly ApplicationErrorDescriptorBase[], void>;
2986
+ watchWithPayloads: RequestType<{
2987
+ maxPayloadBytes: number;
2988
+ methodPrefix?: string | undefined;
2989
+ trafficIgnoreKey?: string | undefined;
2990
+ focusRequest?: {
2991
+ portId: string;
2992
+ requestId: string | number;
2993
+ } | undefined;
2994
+ }, {
2995
+ delivered: number;
2996
+ dropped: number;
2997
+ }, void, never, NoInfer<{
2998
+ type: "transit";
2999
+ timeMs: number;
3000
+ nodeId: string;
3001
+ disposition: "forwarded" | "consumed" | "dropped" | "unroutable";
3002
+ kind: "request" | "notification" | "response" | "stream";
3003
+ in?: {
3004
+ edgeId: string;
3005
+ portId: string;
3006
+ requestId?: string | number | undefined;
3007
+ } | undefined;
3008
+ out?: {
3009
+ edgeId: string;
3010
+ portId: string;
3011
+ requestId?: string | number | undefined;
3012
+ } | undefined;
3013
+ method?: string | undefined;
3014
+ params?: unknown;
3015
+ result?: unknown;
3016
+ error?: {
3017
+ code: number;
3018
+ message: string;
3019
+ data?: unknown;
3020
+ } | undefined;
3021
+ } | {
3022
+ type: "overflow";
3023
+ dropped: number;
3024
+ }>, readonly ApplicationErrorDescriptorBase[], void>;
3025
+ }>;
2569
3026
  //#endregion
2570
- //#region src/identity/capability.d.ts
2571
- /**
2572
- * Pure freshness check for a single capability link: `true` when the cap never
2573
- * expires, or its `expiresAtMs` is still in the future at `now + marginMs`.
2574
- *
2575
- * Mirrors the gate's expiry rule in {@link verifyChain}'s link check
2576
- * (`expiresAtMs < nowMs` ⇒ expired) so a producer can decide, *before signing*,
2577
- * whether to re-acquire a cap rather than attach one the gate will reject as
2578
- * `expired`. The `marginMs` safety window absorbs in-flight transit time and
2579
- * client/hub clock skew — pass the call's `signedAtMs` as `now` so the check
2580
- * evaluates expiry against the same instant baked into the envelope.
2581
- *
2582
- * This checks ONE link. Effective authority requires every link in a
2583
- * delegation chain to be unexpired, so a producer attaching a bag should apply
2584
- * this to every cap it would attach (see {@link capBagFreshAt}).
2585
- */
2586
- declare function capabilityFreshAt(cap: Capability, now: number, marginMs?: number): boolean;
2587
- /**
2588
- * Freshness over a whole presented bag: `true` only when every cap is fresh at
2589
- * `now + marginMs` (see {@link capabilityFreshAt}). An empty bag is trivially
2590
- * fresh. Use this at the cap-production point to decide whether to re-acquire.
2591
- */
2592
- declare function capBagFreshAt(caps: readonly Capability[], now: number, marginMs?: number): boolean;
2593
- type PermitResult = {
2594
- ok: true;
2595
- capabilityNonce: string;
2596
- rootIssuer: PrincipalId;
2597
- } | {
2598
- ok: false;
2599
- reason: string;
2600
- };
2601
- /**
2602
- * A trust anchor accepted as a capability-chain root, plus whether it may be
2603
- * named in authorization error messages.
2604
- */
2605
- interface AcceptedRootIssuer {
2606
- /** The principal accepted as a chain root for the queried service. */
2607
- principal: PrincipalId;
2608
- /**
2609
- * Whether this issuer may be disclosed in `permits` rejection reasons.
2610
- * Public anchors (e.g. a hub's well-known admin identity) are surfaced to
2611
- * help diagnose "wrong root" failures; private ones are withheld so the
2612
- * error never leaks the set of trusted issuers.
2613
- */
2614
- isPublic: boolean;
2615
- }
2616
- /**
2617
- * **The** authorization predicate. A call is permitted iff some presented
2618
- * capability (1) addresses the call, (2) has a genuine, well-delegated
2619
- * chain whose leaf audience is the caller (`call.signer`), and (3) roots
2620
- * at an issuer the verifier accepts **for the call's service**.
2621
- *
2622
- * Pure: it reports the verdict (and the `capabilityNonce` / `rootIssuer`
2623
- * for audit) but performs no consumption. Replay is the caller's job — the
2624
- * gate dedups `call.nonce`, so `callBind` grants are single-use for free.
2625
- *
2626
- * `acceptedRootIssuers` is consulted with the call's `serviceId` and returns
2627
- * the accepted {@link AcceptedRootIssuer} anchors; an empty result rejects
2628
- * every capability (fail closed) — trust is the verifier's, never the
2629
- * token's. Anchors flagged `isPublic` are named in the rejection reason when
2630
- * a chain roots at an unaccepted issuer.
2631
- */
2632
- declare function permits(call: Call, capabilities: readonly SignedCapability[], acceptedRootIssuers: (serviceId: string) => readonly AcceptedRootIssuer[], nowMs: number, opts?: {
2633
- maxDepth?: number;
2634
- }): Promise<PermitResult>;
2635
- /**
2636
- * Sign a `Capability` with a {@link SigningIdentity}. The private key never
2637
- * leaves the identity. The result verifies via {@link verifyChain}.
2638
- */
2639
- declare function signCapability(capability: Capability, issuer: SigningIdentity): Promise<SignedCapability>;
2640
- interface IssueCapabilityOptions {
2641
- /** Identity allowed to present the capability. */
2642
- readonly audience: PublicSigningIdentity;
2643
- /** Authority granted to the audience. */
2644
- readonly permissions: readonly Permission[];
2645
- /** Optional expiration time as Unix milliseconds. */
2646
- readonly expiresAtMs?: number;
2647
- /** Optional parent whose authority this capability narrows. */
2648
- readonly parent?: SignedCapability;
2649
- }
2650
- /**
2651
- * Issue and sign a capability, deriving its issuer, nonce, and optional parent
2652
- * hash. The result is plain JSON data and survives a JSON stringify/parse
2653
- * round-trip without reconstruction.
2654
- */
2655
- declare function issueCapability(issuer: SigningIdentity, options: IssueCapabilityOptions): Promise<SignedCapability>;
2656
- type ParamMatcherFor<T> = {
2657
- exact: T;
2658
- } | {
2659
- enum: T[];
2660
- } | {
2661
- any: true;
2662
- } | (T extends string ? {
2663
- prefix: string;
2664
- } : never) | (T extends readonly string[] ? {
2665
- subsetOf: string[];
2666
- } : never);
2667
- /** Type-safe top-level parameter matchers for one interface member. */
2668
- type ParamMatchers<T> = T extends Record<string, unknown> ? { [K in keyof T]: ParamMatcherFor<Exclude<T[K], undefined>>; } : never;
2669
- type RequestMemberName<TMembers extends MemberMap> = { [K in keyof TMembers]: TMembers[K] extends RequestType<any, any, any, any, any, any, any> ? K : never; }[keyof TMembers] & string;
2670
- type RequestParams<TMember> = TMember extends RequestType<infer TParams, any, any, any, any, any, any> ? TParams : never;
2671
- /** Match a string parameter by prefix. */
2672
- declare function prefix(value: string): {
2673
- prefix: string;
2674
- };
3027
+ //#region src/inspection/node.interfaces.d.ts
3028
+ declare const zNodeInfo: import("zod/mini").ZodMiniObject<{
3029
+ nodeId: import("zod/mini").ZodMiniString<string>;
3030
+ portId: import("zod/mini").ZodMiniString<string>;
3031
+ descriptors: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
3032
+ source: import("zod/mini").ZodMiniEnum<{
3033
+ self: "self";
3034
+ attacher: "attacher";
3035
+ }>;
3036
+ descriptor: import("zod/mini").ZodMiniObject<{
3037
+ type: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
3038
+ label: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
3039
+ processId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
3040
+ processType: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
3041
+ nodeStatusServiceId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
3042
+ 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>]>>>;
3043
+ }, import("zod/v4/core").$strip>;
3044
+ }, import("zod/v4/core").$strip>>>;
3045
+ }, import("zod/v4/core").$strip>;
3046
+ type NodeInfo = output<typeof zNodeInfo>;
2675
3047
  /**
2676
- * Build an invoke permission from a typed interface member. The helper derives
2677
- * the interface id and schema hash and type-checks parameter matcher names and
2678
- * values against the member's params.
3048
+ * Generates unique topology-correlation labels, not security identities.
3049
+ * Custom generators must avoid collisions across nodes and ports. Tests can
3050
+ * supply an independent deterministic sequence for each participant.
2679
3051
  */
2680
- declare function invoke<TMembers extends MemberMap, TMember extends RequestMemberName<TMembers>>(serviceId: string, iface: InterfaceDefinition<TMembers>, member: TMember, params?: ParamMatchers<RequestParams<TMembers[TMember]>>): Permission;
2681
- //#endregion
2682
- //#region src/identity/managedIdentity.d.ts
3052
+ type TopologyIdGenerator = (kind: 'node' | 'port') => string;
2683
3053
  /**
2684
- * Executor-side backing for `identity.storage::*`. Lifecycle tied to a
2685
- * single managed-identity slot; the executor decides where bytes are
2686
- * stored.
3054
+ * Minimal root service for aligning the independently observed topologies at
3055
+ * both ends of a connection.
2687
3056
  */
2688
- interface ManagedIdentityStorageBackend {
2689
- get(key: string): Promise<unknown | undefined>;
2690
- set(key: string, value: unknown): Promise<void>;
2691
- /** Returns `true` iff the key existed before this call. */
2692
- delete(key: string): Promise<boolean>;
2693
- list(prefix?: string): Promise<string[]>;
2694
- }
3057
+ declare const nodeInterface: InterfaceDefinition<{
3058
+ getNodeId: RequestType<Record<string, never>, {
3059
+ nodeId: string;
3060
+ portId: string;
3061
+ descriptors?: {
3062
+ source: "self" | "attacher";
3063
+ descriptor: {
3064
+ type?: string | undefined;
3065
+ label?: string | undefined;
3066
+ processId?: number | undefined;
3067
+ processType?: string | undefined;
3068
+ nodeStatusServiceId?: string | undefined;
3069
+ metadata?: Record<string, string | number | boolean> | undefined;
3070
+ };
3071
+ }[] | undefined;
3072
+ }, any, never, never, readonly ApplicationErrorDescriptorBase[], any>;
3073
+ }>;
3074
+ //#endregion
3075
+ //#region src/connection/streaming.d.ts
2695
3076
  /**
2696
- * In-process storage backend. Used by tests and by any executor that
2697
- * doesn't need at-rest persistence.
3077
+ * Direction a {@link STREAM_METHOD} message travels, relative to the
3078
+ * request it is correlated with. Made explicit on the wire so that a
3079
+ * middlebox (the hub) can *author* a stream message — e.g. inject a
3080
+ * cancel when a caller disconnects — without an inbound message whose
3081
+ * arrival link it could infer the direction from.
2698
3082
  */
2699
- declare class InMemoryManagedIdentityStorage implements ManagedIdentityStorageBackend {
2700
- private readonly _data;
2701
- get(key: string): Promise<unknown | undefined>;
2702
- set(key: string, value: unknown): Promise<void>;
2703
- delete(key: string): Promise<boolean>;
2704
- list(prefix?: string): Promise<string[]>;
2705
- }
3083
+ declare const StreamDir: {
3084
+ /** callee → caller: progress, partial results. Routes like a response. */
3085
+ readonly toCaller: "toCaller";
3086
+ /** caller → callee: input, cancellation, keepalive ping. */
3087
+ readonly toCallee: "toCallee";
3088
+ };
3089
+ type StreamDir = (typeof StreamDir)[keyof typeof StreamDir];
2706
3090
  /**
2707
- * In-process `ManagedIdentity` that holds the private key in memory and
2708
- * uses the package crypto API. Useful for tests and for hub-side features
2709
- * that want a short-lived identity without touching disk.
3091
+ * Reserved control verbs. A control message carries no app `payload`; it
3092
+ * is interpreted by the runtime / hub itself, independently of the
3093
+ * originating method's stream schemas, so *any* request is cancellable
3094
+ * and keep-alive-able even when it declares no app stream.
2710
3095
  */
2711
- declare class InMemoryManagedIdentity implements Identity {
2712
- private readonly _ed;
2713
- private readonly _wrap;
2714
- readonly principal: PrincipalId;
2715
- readonly wrapPublicKey: Uint8Array;
2716
- constructor(_ed: Keypair, _wrap: X25519Keypair);
2717
- get publicSigningIdentity(): PublicSigningIdentity;
2718
- get publicWrappingIdentity(): PublicWrappingIdentity;
2719
- sign(bytes: Uint8Array): Promise<Signature>;
2720
- wrap(domain: string, bytes: Uint8Array): Promise<Uint8Array>;
2721
- unwrap(domain: string, blob: Uint8Array): Promise<Uint8Array>;
2722
- /** Generate a fresh in-memory identity (Ed25519 + X25519 keypairs). */
2723
- static generate(): Promise<InMemoryManagedIdentity>;
2724
- }
3096
+ declare const StreamControlType: {
3097
+ /**
3098
+ * Ask the callee to abort the in-flight request. Always {@link
3099
+ * StreamDir.toCallee}. The callee surfaces this as an `AbortSignal`
3100
+ * and is expected to settle the request (typically with a
3101
+ * `cancelled` error response).
3102
+ */
3103
+ readonly cancel: "cancel";
3104
+ /**
3105
+ * Keepalive / liveness probe. Resets the hub's per-request idle timer
3106
+ * so a long-running call is not reaped, and lets either side actively
3107
+ * probe the peer. Carries a `nonce` the peer echoes in its {@link
3108
+ * StreamControlType.pong}. May travel in either direction. Emitted
3109
+ * automatically (without awaiting a pong) by the channel for streaming
3110
+ * calls; see {@link STREAM_METHOD}.
3111
+ */
3112
+ readonly ping: "ping";
3113
+ /**
3114
+ * Reply to a {@link StreamControlType.ping}, echoing the ping's
3115
+ * `nonce` so the prober can correlate it. Travels opposite the ping.
3116
+ * Carries no app effect — purely a liveness acknowledgement.
3117
+ */
3118
+ readonly pong: "pong";
3119
+ };
3120
+ type StreamControlType = (typeof StreamControlType)[keyof typeof StreamControlType];
2725
3121
  /**
2726
- * Register the `identity` interface on `overlay` so the bound participant
2727
- * can call `identity::sign` etc. on its root overlay. The overlay is
2728
- * private to one participant — no other peer can reach these methods.
2729
- *
2730
- * When `storage` is supplied, the `identity.storage` interface is
2731
- * registered alongside `identity::*`. Lifetime/scope of the backend is
2732
- * the executor's responsibility — for keystore-backed identities the
2733
- * backend lives as long as the identity slot does.
2734
- *
2735
- * Typical caller: the executor (e.g. the VS Code extension), right after
2736
- * `Hub.attachParticipant`, on the `rootOverlay` returned from the attach
2737
- * handle.
3122
+ * Well-known `control.reason` strings. The set is **open** — any string
3123
+ * is valid on the wire; these are the reasons linkrpc itself emits.
2738
3124
  */
2739
- declare function registerIdentityOnOverlay(overlay: LinkRpcConnection, identity: Identity, storage?: ManagedIdentityStorageBackend): void;
3125
+ declare const StreamControlReason: {
3126
+ /**
3127
+ * The caller's transport dropped while the request was in flight; the
3128
+ * hub cancels the callee's now-orphaned work.
3129
+ */
3130
+ readonly clientDisconnected: "clientDisconnected";
3131
+ /**
3132
+ * The request exceeded the hub's idle timeout with no stream activity
3133
+ * (no ping, no stream message). See {@link STREAM_METHOD} docs.
3134
+ */
3135
+ readonly idleTimeout: "idleTimeout";
3136
+ };
3137
+ type StreamControlReason = (typeof StreamControlReason)[keyof typeof StreamControlReason];
2740
3138
  /**
2741
- * Like {@link registerIdentityOnOverlay}, but resolves the identity lazily on
2742
- * first use via `resolveIdentity`. The identity is materialized only when the
2743
- * bound participant actually calls `identity::*` — registering the overlay
2744
- * does NOT create or load any identity.
3139
+ * Streaming sub-protocol. Long-running requests can emit additional
3140
+ * notifications correlated with the original call in either direction
3141
+ * (callee → caller progress, caller → callee input / cancellation /
3142
+ * keepalive).
2745
3143
  *
2746
- * This is essential for the consent model: a host can serve `identity::*` on a
2747
- * keystore slot without making the slot privileged (`hasState`) until the app
2748
- * genuinely opts into an identity. `resolveIdentity` is expected to be cheap on
2749
- * repeat calls (the keystore caches in memory), and to reflect lifecycle
2750
- * changes — e.g. after a slot is wiped and re-created ("Reset Identity"), the
2751
- * next call resolves the fresh identity.
3144
+ * Wire form: a JSON-RPC notification whose method is
3145
+ * `${streamInterface.info.id}::send` and whose params match
3146
+ * `streamInterface.members.send.paramsSchema`. The hub routes purely on
3147
+ * `requestId` (following the originating request's established path, like
3148
+ * a response); the originating request's capability authorization covers
3149
+ * its full stream lifetime, so stream notifications carry no method /
3150
+ * interface namespace of their own. App `payload` contents are typed per
3151
+ * request via the originating method's
3152
+ * `RequestType.clientStreamSchema` / `serverStreamSchema`; reserved
3153
+ * `control` messages are schema-independent.
2752
3154
  *
2753
- * `storage` is registered eagerly because reading/writing storage is itself
2754
- * the privileged act the app must perform to gain state — exposing the
2755
- * interface costs nothing until used.
2756
- */
2757
- declare function registerLazyIdentityOnOverlay(overlay: LinkRpcConnection<unknown>, resolveIdentity: () => Promise<Identity>, storage?: ManagedIdentityStorageBackend): void;
2758
- /**
2759
- * Client-side proxy for `identity.storage::*`. Methods round-trip through
2760
- * the participant's root overlay; the executor enforces key-shape rules
2761
- * server-side.
3155
+ * Idle timeout: a request that never streams (no `control` ping, no
3156
+ * stream message) is subject to the hub's per-request idle timeout
3157
+ * (default 30 minutes) — at which point it is cancelled and its caller
3158
+ * gets a `requestTimeout` error. This bounds the hub's pending-request
3159
+ * table, which is also what protects it from a slow-loris / DDoS that
3160
+ * opens requests and never completes them. Streaming-enabled calls keep
3161
+ * themselves alive by emitting a periodic {@link StreamControlType.ping}.
2762
3162
  *
2763
- * Calls are unsigned (same recursion-guard rationale as
2764
- * {@link createManagedIdentity} — the overlay is private to one
2765
- * participant, so transport-level routing already authenticates).
2766
- */
2767
- interface ManagedIdentityStorage {
2768
- get<T = unknown>(key: string): Promise<T | undefined>;
2769
- set(key: string, value: unknown): Promise<void>;
2770
- delete(key: string): Promise<boolean>;
2771
- list(prefix?: string): Promise<string[]>;
2772
- }
2773
- /**
2774
- * A managed identity resolved from an executor's `identity::*` overlay: a
2775
- * full {@link Identity} (signing + HPKE wrap/unwrap, all round-tripping
2776
- * through the executor — private keys never leave it) plus the
2777
- * per-identity {@link ManagedIdentityStorage}.
3163
+ * The interface is declarative: nobody calls
3164
+ * `LinkRpcConnection.register(streamInterface, ...)`. The channel and the
3165
+ * hub intercept `$stream::send` directly. The definition exists so
3166
+ * reflection / consent UIs can describe the wire shape and so all wire
3167
+ * constants derive from one source.
2778
3168
  */
2779
- interface ManagedIdentity extends Identity {
2780
- /**
2781
- * Per-identity persistent key/value store. Backed by the executor's
2782
- * `identity.storage::*` overlay; calls throw when the executor did not
2783
- * register storage for this slot (e.g. an in-process identity for tests).
2784
- */
2785
- readonly storage: ManagedIdentityStorage;
2786
- }
3169
+ declare const streamInterface: InterfaceDefinition<{
3170
+ send: NotificationType<{
3171
+ requestId: string | number;
3172
+ dir: "toCaller" | "toCallee";
3173
+ control?: {
3174
+ type: "cancel" | "ping" | "pong";
3175
+ reason?: string | undefined;
3176
+ nonce?: string | undefined;
3177
+ } | undefined;
3178
+ payload?: unknown;
3179
+ }>;
3180
+ }>;
2787
3181
  /**
2788
- * Bootstrap a {@link ManagedIdentity} from a sender (typically the raw
2789
- * unsigned sender obtained via `channel.sender` before wrapping with
2790
- * {@link SigningSender}). Makes `identity::*` calls unsigned — the
2791
- * executor's overlay is private to one participant so routing already
2792
- * identifies the caller, preventing signing recursion.
2793
- *
2794
- * The returned identity signs / wraps / unwraps by round-tripping through
2795
- * the executor's `identity::*` overlay; the caller wires it into their
2796
- * {@link SigningSender} configuration (e.g. as a {@link Principal}). No
2797
- * side effects on any existing connection or holder.
3182
+ * Full wire method name for stream notifications. Pulled from the
3183
+ * interface object so we have a single source of truth.
2798
3184
  */
2799
- declare function createManagedIdentity(sender: IRequestSender<unknown>): Promise<ManagedIdentity>;
3185
+ declare const STREAM_METHOD: `${string}::send`;
3186
+ /** Wire-level shape carried on `params` of {@link STREAM_METHOD}. */
3187
+ type StreamSendParams = output<typeof streamInterface.members.send.paramsSchema>;
2800
3188
  //#endregion
2801
- //#region src/identity/capBag.d.ts
2802
- interface CapBagOptions {
2803
- /**
2804
- * Per-identity persistent storage (e.g.
2805
- * {@link ManagedIdentityHandle.storage}). Omit for a memory-only bag
2806
- * that forgets its caps when the process exits.
2807
- */
2808
- readonly storage?: ManagedIdentityStorage;
2809
- /** Storage key. Defaults to `hubrpc.caps.v1`. */
2810
- readonly storageKey?: string;
2811
- /** Optional sink for non-fatal storage warnings. */
2812
- readonly onWarn?: (message: string) => void;
2813
- }
3189
+ //#region src/protocol/jcs.d.ts
2814
3190
  /**
2815
- * A process-lifetime bag of hub-issued capabilities. Plug
2816
- * {@link CapBag.provider} straight into a connection's cap provider so every
2817
- * outbound signed call carries whatever caps have been granted so far. The
2818
- * hub picks whichever cap matches the call per dispatch.
3191
+ * RFC 8785 JSON Canonicalization Scheme (JCS).
3192
+ *
3193
+ * Used as the byte-deterministic encoding under every linkrpc signature
3194
+ * (RPC calls, capabilities, hub-signed previews). Both signer and verifier
3195
+ * canonicalize the same value object and obtain byte-identical UTF-8 bytes.
2819
3196
  *
2820
- * When constructed with {@link CapBagOptions.storage} the bag hydrates from
2821
- * (and persists to) storage, so the next process spawn for the same identity
2822
- * reuses its grants without re-prompting.
3197
+ * Implementation inlined from the `canonicalize` npm package (Apache-2.0,
3198
+ * https://github.com/erdtman/canonicalize) so this module stays
3199
+ * zero-dependency for browser bundlers that don't resolve transitive
3200
+ * npm specifiers (e.g. the in-house app-bundler).
2823
3201
  */
2824
- declare class CapBag {
2825
- /** Create a bag, hydrating from storage when one was supplied. */
2826
- static load(options?: CapBagOptions): Promise<CapBag>;
2827
- private readonly _caps;
2828
- private readonly _storage?;
2829
- private readonly _storageKey;
2830
- private readonly _onWarn;
2831
- private constructor();
2832
- get capabilities(): readonly SignedCapability[];
2833
- /**
2834
- * A {@link CapProvider} reflecting the bag at call-time. Assign it to
2835
- * `HubClientHandle.signing.capProvider` or pass it through
2836
- * `SigningSenderConfig.capProvider`.
2837
- */
2838
- readonly provider: CapProvider;
2839
- /** Append capabilities and persist (when backed by storage). */
2840
- add(...caps: readonly SignedCapability[]): Promise<void>;
2841
- /** Drop all capabilities and persist the empty bag. */
2842
- clear(): Promise<void>;
2843
- private _hydrate;
2844
- private _persist;
2845
- }
3202
+ /** RFC 8785 canonical JSON string for `value`. */
3203
+ declare function jcsCanonicalize(value: unknown): string;
3204
+ /** UTF-8 bytes of the RFC 8785 canonical JSON for `value`. The thing actually signed / hashed. */
3205
+ declare function jcsCanonicalizeBytes(value: unknown): Uint8Array;
2846
3206
  //#endregion
2847
- //#region src/identity/principal.d.ts
3207
+ //#region src/protocol/methodName.d.ts
2848
3208
  /**
2849
- * A signing identity bundled with its durable capability set. The
2850
- * {@link SigningIdentity} is fixed for the life of the principal; the
2851
- * {@link CapBag} is mutable and extensible — caps accumulate as the peer grants
2852
- * them.
3209
+ * Parsed JSON-RPC method string. The linkrpc dialect uses `::` to
3210
+ * separate up to three segments:
2853
3211
  *
2854
- * Transient, per-call (one-shot) grants are deliberately NOT part of a
2855
- * principal: that is a separate policy, see `OneShotCapStaging`.
3212
+ * - `"member"` — bare (preset-bound dispatch)
3213
+ * - `"interfaceId::member"` — interface form (root service)
3214
+ * - `"::interfaceId::member"` — explicit root form
3215
+ * - `"serviceId::interfaceId::member"` — fully-qualified form
2856
3216
  *
2857
- * Lives in its own module (rather than alongside `SigningSender`) so the
2858
- * `SigningSender` ⇄ `createManagedPrincipal` factory cycle does not run through
2859
- * a top-level `class … extends Principal`: such a cycle would hit a TDZ
2860
- * ("Class extends value undefined") depending on module evaluation order.
3217
+ * The hub does not accept the `bare` form (it has no interface context
3218
+ * to route on). Connection-level dispatch accepts all three.
2861
3219
  */
2862
- declare class Principal {
2863
- readonly identity: SigningIdentity;
2864
- readonly capBag: CapBag;
2865
- static create(identity: SigningIdentity, capabilities?: readonly SignedCapability[]): Promise<Principal>;
2866
- constructor(identity: SigningIdentity, capBag: CapBag);
2867
- get id(): PrincipalId;
2868
- }
2869
- //#endregion
2870
- //#region src/identity/managedPrincipal.d.ts
3220
+ type ParsedMethodName = {
3221
+ kind: "bare";
3222
+ member: string;
3223
+ } | {
3224
+ kind: "interface";
3225
+ interfaceId: string;
3226
+ member: string;
3227
+ } | {
3228
+ kind: "full";
3229
+ serviceId: string;
3230
+ interfaceId: string;
3231
+ member: string;
3232
+ };
2871
3233
  /**
2872
- * A {@link Principal} that also exposes the executor-backed per-identity
2873
- * {@link ManagedIdentityStorage}. Returned by {@link createManagedPrincipal}
2874
- * so callers can persist their own app state (e.g. a resolved serviceId)
2875
- * alongside the granted capabilities, using the very same durable store the
2876
- * {@link CapBag} hydrates from — no second storage wiring required.
3234
+ * Parse a JSON-RPC method string. Returns `undefined` if any segment is
3235
+ * empty or the segment count is out of range.
2877
3236
  */
2878
- declare class PrincipalWithStore extends Principal {
2879
- readonly store: ManagedIdentityStorage;
2880
- readonly identity: Identity;
2881
- constructor(identity: Identity, capBag: CapBag, store: ManagedIdentityStorage);
2882
- }
3237
+ declare function parseMethodName(method: string): ParsedMethodName | undefined;
2883
3238
  /**
2884
- * Executor-managed principal: the peer signs for us through its
2885
- * `identity::sign` overlay (we never hold a private key). Bootstrapped purely
2886
- * from the outbound `sender` — no side effects on any connection — and caps
2887
- * persist in the executor-backed per-identity storage. Works over any
2888
- * transport whose peer serves the identity overlay (hub *or* stdio).
2889
- *
2890
- * Call this exactly once per channel: it performs the `identity::*` handshake
2891
- * and hydrates the {@link CapBag} from storage. The returned
2892
- * {@link PrincipalWithStore} additionally surfaces that same durable
2893
- * {@link ManagedIdentityStorage} as `store`.
3239
+ * Convert a parsed method string to a {@link CallTarget} for capability
3240
+ * matching. Interface-form calls are addressed to the root service —
3241
+ * represented as an empty `serviceId`. Throws on `bare` form (no
3242
+ * interface context) and on malformed input.
2894
3243
  */
2895
- declare function createManagedPrincipal(sender: IRequestSender<unknown>): Promise<PrincipalWithStore>;
3244
+ declare function methodNameToTarget(method: string): CallTarget;
2896
3245
  //#endregion
2897
- //#region src/identity/signingSender.d.ts
3246
+ //#region src/protocol/linkRpcEnvelope.d.ts
2898
3247
  /**
2899
- * Per-outbound-call hook. Sees every signed call this sender makes,
2900
- * and gets a chance to:
2901
- * - attach capabilities (the common case),
2902
- * - override `method` / `params` / `interfaceHash` (rewriting,
2903
- * auditing, schema-pinning),
2904
- * - advance `signedAtMs` (e.g. after a slow consent prompt that needs
2905
- * to issue a cap bound to a fresher timestamp than the sender's
2906
- * initial wall-clock).
3248
+ * Signed call meta. Lives under `params.$hubrpc` so it can't collide with
3249
+ * the user's top-level param keys. Present on signed AND unsigned calls
3250
+ * (the latter omit {@link CallMeta.principal} and carry no `$hubrpcSignature`).
2907
3251
  *
2908
- * `signer` and `nonce` are NOT overridable. `signer` is the call's
2909
- * identity; `nonce` ties any cap to this specific call attempt and must
2910
- * not drift between the cap-issuance request and the call itself.
3252
+ * Included verbatim in the bytes a call signature commits to — the
3253
+ * signature covers `signingInput("call", { ...userParams, $hubrpc })`.
2911
3254
  */
2912
- type CapProvider = (req: {
3255
+ interface CallMeta {
3256
+ /** Fully-qualified wire method. The verifier asserts it equals the JSON-RPC `method`. */
2913
3257
  readonly method: string;
2914
- readonly params: JsonValue | undefined;
2915
- readonly signer: PrincipalId;
3258
+ /** Replay-protection nonce (base64url). The gate dedups on this. */
2916
3259
  readonly nonce: string;
3260
+ /** Unix milliseconds. Skew window enforced by the verifier. */
2917
3261
  readonly signedAtMs: number;
3262
+ /** Identity wielding the call. Present iff signed; equals the audience of every presented cap. */
3263
+ readonly principal?: PrincipalId;
3264
+ /** Optional schema hash assertion. Matched against `TargetPattern.interfaceHash`. */
2918
3265
  readonly interfaceHash?: string;
2919
- }) => Promise<CapProviderResult>;
2920
- interface CapProviderResult {
3266
+ }
3267
+ /**
3268
+ * Extrinsic, unsigned attachments carried under `params.$hubrpcUnsigned`.
3269
+ * Not covered by the call signature (they aren't authored by the signer).
3270
+ */
3271
+ interface LinkRpcUnsigned {
3272
+ /** Caller's presented capability bag. Parents are resolved out of this by hash. */
2921
3273
  readonly capabilities?: readonly SignedCapability[];
2922
- /** Override the wire method this sender signs. Default: the original. */
2923
- readonly method?: string;
2924
- /** Override the params this sender signs. Default: the original. */
2925
- readonly params?: JsonValue;
2926
- /** Override the interfaceHash baked into the signed envelope. */
2927
- readonly interfaceHash?: string;
2928
- /** Advance the Unix-ms timestamp baked into the signed envelope. */
2929
- readonly signedAtMs?: number;
3274
+ }
3275
+ /** Reserved wire-key meta carried on a linkrpc call's params object. */
3276
+ interface LinkRpcWireMeta {
3277
+ readonly [HUBRPC_META_KEY]?: CallMeta;
3278
+ readonly [HUBRPC_SIGNATURE_KEY]?: Signatures;
3279
+ readonly [HUBRPC_UNSIGNED_KEY]?: LinkRpcUnsigned;
2930
3280
  }
2931
3281
  /**
2932
- * Per-call ctx the {@link SigningSender} consumes. All fields are
2933
- * optional; the sender's persistent {@link SigningSenderConfig.principal} is
2934
- * the default.
3282
+ * Wire shape of `params` on a linkrpc JSON-RPC call.
2935
3283
  *
2936
- * To install a signer after the sender is already constructed (e.g. a
2937
- * managed-identity bootstrap), mutate the caller-owned config object — it is
2938
- * read fresh on every call. No setter on the sender itself.
3284
+ * The user's params object (if any) is spread as-is, with the
3285
+ * {@link LinkRpcWireMeta} keys attached on top. `TUserParams` carries the
3286
+ * user-visible param shape; defaults to an open object. User params MUST be
3287
+ * a plain object — enforced at signing/verification via
3288
+ * {@link requireObjectParams}.
2939
3289
  */
2940
- interface SigningCallCtx {
3290
+ type LinkRpcWireParams<TUserParams extends {
3291
+ [key: string]: JsonValue | undefined;
3292
+ } = {
3293
+ [key: string]: JsonValue | undefined;
3294
+ }> = TUserParams & LinkRpcWireMeta;
3295
+ /** JSON-RPC request whose `params` carry the linkrpc wire meta. */
3296
+ type LinkRpcJsonRpcRequest<TUserParams extends {
3297
+ [key: string]: JsonValue | undefined;
3298
+ } = {
3299
+ [key: string]: JsonValue | undefined;
3300
+ }> = JsonRpcRequest<LinkRpcWireParams<TUserParams>>;
3301
+ /** JSON-RPC notification whose `params` carry the linkrpc wire meta. */
3302
+ type LinkRpcJsonRpcNotification<TUserParams extends {
3303
+ [key: string]: JsonValue | undefined;
3304
+ } = {
3305
+ [key: string]: JsonValue | undefined;
3306
+ }> = JsonRpcNotification<LinkRpcWireParams<TUserParams>>;
3307
+ /** Either of the two linkrpc-bearing JSON-RPC message shapes. */
3308
+ type LinkRpcJsonRpcMessage<TUserParams extends {
3309
+ [key: string]: JsonValue | undefined;
3310
+ } = {
3311
+ [key: string]: JsonValue | undefined;
3312
+ }> = LinkRpcJsonRpcRequest<TUserParams> | LinkRpcJsonRpcNotification<TUserParams>;
3313
+ /**
3314
+ * The linkrpc signing/cap system accepts only plain-object user params (or
3315
+ * none). Reject arrays/primitives at the boundary so "strip `$hubrpc*`, the
3316
+ * rest is the signed user params" stays unambiguous.
3317
+ */
3318
+ declare function requireObjectParams(userParams: JsonValue | undefined): Record<string, JsonValue | undefined>;
3319
+ /**
3320
+ * Return the application-authored portion of a LinkRPC params value.
3321
+ *
3322
+ * Routing and gate layers must continue forwarding the original wire params so
3323
+ * every chained hub can independently verify the envelope. Terminal dispatch
3324
+ * may use this derived value for application-schema validation without mutating
3325
+ * or replacing the wire message.
3326
+ */
3327
+ declare function stripLinkRpcWireMeta(wireParams: unknown): JsonValue | undefined;
3328
+ //#endregion
3329
+ //#region src/transport/multiplexedTransport.d.ts
3330
+ interface MuxEnvelope {
3331
+ readonly $mux: "v1";
3332
+ readonly ch: string;
3333
+ readonly m: JsonRpcMessage;
3334
+ }
3335
+ declare class MultiplexedTransport<TChannels extends Record<string, string>> implements IDisposable {
3336
+ static create<TChannels extends Record<string, string>>(base: IMessageTransport<MuxEnvelope, MuxEnvelope>, channels: TChannels): MultiplexedTransport<TChannels>;
3337
+ /** Logical transports keyed by the friendly channel names. */
3338
+ readonly transports: { readonly [K in keyof TChannels]: IMessageTransport; };
3339
+ private readonly _base;
3340
+ private readonly _byId;
3341
+ private readonly _usedIds;
3342
+ private _disposed;
3343
+ constructor(base: IMessageTransport<MuxEnvelope, MuxEnvelope>, channels: TChannels);
2941
3344
  /**
2942
- * Override the signer for this call only. Pass `null` to skip
2943
- * signing entirely (plain unsigned JSON-RPC). Bootstrap flows that
2944
- * must talk to `identity::*` before a managed signer is available
2945
- * use `signerOverride: null` for those calls.
3345
+ * Add a logical channel after the multiplexer has started.
3346
+ *
3347
+ * Channel ids are permanently retired when disposed. This prevents a late
3348
+ * envelope for an old iframe from being delivered to a replacement iframe.
2946
3349
  */
2947
- readonly signerOverride?: SigningIdentity | null;
3350
+ addChannel(id: string): IMessageTransport;
3351
+ dispose(): void;
3352
+ private _createChannel;
3353
+ }
3354
+ //#endregion
3355
+ //#region src/connection/bareInterfaceTarget.d.ts
3356
+ /** A metadata-free foreign-protocol interface and its wire-method prefix. */
3357
+ interface BareInterfaceTarget<TDef extends InterfaceDefinition<any>> {
3358
+ readonly mode: 'bare';
3359
+ readonly interface: TDef;
3360
+ readonly prefix: string;
3361
+ }
3362
+ /**
3363
+ * Bundle an interface definition with metadata-free foreign-protocol
3364
+ * addressing for use with `connection.get(target)` or
3365
+ * `connection.register(target, handlers)`.
3366
+ */
3367
+ declare function bareInterfaceTarget<TDef extends InterfaceDefinition<any>>(iface: TDef, options?: {
3368
+ readonly prefix?: string;
3369
+ }): BareInterfaceTarget<TDef>;
3370
+ //#endregion
3371
+ //#region src/connection/interfaceTarget.d.ts
3372
+ /** A qualified LinkRPC route. An empty serviceId addresses the root interface. */
3373
+ interface QualifiedInterfaceTarget<TDef extends InterfaceDefinition<any>> {
3374
+ readonly mode: 'qualified';
3375
+ readonly interface: TDef;
3376
+ readonly serviceId: string;
3377
+ }
3378
+ /** The peer's preset form-1 route, retaining LinkRPC metadata and streaming. */
3379
+ interface DefaultInterfaceTarget<TDef extends InterfaceDefinition<any>> {
3380
+ readonly mode: 'default';
3381
+ readonly interface: TDef;
3382
+ }
3383
+ type InterfaceTarget<TDef extends InterfaceDefinition<any>> = QualifiedInterfaceTarget<TDef> | DefaultInterfaceTarget<TDef> | BareInterfaceTarget<TDef>;
3384
+ declare function interfaceTarget<TDef extends InterfaceDefinition<any>>(iface: TDef, options?: {
3385
+ readonly serviceId?: string;
3386
+ }): QualifiedInterfaceTarget<TDef>;
3387
+ declare function defaultInterfaceTarget<TDef extends InterfaceDefinition<any>>(iface: TDef): DefaultInterfaceTarget<TDef>;
3388
+ declare function isInterfaceTarget<TDef extends InterfaceDefinition<any>>(value: TDef | InterfaceTarget<TDef>): value is InterfaceTarget<TDef>;
3389
+ //#endregion
3390
+ //#region src/connection/channelConnector.d.ts
3391
+ /**
3392
+ * A raw channel that signals when it closes (and, when possible, can be torn
3393
+ * down). Both {@link openHubChannel}'s `HubChannel` and `openStdioChannel`'s
3394
+ * `StdioChannel` satisfy this shape.
3395
+ */
3396
+ type ConnectableChannel = Channel<undefined, unknown> & {
2948
3397
  /**
2949
- * Replace whatever caps the persistent cap provider would attach.
2950
- * Skips the persistent provider for this call.
3398
+ * Fires once when the channel closes. Returns a disposable to unsubscribe.
3399
+ *
3400
+ * Ordering contract: when a close causes a sending method (e.g. a request
3401
+ * or notification) to reject/throw, {@link onClose} must fire *before* that
3402
+ * rejection surfaces to the caller. This lets consumers reliably tell a
3403
+ * close-induced failure (the channel is already observably closed) apart
3404
+ * from a genuine error (the channel is still open). See
3405
+ * {@link ChannelConnector.keepConnected}.
2951
3406
  */
2952
- readonly capsOverride?: readonly SignedCapability[];
3407
+ onClose(listener: () => void): IDisposable;
3408
+ /** Tear the channel down. Optional — stdio channels have no explicit close. */
3409
+ close?(): void;
3410
+ };
3411
+ /** Handle returned by {@link ChannelConnector.keepConnected}. */
3412
+ interface KeepConnectedHandle {
2953
3413
  /**
2954
- * Reserved for the perm-denied / consent retry path. Currently a
2955
- * passthrough — sender does not act on it yet.
3414
+ * Resolves when the loop exits: the channel closed and the connector does
3415
+ * not redial, or {@link stop} (or the supplied signal) fired.
2956
3416
  */
2957
- readonly requestPermissionWhenDenied?: boolean;
3417
+ readonly done: Promise<void>;
3418
+ /** Stop redialing and close the current channel (if any). */
3419
+ stop(): void;
3420
+ }
3421
+ /** Callback run on every (re)connect. The channel is the raw, unsigned channel. */
3422
+ type OnChannelConnect<T extends ConnectableChannel> = (ctx: {
3423
+ channel: T;
3424
+ }) => void | Promise<void>;
3425
+ interface ExpBackoffOptions {
3426
+ readonly initialBackoffMs?: number;
3427
+ readonly maxBackoffMs?: number;
2958
3428
  }
2959
3429
  /**
2960
- * Persistent config for a {@link SigningSender}.
3430
+ * Drives a connect / (re)connect loop over a raw {@link ConnectableChannel}.
2961
3431
  *
2962
- * `principal` is the call identity plus its durable, extensible capability
2963
- * set. `oneShotCaps` is an optional side-policy that may stage a single-use
2964
- * capability onto the very next call without touching the principal. Both
2965
- * fields are read fresh on every call, so callers may install or swap them
2966
- * after the sender has been constructed.
3432
+ * Unlike connection-level helpers, this works at the channel layer: the
3433
+ * caller composes identity / signing on top of the channel handed to
3434
+ * {@link keepConnected} (e.g. `SigningSender.wrapChannel(channel, { principal })`).
2967
3435
  *
2968
- * A missing `principal` means "no signing / no caps" for that call, unless
2969
- * overridden via {@link SigningCallCtx}.
3436
+ * Construct via {@link ChannelConnector.once} (a single, already-open channel
3437
+ * that never redials) or {@link ChannelConnector.expBackoff} (re-open via a
3438
+ * factory with exponential backoff after each close).
2970
3439
  */
2971
- interface SigningSenderConfig {
2972
- /** Identity + persistent (extensible) capabilities. */
2973
- readonly principal?: Principal;
3440
+ declare class ChannelConnector<T extends ConnectableChannel> {
3441
+ private readonly _open;
3442
+ private readonly _redial;
3443
+ private readonly _initialBackoffMs;
3444
+ private readonly _maxBackoffMs;
3445
+ private constructor();
2974
3446
  /**
2975
- * Optional per-call capability provider. Runs at sign-time with the
2976
- * concrete method/params/nonce/timestamp and may return caps and/or
2977
- * signing overrides.
3447
+ * A connector over a single channel (or a promise of one). Never redials;
3448
+ * the loop ends when the channel closes or {@link KeepConnectedHandle.stop}
3449
+ * fires.
2978
3450
  */
2979
- readonly capProvider?: CapProvider;
3451
+ static once<T extends ConnectableChannel>(channel: T | Promise<T>): ChannelConnector<T>;
2980
3452
  /**
2981
- * Optional one-shot capability staging policy. Independent of the
2982
- * principal; drained per outbound signed call.
3453
+ * A redialing connector: `open` is called once per attempt, and the loop
3454
+ * reconnects with exponential backoff after each close (or failed open).
2983
3455
  */
2984
- readonly oneShotCaps?: OneShotCapStaging;
3456
+ static expBackoff<T extends ConnectableChannel>(open: () => Promise<T>, opts?: ExpBackoffOptions): ChannelConnector<T>;
3457
+ /**
3458
+ * Run `onConnect` on every (re)connect with the freshly opened channel.
3459
+ * The callback typically wraps the channel with signing and registers
3460
+ * handlers. Returns once the loop exits (see {@link KeepConnectedHandle}).
3461
+ */
3462
+ keepConnected(onConnect: OnChannelConnect<T>, opts?: {
3463
+ signal?: AbortSignal;
3464
+ }): KeepConnectedHandle;
3465
+ }
3466
+ //#endregion
3467
+ //#region src/connection/requestTimeout.d.ts
3468
+ declare const DEFAULT_RPC_TIMEOUT_MS = 5000;
3469
+ interface CancellableRequest<T> extends Promise<T> {
3470
+ cancel(reason?: string): void | Promise<void>;
3471
+ dispose?(reason?: string): void;
2985
3472
  }
3473
+ declare function withRpcTimeout<T>(request: CancellableRequest<T>, target: string, timeoutMs?: number): Promise<T>;
3474
+ //#endregion
3475
+ //#region src/connection/endpointUri.d.ts
2986
3476
  /**
2987
- * Side-policy for staging *one-shot* capabilities onto the next outbound
2988
- * signed call, independent of any {@link Principal}. The {@link SigningSender}
2989
- * drains the staged caps after attaching them once, so a spent cap never
2990
- * leaks into a later call.
3477
+ * A strict, RFC-3986 URI vocabulary for "where the linkrpc server lives, and
3478
+ * how to reach (or start) it". Every endpoint round-trips through
3479
+ * {@link parseEndpointUri} / {@link formatEndpointUri} and is a valid `new URL()`
3480
+ * — safe to put in env vars, logs, and config.
2991
3481
  *
2992
- * Requesting the one-shot grant (prompting the user / hub) lives next to —
2993
- * not inside — the principal: the principal owns identity and durable
2994
- * capabilities; this owns the transient per-call grant.
3482
+ * Supported schemes:
3483
+ * - `unix:/path/to.sock?token=…` → {@link SocketEndpoint}
3484
+ * - `npipe://./pipe/name?token=…` → {@link SocketEndpoint} (Windows)
3485
+ * - `ws://host:port?token=…` / `wss:…` → {@link WsEndpoint} (LinkRPC handshake)
3486
+ * - `ws-no-init://host:port?…` → {@link WsNoInitEndpoint}
3487
+ * - `cmd-stdio:?command=…` / `…?argv=…` → {@link CmdStdioEndpoint}
3488
+ * - `cmd:?command=…` / `…?argv=…` → {@link CmdEnvEndpoint}
3489
+ *
3490
+ * The command payload is `{ command: string } | { argv: string[] }`:
3491
+ * - `?command=node%20server.js` — one verbatim string, split by the OS shell.
3492
+ * - `?argv=node&argv=server.js` — repeated `argv` params, structure-preserving.
3493
+ *
3494
+ * A bare string with no scheme (legacy `LINKRPC_ENDPOINT`) is auto-detected: a
3495
+ * `ws://`/`wss://` URL stays WebSocket, anything else is a socket path.
2995
3496
  */
2996
- declare class OneShotCapStaging {
2997
- private _staged;
2998
- /** Stage caps for the next signed call. Replaces any still-pending caps. */
2999
- stage(caps: readonly SignedCapability[]): void;
3497
+ /** Verbatim command line (`{ command }`) or pre-split argv (`{ argv }`). */
3498
+ type EndpointCommand = {
3499
+ readonly command: string;
3500
+ } | {
3501
+ readonly argv: readonly string[];
3502
+ };
3503
+ /** Named pipe / unix-domain-socket the server already listens on. */
3504
+ interface SocketEndpoint {
3505
+ readonly kind: 'socket';
3506
+ readonly path: string;
3507
+ readonly token?: string;
3000
3508
  /**
3001
- * Take (and clear) the staged caps. Called by {@link SigningSender} once
3002
- * per outbound signed call.
3509
+ * Present on sockets created by `hub connect`. Local framing still uses the
3510
+ * LinkRPC transport handshake; this describes whether forwarded application
3511
+ * calls target a LinkRPC or plain JSON-RPC peer.
3003
3512
  */
3004
- take(): readonly SignedCapability[];
3513
+ readonly brokerMode?: 'linkrpc' | 'raw';
3514
+ }
3515
+ /** A running WebSocket hub; `token` rides in the `hubrpc::initialize` handshake. */
3516
+ interface WsEndpoint {
3517
+ readonly kind: 'ws';
3518
+ readonly url: string;
3519
+ readonly token?: string;
3005
3520
  }
3006
3521
  /**
3007
- * Outbound sender decorator that wraps every call in a `$hubrpc` signed
3008
- * envelope and (optionally) attaches capabilities. Stateless w.r.t. signing
3009
- * config — the {@link Principal} and {@link OneShotCapStaging} are resolved
3010
- * per-call from {@link SigningSenderConfig}, so the caller can install or
3011
- * swap them after construction by mutating that object.
3522
+ * A running plain-JSON-RPC WebSocket endpoint. Unlike {@link WsEndpoint}, CLI
3523
+ * consumers use it without the `hubrpc::initialize` handshake or LinkRPC signing.
3524
+ * Query parameters are preserved verbatim for protocols that authenticate
3525
+ * during the WebSocket upgrade (for example AHP's `tkn` parameter).
3012
3526
  */
3527
+ interface WsNoInitEndpoint {
3528
+ readonly kind: 'ws-no-init';
3529
+ /** Actual `ws://` URL passed to the WebSocket constructor. */
3530
+ readonly url: string;
3531
+ }
3532
+ /** Spawn a child and talk linkrpc over its stdin/stdout. */
3533
+ interface CmdStdioEndpoint {
3534
+ readonly kind: 'cmd-stdio';
3535
+ readonly command: EndpointCommand;
3536
+ /** Extra environment variables injected into the spawned child. */
3537
+ readonly env?: Readonly<Record<string, string>>;
3538
+ /** Working directory for the spawned child. */
3539
+ readonly cwd?: string;
3540
+ }
3013
3541
  /**
3014
- * The result of {@link SigningSender.fromChannelWithManagedPrincipal} /
3015
- * {@link SigningSender.fromTransportWithManagedPrincipal}: a signing
3016
- * {@link Channel} ready for `LinkRpcConnection`, plus the executor-managed
3017
- * {@link PrincipalWithStore} that drives it (caps, per-identity storage, nodeId).
3542
+ * Spawn a child against a freshly-started *local hub*: the parent listens on a
3543
+ * private socket, hands the child its address + token via `LINKRPC_ENDPOINT` /
3544
+ * `LINKRPC_TOKEN`, and the child dials in as a hub participant (registering its
3545
+ * services), exactly as it would against a remote hub.
3018
3546
  */
3019
- interface ManagedSigningChannel<TInCtx = undefined> {
3020
- readonly channel: Channel<TInCtx, SigningCallCtx>;
3021
- readonly principal: PrincipalWithStore;
3022
- }
3023
- declare class SigningSender<TInCtx = unknown> implements IRequestSender<SigningCallCtx> {
3024
- private readonly _inner;
3025
- private readonly _config;
3026
- /**
3027
- * Wrap an inner channel with signing. Composes via {@link Channel.withSender}
3028
- * so the resulting `Channel<TInCtx, SigningCallCtx>` plugs into
3029
- * `LinkRpcConnection`.
3030
- */
3031
- static wrapChannel<TInCtx>(inner: Channel<TInCtx, unknown>, config: SigningSenderConfig): Channel<TInCtx, SigningCallCtx>;
3032
- /**
3033
- * Bootstrap an executor-managed {@link Principal} over the **unsigned**
3034
- * `channel`, then wrap that same channel with signing driven by it.
3035
- *
3036
- * Crucially, the `identity::*` handshake that mints the managed principal
3037
- * rides the *raw* channel (`channel.sender`), so those bootstrap calls are
3038
- * themselves never signed — there is no "sign the sign call" recursion and
3039
- * no reliance on threading `signerOverride: null` through every transport
3040
- * layer. The returned signing {@link Channel} is what callers hand to
3041
- * `LinkRpcConnection`; the {@link PrincipalWithStore} is returned alongside
3042
- * for caps / per-identity storage / nodeId.
3043
- */
3044
- static fromChannelWithManagedPrincipal<TInCtx>(channel: Channel<TInCtx, unknown>, config?: Omit<SigningSenderConfig, 'principal'>): Promise<ManagedSigningChannel<TInCtx>>;
3547
+ interface CmdEnvEndpoint {
3548
+ readonly kind: 'cmd-env';
3549
+ readonly command: EndpointCommand;
3045
3550
  /**
3046
- * Convenience over {@link fromChannelWithManagedPrincipal}: build the
3047
- * unsigned {@link JsonRpcChannel} from `transport` first. The common entry
3048
- * point for app hosts / services that own a raw {@link IMessageTransport}.
3551
+ * When set, the local hub provisions (or reuses) a *persistent* managed
3552
+ * identity under this slot id, so the child's HPKE wrap/unwrap keys survive
3553
+ * across runs (sealed archives re-open).
3049
3554
  */
3050
- static fromTransportWithManagedPrincipal(transport: IMessageTransport, config?: Omit<SigningSenderConfig, 'principal'>): Promise<ManagedSigningChannel<undefined>>;
3051
- constructor(_inner: IRequestSender<unknown>, _config: SigningSenderConfig);
3052
- sendRequest(method: string, params: JsonValue | undefined, opts?: SendOpts<SigningCallCtx>): Promise<JsonValue>;
3053
- sendNotification(method: string, params: JsonValue | undefined, opts?: SendOpts<SigningCallCtx>): Promise<void>;
3054
- sendRequestWithStream(method: string, params: JsonValue | undefined, opts?: StreamSendOpts<SigningCallCtx>): RawStreamingCall;
3055
- close(): void;
3056
- private _prepareOutbound;
3057
- private _resolveSigner;
3058
- private _createSigningCoordinates;
3059
- private _resolveIntentAndCapabilities;
3060
- private _signPreparedCall;
3555
+ readonly provisionSlot?: string;
3556
+ /** Extra environment variables injected into the spawned child. */
3557
+ readonly env?: Readonly<Record<string, string>>;
3558
+ /** Working directory for the spawned child. */
3559
+ readonly cwd?: string;
3560
+ }
3561
+ type ResolvedEndpoint = SocketEndpoint | WsEndpoint | WsNoInitEndpoint | CmdStdioEndpoint | CmdEnvEndpoint;
3562
+ /**
3563
+ * Parse a strict endpoint URI into an {@link ResolvedEndpoint}. Throws on an
3564
+ * unknown scheme or a malformed command endpoint. A bare (scheme-less) string
3565
+ * is auto-detected as `ws`/`wss` URL or a socket path.
3566
+ */
3567
+ declare function parseEndpointUri(uri: string): ResolvedEndpoint;
3568
+ interface FormatEndpointOptions {
3569
+ /** Emit the real token instead of redacting it. Default: redact. */
3570
+ readonly revealToken?: boolean;
3061
3571
  }
3572
+ /**
3573
+ * Render an {@link ResolvedEndpoint} back to a canonical strict URI. The token is
3574
+ * redacted (`***`) unless `revealToken` is set, so the result is paste-safe for
3575
+ * logs. Round-trips with {@link parseEndpointUri} when `revealToken` is true.
3576
+ */
3577
+ declare function formatEndpointUri(spec: ResolvedEndpoint, options?: FormatEndpointOptions): string;
3578
+ /** True for endpoints that connect to existing, possibly-remote infrastructure. */
3579
+ declare function isHubEndpoint(spec: ResolvedEndpoint): spec is SocketEndpoint | WsEndpoint;
3062
3580
  declare namespace crypto_d_exports {
3063
3581
  export { generateKeypair, generateX25519Keypair, hpkeOpen, hpkeSeal, keypairFromSeed, sha256, sign, verify, x25519KeypairFromSeed };
3064
3582
  }
@@ -3545,8 +4063,11 @@ declare class LinkRpcConnection<TInCtx = any, TOutCtx = any> {
3545
4063
  private readonly _directoryWatchers;
3546
4064
  private readonly _directoryListeners;
3547
4065
  private _inspection;
3548
- private _trafficInspector;
4066
+ private _inspectionHost;
3549
4067
  private readonly _serviceInspectionRegistrations;
4068
+ private readonly _wireObservers;
4069
+ private readonly _closeListeners;
4070
+ private _closed;
3550
4071
  private readonly _wireChannel;
3551
4072
  private readonly _validateOutboundParams;
3552
4073
  /** Bare-method bindings, keyed by their exact wire prefix. */
@@ -3559,35 +4080,31 @@ declare class LinkRpcConnection<TInCtx = any, TOutCtx = any> {
3559
4080
  * useful for bootstrap flows like `createManagedIdentity`).
3560
4081
  */
3561
4082
  constructor(channel: Channel<TInCtx, TOutCtx> | IRequestSender<TOutCtx>, options?: LinkRpcConnectionOptions);
3562
- /** Get a typed metadata-free client for a bundled bare interface target. */
3563
- get<TDef extends InterfaceDefinition<any>>(target: BareInterfaceTarget<TDef>): InterfaceClient<TDef>;
4083
+ /** Get a typed client using a bundled qualified, default, or bare route. */
4084
+ get<TDef extends InterfaceDefinition<any>>(target: InterfaceTarget<TDef>): InterfaceClient<TDef>;
3564
4085
  /** Get a typed client for `iface`, routed to the implicit (root) service. */
3565
4086
  get<TDef extends InterfaceDefinition<any>>(iface: TDef, opts?: GetOptions<TOutCtx>): InterfaceClient<TDef>;
4087
+ private _getClient;
3566
4088
  /**
3567
4089
  * Get a typed client that emits foreign-protocol bare method names.
3568
4090
  * Unlike {@link get}, these calls carry no LinkRPC interface metadata.
3569
4091
  */
3570
4092
  getBare<TDef extends InterfaceDefinition<any>>(iface: TDef, opts?: BareGetOptions): InterfaceClient<TDef>;
4093
+ private _buildBareClient;
4094
+ /** Return request failures as values for a bundled qualified, default, or bare route. */
4095
+ getResultClient<TDef extends InterfaceDefinition<any>>(target: InterfaceTarget<TDef>): InterfaceResultClient<TDef>;
4096
+ /** Return application and generic request failures as values instead of throwing. */
4097
+ getResultClient<TDef extends InterfaceDefinition<any>>(iface: TDef, opts?: GetOptions<TOutCtx>): InterfaceResultClient<TDef>;
3571
4098
  /** Get a service-scoped handle; all interfaces obtained from it route via `serviceId` (form 3). */
3572
4099
  service(serviceId: string): ServiceHandle<TInCtx, TOutCtx>;
3573
- /** Register handlers for an interface on this connection's server side. */
3574
- register<TDef extends InterfaceDefinition<any>>(iface: TDef, handlers: InterfaceHandlers<TDef, TInCtx>, opts?: RegisterOptions): InterfaceRegistration;
4100
+ /** Register handlers, adding preset routing when passed a default or bare target. */
4101
+ register<TDef extends InterfaceDefinition<any>>(ifaceOrTarget: TDef | InterfaceTarget<TDef>, handlers: InterfaceHandlers<TDef, TInCtx>, opts?: RegisterOptions): InterfaceRegistration;
4102
+ /** Register inspection contracts without recursively enabling service inspection. */
4103
+ registerInspection<TDef extends InterfaceDefinition<any>>(iface: TDef, handlers: InterfaceHandlers<TDef, TInCtx>, opts?: RegisterOptions): InterfaceRegistration;
4104
+ /** Observe this connection without replacing another inspection scope's observer. */
4105
+ observeWireMessages(observer: WireMessageObserver): InterfaceRegistration;
4106
+ onDidClose(listener: () => void): InterfaceRegistration;
3575
4107
  private _register;
3576
- /**
3577
- * Declare the preset interface for form-1 (bare-method) dispatch. The
3578
- * interface must already be registered under the root (no serviceId).
3579
- * Surfaced via `hubrpc.defaults::get`.
3580
- */
3581
- setPreset(iface: InterfaceDefinition<any>): void;
3582
- /**
3583
- * Bind foreign-protocol bare methods to an already registered interface.
3584
- * Matching uses the longest prefix; once selected, a missing member does
3585
- * not fall through to a shorter binding.
3586
- */
3587
- bindBare(iface: InterfaceDefinition<any>, opts: {
3588
- prefix: string;
3589
- serviceId?: string;
3590
- }): InterfaceRegistration;
3591
4108
  /** Snapshot of every interface currently registered on this connection. */
3592
4109
  listRegisteredInterfaces(): readonly {
3593
4110
  readonly serviceId: string;
@@ -3640,8 +4157,6 @@ declare class LinkRpcConnection<TInCtx = any, TOutCtx = any> {
3640
4157
  private _installServiceInspection;
3641
4158
  private _removeServiceInspection;
3642
4159
  private _hasBusinessServiceRegistration;
3643
- private _endpointGraph;
3644
- private _watchTraffic;
3645
4160
  }
3646
4161
  /**
3647
4162
  * Options when obtaining a typed client for an interface.
@@ -3693,8 +4208,8 @@ interface InterfaceRegistration {
3693
4208
  /** Generated topology identity and its live root-interface registration. */
3694
4209
  interface InspectionRegistration extends InterfaceRegistration, NodeInfo {
3695
4210
  /**
3696
- * Observe this endpoint's full-payload traffic in-process. Wire observation
3697
- * remains disabled until either this or an RPC traffic watch is active.
4211
+ * Observe this endpoint's full-payload traffic in-process. Watch-control
4212
+ * flows are tracked even when no public observations are active.
3698
4213
  */
3699
4214
  observeTraffic(observer: (transit: TrafficTransitEvent) => void): InterfaceRegistration;
3700
4215
  }
@@ -3703,9 +4218,10 @@ declare class ServiceHandle<TInCtx = undefined, TOutCtx = undefined> {
3703
4218
  private readonly _connection;
3704
4219
  private readonly _serviceId;
3705
4220
  constructor(_connection: LinkRpcConnection<TInCtx, TOutCtx>, _serviceId: string);
4221
+ getResultClient<TDef extends InterfaceDefinition<any>>(iface: TDef, opts?: Partial<TOutCtx>): InterfaceResultClient<TDef>;
3706
4222
  get<TDef extends InterfaceDefinition<any>>(iface: TDef, opts?: Partial<TOutCtx>): InterfaceClient<TDef>;
3707
- register<TDef extends InterfaceDefinition<any>>(iface: TDef, handlers: InterfaceHandlers<TDef, TInCtx>, opts?: Omit<RegisterOptions, 'serviceId'>): InterfaceRegistration;
4223
+ register<TDef extends InterfaceDefinition<any>>(ifaceOrTarget: TDef | BareInterfaceTarget<TDef>, handlers: InterfaceHandlers<TDef, TInCtx>, opts?: Omit<RegisterOptions, 'serviceId'>): InterfaceRegistration;
3708
4224
  }
3709
4225
  //#endregion
3710
- export { ManagedIdentityStorageBackend as $, RequestType as $i, signedHash as $n, zTopologyLinkEndpoint as $r, Result as $t, VerifyRpcCallResult as A, JsonRpcNotification as Aa, InterfaceHandlers as Ai, Capability as An, nodeInterface as Ar, WsNoInitEndpoint as At, OneShotCapStaging as B, defineInterface as Bi, permissionPermits as Bn, TopologyTransportInfo as Br, ExpBackoffOptions as Bt, VerifyCallOptions as C, SchemaBase as Ca, EXTENSION_PREFIX as Ci, ParsedMethodName as Cn, StreamControlReason as Cr, CmdEnvEndpoint as Ct, SignRpcCallOptions as D, ErrorCode as Da, InterfaceClient as Di, Call as Dn, streamInterface as Dr, ResolvedEndpoint as Dt, verifyCall as E, UnionSchema as Ea, CheckedCallResult as Ei, Ability as En, StreamSendParams as Er, FormatEndpointOptions as Et, identityStorageInterface as F, isNotification as Fa, MemberMap as Fi, TargetPattern as Fn, TopologyLink as Fr, DEFAULT_RPC_TIMEOUT_MS as Ft, createManagedPrincipal as G, ApplicationErrorValue as Gi, LINKRPC_META_KEY as Gn, TrafficWatchResult as Gr, Channel as Gt, SigningSender as H, ApplicationErrorDescriptor as Hi, HUBRPC_META_KEY as Hn, TrafficOverflowEvent as Hr, OnChannelConnect as Ht, crypto_d_exports as I, isRequest as Ia, RemoteRpcError as Ii, capabilityPermits as In, TopologyLinkEndpoint as Ir, withRpcTimeout as It, CapBagOptions as J, DeclaredApplicationErrorOf as Ji, SignDomain as Jn, zParticipantDescriptor as Jr, IRequestSender as Jt, Principal as K, ApplicationErrorsOf as Ki, LINKRPC_SIGNATURE_KEY as Kn, topologyInterface as Kr, ChannelTransport as Kt, CapProvider as L, isResponse as La, StreamApi as Li, hasSignedCapabilityShape as Ln, TopologyNode as Lr, JsonRpcChannel as Lt, signRpcCall as M, JsonRpcResponse as Ma, InterfaceMemberRef as Mi, Pattern as Mn, ParticipantDescriptorSource as Mr, isHubEndpoint as Mt, verifyRpcCall as N, JsonRpcSuccess as Na, InterfaceMemberRefMap as Ni, Permission as Nn, RouteClaim as Nr, parseEndpointUri as Nt, SignedRpcCall as O, JsonRpcError as Oa, InterfaceDefinition as Oi, CallBind as On, NodeInfo as Or, SocketEndpoint as Ot, identityInterface as P, RequestId as Pa, LocalRpcError as Pi, SignedCapability as Pn, TopologyGraph as Pr, CancellableRequest as Pt, ManagedIdentityStorage as Q, PublicApplicationErrorOf as Qi, readSignature as Qn, zTopologyLink as Qr, RawStreamingCall as Qt, CapProviderResult as R, JsonValue as Ra, StreamCallOptions as Ri, matchParams as Rn, TopologyPort as Rr, ChannelConnector as Rt, SignParamsOptions as S, RefSchema as Sa, normalizeJsonSchema as Si, stripLinkRpcWireMeta as Sn, STREAM_METHOD as Sr, WrappingIdentity as St, signParams as T, TupleSchema as Ta, CheckedCall as Ti, parseMethodName as Tn, StreamDir as Tr, EndpointCommand as Tt, SigningSenderConfig as U, ApplicationErrorDescriptorBase as Ui, HUBRPC_SIGNATURE_KEY as Un, TrafficTransitEndpoint as Ur, BareInterfaceTarget as Ut, SigningCallCtx as V, interfaceFromSchema as Vi, Base64Sha256 as Vn, TrafficEvent as Vr, KeepConnectedHandle as Vt, PrincipalWithStore as W, ApplicationErrorOf as Wi, HUBRPC_UNSIGNED_KEY as Wn, TrafficTransitEvent as Wr, bareInterfaceTarget as Wt, InMemoryManagedIdentityStorage as X, MemberType as Xi, Signatures as Xn, zRouteClaim as Xr, IncomingStream as Xt, InMemoryManagedIdentity as Y, MemberDocs as Yi, SignatureEnvelope as Yn, zParticipantDescriptorSource as Yr, IncomingCall as Yt, ManagedIdentity as Z, NotificationType as Zi, getKeyId as Zn, zTopologyGraph as Zr, MessageWithCtx as Zt, SeededPrincipalOptions as _, LinkRpcJsonSchema as _a, componentSchemaName as _i, LinkRpcJsonRpcRequest as _n, principalForPublicKey as _r, KeypairSigningIdentity as _t, LinkRpcConnection as a, requestType as aa, zTrafficOverflowEvent as ai, IMessageTransport as an, Keypair as ar, ParamMatcherFor as at, createSeededSigningIdentity as b, ObjectSchema as ba, isAssignable as bi, LinkRpcWireParams as bn, jcsCanonicalize as br, SerializedKeypairSigningIdentity as bt, ServiceHandle as c, LinkRpcInterfaceSchema as ca, zTrafficWatchResult as ci, MessageTransportWithContext as cn, PrivateKey as cr, capBagFreshAt as ct, ServiceIdPattern as d, ArraySchema as da, SchemaToZodContext as di, connectTransports as dn, Signature as dr, issueCapability as dt, Schema as ea, zTopologyNode as ei, RpcError as en, signingDomainValue as er, createManagedIdentity as et, defaultsInterface as f, BooleanSchema as fa, createSchemaToZod as fi, traceMessageTransport as fn, X25519Keypair as fr, permits as ft, zServiceIdPattern as g, IntegerSchema as ga, assertSchemaReferences as gi, LinkRpcJsonRpcNotification as gn, keyIdForPublicKey as gr, KeypairIdentity as gt, schemasInterface as h, EnumSchema as ha, materializeJsonSchema as hi, LinkRpcJsonRpcMessage as hn, keyIdForPrincipal as hr, Identity as ht, InterfaceRegistration as i, notificationType as ia, zTrafficEvent as ii, MuxEnvelope as in, KeyId as ir, IssueCapabilityOptions as it, attachCapabilities as j, JsonRpcRequest as ja, InterfaceInfo as ji, ParamMatcher as jn, ParticipantDescriptor as jr, formatEndpointUri as jt, VerifyRpcCallOptions as k, JsonRpcMessage as ka, InterfaceDefinitionOpts as ki, CallTarget as kn, TopologyIdGenerator as kr, WsEndpoint as kt, RootPrincipalReq as l, MemberAnnotations as la, GenerateInterfaceOptions as li, MessageWithContext as ln, PublicKey as lr, capabilityFreshAt as lt, directoryWatchNever as m, DiscriminatorSchema as ma, MaterializedJsonSchema as mi, CallMeta as mn, bytesToBase64Url as mr, signCapability as mt, GetOptions as n, applicationError as na, zTopologyTransportEndpoint as ni, StreamSendOpts as nn, withSignature as nr, registerLazyIdentityOnOverlay as nt, LinkRpcConnectionOptions as o, zodToSvcJsonSchema as oa, zTrafficTransitEndpoint as oi, MessageTransportDirection as on, PRINCIPAL_PREFIX as or, ParamMatchers as ot, directoryInterface as p, ConstSchema as pa, schemaToZod as pi, IDisposable as pn, base64UrlToBytes as pr, prefix as pt, CapBag as q, CreatedApplicationErrorValue as qi, LINKRPC_UNSIGNED_KEY as qn, trafficInterface as qr, IRequestHandler as qt, InspectionRegistration as r, isApplicationErrorValue as ra, zTopologyTransportInfo as ri, MultiplexedTransport as rn, KEY_ID_PREFIX as rr, AcceptedRootIssuer as rt, RegisterOptions as s, ErrorSchema as sa, zTrafficTransitEvent as si, MessageTransportTrace as sn, PrincipalId as sr, PermitResult as st, BareGetOptions as t, ZodToSvcJsonSchemaOptions as ta, zTopologyPort as ti, SendOpts as tn, signingInput as tr, registerIdentityOnOverlay as tt, RootPrincipalSet as u, MethodSchema as ua, generateTsInterface as ui, TransportPair as un, ResolveSigningKeyArgs as ur, invoke as ut, createMemoryPrincipal as v, NullSchema as va, componentSchemaRef as vi, LinkRpcUnsigned as vn, publicKeyForKeyId as vr, PublicSigningIdentity as vt, VerifyResult as w, StringSchema as wa, computeInterfaceHash as wi, methodNameToTarget as wn, StreamControlType as wr, CmdStdioEndpoint as wt, JsonObject as x, OneOfSchema as xa, matchesJsonSchema as xi, requireObjectParams as xn, jcsCanonicalizeBytes as xr, SigningIdentity as xt, createSeededMemoryPrincipal as y, NumberSchema as ya, Components as yi, LinkRpcWireMeta as yn, resolveSigningKey as yr, PublicWrappingIdentity as yt, ManagedSigningChannel as z, StreamingCall as zi, permissionMatchesTarget as zn, TopologyTransportEndpoint as zr, ConnectableChannel as zt };
3711
- //# sourceMappingURL=linkRpcConnection-BadD37ok.d.ts.map
4226
+ export { ExpBackoffOptions as $, ZodToSvcJsonSchemaOptions as $a, createSchemaToZod as $i, InMemoryManagedIdentityStorage as $n, readSignature as $r, zParticipantDescriptorSource as $t, VerifyRpcCallResult as A, StreamingCall as Aa, RpcError as Ai, WalkHubResult as An, UnionSchema as Ao, CallTarget as Ar, StreamSendParams as At, FormatEndpointOptions as B, ApplicationErrorsOf as Ba, traceMessageTransport as Bi, CapProvider as Bn, isRequest as Bo, permissionMatchesTarget as Br, TopologyLinkEndpoint as Bt, VerifyCallOptions as C, InterfaceResultClient as Ca, IRequestHandler as Ci, HubDirectoryNodeState as Cn, NumberSchema as Co, PublicWrappingIdentity as Cr, parseMethodName as Ct, SignRpcCallOptions as D, RpcCallError as Da, MessageWithCtx as Di, ReflectionChannel as Dn, SchemaBase as Do, Ability as Dr, StreamControlReason as Dt, verifyCall as E, RemoteRpcError as Ea, IncomingStream as Ei, ListOptions as En, RefSchema as Eo, WrappingIdentity as Er, STREAM_METHOD as Et, identityStorageInterface as F, RpcValidationIssue as Fa, MessageTransportTrace as Fi, normalizeServiceIdScopes as Fn, JsonRpcRequest as Fo, SignedCapability as Fr, ParticipantDescriptor as Ft, formatEndpointUri as G, MemberType as Ga, StaticHubSchema as Gi, SigningSender as Gn, HUBRPC_UNSIGNED_KEY as Gr, TrafficEvent as Gt, SocketEndpoint as H, CreatedRpcErrorValue as Ha, GenerateContractOptions as Hi, ManagedSigningChannel as Hn, JsonValue as Ho, Base64Sha256 as Hr, TopologyPort as Ht, crypto_d_exports as I, ApplicationErrorDescriptor as Ia, MessageTransportWithContext as Ii, serviceIdMatchesPattern as In, JsonRpcResponse as Io, TargetPattern as Ir, ParticipantDescriptorSource as It, CancellableRequest as J, RequestType as Ja, StaticService as Ji, createManagedPrincipal as Jn, LINKRPC_UNSIGNED_KEY as Jr, TrafficTransitEvent as Jt, isHubEndpoint as K, NotificationType as Ka, StaticHubSchemaDocument as Ki, SigningSenderConfig as Kn, LINKRPC_META_KEY as Kr, TrafficOverflowEvent as Kt, CmdEnvEndpoint as L, ApplicationErrorDescriptorBase as La, MessageWithContext as Li, serviceIdMatchesScopes as Ln, JsonRpcSuccess as Lo, capabilityPermits as Lr, RouteClaim as Lt, signRpcCall as M, defineInterface as Ma, StreamSendOpts as Mi, fetchSchema as Mn, JsonRpcError as Mo, ParamMatcher as Mr, NodeInfo as Mt, verifyRpcCall as N, interfaceFromSchema as Na, IMessageTransport as Ni, findMethodInSchema as Nn, JsonRpcMessage as No, Pattern as Nr, TopologyIdGenerator as Nt, SignedRpcCall as O, StreamApi as Oa, RawStreamingCall as Oi, ServiceListing as On, StringSchema as Oo, Call as Or, StreamControlType as Ot, identityInterface as P, NonCompliantServerError as Pa, MessageTransportDirection as Pi, intersectServiceIdScopes as Pn, JsonRpcNotification as Po, Permission as Pr, nodeInterface as Pt, ConnectableChannel as Q, Schema as Qa, SchemaToZodContext as Qi, InMemoryManagedIdentity as Qn, getKeyId as Qr, zParticipantDescriptor as Qt, CmdStdioEndpoint as R, ApplicationErrorOf as Ra, TransportPair as Ri, walkHub as Rn, RequestId as Ro, hasSignedCapabilityShape as Rr, TopologyGraph as Rt, SignParamsOptions as S, InterfaceMemberRefMap as Sa, ChannelTransport as Si, HubDirectoryNodeReport as Sn, NullSchema as So, PublicSigningIdentity as Sr, methodNameToTarget as St, signParams as T, MemberMap as Ta, IncomingCall as Ti, InaccessibleDirectory as Tn, OneOfSchema as To, SigningIdentity as Tr, jcsCanonicalizeBytes as Tt, WsEndpoint as U, DeclaredApplicationErrorOf as Ua, generateTsContract as Ui, OneShotCapStaging as Un, HUBRPC_META_KEY as Ur, TopologyTransportEndpoint as Ut, ResolvedEndpoint as V, CreatedApplicationErrorValue as Va, IDisposable as Vi, CapProviderResult as Vn, isResponse as Vo, permissionPermits as Vr, TopologyNode as Vt, WsNoInitEndpoint as W, MemberDocs as Wa, InterfaceRef as Wi, SigningCallCtx as Wn, HUBRPC_SIGNATURE_KEY as Wr, TopologyTransportInfo as Wt, withRpcTimeout as X, RpcErrorDescriptor as Xa, GenerateInterfaceOptions as Xi, CapBag as Xn, SignatureEnvelope as Xr, topologyInterface as Xt, DEFAULT_RPC_TIMEOUT_MS as Y, RpcErrorBody as Ya, parseStaticHubSchema as Yi, Principal as Yn, SignDomain as Yr, TrafficWatchResult as Yt, ChannelConnector as Z, RpcErrorValue as Za, generateTsInterface as Zi, CapBagOptions as Zn, Signatures as Zr, trafficInterface as Zt, SeededPrincipalOptions as _, InterfaceDefinition as _a, keyIdForPublicKey as _i, HubDirectoryChange as _n, ConstSchema as _o, prefix as _r, LinkRpcWireMeta as _t, LinkRpcConnection as a, componentSchemaRef as aa, KeyId as ai, zTopologyPort as an, zodToSvcJsonSchema as ao, registerLazyIdentityOnOverlay as ar, defaultInterfaceTarget as at, createSeededSigningIdentity as b, InterfaceInfo as ba, resolveSigningKey as bi, HubDirectoryGraphSnapshot as bn, IntegerSchema as bo, KeypairIdentity as br, stripLinkRpcWireMeta as bt, ServiceHandle as c, matchesJsonSchema as ca, PrincipalId as ci, zTrafficEvent as cn, isRpcFailure as co, IssueCapabilityOptions as cr, BareInterfaceTarget as ct, ServiceIdPattern as d, EXTENSION_PREFIX as da, ResolveSigningKeyArgs as di, zTrafficTransitEvent as dn, LinkRpcInterfaceSchema as do, PermitResult as dr, MuxEnvelope as dt, schemaToZod as ea, signedHash as ei, zRouteClaim as en, applicationError as eo, ManagedIdentity as er, KeepConnectedHandle as et, defaultsInterface as f, computeInterfaceHash as fa, Signature as fi, zTrafficWatchResult as fn, MemberAnnotations as fo, capBagFreshAt as fr, CallMeta as ft, zServiceIdPattern as g, InterfaceClient as ga, keyIdForPrincipal as gi, DiscoveredListing as gn, BooleanSchema as go, permits as gr, LinkRpcUnsigned as gt, schemasInterface as h, GenericRpcError as ha, bytesToBase64Url as hi, DEFAULT_WALK_DEPTH as hn, ArraySchema as ho, issueCapability as hr, LinkRpcJsonRpcRequest as ht, InterfaceRegistration as i, componentSchemaName as ia, KEY_ID_PREFIX as ii, zTopologyNode as in, rpcError as io, registerIdentityOnOverlay as ir, QualifiedInterfaceTarget as it, attachCapabilities as j, TransportRpcError as ja, SendOpts as ji, fetchDirectory as jn, ErrorCode as jo, Capability as jr, streamInterface as jt, VerifyRpcCallOptions as k, StreamCallOptions as ka, Result as ki, WalkHubOptions as kn, TupleSchema as ko, CallBind as kr, StreamDir as kt, RootPrincipalReq as l, validateJsonSchema as la, PrivateKey as li, zTrafficOverflowEvent as ln, ErrorSchema as lo, ParamMatcherFor as lr, bareInterfaceTarget as lt, directoryWatchNever as m, CheckedCallResult as ma, base64UrlToBytes as mi, exportStaticHubSchema as mn, RawErrorSchema as mo, invoke as mr, LinkRpcJsonRpcNotification as mt, GetOptions as n, materializeJsonSchema as na, signingInput as ni, zTopologyLink as nn, notificationType as no, ManagedIdentityStorageBackend as nr, DefaultInterfaceTarget as nt, LinkRpcConnectionOptions as o, Components as oa, Keypair as oi, zTopologyTransportEndpoint as on, Result$1 as oo, JsonRpcChannel as or, interfaceTarget as ot, directoryInterface as p, CheckedCall as pa, X25519Keypair as pi, ExportStaticHubSchemaOptions as pn, MethodSchema as po, capabilityFreshAt as pr, LinkRpcJsonRpcMessage as pt, parseEndpointUri as q, PublicApplicationErrorOf as qa, StaticInterfaceReference as qi, PrincipalWithStore as qn, LINKRPC_SIGNATURE_KEY as qr, TrafficTransitEndpoint as qt, InspectionRegistration as r, assertSchemaReferences as ra, withSignature as ri, zTopologyLinkEndpoint as rn, requestType as ro, createManagedIdentity as rr, InterfaceTarget as rt, RegisterOptions as s, isAssignable as sa, PRINCIPAL_PREFIX as si, zTopologyTransportInfo as sn, RpcFailure as so, AcceptedRootIssuer as sr, isInterfaceTarget as st, BareGetOptions as t, MaterializedJsonSchema as ta, signingDomainValue as ti, zTopologyGraph as tn, isApplicationErrorValue as to, ManagedIdentityStorage as tr, OnChannelConnect as tt, RootPrincipalSet as u, normalizeJsonSchema as ua, PublicKey as ui, zTrafficTransitEndpoint as un, LegacyErrorSchema as uo, ParamMatchers as ur, MultiplexedTransport as ut, createMemoryPrincipal as v, InterfaceDefinitionOpts as va, principalForPublicKey as vi, HubDirectoryExplorer as vn, DiscriminatorSchema as vo, signCapability as vr, LinkRpcWireParams as vt, VerifyResult as w, LocalRpcError as wa, IRequestSender as wi, HubDirectoryParentReport as wn, ObjectSchema as wo, SerializedKeypairSigningIdentity as wr, jcsCanonicalize as wt, JsonObject as x, InterfaceMemberRef as xa, Channel as xi, HubDirectoryGraphTarget as xn, LinkRpcJsonSchema as xo, KeypairSigningIdentity as xr, ParsedMethodName as xt, createSeededMemoryPrincipal as y, InterfaceHandlers as ya, publicKeyForKeyId as yi, HubDirectoryGraphEvent as yn, EnumSchema as yo, Identity as yr, requireObjectParams as yt, EndpointCommand as z, ApplicationErrorValue as za, connectTransports as zi, walkHubDetailed as zn, isNotification as zo, matchParams as zr, TopologyLink as zt };
4227
+ //# sourceMappingURL=linkRpcConnection-Bbq20hQG.d.ts.map