@ckb-ccc/libp2p 0.2.1 → 0.3.1-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @ckb-ccc/libp2p
2
2
 
3
+ ## 0.3.1-next.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies []:
8
+ - @ckb-ccc/core@2.0.0-next.1
9
+
10
+ ## 0.3.0
11
+
12
+ ### Minor Changes
13
+
14
+ - [#547](https://github.com/ckb-devrel/ccc/pull/547) [`7d5781b`](https://github.com/ckb-devrel/ccc/commit/7d5781be9dc48dc0439d173f6aa45f2281c3ac8c) Thanks [@Hanssen0](https://github.com/Hanssen0)! - Add per-request cancellation and timeout options to JSON-RPC transports.
15
+ WebSocket and libp2p transports now cancel individual operations without
16
+ interrupting unrelated requests, and JSON-RPC errors are exposed as
17
+ `JsonRpcError` instances.
18
+
19
+ - [#547](https://github.com/ckb-devrel/ccc/pull/547) [`8b0a8b5`](https://github.com/ckb-devrel/ccc/commit/8b0a8b50dff0b5ddd8b21c15d5ce1cb8ac4842f0) Thanks [@Hanssen0](https://github.com/Hanssen0)! - Add a relay connection controller that selects an available relay and keeps it
20
+ connected with availability-aware retries. Khie now restores relay and paired
21
+ peer connectivity after network changes.
22
+
23
+ ### Patch Changes
24
+
25
+ - Updated dependencies [[`3ef932a`](https://github.com/ckb-devrel/ccc/commit/3ef932a471f72704502a708241a960ee44d00377), [`0d5cd4b`](https://github.com/ckb-devrel/ccc/commit/0d5cd4bc7113686675dfa5c94a1abacfb9b3e073), [`26f9c4d`](https://github.com/ckb-devrel/ccc/commit/26f9c4d0d77d35bfba0d74483458a24a2077fac9), [`7d5781b`](https://github.com/ckb-devrel/ccc/commit/7d5781be9dc48dc0439d173f6aa45f2281c3ac8c), [`7680821`](https://github.com/ckb-devrel/ccc/commit/7680821e0c113a790f00e0fe53e0d69f92588ce4), [`72309f6`](https://github.com/ckb-devrel/ccc/commit/72309f666471720d4e808c39916a630aa21891f7), [`4cddf9b`](https://github.com/ckb-devrel/ccc/commit/4cddf9bfad50036672dfa3d29c89baea6af1e237), [`7d98b67`](https://github.com/ckb-devrel/ccc/commit/7d98b67137927b39577fa5429f1fa18a7242f88b)]:
26
+ - @ckb-ccc/core@1.22.0
27
+
3
28
  ## 0.2.1
4
29
 
5
30
  ### Patch Changes
package/dist/barrel.d.mts CHANGED
@@ -1,29 +1,33 @@
1
1
  import { ccc } from "@ckb-ccc/core";
2
2
  import { Multiaddr } from "@multiformats/multiaddr";
3
3
  import { AbortOptions, Connection, Libp2p, PeerId } from "@libp2p/interface";
4
- import { AddressManager, ConnectionManager, Registrar } from "@libp2p/interface-internal";
4
+ import { ConnectionManager, Registrar } from "@libp2p/interface-internal";
5
5
  //#region src/dial.d.ts
6
- declare function dialKnownAddresses(node: Libp2p, peerId: PeerId, signal?: AbortSignal): Promise<import("@libp2p/interface").Connection | undefined>;
6
+ export declare function dialKnownAddresses(node: Libp2p, peerId: PeerId, signal?: AbortSignal): Promise<import("@libp2p/interface").Connection | undefined>;
7
7
  //#endregion
8
8
  //#region src/jsonRpcService.d.ts
9
- type JsonRpcServiceComponents = {
9
+ export type JsonRpcServiceComponents = {
10
10
  registrar: Registrar;
11
11
  };
12
- type JsonRpcServiceConfig = {
12
+ export type JsonRpcServiceConfig = {
13
13
  protocol: string;
14
14
  maxMessageLength?: number;
15
+ timeout?: number;
15
16
  };
16
- type JsonRpcRequest = {
17
+ export type JsonRpcRequest = {
17
18
  connection: Connection;
18
19
  peerId: PeerId;
19
20
  payload: ccc.JsonRpcPayload;
21
+ /** Aborts if the service times out or the request stream closes. */
22
+ signal: AbortSignal;
20
23
  };
21
- type JsonRpcRequestHandler<Components extends JsonRpcServiceComponents = JsonRpcServiceComponents> = (this: JsonRpcService<Components>, request: JsonRpcRequest) => unknown;
22
- declare abstract class JsonRpcService<Components extends JsonRpcServiceComponents = JsonRpcServiceComponents> {
24
+ export type JsonRpcRequestHandler<Components extends JsonRpcServiceComponents = JsonRpcServiceComponents> = (this: JsonRpcService<Components>, request: JsonRpcRequest) => unknown;
25
+ export declare abstract class JsonRpcService<Components extends JsonRpcServiceComponents = JsonRpcServiceComponents> {
23
26
  readonly components: Components;
24
27
  readonly config: JsonRpcServiceConfig;
25
28
  private readonly errorListeners;
26
29
  readonly maxMessageLength: number;
30
+ readonly timeout: number;
27
31
  constructor(components: Components, config: JsonRpcServiceConfig);
28
32
  protected abstract handleRequest(request: JsonRpcRequest): unknown;
29
33
  onError(listener: (error: Error) => void): () => boolean;
@@ -32,46 +36,45 @@ declare abstract class JsonRpcService<Components extends JsonRpcServiceComponent
32
36
  private handleProtocol;
33
37
  private handleError;
34
38
  }
35
- declare function jsonRpcService<Components extends JsonRpcServiceComponents = JsonRpcServiceComponents>(config: JsonRpcServiceConfig, handler: JsonRpcRequestHandler<Components>): (components: Components) => JsonRpcService<Components>;
39
+ export declare function jsonRpcService<Components extends JsonRpcServiceComponents = JsonRpcServiceComponents>(config: JsonRpcServiceConfig, handler: JsonRpcRequestHandler<Components>): (components: Components) => JsonRpcService<Components>;
36
40
  //#endregion
37
41
  //#region src/jsonRpcTransport.d.ts
38
- type JsonRpcTransportLibp2pConfig = {
42
+ export type JsonRpcTransportLibp2pConfig = {
39
43
  protocol: string;
40
44
  maxMessageLength?: number;
41
45
  timeout?: number;
42
46
  signal?: AbortSignal;
43
47
  onResponse?: (response: ccc.JsonRpcResponse) => void;
44
48
  };
45
- declare class JsonRpcTransportLibp2p implements ccc.JsonRpcTransport {
49
+ export declare class JsonRpcTransportLibp2p implements ccc.JsonRpcTransport {
46
50
  private readonly node;
47
51
  readonly peerId: PeerId;
48
52
  private readonly config;
49
53
  private readonly maxMessageLength;
50
54
  private readonly timeout;
51
55
  constructor(node: Libp2p, peerId: PeerId, config: JsonRpcTransportLibp2pConfig);
52
- request(payload: ccc.JsonRpcPayload): Promise<ccc.JsonRpcResponse>;
56
+ request(payload: ccc.JsonRpcPayload, options?: ccc.JsonRpcTransportRequestOptions): Promise<ccc.JsonRpcResponse>;
53
57
  private openStream;
54
58
  private connections;
55
59
  }
56
60
  //#endregion
57
61
  //#region src/pairingService.d.ts
58
- type PairingServiceComponents = {
59
- addressManager?: Pick<AddressManager, "getAddresses">;
62
+ export type PairingServiceComponents = {
60
63
  connectionManager: ConnectionManager;
61
64
  registrar: Registrar;
62
65
  };
63
- type PairingServiceConfig = {
66
+ export type PairingServiceConfig = {
64
67
  /** Optional self-reported label shared with the paired peer. */
65
68
  name?: string;
66
69
  protocol: string;
67
70
  pairedPeerTimeoutMs: number;
68
71
  };
69
- type PairingTarget = {
72
+ export type PairingTarget = {
70
73
  addresses: Multiaddr[];
71
74
  secret: string;
72
75
  };
73
- type PairingGuard<Components extends PairingServiceComponents = PairingServiceComponents> = (this: PairingService<Components>, peerId: PeerId) => boolean;
74
- declare abstract class PairingService<Components extends PairingServiceComponents = PairingServiceComponents> {
76
+ export type PairingGuard<Components extends PairingServiceComponents = PairingServiceComponents> = (this: PairingService<Components>, peerId: PeerId) => boolean;
77
+ export declare abstract class PairingService<Components extends PairingServiceComponents = PairingServiceComponents> {
75
78
  readonly components: Components;
76
79
  readonly config: PairingServiceConfig;
77
80
  private currentSecret;
@@ -97,30 +100,48 @@ declare abstract class PairingService<Components extends PairingServiceComponent
97
100
  private handleProtocol;
98
101
  private addPairedPeer;
99
102
  private notifyPairedPeer;
100
- private addresses;
101
- private openFallbackConnection;
102
103
  private rotateSecret;
103
104
  private removePairedPeer;
104
105
  private createPeerTimeout;
105
106
  private openStream;
106
107
  private handleError;
107
108
  }
108
- declare function pairingService<Components extends PairingServiceComponents = PairingServiceComponents>(config: PairingServiceConfig, canPair: PairingGuard<Components>): (components: Components) => PairingService<Components>;
109
+ export declare function pairingService<Components extends PairingServiceComponents = PairingServiceComponents>(config: PairingServiceConfig, canPair: PairingGuard<Components>): (components: Components) => PairingService<Components>;
109
110
  //#endregion
110
111
  //#region src/pairingEndpoint.d.ts
111
- declare class PairingEndpointError extends Error {
112
+ export declare class PairingEndpointError extends Error {
112
113
  constructor(message: string, options?: ErrorOptions);
113
114
  }
114
- declare class PairingEndpointRoleError extends PairingEndpointError {
115
+ export declare class PairingEndpointRoleError extends PairingEndpointError {
115
116
  readonly expectedRole: string;
116
117
  readonly actualRole: string | undefined;
117
118
  constructor(expectedRole: string, actualRole: string | undefined);
118
119
  }
119
- declare function encodePairingEndpoint(endpointUrl: string, addresses: readonly Multiaddr[], secret: string, role?: string): Promise<string>;
120
- declare function decodePairingEndpoint(endpoint: string, expectedRole?: string): Promise<PairingTarget>;
120
+ export declare function encodePairingEndpoint(endpointUrl: string, addresses: readonly Multiaddr[], secret: string, role?: string): Promise<string>;
121
+ export declare function decodePairingEndpoint(endpoint: string, expectedRole?: string): Promise<PairingTarget>;
122
+ //#endregion
123
+ //#region src/relayConnection.d.ts
124
+ export type RelayConnectionControllerOptions = {
125
+ onConnectionChange?: (connection?: Connection) => void;
126
+ };
127
+ /** Maintains a connection to a relay until stopped. */
128
+ export declare class RelayConnectionController {
129
+ private readonly node;
130
+ private readonly options;
131
+ private readonly controller;
132
+ private readonly addresses;
133
+ private selectedAddress?;
134
+ private connection?;
135
+ private connecting?;
136
+ constructor(node: Libp2p, addresses: readonly string[], options?: RelayConnectionControllerOptions);
137
+ connect(): Promise<Connection>;
138
+ stop(): Promise<void>;
139
+ private dialRelay;
140
+ private readonly handleConnectionClose;
141
+ }
121
142
  declare namespace barrel_d_exports {
122
- export { JsonRpcRequest, JsonRpcRequestHandler, JsonRpcService, JsonRpcServiceComponents, JsonRpcServiceConfig, JsonRpcTransportLibp2p, JsonRpcTransportLibp2pConfig, PairingEndpointError, PairingEndpointRoleError, PairingGuard, PairingService, PairingServiceComponents, PairingServiceConfig, PairingTarget, decodePairingEndpoint, dialKnownAddresses, encodePairingEndpoint, jsonRpcService, pairingService };
143
+ export { JsonRpcRequest, JsonRpcRequestHandler, JsonRpcService, JsonRpcServiceComponents, JsonRpcServiceConfig, JsonRpcTransportLibp2p, JsonRpcTransportLibp2pConfig, PairingEndpointError, PairingEndpointRoleError, PairingGuard, PairingService, PairingServiceComponents, PairingServiceConfig, PairingTarget, RelayConnectionController, RelayConnectionControllerOptions, decodePairingEndpoint, dialKnownAddresses, encodePairingEndpoint, jsonRpcService, pairingService };
123
144
  }
124
145
  //#endregion
125
- export { JsonRpcRequest, JsonRpcRequestHandler, JsonRpcService, JsonRpcServiceComponents, JsonRpcServiceConfig, JsonRpcTransportLibp2p, JsonRpcTransportLibp2pConfig, PairingEndpointError, PairingEndpointRoleError, PairingGuard, PairingService, PairingServiceComponents, PairingServiceConfig, PairingTarget, decodePairingEndpoint, dialKnownAddresses, encodePairingEndpoint, jsonRpcService, pairingService, barrel_d_exports as t };
146
+ export { barrel_d_exports as t };
126
147
  //# sourceMappingURL=barrel.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"barrel.d.mts","names":[],"sources":["../src/dial.ts","../src/jsonRpcService.ts","../src/jsonRpcTransport.ts","../src/pairingService.ts","../src/pairingEndpoint.ts","../src/barrel.ts"],"mappings":";;;;;iBAGsB,mBACpB,MAAM,QACN,QAAQ,QACR,SAAS,cAAW,oCAAA;;;KCCV;EACV,WAAW;;KAGD;EACV;EACA;;KAGU;EACV,YAAY;EACZ,QAAQ;EACR,SAAS,IAAI;;KAGH,sBACV,mBAAmB,2BAA2B,6BAC3C,MAAM,eAAe,aAAa,SAAS;uBAE1B,eACpB,mBAAmB,2BAA2B;WAMnC,YAAY;WACZ,QAAQ;mBALF;WACR;EAGE,YAAA,YAAY,YACZ,QAAQ;qBAaA,cAAc,SAAS;EAE1C,QAAQ,WAAW,OAAO;EAKpB,SAAK;EAQL,QAAI;UAII;UA8CN;;iBA4CM,eACd,mBAAmB,2BAA2B,0BAE9C,QAAQ,sBACR,SAAS,sBAAsB,eAC7B,YAAY,eAAe,eAAe;;;KCzJlC;EACV;EACA;EACA;EACA,SAAS;EACT,cAAc,UAAU,IAAI;;cAGjB,kCAAkC,IAAI;mBAK9B;WACR,QAAQ;mBACA;mBANF;mBACA;EAGE,YAAA,MAAM,QACd,QAAQ,QACA,QAAQ;EAoBrB,QAAQ,SAAS,IAAI,iBAAiB,QAAQ,IAAI;UAmC1C;UAsBN;;;;KClFE;EACV,iBAAiB,KAAK;EACtB,mBAAmB;EACnB,WAAW;;KAGD;;EAEV;EACA;EACA;;KAGU;EACV,WAAW;EACX;;KAGU,aACV,mBAAmB,2BAA2B,6BAC3C,MAAM,eAAe,aAAa,QAAQ;uBASzB,eACpB,mBAAmB,2BAA2B;WAenC,YAAY;WACZ,QAAQ;UAdX;mBACS;mBACA;mBAGA;mBACA;mBACA;EAMN,YAAA,YAAY,YACZ,QAAQ;qBAOA,QAAQ,QAAQ;;MAG/B;EAIJ,QAAQ,WAAW,OAAO;EAK1B,SAAS,WAAW,QAAQ,QAAQ;EAKpC,WAAW,WAAW,QAAQ;EAK9B,gBAAgB,WAAW;EAKrB,SAAK;EAQL,QAAI;EAOV,SAAS,QAAQ;EAIjB,QAAQ,QAAQ;EAWV,KACJ,QAAQ,eACR,UAAS,eACR,QAAQ;EAyCL,OAAO,QAAQ,SAAM;UAyBb;UAwDN;UAWA;UAIA;UAIM;UAYN;UAOA;UAgBA;UAkBM;UAsBN;;iBASM,eACd,mBAAmB,2BAA2B,0BAE9C,QAAQ,sBACR,SAAS,aAAa,eACpB,YAAY,eAAe,eAAe;;;cChWjC,6BAA6B;EAC5B,YAAA,iBAAiB,UAAU;;cAM5B,iCAAiC;WAEjC;WACA;EADA,YAAA,sBACA;;iBASS,sBACpB,qBACA,oBAAoB,aACpB,gBACA,gBAAa;iBAuCO,sBACpB,kBACA,wBACC,QAAQ"}
1
+ {"version":3,"file":"barrel.d.mts","names":[],"sources":["../src/dial.ts","../src/jsonRpcService.ts","../src/jsonRpcTransport.ts","../src/pairingService.ts","../src/pairingEndpoint.ts","../src/relayConnection.ts","../src/barrel.ts"],"mappings":";;;;;wBAGsB,mBACpB,MAAM,QACN,QAAQ,QACR,SAAS,cAAW,oCAAA;;;YCEV;EACV,WAAW;;YAGD;EACV;EACA;EACA;;YAGU;EACV,YAAY;EACZ,QAAQ;EACR,SAAS,IAAI;;EAEb,QAAQ;;YAGE,sBACV,mBAAmB,2BAA2B,6BAC3C,MAAM,eAAe,aAAa,SAAS;8BAE1B,eACpB,mBAAmB,2BAA2B;WAOnC,YAAY;WACZ,QAAQ;mBANF;WACR;WACA;EAGE,YAAA,YAAY,YACZ,QAAQ;qBAoBA,cAAc,SAAS;EAE1C,QAAQ,WAAW,OAAO;EAKpB,SAAK;EAQL,QAAI;UAII;UAiFN;;wBAgDM,eACd,mBAAmB,2BAA2B,0BAE9C,QAAQ,sBACR,SAAS,sBAAsB,eAC7B,YAAY,eAAe,eAAe;;;YC5MlC;EACV;EACA;EACA;EACA,SAAS;EACT,cAAc,UAAU,IAAI;;qBAGjB,kCAAkC,IAAI;mBAK9B;WACR,QAAQ;mBACA;mBANF;mBACA;EAGE,YAAA,MAAM,QACd,QAAQ,QACA,QAAQ;EAoBrB,QACJ,SAAS,IAAI,gBACb,UAAU,IAAI,iCACb,QAAQ,IAAI;UAoCD;UAsBN;;;;YC1FE;EACV,mBAAmB;EACnB,WAAW;;YAGD;;EAEV;EACA;EACA;;YAGU;EACV,WAAW;EACX;;YAGU,aACV,mBAAmB,2BAA2B,6BAC3C,MAAM,eAAe,aAAa,QAAQ;8BAQzB,eACpB,mBAAmB,2BAA2B;WAenC,YAAY;WACZ,QAAQ;UAdX;mBACS;mBACA;mBAGA;mBACA;mBACA;EAMN,YAAA,YAAY,YACZ,QAAQ;qBAOA,QAAQ,QAAQ;;MAG/B;EAIJ,QAAQ,WAAW,OAAO;EAK1B,SAAS,WAAW,QAAQ,QAAQ;EAKpC,WAAW,WAAW,QAAQ;EAK9B,gBAAgB,WAAW;EAKrB,SAAK;EAQL,QAAI;EAOV,SAAS,QAAQ;EAIjB,QAAQ,QAAQ;EAWV,KACJ,QAAQ,eACR,UAAS,eACR,QAAQ;EAyCL,OAAO,QAAQ,SAAM;UAyBb;UAkDN;UAWA;UAIA;UAOA;UAgBA;UAkBM;UAsBN;;wBASM,eACd,mBAAmB,2BAA2B,0BAE9C,QAAQ,sBACR,SAAS,aAAa,eACpB,YAAY,eAAe,eAAe;;;qBCpUjC,6BAA6B;EAC5B,YAAA,iBAAiB,UAAU;;qBAM5B,iCAAiC;WAEjC;WACA;EADA,YAAA,sBACA;;wBASS,sBACpB,qBACA,oBAAoB,aACpB,gBACA,gBAAa;wBAuCO,sBACpB,kBACA,wBACC,QAAQ;;;YClEC;EACV,sBAAsB,aAAa;;;qBAIxB;mBAQQ;mBAEA;mBATF;mBACA;UACT;UACA;UACA;EAGW,YAAA,MAAM,QACvB,8BACiB,UAAS;EAW5B,WAAW,QAAQ;EA8Bb,QAAI;UAYI;mBAkCG"}
package/dist/barrel.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import{t as e}from"./rolldown-runtime-DK3Fl9T5.mjs";import{JsonRpcError as t,ccc as n}from"@ckb-ccc/core";import{lpStream as r}from"@libp2p/utils";import{CODE_P2P as i,multiaddr as a}from"@multiformats/multiaddr";import*as o from"it-length-prefixed";async function s(e,t,n){let r=(await e.peerStore.get(t)).addresses.flatMap(({multiaddr:e})=>{let n=c(e,t);return n?[n]:[]});if(r.length!==0)return n?e.dial(r,{signal:n}):e.dial(r)}function c(e,t){let n=e.getComponents().at(-1);return n?.name===`p2p`?n.value===t.toString()?e:void 0:e.encapsulate(`/p2p/${t.toString()}`)}var l=class{constructor(e,t){this.components=e,this.config=t,this.errorListeners=new Set;let n=t.maxMessageLength??1048576;if(!Number.isSafeInteger(n)||n<=0)throw Error(`Maximum JSON-RPC message length must be a positive integer`);this.maxMessageLength=n}onError(e){return this.errorListeners.add(e),()=>this.errorListeners.delete(e)}async start(){await this.components.registrar.handle(this.config.protocol,this.handleProtocol.bind(this),{runOnLimitedConnection:!0})}async stop(){await this.components.registrar.unhandle(this.config.protocol)}async handleProtocol(e,t){let i=!1;try{let a=r(e,{maxDataLength:this.maxMessageLength}),o=d(n.bytesTo((await a.read()).subarray(),`utf8`)),s;try{s={jsonrpc:`2.0`,id:o.id,result:await this.handleRequest({connection:t,peerId:t.remotePeer,payload:o})}}catch(e){i=p(e);let t=u(e);s={jsonrpc:`2.0`,id:o.id,error:{code:t.code,message:t.message,data:t.data}}}await a.write(n.bytesFrom(JSON.stringify(s),`utf8`)),await e.close()}catch(t){if(i)return;this.handleError(t,e)}}handleError(e,t){let n=f(e);return t?.abort(n),this.errorListeners.forEach(e=>e(n)),n}};function u(e){return e instanceof t?e:new t({code:-32603,message:f(e).message})}function d(e){let t=JSON.parse(e);if(t?.jsonrpc!==`2.0`||typeof t.id!=`number`&&typeof t.id!=`string`||typeof t.method!=`string`)throw Error(`Invalid JSON-RPC request`);return t}function f(e){return e instanceof Error?e:Error(`JSON-RPC request failed`)}function p(e){return e instanceof Error&&(e.name===`AbortError`||e.name===`TimeoutError`)}function m(e,t){return n=>new class extends l{handleRequest(e){return t.call(this,e)}}(n,e)}var h=class{constructor(e,t,n){this.node=e,this.peerId=t,this.config=n;let r=n.maxMessageLength??1048576;if(!Number.isSafeInteger(r)||r<=0)throw Error(`Maximum JSON-RPC message length must be a positive integer`);this.maxMessageLength=r;let i=n.timeout??12e4;if(!Number.isSafeInteger(i)||i<=0)throw Error(`JSON-RPC request timeout must be a positive integer`);this.timeout=i}async request(e){let t=AbortSignal.timeout(this.timeout),i=this.config.signal?n.abortSignalAny([this.config.signal,t]):t,a,o;try{a=await this.openStream(i);let t=r(a,{maxDataLength:this.maxMessageLength});await t.write(n.bytesFrom(JSON.stringify(e),`utf8`),{signal:i}),await a.close({signal:i}),o=JSON.parse(n.bytesTo((await t.read({signal:i})).subarray(),`utf8`)),await a.closeRead({signal:i}),i.throwIfAborted()}catch(e){let t=_(e);throw a?.abort(t),t}return this.config.onResponse?.(o),o}async openStream(e){s(this.node,this.peerId).catch(()=>{});for(let t of this.connections())try{return await t.newStream(this.config.protocol,{runOnLimitedConnection:!0,signal:e})}catch{e.throwIfAborted()}return this.node.dialProtocol(this.peerId,this.config.protocol,{runOnLimitedConnection:!0,signal:e})}connections(){return this.node.getConnections(this.peerId).filter(({status:e})=>e===`open`).sort(g)}};function g(e,t){return e.direct===t.direct?e.rtt===void 0?t.rtt===void 0?0:1:t.rtt===void 0?-1:e.rtt-t.rtt:e.direct?-1:1}function _(e){return e instanceof Error?e:Error(`JSON-RPC request failed`)}const v=16384,y=[`addresses`,`role`,`secret`];var b=class extends Error{constructor(e,t){super(e,t),this.name=`PairingEndpointError`}},x=class extends b{constructor(e,t){super(`Expected a ${e} pairing endpoint, received ${t?`role "${t}"`:`an endpoint without a role`}`),this.expectedRole=e,this.actualRole=t,this.name=`PairingEndpointRoleError`}};async function S(e,t,r,i){if(t.length===0)throw Error(`Pairing endpoint requires at least one address`);if(t.length>16)throw Error(`Pairing endpoint supports at most 16 addresses`);let a=T(t);if(a.byteLength>v)throw Error(`Pairing endpoint address data is too large`);let o=await D(a,new CompressionStream(`deflate`)),s=n.bytesTo(o,`base64url`),c=new URL(e),{params:l,route:u}=w(c);return y.forEach(e=>{l.delete(e)}),i&&l.set(`role`,i),l.set(`addresses`,s),l.set(`secret`,r),c.hash=`${u}?${l.toString()}`,c.toString()}async function C(e,t){let n;try{n=new URL(e.trim())}catch(e){throw new b(`Pairing endpoint is not a valid URL`,{cause:e})}let{params:r}=w(n);if(t){let e=r.get(`role`)?.trim()||void 0;if(e!==t)throw new x(t,e)}let i=r.get(`addresses`)?.trim(),a=r.get(`secret`)?.trim();if(!i||!a)throw new b(`Pairing endpoint is incomplete`);return{addresses:await E(i),secret:a}}function w(e){let t=e.hash.slice(1),n=t.indexOf(`?`);return n===-1?{params:new URLSearchParams,route:t}:{params:new URLSearchParams(t.slice(n+1)),route:t.slice(0,n)}}function T(e){return n.bytesConcat(...o.encode(e.map(e=>e.bytes)))}async function E(e){try{let t=await D(n.bytesFrom(e,`base64url`),new DecompressionStream(`deflate`),v),r=[];for(let e of o.decode([t],{maxDataLength:v})){if(r.length>=16)throw Error(`Too many addresses`);r.push(a(e.subarray()))}if(r.length===0)throw Error(`Missing addresses`);return r}catch(e){throw new b(`Pairing endpoint contains invalid compressed addresses`,{cause:e})}}async function D(e,t,n){let r=n===void 0?t.readable:t.readable.pipeThrough(O(n)),i=new Response(r).arrayBuffer().then(e=>({buffer:e,ok:!0}),e=>({error:e,ok:!1})),a=t.writable.getWriter();try{await a.write(Uint8Array.from(e)),await a.close()}catch(e){let t=await i;throw t.ok?e:t.error}let o=await i;if(!o.ok)throw o.error;return new Uint8Array(o.buffer)}function O(e){let t=0;return new TransformStream({transform(n,r){if(n.byteLength>e-t)throw Error(`Decompressed address data is too large`);t+=n.byteLength,r.enqueue(n)}})}const k=1024;var A=class{constructor(e,t){if(this.components=e,this.config=t,this.currentSecret=B(),this.errorListeners=new Set,this.pairedListeners=new Set,this.unpairedListeners=new Set,this.secretChangedListeners=new Set,this.pairingTimeouts=new Map,t.pairedPeerTimeoutMs<=0)throw Error(`Paired peer timeout must be greater than zero`)}get secret(){return this.currentSecret}onError(e){return this.errorListeners.add(e),()=>this.errorListeners.delete(e)}onPaired(e){return this.pairedListeners.add(e),()=>this.pairedListeners.delete(e)}onUnpaired(e){return this.unpairedListeners.add(e),()=>this.unpairedListeners.delete(e)}onSecretChanged(e){return this.secretChangedListeners.add(e),()=>this.secretChangedListeners.delete(e)}async start(){await this.components.registrar.handle(this.config.protocol,this.handleProtocol.bind(this),{runOnLimitedConnection:!0})}async stop(){await this.components.registrar.unhandle(this.config.protocol),this.pairingTimeouts.forEach(e=>clearTimeout(e)),this.pairingTimeouts.clear()}isPaired(e){return this.pairingTimeouts.has(e.toString())}refresh(e){let t=e.toString(),n=this.pairingTimeouts.get(t);n!==void 0&&(clearTimeout(n),this.pairingTimeouts.set(t,this.createPeerTimeout(e)))}async pair(e,t={}){let n,r;try{let i=await this.openStream(e.addresses,t);if(n=i.stream,!i.connection)throw Error(`Could not determine remote peer`);this.addPairedPeer(i.connection.remotePeer)&&(r=i.connection.remotePeer);let a=await M(n,N(e.secret,this.config.name,this.addresses()),t);if(t.signal?.throwIfAborted(),n=void 0,!a.ok)throw Error(a.error);return r&&(this.rotateSecret(),this.notifyPairedPeer(r,a.name)),i.connection.remotePeer}catch(e){throw r&&this.removePairedPeer(r,!1),this.handleError(e,n)}}async unpair(e){if(!this.removePairedPeer(e))return;let t={signal:AbortSignal.timeout(1e4)},n;try{let r=await this.openStream(e,t);n=r.stream;let i=await M(r.stream,{type:`unpair`},t);if(n=void 0,!i.ok)throw Error(i.error)}catch(e){this.handleError(e,n)}}async handleProtocol(e,t){let n;try{let i=r(e,{maxDataLength:k}),a=I((await i.read()).subarray());if(a.type===`unpair`){this.removePairedPeer(t.remotePeer),await F(i,e,{ok:!0});return}if(a.secret!==this.secret||!this.canPair(t.remotePeer)){await F(i,e,{ok:!1,error:`Pairing rejected`});return}let o=R(a.addresses,t.remotePeer);this.rotateSecret(),this.addPairedPeer(t.remotePeer)&&(n=t.remotePeer),await F(i,e,{ok:!0,name:this.config.name}),n&&(this.notifyPairedPeer(n,a.name),this.openFallbackConnection(o))}catch(t){n&&this.removePairedPeer(n,!1),this.handleError(t,e)}}addPairedPeer(e){let t=e.toString(),n=this.pairingTimeouts.get(t);return n!==void 0&&clearTimeout(n),this.pairingTimeouts.set(t,this.createPeerTimeout(e)),n===void 0}notifyPairedPeer(e,t){this.pairedListeners.forEach(n=>n(e,t))}addresses(){return this.components.addressManager?.getAddresses()??[]}async openFallbackConnection(e){if(e.length!==0)try{await this.components.connectionManager.openConnection(e)}catch{}}rotateSecret(){this.currentSecret=B(),this.secretChangedListeners.forEach(e=>e(this.currentSecret))}removePairedPeer(e,t=!0){let n=e.toString(),r=this.pairingTimeouts.get(n);return r!==void 0&&(clearTimeout(r),this.pairingTimeouts.delete(n),t&&this.unpairedListeners.forEach(t=>t(e)),!0)}createPeerTimeout(e){return setTimeout(()=>{if(this.components.connectionManager.getConnections(e).some(({status:e})=>e===`open`)){this.pairingTimeouts.set(e.toString(),this.createPeerTimeout(e));return}this.removePairedPeer(e)},this.config.pairedPeerTimeoutMs)}async openStream(e,t){let n;return{stream:await this.components.connectionManager.openStream(e,this.config.protocol,{runOnLimitedConnection:!0,signal:t.signal,onProgress(e){e.type===`connection:opened-stream`&&(n=e.detail.connection)}}),connection:n}}handleError(e,t){let n=V(e,`Pairing operation failed`);return t?.abort(n),this.errorListeners.forEach(e=>e(n)),n}};function j(e,t){return n=>new class extends A{canPair(e){return t.call(this,e)}}(n,e)}async function M(e,t,i){let a=r(e,{maxDataLength:k});await a.write(n.bytesFrom(JSON.stringify(t),`utf8`),{signal:i.signal}),await e.close(i);let o=z((await a.read(i)).subarray());return await e.closeRead(i),o}function N(e,t,n){let r=n.map(e=>e.toString()),i={type:`pair`,secret:e,name:t,addresses:r};for(;r.length>0&&!P(i);)r.pop();if(P(i)||delete i.addresses,P(i)||delete i.name,!P(i))throw Error(`Pairing request is too large`);return i}function P(e){return n.bytesFrom(JSON.stringify(e),`utf8`).byteLength<=k}async function F(e,t,r){await e.write(n.bytesFrom(JSON.stringify(r),`utf8`)),await t.close()}function I(e){let t=JSON.parse(n.bytesTo(e,`utf8`));if(t.type===`pair`&&typeof t.secret==`string`&&t.secret)return{type:`pair`,secret:t.secret,name:typeof t.name==`string`?t.name:void 0,addresses:L(t.addresses)};if(t.type===`unpair`)return{type:`unpair`};throw Error(`Invalid pairing request`)}function L(e){if(Array.isArray(e))return e.filter(e=>typeof e==`string`&&e.length>0)}function R(e,t){return(e??[]).flatMap(e=>{try{let n=a(e);return n.getComponents().filter(({code:e})=>e===i).at(-1)?.value===t.toString()?[n]:[]}catch{return[]}})}function z(e){let t=JSON.parse(n.bytesTo(e,`utf8`));if(t.ok===!0)return{ok:!0,name:typeof t.name==`string`?t.name:void 0};if(t.ok===!1&&typeof t.error==`string`)return{ok:!1,error:t.error};throw Error(`Invalid pairing response`)}function B(){return n.bytesTo(crypto.getRandomValues(new Uint8Array(16)),`base64url`)}function V(e,t){return e instanceof Error?e:Error(t)}var H=e({JsonRpcService:()=>l,JsonRpcTransportLibp2p:()=>h,PairingEndpointError:()=>b,PairingEndpointRoleError:()=>x,PairingService:()=>A,decodePairingEndpoint:()=>C,dialKnownAddresses:()=>s,encodePairingEndpoint:()=>S,jsonRpcService:()=>m,pairingService:()=>j});export{l as JsonRpcService,h as JsonRpcTransportLibp2p,b as PairingEndpointError,x as PairingEndpointRoleError,A as PairingService,C as decodePairingEndpoint,s as dialKnownAddresses,S as encodePairingEndpoint,m as jsonRpcService,j as pairingService,H as t};
1
+ import{t as e}from"./rolldown-runtime-DK3Fl9T5.mjs";import{JsonRpcError as t,ccc as n}from"@ckb-ccc/core";import{lpStream as r}from"@libp2p/utils";import{multiaddr as i}from"@multiformats/multiaddr";import*as a from"it-length-prefixed";async function o(e,t,n){let r=(await e.peerStore.get(t)).addresses.flatMap(({multiaddr:e})=>{let n=s(e,t);return n?[n]:[]});if(r.length!==0)return n?e.dial(r,{signal:n}):e.dial(r)}function s(e,t){let n=e.getComponents().at(-1);return n?.name===`p2p`?n.value===t.toString()?e:void 0:e.encapsulate(`/p2p/${t.toString()}`)}var c=class{constructor(e,t){this.components=e,this.config=t,this.errorListeners=new Set;let n=t.maxMessageLength??1048576;if(!Number.isSafeInteger(n)||n<=0)throw Error(`Maximum JSON-RPC message length must be a positive integer`);this.maxMessageLength=n;let r=t.timeout??3e4;if(!Number.isSafeInteger(r)||r<=0)throw Error(`JSON-RPC request timeout must be a positive integer`);this.timeout=r}onError(e){return this.errorListeners.add(e),()=>this.errorListeners.delete(e)}async start(){await this.components.registrar.handle(this.config.protocol,this.handleProtocol.bind(this),{runOnLimitedConnection:!0})}async stop(){await this.components.registrar.unhandle(this.config.protocol)}async handleProtocol(e,t){let i=!1,a=new AbortController,o=AbortSignal.timeout(this.timeout),s=e=>{i=!0;let t=Error(e.error?.message??`JSON-RPC stream closed`);t.name=`AbortError`,a.abort(t)},c=()=>{i=!0;let t=f(o,`JSON-RPC request timed out`);a.abort(t),e.abort(t)};e.addEventListener(`close`,s,{once:!0}),o.addEventListener(`abort`,c,{once:!0}),e.status!==`open`&&s({});try{let o=r(e,{maxDataLength:this.maxMessageLength}),c=u(n.bytesTo((await o.read({signal:a.signal})).subarray(),`utf8`)),d;try{a.signal.throwIfAborted(),d={jsonrpc:`2.0`,id:c.id,result:await Promise.race([Promise.resolve(this.handleRequest({connection:t,peerId:t.remotePeer,payload:c,signal:a.signal})),n.abortSignalToPromise(a.signal)])}}catch(e){i||=p(e);let t=l(e);d={jsonrpc:`2.0`,id:c.id,error:{code:t.code,message:t.message,data:t.data}}}await o.write(n.bytesFrom(JSON.stringify(d),`utf8`),{signal:a.signal}),e.removeEventListener(`close`,s),await e.close({signal:a.signal})}catch(t){if(i)return;this.handleError(t,e)}finally{e.removeEventListener(`close`,s),o.removeEventListener(`abort`,c)}}handleError(e,t){let n=d(e);return t?.abort(n),this.errorListeners.forEach(e=>e(n)),n}};function l(e){return e instanceof t?e:new t({code:-32603,message:d(e).message})}function u(e){let t=JSON.parse(e);if(t?.jsonrpc!==`2.0`||typeof t.id!=`number`&&typeof t.id!=`string`||typeof t.method!=`string`)throw Error(`Invalid JSON-RPC request`);return t}function d(e){return e instanceof Error?e:Error(`JSON-RPC request failed`)}function f(e,t){return e.reason instanceof Error?e.reason:Error(t)}function p(e){return e instanceof Error&&(e.name===`AbortError`||e.name===`TimeoutError`)}function m(e,t){return n=>new class extends c{handleRequest(e){return t.call(this,e)}}(n,e)}var h=class{constructor(e,t,n){this.node=e,this.peerId=t,this.config=n;let r=n.maxMessageLength??1048576;if(!Number.isSafeInteger(r)||r<=0)throw Error(`Maximum JSON-RPC message length must be a positive integer`);this.maxMessageLength=r;let i=n.timeout??3e4;if(!Number.isSafeInteger(i)||i<=0)throw Error(`JSON-RPC request timeout must be a positive integer`);this.timeout=i}async request(e,t){let i=AbortSignal.timeout(t?.timeout??this.timeout),a=[this.config.signal,t?.signal,i].filter(e=>e!==void 0),o=n.abortSignalAny(a),s,c;try{s=await this.openStream(o);let t=r(s,{maxDataLength:this.maxMessageLength});await t.write(n.bytesFrom(JSON.stringify(e),`utf8`),{signal:o}),await s.close({signal:o}),c=JSON.parse(n.bytesTo((await t.read({signal:o})).subarray(),`utf8`)),await s.closeRead({signal:o}),o.throwIfAborted()}catch(e){let t=_(e);throw s?.abort(t),t}return this.config.onResponse?.(c),c}async openStream(e){o(this.node,this.peerId).catch(()=>{});for(let t of this.connections())try{return await t.newStream(this.config.protocol,{runOnLimitedConnection:!0,signal:e})}catch{e.throwIfAborted()}return this.node.dialProtocol(this.peerId,this.config.protocol,{runOnLimitedConnection:!0,signal:e})}connections(){return this.node.getConnections(this.peerId).filter(({status:e})=>e===`open`).sort(g)}};function g(e,t){return e.direct===t.direct?e.rtt===void 0?t.rtt===void 0?0:1:t.rtt===void 0?-1:e.rtt-t.rtt:e.direct?-1:1}function _(e){return e instanceof Error?e:Error(`JSON-RPC request failed`)}const v=16384,y=[`addresses`,`role`,`secret`];var b=class extends Error{constructor(e,t){super(e,t),this.name=`PairingEndpointError`}},x=class extends b{constructor(e,t){super(`Expected a ${e} pairing endpoint, received ${t?`role "${t}"`:`an endpoint without a role`}`),this.expectedRole=e,this.actualRole=t,this.name=`PairingEndpointRoleError`}};async function S(e,t,r,i){if(t.length===0)throw Error(`Pairing endpoint requires at least one address`);if(t.length>16)throw Error(`Pairing endpoint supports at most 16 addresses`);let a=T(t);if(a.byteLength>v)throw Error(`Pairing endpoint address data is too large`);let o=await D(a,new CompressionStream(`deflate`)),s=n.bytesTo(o,`base64url`),c=new URL(e),{params:l,route:u}=w(c);return y.forEach(e=>{l.delete(e)}),i&&l.set(`role`,i),l.set(`addresses`,s),l.set(`secret`,r),c.hash=`${u}?${l.toString()}`,c.toString()}async function C(e,t){let n;try{n=new URL(e.trim())}catch(e){throw new b(`Pairing endpoint is not a valid URL`,{cause:e})}let{params:r}=w(n);if(t){let e=r.get(`role`)?.trim()||void 0;if(e!==t)throw new x(t,e)}let i=r.get(`addresses`)?.trim(),a=r.get(`secret`)?.trim();if(!i||!a)throw new b(`Pairing endpoint is incomplete`);return{addresses:await E(i),secret:a}}function w(e){let t=e.hash.slice(1),n=t.indexOf(`?`);return n===-1?{params:new URLSearchParams,route:t}:{params:new URLSearchParams(t.slice(n+1)),route:t.slice(0,n)}}function T(e){return n.bytesConcat(...a.encode(e.map(e=>e.bytes)))}async function E(e){try{let t=await D(n.bytesFrom(e,`base64url`),new DecompressionStream(`deflate`),v),r=[];for(let e of a.decode([t],{maxDataLength:v})){if(r.length>=16)throw Error(`Too many addresses`);r.push(i(e.subarray()))}if(r.length===0)throw Error(`Missing addresses`);return r}catch(e){throw new b(`Pairing endpoint contains invalid compressed addresses`,{cause:e})}}async function D(e,t,n){let r=n===void 0?t.readable:t.readable.pipeThrough(O(n)),i=new Response(r).arrayBuffer().then(e=>({buffer:e,ok:!0}),e=>({error:e,ok:!1})),a=t.writable.getWriter();try{await a.write(Uint8Array.from(e)),await a.close()}catch(e){let t=await i;throw t.ok?e:t.error}let o=await i;if(!o.ok)throw o.error;return new Uint8Array(o.buffer)}function O(e){let t=0;return new TransformStream({transform(n,r){if(n.byteLength>e-t)throw Error(`Decompressed address data is too large`);t+=n.byteLength,r.enqueue(n)}})}const k=1024;var A=class{constructor(e,t){if(this.components=e,this.config=t,this.currentSecret=R(),this.errorListeners=new Set,this.pairedListeners=new Set,this.unpairedListeners=new Set,this.secretChangedListeners=new Set,this.pairingTimeouts=new Map,t.pairedPeerTimeoutMs<=0)throw Error(`Paired peer timeout must be greater than zero`)}get secret(){return this.currentSecret}onError(e){return this.errorListeners.add(e),()=>this.errorListeners.delete(e)}onPaired(e){return this.pairedListeners.add(e),()=>this.pairedListeners.delete(e)}onUnpaired(e){return this.unpairedListeners.add(e),()=>this.unpairedListeners.delete(e)}onSecretChanged(e){return this.secretChangedListeners.add(e),()=>this.secretChangedListeners.delete(e)}async start(){await this.components.registrar.handle(this.config.protocol,this.handleProtocol.bind(this),{runOnLimitedConnection:!0})}async stop(){await this.components.registrar.unhandle(this.config.protocol),this.pairingTimeouts.forEach(e=>clearTimeout(e)),this.pairingTimeouts.clear()}isPaired(e){return this.pairingTimeouts.has(e.toString())}refresh(e){let t=e.toString(),n=this.pairingTimeouts.get(t);n!==void 0&&(clearTimeout(n),this.pairingTimeouts.set(t,this.createPeerTimeout(e)))}async pair(e,t={}){let n,r;try{let i=await this.openStream(e.addresses,t);if(n=i.stream,!i.connection)throw Error(`Could not determine remote peer`);this.addPairedPeer(i.connection.remotePeer)&&(r=i.connection.remotePeer);let a=await M(n,N(e.secret,this.config.name),t);if(t.signal?.throwIfAborted(),n=void 0,!a.ok)throw Error(a.error);return r&&(this.rotateSecret(),this.notifyPairedPeer(r,a.name)),i.connection.remotePeer}catch(e){throw r&&this.removePairedPeer(r,!1),this.handleError(e,n)}}async unpair(e){if(!this.removePairedPeer(e))return;let t={signal:AbortSignal.timeout(1e4)},n;try{let r=await this.openStream(e,t);n=r.stream;let i=await M(r.stream,{type:`unpair`},t);if(n=void 0,!i.ok)throw Error(i.error)}catch(e){this.handleError(e,n)}}async handleProtocol(e,t){let n;try{let i=r(e,{maxDataLength:k}),a=I((await i.read()).subarray());if(a.type===`unpair`){this.removePairedPeer(t.remotePeer),await F(i,e,{ok:!0});return}if(a.secret!==this.secret||!this.canPair(t.remotePeer)){await F(i,e,{ok:!1,error:`Pairing rejected`});return}this.rotateSecret(),this.addPairedPeer(t.remotePeer)&&(n=t.remotePeer),await F(i,e,{ok:!0,name:this.config.name}),n&&this.notifyPairedPeer(n,a.name)}catch(t){n&&this.removePairedPeer(n,!1),this.handleError(t,e)}}addPairedPeer(e){let t=e.toString(),n=this.pairingTimeouts.get(t);return n!==void 0&&clearTimeout(n),this.pairingTimeouts.set(t,this.createPeerTimeout(e)),n===void 0}notifyPairedPeer(e,t){this.pairedListeners.forEach(n=>n(e,t))}rotateSecret(){this.currentSecret=R(),this.secretChangedListeners.forEach(e=>e(this.currentSecret))}removePairedPeer(e,t=!0){let n=e.toString(),r=this.pairingTimeouts.get(n);return r!==void 0&&(clearTimeout(r),this.pairingTimeouts.delete(n),t&&this.unpairedListeners.forEach(t=>t(e)),!0)}createPeerTimeout(e){return setTimeout(()=>{if(this.components.connectionManager.getConnections(e).some(({status:e})=>e===`open`)){this.pairingTimeouts.set(e.toString(),this.createPeerTimeout(e));return}this.removePairedPeer(e)},this.config.pairedPeerTimeoutMs)}async openStream(e,t){let n;return{stream:await this.components.connectionManager.openStream(e,this.config.protocol,{runOnLimitedConnection:!0,signal:t.signal,onProgress(e){e.type===`connection:opened-stream`&&(n=e.detail.connection)}}),connection:n}}handleError(e,t){let n=z(e,`Pairing operation failed`);return t?.abort(n),this.errorListeners.forEach(e=>e(n)),n}};function j(e,t){return n=>new class extends A{canPair(e){return t.call(this,e)}}(n,e)}async function M(e,t,i){let a=r(e,{maxDataLength:k});await a.write(n.bytesFrom(JSON.stringify(t),`utf8`),{signal:i.signal}),await e.close(i);let o=L((await a.read(i)).subarray());return await e.closeRead(i),o}function N(e,t){let n={type:`pair`,secret:e,name:t};if(P(n)||delete n.name,!P(n))throw Error(`Pairing request is too large`);return n}function P(e){return n.bytesFrom(JSON.stringify(e),`utf8`).byteLength<=k}async function F(e,t,r){await e.write(n.bytesFrom(JSON.stringify(r),`utf8`)),await t.close()}function I(e){let t=JSON.parse(n.bytesTo(e,`utf8`));if(t.type===`pair`&&typeof t.secret==`string`&&t.secret)return{type:`pair`,secret:t.secret,name:typeof t.name==`string`?t.name:void 0};if(t.type===`unpair`)return{type:`unpair`};throw Error(`Invalid pairing request`)}function L(e){let t=JSON.parse(n.bytesTo(e,`utf8`));if(t.ok===!0)return{ok:!0,name:typeof t.name==`string`?t.name:void 0};if(t.ok===!1&&typeof t.error==`string`)return{ok:!1,error:t.error};throw Error(`Invalid pairing response`)}function R(){return n.bytesTo(crypto.getRandomValues(new Uint8Array(16)),`base64url`)}function z(e,t){return e instanceof Error?e:Error(t)}const B=[5e3,1e4,2e4];var V=class{constructor(e,t,n={}){if(this.node=e,this.options=n,this.controller=new AbortController,this.handleConnectionClose=e=>{e.detail.id===this.connection?.id&&(this.connection=void 0,this.options.onConnectionChange?.(),this.connect().catch(()=>{}))},t.length===0)throw Error(`At least one relay address is required`);this.addresses=t.map(e=>i(e.trim())),e.addEventListener(`connection:close`,this.handleConnectionClose,{signal:this.controller.signal})}connect(){if(this.controller.signal.throwIfAborted(),this.connection?.status===`open`)return Promise.resolve(this.connection);if(this.connecting)return this.connecting;this.connection=void 0;let e=n.retry(B,async({resolve:e})=>e(await this.dialRelay()),{repeat:3e4,signal:this.controller.signal}).finally(()=>{this.connecting===e&&(this.connecting=void 0),!this.controller.signal.aborted&&!this.connection&&this.connect().catch(()=>{})});return this.connecting=e,e}async stop(){if(this.controller.signal.aborted)return;this.controller.abort();let e=this.connection;this.connection=void 0,this.options.onConnectionChange?.(),await e?.close()}async dialRelay(){let e=this.selectedAddress?[this.selectedAddress]:this.addresses,t;for(let r of e){await n.waitForAvailability(this.controller.signal);let e;try{if(e=await this.node.dial(r,{signal:n.abortSignalAny([this.controller.signal,AbortSignal.timeout(1e4)])}),this.controller.signal.throwIfAborted(),this.connection=e,e.status!==`open`)throw this.connection=void 0,Error(`Relay connection closed while dialing`);return this.selectedAddress=r,this.options.onConnectionChange?.(e),e}catch(n){t=n,await e?.close()}}throw t}},H=e({JsonRpcService:()=>c,JsonRpcTransportLibp2p:()=>h,PairingEndpointError:()=>b,PairingEndpointRoleError:()=>x,PairingService:()=>A,RelayConnectionController:()=>V,decodePairingEndpoint:()=>C,dialKnownAddresses:()=>o,encodePairingEndpoint:()=>S,jsonRpcService:()=>m,pairingService:()=>j});export{c as JsonRpcService,h as JsonRpcTransportLibp2p,b as PairingEndpointError,x as PairingEndpointRoleError,A as PairingService,V as RelayConnectionController,C as decodePairingEndpoint,o as dialKnownAddresses,S as encodePairingEndpoint,m as jsonRpcService,j as pairingService,H as t};
2
2
  //# sourceMappingURL=barrel.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"barrel.mjs","names":["DEFAULT_MAX_MESSAGE_LENGTH","asJsonRpcError"],"sources":["../src/dial.ts","../src/jsonRpcService.ts","../src/jsonRpcTransport.ts","../src/pairingEndpoint.ts","../src/pairingService.ts","../src/barrel.ts"],"sourcesContent":["import type { Libp2p, PeerId } from \"@libp2p/interface\";\nimport type { Multiaddr } from \"@multiformats/multiaddr\";\n\nexport async function dialKnownAddresses(\n node: Libp2p,\n peerId: PeerId,\n signal?: AbortSignal,\n) {\n const peer = await node.peerStore.get(peerId);\n // PeerStore may omit the target peer id. Restore it so libp2p can\n // attempt a direct upgrade without force-dialing.\n const addresses = peer.addresses.flatMap(({ multiaddr }) => {\n const address = addressForPeer(multiaddr, peerId);\n return address ? [address] : [];\n });\n if (addresses.length === 0) {\n return;\n }\n\n return signal ? node.dial(addresses, { signal }) : node.dial(addresses);\n}\n\nfunction addressForPeer(address: Multiaddr, peerId: PeerId) {\n const last = address.getComponents().at(-1);\n if (last?.name !== \"p2p\") {\n return address.encapsulate(`/p2p/${peerId.toString()}`);\n }\n return last.value === peerId.toString() ? address : undefined;\n}\n","import { ccc, JsonRpcError } from \"@ckb-ccc/core\";\nimport type { Connection, PeerId, Stream } from \"@libp2p/interface\";\nimport type { Registrar } from \"@libp2p/interface-internal\";\nimport { lpStream } from \"@libp2p/utils\";\n\nconst DEFAULT_MAX_MESSAGE_LENGTH = 1024 * 1024;\n\nexport type JsonRpcServiceComponents = {\n registrar: Registrar;\n};\n\nexport type JsonRpcServiceConfig = {\n protocol: string;\n maxMessageLength?: number;\n};\n\nexport type JsonRpcRequest = {\n connection: Connection;\n peerId: PeerId;\n payload: ccc.JsonRpcPayload;\n};\n\nexport type JsonRpcRequestHandler<\n Components extends JsonRpcServiceComponents = JsonRpcServiceComponents,\n> = (this: JsonRpcService<Components>, request: JsonRpcRequest) => unknown;\n\nexport abstract class JsonRpcService<\n Components extends JsonRpcServiceComponents = JsonRpcServiceComponents,\n> {\n private readonly errorListeners = new Set<(error: Error) => void>();\n readonly maxMessageLength: number;\n\n constructor(\n readonly components: Components,\n readonly config: JsonRpcServiceConfig,\n ) {\n const maxMessageLength =\n config.maxMessageLength ?? DEFAULT_MAX_MESSAGE_LENGTH;\n if (!Number.isSafeInteger(maxMessageLength) || maxMessageLength <= 0) {\n throw new Error(\n \"Maximum JSON-RPC message length must be a positive integer\",\n );\n }\n\n this.maxMessageLength = maxMessageLength;\n }\n\n protected abstract handleRequest(request: JsonRpcRequest): unknown;\n\n onError(listener: (error: Error) => void) {\n this.errorListeners.add(listener);\n return () => this.errorListeners.delete(listener);\n }\n\n async start() {\n await this.components.registrar.handle(\n this.config.protocol,\n this.handleProtocol.bind(this),\n { runOnLimitedConnection: true },\n );\n }\n\n async stop() {\n await this.components.registrar.unhandle(this.config.protocol);\n }\n\n private async handleProtocol(stream: Stream, connection: Connection) {\n let requestAborted = false;\n\n try {\n const rpcStream = lpStream(stream, {\n maxDataLength: this.maxMessageLength,\n });\n const payload = parseJsonRpcRequest(\n ccc.bytesTo((await rpcStream.read()).subarray(), \"utf8\"),\n );\n\n let response: ccc.JsonRpcResponse;\n try {\n response = {\n jsonrpc: \"2.0\",\n id: payload.id,\n result: await this.handleRequest({\n connection,\n peerId: connection.remotePeer,\n payload,\n }),\n };\n } catch (cause) {\n requestAborted = isAbortError(cause);\n const error = toJsonRpcError(cause);\n response = {\n jsonrpc: \"2.0\",\n id: payload.id,\n error: {\n code: error.code,\n message: error.message,\n data: error.data,\n },\n };\n }\n\n await rpcStream.write(ccc.bytesFrom(JSON.stringify(response), \"utf8\"));\n await stream.close();\n } catch (cause) {\n if (requestAborted) {\n return;\n }\n this.handleError(cause, stream);\n }\n }\n\n private handleError(cause: unknown, stream?: Stream) {\n const error = asJsonRpcError(cause);\n\n stream?.abort(error);\n this.errorListeners.forEach((listener) => listener(error));\n return error;\n }\n}\n\nfunction toJsonRpcError(cause: unknown) {\n if (cause instanceof JsonRpcError) {\n return cause;\n }\n\n return new JsonRpcError({\n code: -32603,\n message: asJsonRpcError(cause).message,\n });\n}\n\nfunction parseJsonRpcRequest(data: string) {\n const payload = JSON.parse(data) as Partial<ccc.JsonRpcPayload>;\n if (\n payload?.jsonrpc !== \"2.0\" ||\n (typeof payload.id !== \"number\" && typeof payload.id !== \"string\") ||\n typeof payload.method !== \"string\"\n ) {\n throw new Error(\"Invalid JSON-RPC request\");\n }\n\n return payload as ccc.JsonRpcPayload;\n}\n\nfunction asJsonRpcError(cause: unknown) {\n return cause instanceof Error ? cause : new Error(\"JSON-RPC request failed\");\n}\n\nfunction isAbortError(cause: unknown) {\n return (\n cause instanceof Error &&\n (cause.name === \"AbortError\" || cause.name === \"TimeoutError\")\n );\n}\n\nexport function jsonRpcService<\n Components extends JsonRpcServiceComponents = JsonRpcServiceComponents,\n>(\n config: JsonRpcServiceConfig,\n handler: JsonRpcRequestHandler<Components>,\n): (components: Components) => JsonRpcService<Components> {\n return (components: Components) =>\n new (class extends JsonRpcService<Components> {\n protected handleRequest(request: JsonRpcRequest) {\n return handler.call(this, request);\n }\n })(components, config);\n}\n","import { ccc } from \"@ckb-ccc/core\";\nimport type { Connection, Libp2p, PeerId, Stream } from \"@libp2p/interface\";\nimport { lpStream } from \"@libp2p/utils\";\nimport { dialKnownAddresses } from \"./dial.js\";\n\nconst DEFAULT_MAX_MESSAGE_LENGTH = 1024 * 1024;\nconst DEFAULT_TIMEOUT = 120_000;\n\nexport type JsonRpcTransportLibp2pConfig = {\n protocol: string;\n maxMessageLength?: number;\n timeout?: number;\n signal?: AbortSignal;\n onResponse?: (response: ccc.JsonRpcResponse) => void;\n};\n\nexport class JsonRpcTransportLibp2p implements ccc.JsonRpcTransport {\n private readonly maxMessageLength: number;\n private readonly timeout: number;\n\n constructor(\n private readonly node: Libp2p,\n readonly peerId: PeerId,\n private readonly config: JsonRpcTransportLibp2pConfig,\n ) {\n const maxMessageLength =\n config.maxMessageLength ?? DEFAULT_MAX_MESSAGE_LENGTH;\n if (!Number.isSafeInteger(maxMessageLength) || maxMessageLength <= 0) {\n throw new Error(\n \"Maximum JSON-RPC message length must be a positive integer\",\n );\n }\n\n this.maxMessageLength = maxMessageLength;\n\n const timeout = config.timeout ?? DEFAULT_TIMEOUT;\n if (!Number.isSafeInteger(timeout) || timeout <= 0) {\n throw new Error(\"JSON-RPC request timeout must be a positive integer\");\n }\n\n this.timeout = timeout;\n }\n\n async request(payload: ccc.JsonRpcPayload): Promise<ccc.JsonRpcResponse> {\n const timeoutSignal = AbortSignal.timeout(this.timeout);\n const signal = this.config.signal\n ? ccc.abortSignalAny([this.config.signal, timeoutSignal])\n : timeoutSignal;\n\n let stream: Stream | undefined;\n let response: ccc.JsonRpcResponse;\n try {\n stream = await this.openStream(signal);\n\n const rpcStream = lpStream(stream, {\n maxDataLength: this.maxMessageLength,\n });\n\n await rpcStream.write(ccc.bytesFrom(JSON.stringify(payload), \"utf8\"), {\n signal,\n });\n await stream.close({ signal });\n\n response = JSON.parse(\n ccc.bytesTo((await rpcStream.read({ signal })).subarray(), \"utf8\"),\n ) as ccc.JsonRpcResponse;\n await stream.closeRead({ signal });\n signal.throwIfAborted();\n } catch (cause) {\n const error = asJsonRpcError(cause);\n stream?.abort(error);\n throw error;\n }\n\n this.config.onResponse?.(response);\n return response;\n }\n\n private async openStream(signal: AbortSignal) {\n void dialKnownAddresses(this.node, this.peerId).catch(() => {\n // This is opportunistic; the current stream can still use relay/fallbacks.\n });\n\n for (const connection of this.connections()) {\n try {\n return await connection.newStream(this.config.protocol, {\n runOnLimitedConnection: true,\n signal,\n });\n } catch {\n signal.throwIfAborted();\n }\n }\n\n return this.node.dialProtocol(this.peerId, this.config.protocol, {\n runOnLimitedConnection: true,\n signal,\n });\n }\n\n private connections() {\n return this.node\n .getConnections(this.peerId)\n .filter(({ status }) => status === \"open\")\n .sort(compareConnections);\n }\n}\n\nfunction compareConnections(a: Connection, b: Connection) {\n if (a.direct !== b.direct) {\n return a.direct ? -1 : 1;\n }\n if (a.rtt === undefined) {\n return b.rtt === undefined ? 0 : 1;\n }\n return b.rtt === undefined ? -1 : a.rtt - b.rtt;\n}\n\nfunction asJsonRpcError(cause: unknown) {\n return cause instanceof Error ? cause : new Error(\"JSON-RPC request failed\");\n}\n","import { ccc } from \"@ckb-ccc/core\";\nimport { multiaddr, type Multiaddr } from \"@multiformats/multiaddr\";\nimport * as lp from \"it-length-prefixed\";\nimport type { PairingTarget } from \"./pairingService.js\";\n\nconst MAX_DECOMPRESSED_ADDRESSES_LENGTH = 16 * 1024;\nconst MAX_ADDRESSES = 16;\nconst PAIRING_PARAMETER_NAMES = [\"addresses\", \"role\", \"secret\"] as const;\n\nexport class PairingEndpointError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"PairingEndpointError\";\n }\n}\n\nexport class PairingEndpointRoleError extends PairingEndpointError {\n constructor(\n readonly expectedRole: string,\n readonly actualRole: string | undefined,\n ) {\n super(\n `Expected a ${expectedRole} pairing endpoint, received ${actualRole ? `role \"${actualRole}\"` : \"an endpoint without a role\"}`,\n );\n this.name = \"PairingEndpointRoleError\";\n }\n}\n\nexport async function encodePairingEndpoint(\n endpointUrl: string,\n addresses: readonly Multiaddr[],\n secret: string,\n role?: string,\n) {\n if (addresses.length === 0) {\n throw new Error(\"Pairing endpoint requires at least one address\");\n }\n if (addresses.length > MAX_ADDRESSES) {\n throw new Error(\n `Pairing endpoint supports at most ${MAX_ADDRESSES} addresses`,\n );\n }\n\n const addressBytes = encodeAddresses(addresses);\n if (addressBytes.byteLength > MAX_DECOMPRESSED_ADDRESSES_LENGTH) {\n throw new Error(\"Pairing endpoint address data is too large\");\n }\n\n const compressedAddressBytes = await transformBytes(\n addressBytes,\n new CompressionStream(\"deflate\"),\n );\n\n const encodedAddresses = ccc.bytesTo(compressedAddressBytes, \"base64url\");\n\n const url = new URL(endpointUrl);\n const { params, route } = fragmentParameters(url);\n\n PAIRING_PARAMETER_NAMES.forEach((name) => {\n params.delete(name);\n });\n if (role) {\n params.set(\"role\", role);\n }\n params.set(\"addresses\", encodedAddresses);\n params.set(\"secret\", secret);\n url.hash = `${route}?${params.toString()}`;\n\n return url.toString();\n}\n\nexport async function decodePairingEndpoint(\n endpoint: string,\n expectedRole?: string,\n): Promise<PairingTarget> {\n let url: URL;\n try {\n url = new URL(endpoint.trim());\n } catch (cause) {\n throw new PairingEndpointError(\"Pairing endpoint is not a valid URL\", {\n cause,\n });\n }\n const { params } = fragmentParameters(url);\n if (expectedRole) {\n const actualRole = params.get(\"role\")?.trim() || undefined;\n if (actualRole !== expectedRole) {\n throw new PairingEndpointRoleError(expectedRole, actualRole);\n }\n }\n const compressedAddresses = params.get(\"addresses\")?.trim();\n const secret = params.get(\"secret\")?.trim();\n\n if (!compressedAddresses || !secret) {\n throw new PairingEndpointError(\"Pairing endpoint is incomplete\");\n }\n\n const addresses = await decodeCompressedAddresses(compressedAddresses);\n\n return { addresses, secret };\n}\n\nfunction fragmentParameters(url: URL) {\n const fragment = url.hash.slice(1);\n const separator = fragment.indexOf(\"?\");\n if (separator === -1) {\n return { params: new URLSearchParams(), route: fragment };\n }\n\n return {\n params: new URLSearchParams(fragment.slice(separator + 1)),\n route: fragment.slice(0, separator),\n };\n}\n\nfunction encodeAddresses(addresses: readonly Multiaddr[]): Uint8Array {\n return ccc.bytesConcat(\n ...lp.encode(addresses.map((address) => address.bytes)),\n );\n}\n\nasync function decodeCompressedAddresses(value: string): Promise<Multiaddr[]> {\n try {\n const compressedBytes = ccc.bytesFrom(value, \"base64url\");\n const bytes = await transformBytes(\n compressedBytes,\n new DecompressionStream(\"deflate\"),\n MAX_DECOMPRESSED_ADDRESSES_LENGTH,\n );\n const addresses: Multiaddr[] = [];\n for (const address of lp.decode([bytes], {\n maxDataLength: MAX_DECOMPRESSED_ADDRESSES_LENGTH,\n })) {\n if (addresses.length >= MAX_ADDRESSES) {\n throw new Error(\"Too many addresses\");\n }\n addresses.push(multiaddr(address.subarray()));\n }\n\n if (addresses.length === 0) {\n throw new Error(\"Missing addresses\");\n }\n return addresses;\n } catch (cause) {\n throw new PairingEndpointError(\n \"Pairing endpoint contains invalid compressed addresses\",\n { cause },\n );\n }\n}\n\nasync function transformBytes(\n bytes: Uint8Array,\n transform: CompressionStream | DecompressionStream,\n maxOutputLength?: number,\n) {\n const readable =\n maxOutputLength === undefined\n ? transform.readable\n : transform.readable.pipeThrough(limitBytes(maxOutputLength));\n const output = new Response(readable).arrayBuffer().then(\n (buffer) => ({ buffer, ok: true }) as const,\n (error: unknown) => ({ error, ok: false }) as const,\n );\n const writer = transform.writable.getWriter();\n try {\n await writer.write(Uint8Array.from(bytes));\n await writer.close();\n } catch (cause) {\n const result = await output;\n if (!result.ok) {\n throw result.error;\n }\n throw cause;\n }\n\n const result = await output;\n if (!result.ok) {\n throw result.error;\n }\n return new Uint8Array(result.buffer);\n}\n\nfunction limitBytes(maxLength: number) {\n let length = 0;\n\n return new TransformStream<Uint8Array, Uint8Array>({\n transform(chunk, controller) {\n if (chunk.byteLength > maxLength - length) {\n throw new Error(\"Decompressed address data is too large\");\n }\n length += chunk.byteLength;\n controller.enqueue(chunk);\n },\n });\n}\n","import { ccc } from \"@ckb-ccc/core\";\nimport type {\n AbortOptions,\n Connection,\n PeerId,\n Stream,\n} from \"@libp2p/interface\";\nimport type {\n AddressManager,\n ConnectionManager,\n Registrar,\n} from \"@libp2p/interface-internal\";\nimport { lpStream } from \"@libp2p/utils\";\nimport { CODE_P2P, multiaddr, type Multiaddr } from \"@multiformats/multiaddr\";\n\nconst MAX_PAIRING_MESSAGE_LENGTH = 1024;\nconst UNPAIR_TIMEOUT_MS = 10_000;\n\nexport type PairingServiceComponents = {\n addressManager?: Pick<AddressManager, \"getAddresses\">;\n connectionManager: ConnectionManager;\n registrar: Registrar;\n};\n\nexport type PairingServiceConfig = {\n /** Optional self-reported label shared with the paired peer. */\n name?: string;\n protocol: string;\n pairedPeerTimeoutMs: number;\n};\n\nexport type PairingTarget = {\n addresses: Multiaddr[];\n secret: string;\n};\n\nexport type PairingGuard<\n Components extends PairingServiceComponents = PairingServiceComponents,\n> = (this: PairingService<Components>, peerId: PeerId) => boolean;\n\ntype PairingRequest =\n | { type: \"pair\"; secret: string; name?: string; addresses?: string[] }\n | { type: \"unpair\" };\n\ntype PairingResponse =\n { ok: true; name?: string } | { ok: false; error: string };\n\nexport abstract class PairingService<\n Components extends PairingServiceComponents = PairingServiceComponents,\n> {\n private currentSecret = createSecret();\n private readonly errorListeners = new Set<(error: Error) => void>();\n private readonly pairedListeners = new Set<\n (peerId: PeerId, name?: string) => void\n >();\n private readonly unpairedListeners = new Set<(peerId: PeerId) => void>();\n private readonly secretChangedListeners = new Set<(secret: string) => void>();\n private readonly pairingTimeouts = new Map<\n string,\n ReturnType<typeof setTimeout>\n >();\n\n constructor(\n readonly components: Components,\n readonly config: PairingServiceConfig,\n ) {\n if (config.pairedPeerTimeoutMs <= 0) {\n throw new Error(\"Paired peer timeout must be greater than zero\");\n }\n }\n\n protected abstract canPair(peerId: PeerId): boolean;\n\n /** The credential to include in the currently issued pairing endpoint. */\n get secret() {\n return this.currentSecret;\n }\n\n onError(listener: (error: Error) => void) {\n this.errorListeners.add(listener);\n return () => this.errorListeners.delete(listener);\n }\n\n onPaired(listener: (peerId: PeerId, name?: string) => void) {\n this.pairedListeners.add(listener);\n return () => this.pairedListeners.delete(listener);\n }\n\n onUnpaired(listener: (peerId: PeerId) => void) {\n this.unpairedListeners.add(listener);\n return () => this.unpairedListeners.delete(listener);\n }\n\n onSecretChanged(listener: (secret: string) => void) {\n this.secretChangedListeners.add(listener);\n return () => this.secretChangedListeners.delete(listener);\n }\n\n async start() {\n await this.components.registrar.handle(\n this.config.protocol,\n this.handleProtocol.bind(this),\n { runOnLimitedConnection: true },\n );\n }\n\n async stop() {\n await this.components.registrar.unhandle(this.config.protocol);\n\n this.pairingTimeouts.forEach((timeout) => clearTimeout(timeout));\n this.pairingTimeouts.clear();\n }\n\n isPaired(peerId: PeerId) {\n return this.pairingTimeouts.has(peerId.toString());\n }\n\n refresh(peerId: PeerId) {\n const key = peerId.toString();\n const timeout = this.pairingTimeouts.get(key);\n if (timeout === undefined) {\n return;\n }\n\n clearTimeout(timeout);\n this.pairingTimeouts.set(key, this.createPeerTimeout(peerId));\n }\n\n async pair(\n target: PairingTarget,\n options: AbortOptions = {},\n ): Promise<PeerId> {\n let stream: Stream | undefined;\n let addedPeer: PeerId | undefined;\n\n try {\n const opened = await this.openStream(target.addresses, options);\n stream = opened.stream;\n\n if (!opened.connection) {\n throw new Error(\"Could not determine remote peer\");\n }\n\n if (this.addPairedPeer(opened.connection.remotePeer)) {\n addedPeer = opened.connection.remotePeer;\n }\n\n const response = await exchange(\n stream,\n createPairRequest(target.secret, this.config.name, this.addresses()),\n options,\n );\n options.signal?.throwIfAborted();\n stream = undefined;\n\n if (!response.ok) {\n throw new Error(response.error);\n }\n\n if (addedPeer) {\n this.rotateSecret();\n this.notifyPairedPeer(addedPeer, response.name);\n }\n return opened.connection.remotePeer;\n } catch (cause) {\n if (addedPeer) {\n this.removePairedPeer(addedPeer, false);\n }\n throw this.handleError(cause, stream);\n }\n }\n\n async unpair(peerId: PeerId) {\n if (!this.removePairedPeer(peerId)) {\n return;\n }\n\n const options = { signal: AbortSignal.timeout(UNPAIR_TIMEOUT_MS) };\n\n let stream: Stream | undefined;\n try {\n const opened = await this.openStream(peerId, options);\n stream = opened.stream;\n const response = await exchange(\n opened.stream,\n { type: \"unpair\" },\n options,\n );\n stream = undefined;\n if (!response.ok) {\n throw new Error(response.error);\n }\n } catch (cause) {\n this.handleError(cause, stream);\n }\n }\n\n private async handleProtocol(stream: Stream, connection: Connection) {\n let addedPeer: PeerId | undefined;\n\n try {\n const pairingStream = lpStream(stream, {\n maxDataLength: MAX_PAIRING_MESSAGE_LENGTH,\n });\n const request = parsePairingRequest(\n (await pairingStream.read()).subarray(),\n );\n\n if (request.type === \"unpair\") {\n this.removePairedPeer(connection.remotePeer);\n await writeResponse(pairingStream, stream, { ok: true });\n return;\n }\n\n if (\n request.secret !== this.secret ||\n !this.canPair(connection.remotePeer)\n ) {\n await writeResponse(pairingStream, stream, {\n ok: false,\n error: \"Pairing rejected\",\n });\n return;\n }\n\n const addresses = parseAddresses(\n request.addresses,\n connection.remotePeer,\n );\n\n // Consume the credential before the next asynchronous boundary so two\n // concurrent requests cannot both pair with the same endpoint.\n this.rotateSecret();\n\n if (this.addPairedPeer(connection.remotePeer)) {\n addedPeer = connection.remotePeer;\n }\n await writeResponse(pairingStream, stream, {\n ok: true,\n name: this.config.name,\n });\n if (addedPeer) {\n this.notifyPairedPeer(addedPeer, request.name);\n void this.openFallbackConnection(addresses);\n }\n } catch (cause) {\n if (addedPeer) {\n this.removePairedPeer(addedPeer, false);\n }\n this.handleError(cause, stream);\n }\n }\n\n private addPairedPeer(peerId: PeerId) {\n const key = peerId.toString();\n const timeout = this.pairingTimeouts.get(key);\n if (timeout !== undefined) {\n clearTimeout(timeout);\n }\n\n this.pairingTimeouts.set(key, this.createPeerTimeout(peerId));\n return timeout === undefined;\n }\n\n private notifyPairedPeer(peerId: PeerId, name?: string) {\n this.pairedListeners.forEach((listener) => listener(peerId, name));\n }\n\n private addresses() {\n return this.components.addressManager?.getAddresses() ?? [];\n }\n\n private async openFallbackConnection(addresses: Multiaddr[]) {\n if (addresses.length === 0) {\n return;\n }\n\n try {\n await this.components.connectionManager.openConnection(addresses);\n } catch {\n // The original pairing connection remains usable when the fallback fails.\n }\n }\n\n private rotateSecret() {\n this.currentSecret = createSecret();\n this.secretChangedListeners.forEach((listener) =>\n listener(this.currentSecret),\n );\n }\n\n private removePairedPeer(peerId: PeerId, notify = true) {\n const key = peerId.toString();\n const timeout = this.pairingTimeouts.get(key);\n if (timeout === undefined) {\n return false;\n }\n\n clearTimeout(timeout);\n this.pairingTimeouts.delete(key);\n\n if (notify) {\n this.unpairedListeners.forEach((listener) => listener(peerId));\n }\n return true;\n }\n\n private createPeerTimeout(peerId: PeerId) {\n return setTimeout(() => {\n if (\n this.components.connectionManager\n .getConnections(peerId)\n .some(({ status }) => status === \"open\")\n ) {\n this.pairingTimeouts.set(\n peerId.toString(),\n this.createPeerTimeout(peerId),\n );\n return;\n }\n\n this.removePairedPeer(peerId);\n }, this.config.pairedPeerTimeoutMs);\n }\n\n private async openStream(\n target: PeerId | Multiaddr | Multiaddr[],\n options: AbortOptions,\n ) {\n let connection: Connection | undefined;\n const stream = await this.components.connectionManager.openStream(\n target,\n this.config.protocol,\n {\n runOnLimitedConnection: true,\n signal: options.signal,\n onProgress(event) {\n if (event.type === \"connection:opened-stream\") {\n connection = event.detail.connection;\n }\n },\n },\n );\n\n return { stream, connection };\n }\n\n private handleError(cause: unknown, stream?: Stream) {\n const error = asError(cause, \"Pairing operation failed\");\n\n stream?.abort(error);\n this.errorListeners.forEach((listener) => listener(error));\n return error;\n }\n}\n\nexport function pairingService<\n Components extends PairingServiceComponents = PairingServiceComponents,\n>(\n config: PairingServiceConfig,\n canPair: PairingGuard<Components>,\n): (components: Components) => PairingService<Components> {\n return (components: Components) =>\n new (class extends PairingService<Components> {\n protected canPair(peerId: PeerId) {\n return canPair.call(this, peerId);\n }\n })(components, config);\n}\n\nasync function exchange(\n stream: Stream,\n request: PairingRequest,\n options: AbortOptions,\n) {\n const pairingStream = lpStream(stream, {\n maxDataLength: MAX_PAIRING_MESSAGE_LENGTH,\n });\n\n await pairingStream.write(ccc.bytesFrom(JSON.stringify(request), \"utf8\"), {\n signal: options.signal,\n });\n await stream.close(options);\n\n const response = parsePairingResponse(\n (await pairingStream.read(options)).subarray(),\n );\n await stream.closeRead(options);\n return response;\n}\n\nfunction createPairRequest(\n secret: string,\n name: string | undefined,\n addresses: Multiaddr[],\n): PairingRequest {\n const addressStrings = addresses.map((address) => address.toString());\n const request: PairingRequest = {\n type: \"pair\",\n secret,\n name,\n addresses: addressStrings,\n };\n while (addressStrings.length > 0 && !pairingRequestFits(request)) {\n addressStrings.pop();\n }\n\n if (!pairingRequestFits(request)) {\n delete request.addresses;\n }\n if (!pairingRequestFits(request)) {\n delete request.name;\n }\n if (!pairingRequestFits(request)) {\n throw new Error(\"Pairing request is too large\");\n }\n return request;\n}\n\nfunction pairingRequestFits(request: PairingRequest) {\n return (\n ccc.bytesFrom(JSON.stringify(request), \"utf8\").byteLength <=\n MAX_PAIRING_MESSAGE_LENGTH\n );\n}\n\nasync function writeResponse(\n pairingStream: ReturnType<typeof lpStream>,\n stream: Stream,\n response: PairingResponse,\n) {\n await pairingStream.write(ccc.bytesFrom(JSON.stringify(response), \"utf8\"));\n await stream.close();\n}\n\nfunction parsePairingRequest(data: Uint8Array): PairingRequest {\n const request = JSON.parse(\n ccc.bytesTo(data, \"utf8\"),\n ) as Partial<PairingRequest>;\n if (\n request.type === \"pair\" &&\n typeof request.secret === \"string\" &&\n request.secret\n ) {\n return {\n type: \"pair\",\n secret: request.secret,\n name: typeof request.name === \"string\" ? request.name : undefined,\n addresses: parseAddressStrings(request.addresses),\n };\n }\n\n if (request.type === \"unpair\") {\n return { type: \"unpair\" };\n }\n\n throw new Error(\"Invalid pairing request\");\n}\n\nfunction parseAddressStrings(value: unknown): string[] | undefined {\n if (!Array.isArray(value)) {\n return undefined;\n }\n return value.filter(\n (address): address is string =>\n typeof address === \"string\" && address.length > 0,\n );\n}\n\nfunction parseAddresses(values: string[] | undefined, peerId: PeerId) {\n return (values ?? []).flatMap((value) => {\n try {\n const address = multiaddr(value);\n const peer = address\n .getComponents()\n .filter(({ code }) => code === CODE_P2P)\n .at(-1)?.value;\n return peer === peerId.toString() ? [address] : [];\n } catch {\n return [];\n }\n });\n}\n\nfunction parsePairingResponse(data: Uint8Array): PairingResponse {\n const response = JSON.parse(\n ccc.bytesTo(data, \"utf8\"),\n ) as Partial<PairingResponse>;\n if (response.ok === true) {\n return {\n ok: true,\n name: typeof response.name === \"string\" ? response.name : undefined,\n };\n }\n if (response.ok === false && typeof response.error === \"string\") {\n return { ok: false, error: response.error };\n }\n\n throw new Error(\"Invalid pairing response\");\n}\n\nfunction createSecret() {\n return ccc.bytesTo(crypto.getRandomValues(new Uint8Array(16)), \"base64url\");\n}\n\nfunction asError(cause: unknown, fallback: string) {\n return cause instanceof Error ? cause : new Error(fallback);\n}\n","export * from \"./dial.js\";\nexport * from \"./jsonRpcService.js\";\nexport * from \"./jsonRpcTransport.js\";\nexport * from \"./pairingEndpoint.js\";\nexport * from \"./pairingService.js\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"barrel.mjs","names":["DEFAULT_MAX_MESSAGE_LENGTH","DEFAULT_TIMEOUT","asJsonRpcError"],"sources":["../src/dial.ts","../src/jsonRpcService.ts","../src/jsonRpcTransport.ts","../src/pairingEndpoint.ts","../src/pairingService.ts","../src/relayConnection.ts","../src/barrel.ts"],"sourcesContent":["import type { Libp2p, PeerId } from \"@libp2p/interface\";\nimport type { Multiaddr } from \"@multiformats/multiaddr\";\n\nexport async function dialKnownAddresses(\n node: Libp2p,\n peerId: PeerId,\n signal?: AbortSignal,\n) {\n const peer = await node.peerStore.get(peerId);\n // PeerStore may omit the target peer id. Restore it so libp2p can\n // attempt a direct upgrade without force-dialing.\n const addresses = peer.addresses.flatMap(({ multiaddr }) => {\n const address = addressForPeer(multiaddr, peerId);\n return address ? [address] : [];\n });\n if (addresses.length === 0) {\n return;\n }\n\n return signal ? node.dial(addresses, { signal }) : node.dial(addresses);\n}\n\nfunction addressForPeer(address: Multiaddr, peerId: PeerId) {\n const last = address.getComponents().at(-1);\n if (last?.name !== \"p2p\") {\n return address.encapsulate(`/p2p/${peerId.toString()}`);\n }\n return last.value === peerId.toString() ? address : undefined;\n}\n","import { ccc, JsonRpcError } from \"@ckb-ccc/core\";\nimport type { Connection, PeerId, Stream } from \"@libp2p/interface\";\nimport type { Registrar } from \"@libp2p/interface-internal\";\nimport { lpStream } from \"@libp2p/utils\";\n\nconst DEFAULT_MAX_MESSAGE_LENGTH = 1024 * 1024;\nconst DEFAULT_TIMEOUT = 30_000;\n\nexport type JsonRpcServiceComponents = {\n registrar: Registrar;\n};\n\nexport type JsonRpcServiceConfig = {\n protocol: string;\n maxMessageLength?: number;\n timeout?: number;\n};\n\nexport type JsonRpcRequest = {\n connection: Connection;\n peerId: PeerId;\n payload: ccc.JsonRpcPayload;\n /** Aborts if the service times out or the request stream closes. */\n signal: AbortSignal;\n};\n\nexport type JsonRpcRequestHandler<\n Components extends JsonRpcServiceComponents = JsonRpcServiceComponents,\n> = (this: JsonRpcService<Components>, request: JsonRpcRequest) => unknown;\n\nexport abstract class JsonRpcService<\n Components extends JsonRpcServiceComponents = JsonRpcServiceComponents,\n> {\n private readonly errorListeners = new Set<(error: Error) => void>();\n readonly maxMessageLength: number;\n readonly timeout: number;\n\n constructor(\n readonly components: Components,\n readonly config: JsonRpcServiceConfig,\n ) {\n const maxMessageLength =\n config.maxMessageLength ?? DEFAULT_MAX_MESSAGE_LENGTH;\n if (!Number.isSafeInteger(maxMessageLength) || maxMessageLength <= 0) {\n throw new Error(\n \"Maximum JSON-RPC message length must be a positive integer\",\n );\n }\n\n this.maxMessageLength = maxMessageLength;\n\n const timeout = config.timeout ?? DEFAULT_TIMEOUT;\n if (!Number.isSafeInteger(timeout) || timeout <= 0) {\n throw new Error(\"JSON-RPC request timeout must be a positive integer\");\n }\n\n this.timeout = timeout;\n }\n\n protected abstract handleRequest(request: JsonRpcRequest): unknown;\n\n onError(listener: (error: Error) => void) {\n this.errorListeners.add(listener);\n return () => this.errorListeners.delete(listener);\n }\n\n async start() {\n await this.components.registrar.handle(\n this.config.protocol,\n this.handleProtocol.bind(this),\n { runOnLimitedConnection: true },\n );\n }\n\n async stop() {\n await this.components.registrar.unhandle(this.config.protocol);\n }\n\n private async handleProtocol(stream: Stream, connection: Connection) {\n let requestAborted = false;\n const controller = new AbortController();\n const timeoutSignal = AbortSignal.timeout(this.timeout);\n const abortRequest = (event: { error?: Error }) => {\n requestAborted = true;\n const error = new Error(event.error?.message ?? \"JSON-RPC stream closed\");\n error.name = \"AbortError\";\n controller.abort(error);\n };\n const abortTimeout = () => {\n requestAborted = true;\n const error = abortReason(timeoutSignal, \"JSON-RPC request timed out\");\n controller.abort(error);\n stream.abort(error);\n };\n stream.addEventListener(\"close\", abortRequest, { once: true });\n timeoutSignal.addEventListener(\"abort\", abortTimeout, { once: true });\n if (stream.status !== \"open\") {\n abortRequest({});\n }\n\n try {\n const rpcStream = lpStream(stream, {\n maxDataLength: this.maxMessageLength,\n });\n const payload = parseJsonRpcRequest(\n ccc.bytesTo(\n (await rpcStream.read({ signal: controller.signal })).subarray(),\n \"utf8\",\n ),\n );\n\n let response: ccc.JsonRpcResponse;\n try {\n controller.signal.throwIfAborted();\n response = {\n jsonrpc: \"2.0\",\n id: payload.id,\n result: await Promise.race([\n Promise.resolve(\n this.handleRequest({\n connection,\n peerId: connection.remotePeer,\n payload,\n signal: controller.signal,\n }),\n ),\n ccc.abortSignalToPromise(controller.signal),\n ]),\n };\n } catch (cause) {\n requestAborted ||= isAbortError(cause);\n const error = toJsonRpcError(cause);\n response = {\n jsonrpc: \"2.0\",\n id: payload.id,\n error: {\n code: error.code,\n message: error.message,\n data: error.data,\n },\n };\n }\n\n await rpcStream.write(ccc.bytesFrom(JSON.stringify(response), \"utf8\"), {\n signal: controller.signal,\n });\n stream.removeEventListener(\"close\", abortRequest);\n await stream.close({ signal: controller.signal });\n } catch (cause) {\n if (requestAborted) {\n return;\n }\n this.handleError(cause, stream);\n } finally {\n stream.removeEventListener(\"close\", abortRequest);\n timeoutSignal.removeEventListener(\"abort\", abortTimeout);\n }\n }\n\n private handleError(cause: unknown, stream?: Stream) {\n const error = asJsonRpcError(cause);\n\n stream?.abort(error);\n this.errorListeners.forEach((listener) => listener(error));\n return error;\n }\n}\n\nfunction toJsonRpcError(cause: unknown) {\n if (cause instanceof JsonRpcError) {\n return cause;\n }\n\n return new JsonRpcError({\n code: -32603,\n message: asJsonRpcError(cause).message,\n });\n}\n\nfunction parseJsonRpcRequest(data: string) {\n const payload = JSON.parse(data) as Partial<ccc.JsonRpcPayload>;\n if (\n payload?.jsonrpc !== \"2.0\" ||\n (typeof payload.id !== \"number\" && typeof payload.id !== \"string\") ||\n typeof payload.method !== \"string\"\n ) {\n throw new Error(\"Invalid JSON-RPC request\");\n }\n\n return payload as ccc.JsonRpcPayload;\n}\n\nfunction asJsonRpcError(cause: unknown) {\n return cause instanceof Error ? cause : new Error(\"JSON-RPC request failed\");\n}\n\nfunction abortReason(signal: AbortSignal, fallback: string) {\n return signal.reason instanceof Error ? signal.reason : new Error(fallback);\n}\n\nfunction isAbortError(cause: unknown) {\n return (\n cause instanceof Error &&\n (cause.name === \"AbortError\" || cause.name === \"TimeoutError\")\n );\n}\n\nexport function jsonRpcService<\n Components extends JsonRpcServiceComponents = JsonRpcServiceComponents,\n>(\n config: JsonRpcServiceConfig,\n handler: JsonRpcRequestHandler<Components>,\n): (components: Components) => JsonRpcService<Components> {\n return (components: Components) =>\n new (class extends JsonRpcService<Components> {\n protected handleRequest(request: JsonRpcRequest) {\n return handler.call(this, request);\n }\n })(components, config);\n}\n","import { ccc } from \"@ckb-ccc/core\";\nimport type { Connection, Libp2p, PeerId, Stream } from \"@libp2p/interface\";\nimport { lpStream } from \"@libp2p/utils\";\nimport { dialKnownAddresses } from \"./dial.js\";\n\nconst DEFAULT_MAX_MESSAGE_LENGTH = 1024 * 1024;\nconst DEFAULT_TIMEOUT = 30_000;\n\nexport type JsonRpcTransportLibp2pConfig = {\n protocol: string;\n maxMessageLength?: number;\n timeout?: number;\n signal?: AbortSignal;\n onResponse?: (response: ccc.JsonRpcResponse) => void;\n};\n\nexport class JsonRpcTransportLibp2p implements ccc.JsonRpcTransport {\n private readonly maxMessageLength: number;\n private readonly timeout: number;\n\n constructor(\n private readonly node: Libp2p,\n readonly peerId: PeerId,\n private readonly config: JsonRpcTransportLibp2pConfig,\n ) {\n const maxMessageLength =\n config.maxMessageLength ?? DEFAULT_MAX_MESSAGE_LENGTH;\n if (!Number.isSafeInteger(maxMessageLength) || maxMessageLength <= 0) {\n throw new Error(\n \"Maximum JSON-RPC message length must be a positive integer\",\n );\n }\n\n this.maxMessageLength = maxMessageLength;\n\n const timeout = config.timeout ?? DEFAULT_TIMEOUT;\n if (!Number.isSafeInteger(timeout) || timeout <= 0) {\n throw new Error(\"JSON-RPC request timeout must be a positive integer\");\n }\n\n this.timeout = timeout;\n }\n\n async request(\n payload: ccc.JsonRpcPayload,\n options?: ccc.JsonRpcTransportRequestOptions,\n ): Promise<ccc.JsonRpcResponse> {\n const timeoutSignal = AbortSignal.timeout(options?.timeout ?? this.timeout);\n const signals = [this.config.signal, options?.signal, timeoutSignal].filter(\n (signal): signal is AbortSignal => signal !== undefined,\n );\n const signal = ccc.abortSignalAny(signals);\n\n let stream: Stream | undefined;\n let response: ccc.JsonRpcResponse;\n try {\n stream = await this.openStream(signal);\n\n const rpcStream = lpStream(stream, {\n maxDataLength: this.maxMessageLength,\n });\n\n await rpcStream.write(ccc.bytesFrom(JSON.stringify(payload), \"utf8\"), {\n signal,\n });\n await stream.close({ signal });\n\n response = JSON.parse(\n ccc.bytesTo((await rpcStream.read({ signal })).subarray(), \"utf8\"),\n ) as ccc.JsonRpcResponse;\n await stream.closeRead({ signal });\n signal.throwIfAborted();\n } catch (cause) {\n const error = asJsonRpcError(cause);\n stream?.abort(error);\n throw error;\n }\n\n this.config.onResponse?.(response);\n return response;\n }\n\n private async openStream(signal: AbortSignal) {\n void dialKnownAddresses(this.node, this.peerId).catch(() => {\n // This is opportunistic; the current stream can still use relay/fallbacks.\n });\n\n for (const connection of this.connections()) {\n try {\n return await connection.newStream(this.config.protocol, {\n runOnLimitedConnection: true,\n signal,\n });\n } catch {\n signal.throwIfAborted();\n }\n }\n\n return this.node.dialProtocol(this.peerId, this.config.protocol, {\n runOnLimitedConnection: true,\n signal,\n });\n }\n\n private connections() {\n return this.node\n .getConnections(this.peerId)\n .filter(({ status }) => status === \"open\")\n .sort(compareConnections);\n }\n}\n\nfunction compareConnections(a: Connection, b: Connection) {\n if (a.direct !== b.direct) {\n return a.direct ? -1 : 1;\n }\n if (a.rtt === undefined) {\n return b.rtt === undefined ? 0 : 1;\n }\n return b.rtt === undefined ? -1 : a.rtt - b.rtt;\n}\n\nfunction asJsonRpcError(cause: unknown) {\n return cause instanceof Error ? cause : new Error(\"JSON-RPC request failed\");\n}\n","import { ccc } from \"@ckb-ccc/core\";\nimport { multiaddr, type Multiaddr } from \"@multiformats/multiaddr\";\nimport * as lp from \"it-length-prefixed\";\nimport type { PairingTarget } from \"./pairingService.js\";\n\nconst MAX_DECOMPRESSED_ADDRESSES_LENGTH = 16 * 1024;\nconst MAX_ADDRESSES = 16;\nconst PAIRING_PARAMETER_NAMES = [\"addresses\", \"role\", \"secret\"] as const;\n\nexport class PairingEndpointError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"PairingEndpointError\";\n }\n}\n\nexport class PairingEndpointRoleError extends PairingEndpointError {\n constructor(\n readonly expectedRole: string,\n readonly actualRole: string | undefined,\n ) {\n super(\n `Expected a ${expectedRole} pairing endpoint, received ${actualRole ? `role \"${actualRole}\"` : \"an endpoint without a role\"}`,\n );\n this.name = \"PairingEndpointRoleError\";\n }\n}\n\nexport async function encodePairingEndpoint(\n endpointUrl: string,\n addresses: readonly Multiaddr[],\n secret: string,\n role?: string,\n) {\n if (addresses.length === 0) {\n throw new Error(\"Pairing endpoint requires at least one address\");\n }\n if (addresses.length > MAX_ADDRESSES) {\n throw new Error(\n `Pairing endpoint supports at most ${MAX_ADDRESSES} addresses`,\n );\n }\n\n const addressBytes = encodeAddresses(addresses);\n if (addressBytes.byteLength > MAX_DECOMPRESSED_ADDRESSES_LENGTH) {\n throw new Error(\"Pairing endpoint address data is too large\");\n }\n\n const compressedAddressBytes = await transformBytes(\n addressBytes,\n new CompressionStream(\"deflate\"),\n );\n\n const encodedAddresses = ccc.bytesTo(compressedAddressBytes, \"base64url\");\n\n const url = new URL(endpointUrl);\n const { params, route } = fragmentParameters(url);\n\n PAIRING_PARAMETER_NAMES.forEach((name) => {\n params.delete(name);\n });\n if (role) {\n params.set(\"role\", role);\n }\n params.set(\"addresses\", encodedAddresses);\n params.set(\"secret\", secret);\n url.hash = `${route}?${params.toString()}`;\n\n return url.toString();\n}\n\nexport async function decodePairingEndpoint(\n endpoint: string,\n expectedRole?: string,\n): Promise<PairingTarget> {\n let url: URL;\n try {\n url = new URL(endpoint.trim());\n } catch (cause) {\n throw new PairingEndpointError(\"Pairing endpoint is not a valid URL\", {\n cause,\n });\n }\n const { params } = fragmentParameters(url);\n if (expectedRole) {\n const actualRole = params.get(\"role\")?.trim() || undefined;\n if (actualRole !== expectedRole) {\n throw new PairingEndpointRoleError(expectedRole, actualRole);\n }\n }\n const compressedAddresses = params.get(\"addresses\")?.trim();\n const secret = params.get(\"secret\")?.trim();\n\n if (!compressedAddresses || !secret) {\n throw new PairingEndpointError(\"Pairing endpoint is incomplete\");\n }\n\n const addresses = await decodeCompressedAddresses(compressedAddresses);\n\n return { addresses, secret };\n}\n\nfunction fragmentParameters(url: URL) {\n const fragment = url.hash.slice(1);\n const separator = fragment.indexOf(\"?\");\n if (separator === -1) {\n return { params: new URLSearchParams(), route: fragment };\n }\n\n return {\n params: new URLSearchParams(fragment.slice(separator + 1)),\n route: fragment.slice(0, separator),\n };\n}\n\nfunction encodeAddresses(addresses: readonly Multiaddr[]): Uint8Array {\n return ccc.bytesConcat(\n ...lp.encode(addresses.map((address) => address.bytes)),\n );\n}\n\nasync function decodeCompressedAddresses(value: string): Promise<Multiaddr[]> {\n try {\n const compressedBytes = ccc.bytesFrom(value, \"base64url\");\n const bytes = await transformBytes(\n compressedBytes,\n new DecompressionStream(\"deflate\"),\n MAX_DECOMPRESSED_ADDRESSES_LENGTH,\n );\n const addresses: Multiaddr[] = [];\n for (const address of lp.decode([bytes], {\n maxDataLength: MAX_DECOMPRESSED_ADDRESSES_LENGTH,\n })) {\n if (addresses.length >= MAX_ADDRESSES) {\n throw new Error(\"Too many addresses\");\n }\n addresses.push(multiaddr(address.subarray()));\n }\n\n if (addresses.length === 0) {\n throw new Error(\"Missing addresses\");\n }\n return addresses;\n } catch (cause) {\n throw new PairingEndpointError(\n \"Pairing endpoint contains invalid compressed addresses\",\n { cause },\n );\n }\n}\n\nasync function transformBytes(\n bytes: Uint8Array,\n transform: CompressionStream | DecompressionStream,\n maxOutputLength?: number,\n) {\n const readable =\n maxOutputLength === undefined\n ? transform.readable\n : transform.readable.pipeThrough(limitBytes(maxOutputLength));\n const output = new Response(readable).arrayBuffer().then(\n (buffer) => ({ buffer, ok: true }) as const,\n (error: unknown) => ({ error, ok: false }) as const,\n );\n const writer = transform.writable.getWriter();\n try {\n await writer.write(Uint8Array.from(bytes));\n await writer.close();\n } catch (cause) {\n const result = await output;\n if (!result.ok) {\n throw result.error;\n }\n throw cause;\n }\n\n const result = await output;\n if (!result.ok) {\n throw result.error;\n }\n return new Uint8Array(result.buffer);\n}\n\nfunction limitBytes(maxLength: number) {\n let length = 0;\n\n return new TransformStream<Uint8Array, Uint8Array>({\n transform(chunk, controller) {\n if (chunk.byteLength > maxLength - length) {\n throw new Error(\"Decompressed address data is too large\");\n }\n length += chunk.byteLength;\n controller.enqueue(chunk);\n },\n });\n}\n","import { ccc } from \"@ckb-ccc/core\";\nimport type {\n AbortOptions,\n Connection,\n PeerId,\n Stream,\n} from \"@libp2p/interface\";\nimport type { ConnectionManager, Registrar } from \"@libp2p/interface-internal\";\nimport { lpStream } from \"@libp2p/utils\";\nimport type { Multiaddr } from \"@multiformats/multiaddr\";\n\nconst MAX_PAIRING_MESSAGE_LENGTH = 1024;\nconst UNPAIR_TIMEOUT_MS = 10_000;\n\nexport type PairingServiceComponents = {\n connectionManager: ConnectionManager;\n registrar: Registrar;\n};\n\nexport type PairingServiceConfig = {\n /** Optional self-reported label shared with the paired peer. */\n name?: string;\n protocol: string;\n pairedPeerTimeoutMs: number;\n};\n\nexport type PairingTarget = {\n addresses: Multiaddr[];\n secret: string;\n};\n\nexport type PairingGuard<\n Components extends PairingServiceComponents = PairingServiceComponents,\n> = (this: PairingService<Components>, peerId: PeerId) => boolean;\n\ntype PairingRequest =\n { type: \"pair\"; secret: string; name?: string } | { type: \"unpair\" };\n\ntype PairingResponse =\n { ok: true; name?: string } | { ok: false; error: string };\n\nexport abstract class PairingService<\n Components extends PairingServiceComponents = PairingServiceComponents,\n> {\n private currentSecret = createSecret();\n private readonly errorListeners = new Set<(error: Error) => void>();\n private readonly pairedListeners = new Set<\n (peerId: PeerId, name?: string) => void\n >();\n private readonly unpairedListeners = new Set<(peerId: PeerId) => void>();\n private readonly secretChangedListeners = new Set<(secret: string) => void>();\n private readonly pairingTimeouts = new Map<\n string,\n ReturnType<typeof setTimeout>\n >();\n\n constructor(\n readonly components: Components,\n readonly config: PairingServiceConfig,\n ) {\n if (config.pairedPeerTimeoutMs <= 0) {\n throw new Error(\"Paired peer timeout must be greater than zero\");\n }\n }\n\n protected abstract canPair(peerId: PeerId): boolean;\n\n /** The credential to include in the currently issued pairing endpoint. */\n get secret() {\n return this.currentSecret;\n }\n\n onError(listener: (error: Error) => void) {\n this.errorListeners.add(listener);\n return () => this.errorListeners.delete(listener);\n }\n\n onPaired(listener: (peerId: PeerId, name?: string) => void) {\n this.pairedListeners.add(listener);\n return () => this.pairedListeners.delete(listener);\n }\n\n onUnpaired(listener: (peerId: PeerId) => void) {\n this.unpairedListeners.add(listener);\n return () => this.unpairedListeners.delete(listener);\n }\n\n onSecretChanged(listener: (secret: string) => void) {\n this.secretChangedListeners.add(listener);\n return () => this.secretChangedListeners.delete(listener);\n }\n\n async start() {\n await this.components.registrar.handle(\n this.config.protocol,\n this.handleProtocol.bind(this),\n { runOnLimitedConnection: true },\n );\n }\n\n async stop() {\n await this.components.registrar.unhandle(this.config.protocol);\n\n this.pairingTimeouts.forEach((timeout) => clearTimeout(timeout));\n this.pairingTimeouts.clear();\n }\n\n isPaired(peerId: PeerId) {\n return this.pairingTimeouts.has(peerId.toString());\n }\n\n refresh(peerId: PeerId) {\n const key = peerId.toString();\n const timeout = this.pairingTimeouts.get(key);\n if (timeout === undefined) {\n return;\n }\n\n clearTimeout(timeout);\n this.pairingTimeouts.set(key, this.createPeerTimeout(peerId));\n }\n\n async pair(\n target: PairingTarget,\n options: AbortOptions = {},\n ): Promise<PeerId> {\n let stream: Stream | undefined;\n let addedPeer: PeerId | undefined;\n\n try {\n const opened = await this.openStream(target.addresses, options);\n stream = opened.stream;\n\n if (!opened.connection) {\n throw new Error(\"Could not determine remote peer\");\n }\n\n if (this.addPairedPeer(opened.connection.remotePeer)) {\n addedPeer = opened.connection.remotePeer;\n }\n\n const response = await exchange(\n stream,\n createPairRequest(target.secret, this.config.name),\n options,\n );\n options.signal?.throwIfAborted();\n stream = undefined;\n\n if (!response.ok) {\n throw new Error(response.error);\n }\n\n if (addedPeer) {\n this.rotateSecret();\n this.notifyPairedPeer(addedPeer, response.name);\n }\n return opened.connection.remotePeer;\n } catch (cause) {\n if (addedPeer) {\n this.removePairedPeer(addedPeer, false);\n }\n throw this.handleError(cause, stream);\n }\n }\n\n async unpair(peerId: PeerId) {\n if (!this.removePairedPeer(peerId)) {\n return;\n }\n\n const options = { signal: AbortSignal.timeout(UNPAIR_TIMEOUT_MS) };\n\n let stream: Stream | undefined;\n try {\n const opened = await this.openStream(peerId, options);\n stream = opened.stream;\n const response = await exchange(\n opened.stream,\n { type: \"unpair\" },\n options,\n );\n stream = undefined;\n if (!response.ok) {\n throw new Error(response.error);\n }\n } catch (cause) {\n this.handleError(cause, stream);\n }\n }\n\n private async handleProtocol(stream: Stream, connection: Connection) {\n let addedPeer: PeerId | undefined;\n\n try {\n const pairingStream = lpStream(stream, {\n maxDataLength: MAX_PAIRING_MESSAGE_LENGTH,\n });\n const request = parsePairingRequest(\n (await pairingStream.read()).subarray(),\n );\n\n if (request.type === \"unpair\") {\n this.removePairedPeer(connection.remotePeer);\n await writeResponse(pairingStream, stream, { ok: true });\n return;\n }\n\n if (\n request.secret !== this.secret ||\n !this.canPair(connection.remotePeer)\n ) {\n await writeResponse(pairingStream, stream, {\n ok: false,\n error: \"Pairing rejected\",\n });\n return;\n }\n\n // Consume the credential before the next asynchronous boundary so two\n // concurrent requests cannot both pair with the same endpoint.\n this.rotateSecret();\n\n if (this.addPairedPeer(connection.remotePeer)) {\n addedPeer = connection.remotePeer;\n }\n await writeResponse(pairingStream, stream, {\n ok: true,\n name: this.config.name,\n });\n if (addedPeer) {\n this.notifyPairedPeer(addedPeer, request.name);\n }\n } catch (cause) {\n if (addedPeer) {\n this.removePairedPeer(addedPeer, false);\n }\n this.handleError(cause, stream);\n }\n }\n\n private addPairedPeer(peerId: PeerId) {\n const key = peerId.toString();\n const timeout = this.pairingTimeouts.get(key);\n if (timeout !== undefined) {\n clearTimeout(timeout);\n }\n\n this.pairingTimeouts.set(key, this.createPeerTimeout(peerId));\n return timeout === undefined;\n }\n\n private notifyPairedPeer(peerId: PeerId, name?: string) {\n this.pairedListeners.forEach((listener) => listener(peerId, name));\n }\n\n private rotateSecret() {\n this.currentSecret = createSecret();\n this.secretChangedListeners.forEach((listener) =>\n listener(this.currentSecret),\n );\n }\n\n private removePairedPeer(peerId: PeerId, notify = true) {\n const key = peerId.toString();\n const timeout = this.pairingTimeouts.get(key);\n if (timeout === undefined) {\n return false;\n }\n\n clearTimeout(timeout);\n this.pairingTimeouts.delete(key);\n\n if (notify) {\n this.unpairedListeners.forEach((listener) => listener(peerId));\n }\n return true;\n }\n\n private createPeerTimeout(peerId: PeerId) {\n return setTimeout(() => {\n if (\n this.components.connectionManager\n .getConnections(peerId)\n .some(({ status }) => status === \"open\")\n ) {\n this.pairingTimeouts.set(\n peerId.toString(),\n this.createPeerTimeout(peerId),\n );\n return;\n }\n\n this.removePairedPeer(peerId);\n }, this.config.pairedPeerTimeoutMs);\n }\n\n private async openStream(\n target: PeerId | Multiaddr | Multiaddr[],\n options: AbortOptions,\n ) {\n let connection: Connection | undefined;\n const stream = await this.components.connectionManager.openStream(\n target,\n this.config.protocol,\n {\n runOnLimitedConnection: true,\n signal: options.signal,\n onProgress(event) {\n if (event.type === \"connection:opened-stream\") {\n connection = event.detail.connection;\n }\n },\n },\n );\n\n return { stream, connection };\n }\n\n private handleError(cause: unknown, stream?: Stream) {\n const error = asError(cause, \"Pairing operation failed\");\n\n stream?.abort(error);\n this.errorListeners.forEach((listener) => listener(error));\n return error;\n }\n}\n\nexport function pairingService<\n Components extends PairingServiceComponents = PairingServiceComponents,\n>(\n config: PairingServiceConfig,\n canPair: PairingGuard<Components>,\n): (components: Components) => PairingService<Components> {\n return (components: Components) =>\n new (class extends PairingService<Components> {\n protected canPair(peerId: PeerId) {\n return canPair.call(this, peerId);\n }\n })(components, config);\n}\n\nasync function exchange(\n stream: Stream,\n request: PairingRequest,\n options: AbortOptions,\n) {\n const pairingStream = lpStream(stream, {\n maxDataLength: MAX_PAIRING_MESSAGE_LENGTH,\n });\n\n await pairingStream.write(ccc.bytesFrom(JSON.stringify(request), \"utf8\"), {\n signal: options.signal,\n });\n await stream.close(options);\n\n const response = parsePairingResponse(\n (await pairingStream.read(options)).subarray(),\n );\n await stream.closeRead(options);\n return response;\n}\n\nfunction createPairRequest(\n secret: string,\n name: string | undefined,\n): PairingRequest {\n const request: PairingRequest = {\n type: \"pair\",\n secret,\n name,\n };\n if (!pairingRequestFits(request)) {\n delete request.name;\n }\n if (!pairingRequestFits(request)) {\n throw new Error(\"Pairing request is too large\");\n }\n return request;\n}\n\nfunction pairingRequestFits(request: PairingRequest) {\n return (\n ccc.bytesFrom(JSON.stringify(request), \"utf8\").byteLength <=\n MAX_PAIRING_MESSAGE_LENGTH\n );\n}\n\nasync function writeResponse(\n pairingStream: ReturnType<typeof lpStream>,\n stream: Stream,\n response: PairingResponse,\n) {\n await pairingStream.write(ccc.bytesFrom(JSON.stringify(response), \"utf8\"));\n await stream.close();\n}\n\nfunction parsePairingRequest(data: Uint8Array): PairingRequest {\n const request = JSON.parse(\n ccc.bytesTo(data, \"utf8\"),\n ) as Partial<PairingRequest>;\n if (\n request.type === \"pair\" &&\n typeof request.secret === \"string\" &&\n request.secret\n ) {\n return {\n type: \"pair\",\n secret: request.secret,\n name: typeof request.name === \"string\" ? request.name : undefined,\n };\n }\n\n if (request.type === \"unpair\") {\n return { type: \"unpair\" };\n }\n\n throw new Error(\"Invalid pairing request\");\n}\n\nfunction parsePairingResponse(data: Uint8Array): PairingResponse {\n const response = JSON.parse(\n ccc.bytesTo(data, \"utf8\"),\n ) as Partial<PairingResponse>;\n if (response.ok === true) {\n return {\n ok: true,\n name: typeof response.name === \"string\" ? response.name : undefined,\n };\n }\n if (response.ok === false && typeof response.error === \"string\") {\n return { ok: false, error: response.error };\n }\n\n throw new Error(\"Invalid pairing response\");\n}\n\nfunction createSecret() {\n return ccc.bytesTo(crypto.getRandomValues(new Uint8Array(16)), \"base64url\");\n}\n\nfunction asError(cause: unknown, fallback: string) {\n return cause instanceof Error ? cause : new Error(fallback);\n}\n","import { ccc } from \"@ckb-ccc/core\";\nimport type { Connection, Libp2p } from \"@libp2p/interface\";\nimport { multiaddr, type Multiaddr } from \"@multiformats/multiaddr\";\n\nconst DIAL_TIMEOUT_MS = 10_000;\nconst RETRY_DELAYS_MS = [5_000, 10_000, 20_000] as const;\nconst RETRY_REPEAT_MS = 30_000;\n\nexport type RelayConnectionControllerOptions = {\n onConnectionChange?: (connection?: Connection) => void;\n};\n\n/** Maintains a connection to a relay until stopped. */\nexport class RelayConnectionController {\n private readonly controller = new AbortController();\n private readonly addresses: readonly Multiaddr[];\n private selectedAddress?: Multiaddr;\n private connection?: Connection;\n private connecting?: Promise<Connection>;\n\n constructor(\n private readonly node: Libp2p,\n addresses: readonly string[],\n private readonly options: RelayConnectionControllerOptions = {},\n ) {\n if (addresses.length === 0) {\n throw new Error(\"At least one relay address is required\");\n }\n this.addresses = addresses.map((address) => multiaddr(address.trim()));\n node.addEventListener(\"connection:close\", this.handleConnectionClose, {\n signal: this.controller.signal,\n });\n }\n\n connect(): Promise<Connection> {\n this.controller.signal.throwIfAborted();\n if (this.connection?.status === \"open\") {\n return Promise.resolve(this.connection);\n }\n if (this.connecting) {\n return this.connecting;\n }\n\n this.connection = undefined;\n const connecting = ccc\n .retry<Connection>(\n RETRY_DELAYS_MS,\n async ({ resolve }) => {\n return resolve(await this.dialRelay());\n },\n { repeat: RETRY_REPEAT_MS, signal: this.controller.signal },\n )\n .finally(() => {\n if (this.connecting === connecting) {\n this.connecting = undefined;\n }\n if (!this.controller.signal.aborted && !this.connection) {\n void this.connect().catch(() => {});\n }\n });\n this.connecting = connecting;\n return connecting;\n }\n\n async stop() {\n if (this.controller.signal.aborted) {\n return;\n }\n\n this.controller.abort();\n const connection = this.connection;\n this.connection = undefined;\n this.options.onConnectionChange?.();\n await connection?.close();\n }\n\n private async dialRelay() {\n const addresses = this.selectedAddress\n ? [this.selectedAddress]\n : this.addresses;\n let lastError: unknown;\n\n for (const address of addresses) {\n await ccc.waitForAvailability(this.controller.signal);\n let connection: Connection | undefined;\n try {\n connection = await this.node.dial(address, {\n signal: ccc.abortSignalAny([\n this.controller.signal,\n AbortSignal.timeout(DIAL_TIMEOUT_MS),\n ]),\n });\n this.controller.signal.throwIfAborted();\n this.connection = connection;\n if (connection.status !== \"open\") {\n this.connection = undefined;\n throw new Error(\"Relay connection closed while dialing\");\n }\n this.selectedAddress = address;\n this.options.onConnectionChange?.(connection);\n return connection;\n } catch (cause) {\n lastError = cause;\n await connection?.close();\n }\n }\n\n throw lastError;\n }\n\n private readonly handleConnectionClose = (event: CustomEvent<Connection>) => {\n if (event.detail.id !== this.connection?.id) {\n return;\n }\n\n this.connection = undefined;\n this.options.onConnectionChange?.();\n void this.connect().catch(() => {});\n };\n}\n","export * from \"./dial.js\";\nexport * from \"./jsonRpcService.js\";\nexport * from \"./jsonRpcTransport.js\";\nexport * from \"./pairingEndpoint.js\";\nexport * from \"./pairingService.js\";\nexport * from \"./relayConnection.js\";\n"],"mappings":"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"}