@ckb-ccc/libp2p 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @ckb-ccc/libp2p
2
2
 
3
+ ## 0.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#538](https://github.com/ckb-devrel/ccc/pull/538) [`272dd4e`](https://github.com/ckb-devrel/ccc/commit/272dd4e1c4cbd4e2027d78379b92cb25df9f111d) Thanks [@Hanssen0](https://github.com/Hanssen0)! - Show the Khie pairing guidance for every invalid endpoint input instead of
8
+ exposing low-level parsing errors.
9
+
3
10
  ## 0.2.0
4
11
 
5
12
  ### Minor Changes
package/dist/barrel.d.mts CHANGED
@@ -108,7 +108,10 @@ declare abstract class PairingService<Components extends PairingServiceComponent
108
108
  declare function pairingService<Components extends PairingServiceComponents = PairingServiceComponents>(config: PairingServiceConfig, canPair: PairingGuard<Components>): (components: Components) => PairingService<Components>;
109
109
  //#endregion
110
110
  //#region src/pairingEndpoint.d.ts
111
- declare class PairingEndpointRoleError extends Error {
111
+ declare class PairingEndpointError extends Error {
112
+ constructor(message: string, options?: ErrorOptions);
113
+ }
114
+ declare class PairingEndpointRoleError extends PairingEndpointError {
112
115
  readonly expectedRole: string;
113
116
  readonly actualRole: string | undefined;
114
117
  constructor(expectedRole: string, actualRole: string | undefined);
@@ -116,8 +119,8 @@ declare class PairingEndpointRoleError extends Error {
116
119
  declare function encodePairingEndpoint(endpointUrl: string, addresses: readonly Multiaddr[], secret: string, role?: string): Promise<string>;
117
120
  declare function decodePairingEndpoint(endpoint: string, expectedRole?: string): Promise<PairingTarget>;
118
121
  declare namespace barrel_d_exports {
119
- export { JsonRpcRequest, JsonRpcRequestHandler, JsonRpcService, JsonRpcServiceComponents, JsonRpcServiceConfig, JsonRpcTransportLibp2p, JsonRpcTransportLibp2pConfig, PairingEndpointRoleError, PairingGuard, PairingService, PairingServiceComponents, PairingServiceConfig, PairingTarget, decodePairingEndpoint, dialKnownAddresses, encodePairingEndpoint, jsonRpcService, pairingService };
122
+ export { JsonRpcRequest, JsonRpcRequestHandler, JsonRpcService, JsonRpcServiceComponents, JsonRpcServiceConfig, JsonRpcTransportLibp2p, JsonRpcTransportLibp2pConfig, PairingEndpointError, PairingEndpointRoleError, PairingGuard, PairingService, PairingServiceComponents, PairingServiceConfig, PairingTarget, decodePairingEndpoint, dialKnownAddresses, encodePairingEndpoint, jsonRpcService, pairingService };
120
123
  }
121
124
  //#endregion
122
- export { JsonRpcRequest, JsonRpcRequestHandler, JsonRpcService, JsonRpcServiceComponents, JsonRpcServiceConfig, JsonRpcTransportLibp2p, JsonRpcTransportLibp2pConfig, PairingEndpointRoleError, PairingGuard, PairingService, PairingServiceComponents, PairingServiceConfig, PairingTarget, decodePairingEndpoint, dialKnownAddresses, encodePairingEndpoint, jsonRpcService, pairingService, barrel_d_exports as t };
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 };
123
126
  //# 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,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/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"}
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(`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 x(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=w(t);if(a.byteLength>v)throw Error(`Pairing endpoint address data is too large`);let o=await E(a,new CompressionStream(`deflate`)),s=n.bytesTo(o,`base64url`),c=new URL(e),{params:l,route:u}=C(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 S(e,t){let{params:n}=C(new URL(e.trim()));if(t){let e=n.get(`role`)?.trim()||void 0;if(e!==t)throw new b(t,e)}let r=n.get(`addresses`)?.trim(),i=n.get(`secret`)?.trim();if(!r||!i)throw Error(`Pairing endpoint is incomplete`);return{addresses:await T(r),secret:i}}function C(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 w(e){return n.bytesConcat(...o.encode(e.map(e=>e.bytes)))}async function T(e){try{let t=await E(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 Error(`Pairing endpoint contains invalid compressed addresses`,{cause:e})}}async function E(e,t,n){let r=n===void 0?t.readable:t.readable.pipeThrough(D(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 D(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 O=1024;var k=class{constructor(e,t){if(this.components=e,this.config=t,this.currentSecret=z(),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 j(n,M(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 j(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:O}),a=F((await i.read()).subarray());if(a.type===`unpair`){this.removePairedPeer(t.remotePeer),await P(i,e,{ok:!0});return}if(a.secret!==this.secret||!this.canPair(t.remotePeer)){await P(i,e,{ok:!1,error:`Pairing rejected`});return}let o=L(a.addresses,t.remotePeer);this.rotateSecret(),this.addPairedPeer(t.remotePeer)&&(n=t.remotePeer),await P(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=z(),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=B(e,`Pairing operation failed`);return t?.abort(n),this.errorListeners.forEach(e=>e(n)),n}};function A(e,t){return n=>new class extends k{canPair(e){return t.call(this,e)}}(n,e)}async function j(e,t,i){let a=r(e,{maxDataLength:O});await a.write(n.bytesFrom(JSON.stringify(t),`utf8`),{signal:i.signal}),await e.close(i);let o=R((await a.read(i)).subarray());return await e.closeRead(i),o}function M(e,t,n){let r=n.map(e=>e.toString()),i={type:`pair`,secret:e,name:t,addresses:r};for(;r.length>0&&!N(i);)r.pop();if(N(i)||delete i.addresses,N(i)||delete i.name,!N(i))throw Error(`Pairing request is too large`);return i}function N(e){return n.bytesFrom(JSON.stringify(e),`utf8`).byteLength<=O}async function P(e,t,r){await e.write(n.bytesFrom(JSON.stringify(r),`utf8`)),await t.close()}function F(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:I(t.addresses)};if(t.type===`unpair`)return{type:`unpair`};throw Error(`Invalid pairing request`)}function I(e){if(Array.isArray(e))return e.filter(e=>typeof e==`string`&&e.length>0)}function L(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 R(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 z(){return n.bytesTo(crypto.getRandomValues(new Uint8Array(16)),`base64url`)}function B(e,t){return e instanceof Error?e:Error(t)}var V=e({JsonRpcService:()=>l,JsonRpcTransportLibp2p:()=>h,PairingEndpointRoleError:()=>b,PairingService:()=>k,decodePairingEndpoint:()=>S,dialKnownAddresses:()=>s,encodePairingEndpoint:()=>x,jsonRpcService:()=>m,pairingService:()=>A});export{l as JsonRpcService,h as JsonRpcTransportLibp2p,b as PairingEndpointRoleError,k as PairingService,S as decodePairingEndpoint,s as dialKnownAddresses,x as encodePairingEndpoint,m as jsonRpcService,A as pairingService,V 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{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};
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 PairingEndpointRoleError extends Error {\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 const url = new URL(endpoint.trim());\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 Error(\"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 Error(\"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","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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"}
@@ -109,7 +109,10 @@ declare abstract class PairingService<Components extends PairingServiceComponent
109
109
  declare function pairingService<Components extends PairingServiceComponents = PairingServiceComponents>(config: PairingServiceConfig, canPair: PairingGuard<Components>): (components: Components) => PairingService<Components>;
110
110
  //#endregion
111
111
  //#region src/pairingEndpoint.d.ts
112
- declare class PairingEndpointRoleError extends Error {
112
+ declare class PairingEndpointError extends Error {
113
+ constructor(message: string, options?: ErrorOptions);
114
+ }
115
+ declare class PairingEndpointRoleError extends PairingEndpointError {
113
116
  readonly expectedRole: string;
114
117
  readonly actualRole: string | undefined;
115
118
  constructor(expectedRole: string, actualRole: string | undefined);
@@ -117,8 +120,8 @@ declare class PairingEndpointRoleError extends Error {
117
120
  declare function encodePairingEndpoint(endpointUrl: string, addresses: readonly Multiaddr[], secret: string, role?: string): Promise<string>;
118
121
  declare function decodePairingEndpoint(endpoint: string, expectedRole?: string): Promise<PairingTarget>;
119
122
  declare namespace barrel_d_exports {
120
- export { JsonRpcRequest, JsonRpcRequestHandler, JsonRpcService, JsonRpcServiceComponents, JsonRpcServiceConfig, JsonRpcTransportLibp2p, JsonRpcTransportLibp2pConfig, PairingEndpointRoleError, PairingGuard, PairingService, PairingServiceComponents, PairingServiceConfig, PairingTarget, decodePairingEndpoint, dialKnownAddresses, encodePairingEndpoint, jsonRpcService, pairingService };
123
+ export { JsonRpcRequest, JsonRpcRequestHandler, JsonRpcService, JsonRpcServiceComponents, JsonRpcServiceConfig, JsonRpcTransportLibp2p, JsonRpcTransportLibp2pConfig, PairingEndpointError, PairingEndpointRoleError, PairingGuard, PairingService, PairingServiceComponents, PairingServiceConfig, PairingTarget, decodePairingEndpoint, dialKnownAddresses, encodePairingEndpoint, jsonRpcService, pairingService };
121
124
  }
122
125
  //#endregion
123
- export { JsonRpcRequest, JsonRpcRequestHandler, JsonRpcService, JsonRpcServiceComponents, JsonRpcServiceConfig, JsonRpcTransportLibp2p, JsonRpcTransportLibp2pConfig, PairingEndpointRoleError, PairingGuard, PairingService, PairingServiceComponents, PairingServiceConfig, PairingTarget, decodePairingEndpoint, dialKnownAddresses, encodePairingEndpoint, jsonRpcService, pairingService, barrel_d_exports as t };
126
+ 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 };
124
127
  //# sourceMappingURL=barrel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"barrel.d.ts","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,iCAAiC;WAEjC;WACA;EADA,YAAA,sBACA;;iBASS,sBACpB,qBACA,oBAAoB,aACpB,gBACA,gBAAa;iBAuCO,sBACpB,kBACA,wBACC,QAAQ"}
1
+ {"version":3,"file":"barrel.d.ts","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,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,n)=>{let r={};for(var i in e)t(r,i,{get:e[i],enumerable:!0});return n||t(r,Symbol.toStringTag,{value:`Module`}),r},s=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},c=(n,r,o)=>(o=n==null?{}:e(i(n)),s(r||!n||!n.__esModule||!a.call(n,`default`)?t(o,`default`,{value:n,enumerable:!0}):o,n));let l=require("@ckb-ccc/core"),u=require("@libp2p/utils"),d=require("@multiformats/multiaddr"),f=require("it-length-prefixed");f=c(f);async function p(e,t,n){let r=(await e.peerStore.get(t)).addresses.flatMap(({multiaddr:e})=>{let n=m(e,t);return n?[n]:[]});if(r.length!==0)return n?e.dial(r,{signal:n}):e.dial(r)}function m(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 h=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 n=!1;try{let r=(0,u.lpStream)(e,{maxDataLength:this.maxMessageLength}),i=_(l.ccc.bytesTo((await r.read()).subarray(),`utf8`)),a;try{a={jsonrpc:`2.0`,id:i.id,result:await this.handleRequest({connection:t,peerId:t.remotePeer,payload:i})}}catch(e){n=y(e);let t=g(e);a={jsonrpc:`2.0`,id:i.id,error:{code:t.code,message:t.message,data:t.data}}}await r.write(l.ccc.bytesFrom(JSON.stringify(a),`utf8`)),await e.close()}catch(t){if(n)return;this.handleError(t,e)}}handleError(e,t){let n=v(e);return t?.abort(n),this.errorListeners.forEach(e=>e(n)),n}};function g(e){return e instanceof l.JsonRpcError?e:new l.JsonRpcError({code:-32603,message:v(e).message})}function _(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 v(e){return e instanceof Error?e:Error(`JSON-RPC request failed`)}function y(e){return e instanceof Error&&(e.name===`AbortError`||e.name===`TimeoutError`)}function b(e,t){return n=>new class extends h{handleRequest(e){return t.call(this,e)}}(n,e)}var x=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),n=this.config.signal?l.ccc.abortSignalAny([this.config.signal,t]):t,r,i;try{r=await this.openStream(n);let t=(0,u.lpStream)(r,{maxDataLength:this.maxMessageLength});await t.write(l.ccc.bytesFrom(JSON.stringify(e),`utf8`),{signal:n}),await r.close({signal:n}),i=JSON.parse(l.ccc.bytesTo((await t.read({signal:n})).subarray(),`utf8`)),await r.closeRead({signal:n}),n.throwIfAborted()}catch(e){let t=C(e);throw r?.abort(t),t}return this.config.onResponse?.(i),i}async openStream(e){p(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(S)}};function S(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 C(e){return e instanceof Error?e:Error(`JSON-RPC request failed`)}const w=16384,T=[`addresses`,`role`,`secret`];var E=class extends Error{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 D(e,t,n,r){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 i=A(t);if(i.byteLength>w)throw Error(`Pairing endpoint address data is too large`);let a=await M(i,new CompressionStream(`deflate`)),o=l.ccc.bytesTo(a,`base64url`),s=new URL(e),{params:c,route:u}=k(s);return T.forEach(e=>{c.delete(e)}),r&&c.set(`role`,r),c.set(`addresses`,o),c.set(`secret`,n),s.hash=`${u}?${c.toString()}`,s.toString()}async function O(e,t){let{params:n}=k(new URL(e.trim()));if(t){let e=n.get(`role`)?.trim()||void 0;if(e!==t)throw new E(t,e)}let r=n.get(`addresses`)?.trim(),i=n.get(`secret`)?.trim();if(!r||!i)throw Error(`Pairing endpoint is incomplete`);return{addresses:await j(r),secret:i}}function k(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 A(e){return l.ccc.bytesConcat(...f.encode(e.map(e=>e.bytes)))}async function j(e){try{let t=await M(l.ccc.bytesFrom(e,`base64url`),new DecompressionStream(`deflate`),w),n=[];for(let e of f.decode([t],{maxDataLength:w})){if(n.length>=16)throw Error(`Too many addresses`);n.push((0,d.multiaddr)(e.subarray()))}if(n.length===0)throw Error(`Missing addresses`);return n}catch(e){throw Error(`Pairing endpoint contains invalid compressed addresses`,{cause:e})}}async function M(e,t,n){let r=n===void 0?t.readable:t.readable.pipeThrough(N(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 N(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 P=1024;var F=class{constructor(e,t){if(this.components=e,this.config=t,this.currentSecret=G(),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 L(n,R(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 L(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 r=(0,u.lpStream)(e,{maxDataLength:P}),i=V((await r.read()).subarray());if(i.type===`unpair`){this.removePairedPeer(t.remotePeer),await B(r,e,{ok:!0});return}if(i.secret!==this.secret||!this.canPair(t.remotePeer)){await B(r,e,{ok:!1,error:`Pairing rejected`});return}let a=U(i.addresses,t.remotePeer);this.rotateSecret(),this.addPairedPeer(t.remotePeer)&&(n=t.remotePeer),await B(r,e,{ok:!0,name:this.config.name}),n&&(this.notifyPairedPeer(n,i.name),this.openFallbackConnection(a))}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=G(),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=K(e,`Pairing operation failed`);return t?.abort(n),this.errorListeners.forEach(e=>e(n)),n}};function I(e,t){return n=>new class extends F{canPair(e){return t.call(this,e)}}(n,e)}async function L(e,t,n){let r=(0,u.lpStream)(e,{maxDataLength:P});await r.write(l.ccc.bytesFrom(JSON.stringify(t),`utf8`),{signal:n.signal}),await e.close(n);let i=W((await r.read(n)).subarray());return await e.closeRead(n),i}function R(e,t,n){let r=n.map(e=>e.toString()),i={type:`pair`,secret:e,name:t,addresses:r};for(;r.length>0&&!z(i);)r.pop();if(z(i)||delete i.addresses,z(i)||delete i.name,!z(i))throw Error(`Pairing request is too large`);return i}function z(e){return l.ccc.bytesFrom(JSON.stringify(e),`utf8`).byteLength<=P}async function B(e,t,n){await e.write(l.ccc.bytesFrom(JSON.stringify(n),`utf8`)),await t.close()}function V(e){let t=JSON.parse(l.ccc.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:H(t.addresses)};if(t.type===`unpair`)return{type:`unpair`};throw Error(`Invalid pairing request`)}function H(e){if(Array.isArray(e))return e.filter(e=>typeof e==`string`&&e.length>0)}function U(e,t){return(e??[]).flatMap(e=>{try{let n=(0,d.multiaddr)(e);return n.getComponents().filter(({code:e})=>e===d.CODE_P2P).at(-1)?.value===t.toString()?[n]:[]}catch{return[]}})}function W(e){let t=JSON.parse(l.ccc.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 G(){return l.ccc.bytesTo(crypto.getRandomValues(new Uint8Array(16)),`base64url`)}function K(e,t){return e instanceof Error?e:Error(t)}var q=o({JsonRpcService:()=>h,JsonRpcTransportLibp2p:()=>x,PairingEndpointRoleError:()=>E,PairingService:()=>F,decodePairingEndpoint:()=>O,dialKnownAddresses:()=>p,encodePairingEndpoint:()=>D,jsonRpcService:()=>b,pairingService:()=>I});exports.JsonRpcService=h,exports.JsonRpcTransportLibp2p=x,exports.PairingEndpointRoleError=E,exports.PairingService=F,exports.decodePairingEndpoint=O,exports.dialKnownAddresses=p,exports.encodePairingEndpoint=D,exports.jsonRpcService=b,exports.pairingService=I,Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return q}});
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,n)=>{let r={};for(var i in e)t(r,i,{get:e[i],enumerable:!0});return n||t(r,Symbol.toStringTag,{value:`Module`}),r},s=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},c=(n,r,o)=>(o=n==null?{}:e(i(n)),s(r||!n||!n.__esModule||!a.call(n,`default`)?t(o,`default`,{value:n,enumerable:!0}):o,n));let l=require("@ckb-ccc/core"),u=require("@libp2p/utils"),d=require("@multiformats/multiaddr"),f=require("it-length-prefixed");f=c(f);async function p(e,t,n){let r=(await e.peerStore.get(t)).addresses.flatMap(({multiaddr:e})=>{let n=m(e,t);return n?[n]:[]});if(r.length!==0)return n?e.dial(r,{signal:n}):e.dial(r)}function m(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 h=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 n=!1;try{let r=(0,u.lpStream)(e,{maxDataLength:this.maxMessageLength}),i=_(l.ccc.bytesTo((await r.read()).subarray(),`utf8`)),a;try{a={jsonrpc:`2.0`,id:i.id,result:await this.handleRequest({connection:t,peerId:t.remotePeer,payload:i})}}catch(e){n=y(e);let t=g(e);a={jsonrpc:`2.0`,id:i.id,error:{code:t.code,message:t.message,data:t.data}}}await r.write(l.ccc.bytesFrom(JSON.stringify(a),`utf8`)),await e.close()}catch(t){if(n)return;this.handleError(t,e)}}handleError(e,t){let n=v(e);return t?.abort(n),this.errorListeners.forEach(e=>e(n)),n}};function g(e){return e instanceof l.JsonRpcError?e:new l.JsonRpcError({code:-32603,message:v(e).message})}function _(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 v(e){return e instanceof Error?e:Error(`JSON-RPC request failed`)}function y(e){return e instanceof Error&&(e.name===`AbortError`||e.name===`TimeoutError`)}function b(e,t){return n=>new class extends h{handleRequest(e){return t.call(this,e)}}(n,e)}var x=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),n=this.config.signal?l.ccc.abortSignalAny([this.config.signal,t]):t,r,i;try{r=await this.openStream(n);let t=(0,u.lpStream)(r,{maxDataLength:this.maxMessageLength});await t.write(l.ccc.bytesFrom(JSON.stringify(e),`utf8`),{signal:n}),await r.close({signal:n}),i=JSON.parse(l.ccc.bytesTo((await t.read({signal:n})).subarray(),`utf8`)),await r.closeRead({signal:n}),n.throwIfAborted()}catch(e){let t=C(e);throw r?.abort(t),t}return this.config.onResponse?.(i),i}async openStream(e){p(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(S)}};function S(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 C(e){return e instanceof Error?e:Error(`JSON-RPC request failed`)}const w=16384,T=[`addresses`,`role`,`secret`];var E=class extends Error{constructor(e,t){super(e,t),this.name=`PairingEndpointError`}},D=class extends E{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 O(e,t,n,r){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 i=j(t);if(i.byteLength>w)throw Error(`Pairing endpoint address data is too large`);let a=await N(i,new CompressionStream(`deflate`)),o=l.ccc.bytesTo(a,`base64url`),s=new URL(e),{params:c,route:u}=A(s);return T.forEach(e=>{c.delete(e)}),r&&c.set(`role`,r),c.set(`addresses`,o),c.set(`secret`,n),s.hash=`${u}?${c.toString()}`,s.toString()}async function k(e,t){let n;try{n=new URL(e.trim())}catch(e){throw new E(`Pairing endpoint is not a valid URL`,{cause:e})}let{params:r}=A(n);if(t){let e=r.get(`role`)?.trim()||void 0;if(e!==t)throw new D(t,e)}let i=r.get(`addresses`)?.trim(),a=r.get(`secret`)?.trim();if(!i||!a)throw new E(`Pairing endpoint is incomplete`);return{addresses:await M(i),secret:a}}function A(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 j(e){return l.ccc.bytesConcat(...f.encode(e.map(e=>e.bytes)))}async function M(e){try{let t=await N(l.ccc.bytesFrom(e,`base64url`),new DecompressionStream(`deflate`),w),n=[];for(let e of f.decode([t],{maxDataLength:w})){if(n.length>=16)throw Error(`Too many addresses`);n.push((0,d.multiaddr)(e.subarray()))}if(n.length===0)throw Error(`Missing addresses`);return n}catch(e){throw new E(`Pairing endpoint contains invalid compressed addresses`,{cause:e})}}async function N(e,t,n){let r=n===void 0?t.readable:t.readable.pipeThrough(P(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 P(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 F=1024;var I=class{constructor(e,t){if(this.components=e,this.config=t,this.currentSecret=K(),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 R(n,z(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 R(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 r=(0,u.lpStream)(e,{maxDataLength:F}),i=H((await r.read()).subarray());if(i.type===`unpair`){this.removePairedPeer(t.remotePeer),await V(r,e,{ok:!0});return}if(i.secret!==this.secret||!this.canPair(t.remotePeer)){await V(r,e,{ok:!1,error:`Pairing rejected`});return}let a=W(i.addresses,t.remotePeer);this.rotateSecret(),this.addPairedPeer(t.remotePeer)&&(n=t.remotePeer),await V(r,e,{ok:!0,name:this.config.name}),n&&(this.notifyPairedPeer(n,i.name),this.openFallbackConnection(a))}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=K(),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=q(e,`Pairing operation failed`);return t?.abort(n),this.errorListeners.forEach(e=>e(n)),n}};function L(e,t){return n=>new class extends I{canPair(e){return t.call(this,e)}}(n,e)}async function R(e,t,n){let r=(0,u.lpStream)(e,{maxDataLength:F});await r.write(l.ccc.bytesFrom(JSON.stringify(t),`utf8`),{signal:n.signal}),await e.close(n);let i=G((await r.read(n)).subarray());return await e.closeRead(n),i}function z(e,t,n){let r=n.map(e=>e.toString()),i={type:`pair`,secret:e,name:t,addresses:r};for(;r.length>0&&!B(i);)r.pop();if(B(i)||delete i.addresses,B(i)||delete i.name,!B(i))throw Error(`Pairing request is too large`);return i}function B(e){return l.ccc.bytesFrom(JSON.stringify(e),`utf8`).byteLength<=F}async function V(e,t,n){await e.write(l.ccc.bytesFrom(JSON.stringify(n),`utf8`)),await t.close()}function H(e){let t=JSON.parse(l.ccc.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:U(t.addresses)};if(t.type===`unpair`)return{type:`unpair`};throw Error(`Invalid pairing request`)}function U(e){if(Array.isArray(e))return e.filter(e=>typeof e==`string`&&e.length>0)}function W(e,t){return(e??[]).flatMap(e=>{try{let n=(0,d.multiaddr)(e);return n.getComponents().filter(({code:e})=>e===d.CODE_P2P).at(-1)?.value===t.toString()?[n]:[]}catch{return[]}})}function G(e){let t=JSON.parse(l.ccc.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 K(){return l.ccc.bytesTo(crypto.getRandomValues(new Uint8Array(16)),`base64url`)}function q(e,t){return e instanceof Error?e:Error(t)}var J=o({JsonRpcService:()=>h,JsonRpcTransportLibp2p:()=>x,PairingEndpointError:()=>E,PairingEndpointRoleError:()=>D,PairingService:()=>I,decodePairingEndpoint:()=>k,dialKnownAddresses:()=>p,encodePairingEndpoint:()=>O,jsonRpcService:()=>b,pairingService:()=>L});exports.JsonRpcService=h,exports.JsonRpcTransportLibp2p=x,exports.PairingEndpointError=E,exports.PairingEndpointRoleError=D,exports.PairingService=I,exports.decodePairingEndpoint=k,exports.dialKnownAddresses=p,exports.encodePairingEndpoint=O,exports.jsonRpcService=b,exports.pairingService=L,Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return J}});
2
2
  //# sourceMappingURL=barrel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"barrel.js","names":["DEFAULT_MAX_MESSAGE_LENGTH","lpStream","ccc","asJsonRpcError","JsonRpcError","ccc","lpStream","ccc","lp","multiaddr","lpStream","ccc","multiaddr","CODE_P2P"],"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 PairingEndpointRoleError extends Error {\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 const url = new URL(endpoint.trim());\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 Error(\"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 Error(\"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.js","names":["DEFAULT_MAX_MESSAGE_LENGTH","lpStream","ccc","asJsonRpcError","JsonRpcError","ccc","lpStream","ccc","lp","multiaddr","lpStream","ccc","multiaddr","CODE_P2P"],"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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ckb-ccc/libp2p",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "CCC support for libp2p",
5
5
  "author": "Hanssen0 <0@hanssen0.com>",
6
6
  "license": "MIT",
@@ -7,7 +7,14 @@ const MAX_DECOMPRESSED_ADDRESSES_LENGTH = 16 * 1024;
7
7
  const MAX_ADDRESSES = 16;
8
8
  const PAIRING_PARAMETER_NAMES = ["addresses", "role", "secret"] as const;
9
9
 
10
- export class PairingEndpointRoleError extends Error {
10
+ export class PairingEndpointError extends Error {
11
+ constructor(message: string, options?: ErrorOptions) {
12
+ super(message, options);
13
+ this.name = "PairingEndpointError";
14
+ }
15
+ }
16
+
17
+ export class PairingEndpointRoleError extends PairingEndpointError {
11
18
  constructor(
12
19
  readonly expectedRole: string,
13
20
  readonly actualRole: string | undefined,
@@ -66,7 +73,14 @@ export async function decodePairingEndpoint(
66
73
  endpoint: string,
67
74
  expectedRole?: string,
68
75
  ): Promise<PairingTarget> {
69
- const url = new URL(endpoint.trim());
76
+ let url: URL;
77
+ try {
78
+ url = new URL(endpoint.trim());
79
+ } catch (cause) {
80
+ throw new PairingEndpointError("Pairing endpoint is not a valid URL", {
81
+ cause,
82
+ });
83
+ }
70
84
  const { params } = fragmentParameters(url);
71
85
  if (expectedRole) {
72
86
  const actualRole = params.get("role")?.trim() || undefined;
@@ -78,7 +92,7 @@ export async function decodePairingEndpoint(
78
92
  const secret = params.get("secret")?.trim();
79
93
 
80
94
  if (!compressedAddresses || !secret) {
81
- throw new Error("Pairing endpoint is incomplete");
95
+ throw new PairingEndpointError("Pairing endpoint is incomplete");
82
96
  }
83
97
 
84
98
  const addresses = await decodeCompressedAddresses(compressedAddresses);
@@ -128,9 +142,10 @@ async function decodeCompressedAddresses(value: string): Promise<Multiaddr[]> {
128
142
  }
129
143
  return addresses;
130
144
  } catch (cause) {
131
- throw new Error("Pairing endpoint contains invalid compressed addresses", {
132
- cause,
133
- });
145
+ throw new PairingEndpointError(
146
+ "Pairing endpoint contains invalid compressed addresses",
147
+ { cause },
148
+ );
134
149
  }
135
150
  }
136
151