@hediet/linkrpc 0.0.2 → 0.0.3

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