@robota-sdk/agent-transport-webrtc 3.0.0-beta.100

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/CHANGELOG.md +694 -0
  2. package/LICENSE +661 -0
  3. package/README.md +111 -0
  4. package/dist/node/index.cjs +1 -0
  5. package/dist/node/index.d.cts +1650 -0
  6. package/dist/node/index.d.cts.map +1 -0
  7. package/dist/node/index.d.ts +1650 -0
  8. package/dist/node/index.d.ts.map +1 -0
  9. package/dist/node/index.js +2 -0
  10. package/dist/node/index.js.map +1 -0
  11. package/package.json +93 -0
  12. package/src/__tests__/admission-secure-by-default.test.ts +63 -0
  13. package/src/__tests__/admission-steps.test.ts +46 -0
  14. package/src/__tests__/device-mesh-relay.test.ts +441 -0
  15. package/src/__tests__/device-mesh.test.ts +682 -0
  16. package/src/__tests__/discovering-mesh-relay.test.ts +234 -0
  17. package/src/__tests__/enrollment-link.test.ts +103 -0
  18. package/src/__tests__/fake-datachannel.ts +83 -0
  19. package/src/__tests__/handoff-grant-gate.test.ts +403 -0
  20. package/src/__tests__/local-peer-proof-gate.test.ts +215 -0
  21. package/src/__tests__/mesh-admission-contract.test.ts +38 -0
  22. package/src/__tests__/mesh-discovery.test.ts +820 -0
  23. package/src/__tests__/mesh-fixtures.ts +148 -0
  24. package/src/__tests__/mesh-internet.test.ts +942 -0
  25. package/src/__tests__/mesh-turn-relay.test.ts +161 -0
  26. package/src/__tests__/negotiated-certificate.test.ts +76 -0
  27. package/src/__tests__/nostr-source-condition.test.ts +27 -0
  28. package/src/__tests__/operator-approval-gate.test.ts +308 -0
  29. package/src/__tests__/outbound-delivery-carrier.test.ts +155 -0
  30. package/src/__tests__/pairing-e2e.test.ts +237 -0
  31. package/src/__tests__/pairing-gate-e3.test.ts +194 -0
  32. package/src/__tests__/pairing-gate-e4.test.ts +110 -0
  33. package/src/__tests__/pairing-gate.test.ts +296 -0
  34. package/src/__tests__/pairing-relay-in-the-middle.test.ts +225 -0
  35. package/src/__tests__/rtc-channel-close.test.ts +52 -0
  36. package/src/__tests__/rtc-peer-candidates.test.ts +61 -0
  37. package/src/__tests__/session-attachment-app-view.test.ts +66 -0
  38. package/src/__tests__/session-attachment-budget.test.ts +136 -0
  39. package/src/__tests__/turn-server-bind.test.ts +59 -0
  40. package/src/__tests__/turn-server.test.ts +335 -0
  41. package/src/__tests__/turn-test-client.ts +256 -0
  42. package/src/__tests__/webrtc-implementation.test.ts +83 -0
  43. package/src/__tests__/webrtc-transport.test.ts +349 -0
  44. package/src/__tests__/ws-mesh-relay-client.test.ts +95 -0
  45. package/src/__tests__/ws-signaling-client.test.ts +108 -0
  46. package/src/admission-steps.ts +55 -0
  47. package/src/channel-delivery.ts +44 -0
  48. package/src/datachannel-loader.ts +86 -0
  49. package/src/device-mesh-node.ts +1019 -0
  50. package/src/discovering-mesh-relay.ts +675 -0
  51. package/src/enrollment-link.ts +465 -0
  52. package/src/handoff-grant-gate.ts +186 -0
  53. package/src/index.ts +139 -0
  54. package/src/local-peer-proof.ts +135 -0
  55. package/src/mainline-dht-store.ts +174 -0
  56. package/src/mesh-dht.ts +446 -0
  57. package/src/mesh-discovery.ts +87 -0
  58. package/src/mesh-item-store.ts +287 -0
  59. package/src/mesh-lan-listener.ts +193 -0
  60. package/src/mesh-mdns.ts +406 -0
  61. package/src/mesh-peer-link.ts +600 -0
  62. package/src/mesh-public-relays.ts +25 -0
  63. package/src/mesh-records.ts +357 -0
  64. package/src/mesh-relay.ts +98 -0
  65. package/src/mesh-signal.ts +116 -0
  66. package/src/mesh-turn-relay.ts +238 -0
  67. package/src/negotiated-certificate.ts +72 -0
  68. package/src/nostr-mesh-relay.ts +391 -0
  69. package/src/pairing-channel-lifecycle.ts +31 -0
  70. package/src/pairing-controllers.ts +81 -0
  71. package/src/pairing-frames.ts +34 -0
  72. package/src/pairing-gate-options.ts +133 -0
  73. package/src/pairing-gate.ts +397 -0
  74. package/src/rtc-peer.ts +429 -0
  75. package/src/session-attachment.ts +96 -0
  76. package/src/signaling.ts +62 -0
  77. package/src/stun-message.ts +341 -0
  78. package/src/transport-lifecycle-error.ts +11 -0
  79. package/src/turn-server.ts +1028 -0
  80. package/src/webrtc-delivery-lifecycle.ts +54 -0
  81. package/src/webrtc-transport-options.ts +87 -0
  82. package/src/webrtc-transport.ts +368 -0
  83. package/src/ws-mesh-relay-client.ts +117 -0
  84. package/src/ws-signaling-client.ts +139 -0
package/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # @robota-sdk/agent-transport-webrtc
2
+
3
+ WebRTC peer-to-peer transport for the Robota SDK (Node.js). `WebRtcTransport` carries an agent runtime
4
+ session over an `RTCDataChannel`, so a remote client can drive a live session directly, peer to
5
+ peer, without session content passing through a server. It reuses the transport-neutral session
6
+ bridge and wire protocol from `@robota-sdk/agent-transport`, the same ones the WebSocket transport
7
+ uses. The package also contains the building blocks for connecting one user's devices to each other
8
+ (the device mesh): peer discovery and signaling, device enrollment and a TURN relay.
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ npm install @robota-sdk/agent-transport-webrtc @robota-sdk/agent-transport node-datachannel
14
+ ```
15
+
16
+ Requires Node.js 22.12 or later. The WebRTC implementation, `node-datachannel` (libdatachannel, a
17
+ native module), is an optional peer dependency loaded lazily. If it is not installed or has no
18
+ prebuilt binary for the platform, `start()` fails with an explicit `WebRTC transport unavailable`
19
+ error; there is no fallback implementation. `@robota-sdk/agent-transport` provides the
20
+ `IProtocolSession` type used below.
21
+
22
+ ## Usage
23
+
24
+ ```typescript
25
+ import { WebRtcTransport, WsSignalingClient } from '@robota-sdk/agent-transport-webrtc';
26
+ import type { IProtocolSession } from '@robota-sdk/agent-transport';
27
+
28
+ declare const session: IProtocolSession; // e.g. a live interactive session
29
+ declare const pairingSecret: string; // shared with the remote client out of band
30
+
31
+ const signaling = new WsSignalingClient({
32
+ url: 'wss://signaling.example.com',
33
+ rendezvous: 'my-rendezvous-id',
34
+ onError: (error) => console.error(error),
35
+ });
36
+
37
+ const transport = new WebRtcTransport({
38
+ signaling,
39
+ secret: pairingSecret,
40
+ onPaired: () => console.log('remote client paired'),
41
+ onPairingFailed: () => console.log('pairing failed; channel closed'),
42
+ });
43
+
44
+ transport.attach(session);
45
+ await transport.start(); // the host is the offerer: creates the peer and data channel, sends the offer
46
+ // ...
47
+ await transport.stop();
48
+ ```
49
+
50
+ Admission is decided at construction. With `secret`, the data channel carries only pairing frames
51
+ until the pairing handshake from `@robota-sdk/agent-remote-pairing` accepts, bound to the DTLS
52
+ fingerprints of the connection; only then is the session exposed, and a mismatch or timeout closes
53
+ the channel. To run without pairing (for example over loopback in tests), pass
54
+ `{ open: true, openReason: '<why this is safe>' }` instead. The constructor throws when neither is
55
+ given, or when both are.
56
+
57
+ Signaling is an injected port (`ISignalingClient`) that only carries SDP offers/answers and ICE
58
+ candidates, never session content. `createInMemorySignalingPair()` wires two in-process clients
59
+ together for tests; `WsSignalingClient` joins a rendezvous on a WebSocket signaling relay.
60
+
61
+ ## `WebRtcTransport` options
62
+
63
+ | Option | Type | Description |
64
+ | ------------------------------------------------------------------------ | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
65
+ | `signaling` | `ISignalingClient` | Required. Exchanges SDP/ICE with the remote peer. |
66
+ | `secret` | `string` | Pairing secret; gates the data channel until the pairing handshake accepts. |
67
+ | `open` / `openReason` | `boolean` / `string` | Runs without a pairing gate; `openReason` must say why. |
68
+ | `iceServers` | `readonly IIceServer[]` | STUN/TURN servers. Omitted: host candidates only. |
69
+ | `forceTurn` | `boolean` | Restricts ICE to relay (TURN) candidates; needs a TURN server in `iceServers`. |
70
+ | `onPaired` / `onPairingFailed` | callbacks | Called when pairing accepts (session exposed) or rejects/times out (channel closed). |
71
+ | `reconnect` | `IHostReconnectConfig` | With `secret`: admits either a first pairing (with device enrollment) or a pinned-device reconnect. |
72
+ | `connectionApproval` | `IConnectionApproval` | With `secret`: asks an operator to approve each connection before it reaches the session. |
73
+ | `localPeer` | `ILocalPeerProof` | With `secret`: also requires a nonce issued at a guarded local rendezvous. |
74
+ | `resumeBridge` / `onDropped` | `SessionResumeBridge` / callback | With `secret`: `resumeBridge` carries the paired session across channel drops; `onDropped` is called when a paired channel drops. |
75
+ | `onDeliveryError` | callback | Observes an outbound delivery failure before the channel is dropped. |
76
+ | `personalUsageReporter` / `usageReporter` / `storedSessionUsageReporter` | reporters | Host-owned usage read models, available to the peer only after admission. |
77
+
78
+ `start()` before `attach()` throws; `stop()` is safe to call more than once, and starting again
79
+ requires attaching again.
80
+
81
+ ## Other exports
82
+
83
+ - Peers: `RtcPeer`, `RtcChannel` and `loadDataChannel`, one peer connection over `node-datachannel`.
84
+ - Device mesh: `DeviceMeshNode` connects one user's devices, admitted by the device handshake.
85
+ Discovery and signaling for it: `DiscoveringMeshRelay`, `MeshMdns`, `MeshDht`, `NostrMeshRelay`,
86
+ `WsMeshRelayClient`, `startLanMeshRelay`.
87
+ - Relay: `TurnServer` and `MeshTurnRelay`, a TURN relay one of the user's devices can run for its
88
+ paired devices.
89
+ - Enrollment: `dialEnrollment` and `listenForEnrollment` open the channel used to enroll a new
90
+ device; they fail with `EnrollmentLinkError`.
91
+ - Admission frames: `localProofFrame` (the local-peer nonce) and `handoffGrantFrame` /
92
+ `judgeHandoffGrant` (a signed cross-device hand-off grant, verified by a host-supplied verifier).
93
+
94
+ ## Related packages
95
+
96
+ - [`@robota-sdk/agent-transport`](../agent-transport/README.md): the transport-neutral session
97
+ bridge and wire protocol this transport carries.
98
+ - [`@robota-sdk/agent-remote-pairing`](../agent-remote-pairing/README.md): the pairing handshake and
99
+ DTLS-fingerprint channel binding the pairing gate uses.
100
+ - [`@robota-sdk/agent-transport-ws`](../agent-transport-ws/README.md): the WebSocket transport for
101
+ the same protocol.
102
+ - [`@robota-sdk/agent-transport-webrtc-web`](../agent-transport-webrtc-web/README.md): the browser
103
+ peer that answers this transport's offer (internal).
104
+
105
+ For how the agent runtime CLI uses this for remote control and connecting your own devices, see the
106
+ [devices and remote access guide](../../content/guide/devices-and-remote.md). See
107
+ [docs/SPEC.md](docs/SPEC.md) for the package contract.
108
+
109
+ ## License
110
+
111
+ This package is dual-licensed under the [GNU AGPL-3.0](../../LICENSE) or a [commercial license](../../COMMERCIAL.md). See [LICENSING.md](../../LICENSING.md).
@@ -0,0 +1 @@
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,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},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require("@robota-sdk/agent-transport"),l=require("@robota-sdk/agent-transport/node"),u=require("@robota-sdk/agent-remote-pairing"),d=require("node:module"),f=require("ws");f=s(f,1);let ee=require("@robota-sdk/agent-interface-session-mobility"),p=require("node:crypto"),te=require("node:dgram"),m=require("node:net"),h=require("node:os"),ne=require("nostr-tools/pool"),g=require("nostr-tools/pure");function re(e,t){return(0,c.createOutboundDelivery)(t=>e.send(JSON.stringify(t)),(e,n)=>t(e,n),()=>e.bufferedAmount)}const ie=/^[0-9A-F]{2}(?::[0-9A-F]{2})+$/;function _(e,t,n,r){let i=!1,a=()=>{if(i)return;i=!0;let a=e.remoteFingerprint();if(a===void 0){r(`the DTLS layer exposed no remote certificate`);return}let o=a.value.toUpperCase();if(a.algorithm.toLowerCase()!==t.toLowerCase()){r(`the remote certificate was checked with ${a.algorithm}, not ${t}`);return}if(!ie.test(o)){r(`the remote certificate fingerprint is malformed`);return}n(o)},o=e=>{i||(i=!0,r(`the connection ended ${e} before DTLS completed`))};if(e.state===`connected`)return a(),()=>void 0;if(e.state===`failed`||e.state===`closed`)return o(e.state),()=>void 0;let s=e.onStateChange(e=>{if(e===`connected`)a();else if(e===`failed`||e===`closed`)o(e);else return;s()});return s}const ae=e=>(0,d.createRequire)(require("url").pathToFileURL(__filename).href)(e);function oe(e=ae){try{let t=e(`node-datachannel`);if(typeof t?.PeerConnection!=`function`)throw Error(`no PeerConnection export`);return t}catch{throw Error(`WebRTC transport unavailable — the optional dependency "node-datachannel" is not installed or has no prebuilt binary for this platform (${process.platform}-${process.arch}).`)}}function v(e){try{return e?.()}catch{return}}function se(e){return e instanceof Error?e.message:String(e)}const ce={stun:3478,turn:3478,turns:5349};function le(e){let t=/^(stuns?|turns?):([^:?]+|\[[^\]]+\])(?::(\d{1,5}))?(?:\?transport=(udp|tcp))?$/i.exec(e.urls);if(!t)throw Error(`unsupported ICE server url: ${e.urls}`);let n=t[1].toLowerCase(),r=t[2].replace(/^\[|\]$/g,``),i=t[3]===void 0?ce[n]??3478:Number(t[3]);return n===`stun`||n===`stuns`?`stun:${r}:${i}`:{hostname:r,port:i,...e.username===void 0?{}:{username:e.username},...e.credential===void 0?{}:{password:e.credential},relayType:n===`turns`?`TurnTls`:t[4]?.toLowerCase()===`tcp`?`TurnTcp`:`TurnUdp`}}function ue(e){return typeof e==`string`?e:Buffer.from(e).toString(`utf8`)}var y=class{native;fault;stateValue;closeCauseValue;closedLocally=!1;messageHandlers=new Set;stateHandlers=new Set;constructor(e,t){this.native=e,this.fault=t,this.stateValue=e.isOpen()?`open`:`connecting`,e.onOpen(()=>this.guard(()=>this.setState(`open`))),e.onClosed(()=>this.guard(()=>this.closedWith(`closed by the peer or the transport`))),e.onError(e=>this.guard(()=>this.closedWith(`error: ${e}`))),e.onMessage(e=>this.guard(()=>{if(this.closedLocally)return;let t=ue(e);for(let e of this.messageHandlers)e(t)}))}guard(e){try{e()}catch(e){this.closeCauseValue??=`handler error: ${se(e)}`,this.fault(e)}}closedWith(e){this.closeCauseValue??=e,this.setState(`closed`)}get closeCause(){return this.closeCauseValue}setState(e){if(this.stateValue!==e&&this.stateValue!==`closed`){this.stateValue=e;for(let t of this.stateHandlers)t(e)}}get readyState(){return this.stateValue}get label(){try{return this.native.getLabel?.()??``}catch{return``}}get bufferedAmount(){try{return this.native.bufferedAmount()}catch{return 0}}send(e){if(this.stateValue!==`open`)throw Error(`data channel is not open`);this.native.sendMessage(e)}onMessage(e){return this.messageHandlers.add(e),()=>this.messageHandlers.delete(e)}onStateChange(e){return this.stateHandlers.add(e),()=>this.stateHandlers.delete(e)}close(){if(this.stateValue===`closed`)return;this.closedLocally=!0;let e=this.native;setTimeout(()=>{try{e.close()}catch{}},250).unref?.(),this.closedWith(`closed by this side`)}},b=class{native;stateValue=`new`;stateHandlers=new Set;candidateHandlers=new Set;channelHandlers=new Set;descriptionWaiters=[];hasRemoteDescription=!1;history=[];closedBy;handlerError;localCandidateCount=0;remoteCandidateCount=0;heldLocalCandidates=[];earlyCandidates=[];closed=!1;constructor(e={}){let t=(e.loadDataChannel??oe)();this.native=new t.PeerConnection(`agent`,{iceServers:(e.iceServers??[]).map(le),...e.forceTurn===!0?{iceTransportPolicy:`relay`}:{},disableAutoNegotiation:!0}),this.native.onStateChange(e=>this.guard(()=>{if(e!==this.stateValue&&this.stateValue!==`closed`){this.stateValue=e,this.remember(this.stateValue);for(let e of this.stateHandlers)e(this.stateValue)}})),this.native.onLocalCandidate((e,t)=>this.guard(()=>{let n=e.startsWith(`a=`)?e.slice(2):e;if(n.length!==0){if(!this.hasRemoteDescription){this.heldLocalCandidates.push({candidate:n,mid:t});return}this.handOut({candidate:n,mid:t})}})),this.native.onLocalDescription(e=>this.guard(()=>{for(let t of this.descriptionWaiters.splice(0))t(e)})),this.native.onDataChannel(e=>this.guard(()=>{let t=new y(e,e=>this.fault(e));for(let e of this.channelHandlers)e(t)}))}guard(e){try{e()}catch(e){this.fault(e)}}fault(e){this.closed||(this.closedBy=`handler-error`,this.handlerError=se(e),this.close())}remember(e){this.history.length<16&&this.history.push(e)}diagnostics(){let e=v(this.native.iceState?.bind(this.native)),t=v(this.native.gatheringState?.bind(this.native)),n=v(this.native.signalingState?.bind(this.native));return{state:this.stateValue,...e===void 0?{}:{ice:e},...t===void 0?{}:{gathering:t},...n===void 0?{}:{signaling:n},history:[...this.history],...this.closedBy===void 0?{}:{closedBy:this.closedBy},...this.handlerError===void 0?{}:{handlerError:this.handlerError},localCandidates:this.localCandidateCount,remoteCandidates:this.remoteCandidateCount}}get state(){return this.stateValue}createDataChannel(e){return new y(this.native.createDataChannel(e),e=>this.fault(e))}localDescription(e){return new Promise((t,n)=>{this.descriptionWaiters.push(t);try{this.native.setLocalDescription(e)}catch(e){let r=this.descriptionWaiters.indexOf(t);r>=0&&this.descriptionWaiters.splice(r,1),n(e instanceof Error?e:Error(String(e)))}})}createOffer(){return this.localDescription(`offer`)}async acceptOffer(e){return this.native.setRemoteDescription(e,`offer`),this.remoteDescriptionApplied(),this.localDescription(`answer`)}acceptAnswer(e){this.native.setRemoteDescription(e,`answer`),this.remoteDescriptionApplied()}remoteDescriptionApplied(){this.hasRemoteDescription=!0;for(let e of this.earlyCandidates.splice(0))this.addRemoteCandidate(e);let e=this.heldLocalCandidates.splice(0);this.guard(()=>{for(let t of e)this.handOut(t)})}handOut(e){if(!this.closed){this.localCandidateCount+=1;for(let t of this.candidateHandlers)t(e)}}addRemoteCandidate(e){if(!this.closed){if(!this.hasRemoteDescription){this.earlyCandidates.length<64&&this.earlyCandidates.push(e);return}try{this.native.addRemoteCandidate(e.candidate,e.mid),this.remoteCandidateCount+=1}catch{}}}remoteFingerprint(){if(this.stateValue===`connected`)try{let e=this.native.remoteFingerprint();return e.value.length>0?e:void 0}catch{return}}onStateChange(e){return this.stateHandlers.add(e),()=>this.stateHandlers.delete(e)}onLocalCandidate(e){return this.candidateHandlers.add(e),()=>this.candidateHandlers.delete(e)}onDataChannel(e){return this.channelHandlers.add(e),()=>this.channelHandlers.delete(e)}close(){if(!this.closed){this.closed=!0,this.closedBy??=`local`;try{this.native.close()}catch{}if(this.stateValue!==`closed`){this.stateValue=`closed`,this.remember(`closed`);for(let e of this.stateHandlers)e(`closed`)}}}};function de(e,t){let n=t===`operator-approval`;return e.localPeer!==void 0&&t!==`local-proof`&&t!==`handoff-grant`&&!n?`local-proof`:e.handoffGrant!==void 0&&t!==`handoff-grant`&&!n?`handoff-grant`:e.connectionApproval!==void 0&&!n?`operator-approval`:null}function fe(e){return typeof e==`object`&&!!e&&e.t===`handoff-grant`&&e.grant!==void 0}function x(e){return{admitted:!1,trust:`unproven`,reason:e}}async function pe(e,t){if(t===void 0)return x(`no hand-off grant verifier is configured for this channel`);if(!fe(e))return x(`expected a handoff-grant frame carrying the signed grant`);try{let n=await t.verify(e.grant);return n.admitted&&n.trust===`same-user-same-host`?x(`the grant verifier returned same-user-same-host. A cross-device grant proves the user, not the machine — see SEC-010 for what same-host requires.`):!n.admitted||t.consent===void 0||await t.consent(n)?n:x(`the person at this machine declined the transfer`)}catch(e){return x(`the grant verifier could not decide: ${e instanceof Error?e.message:`unknown error`}`)}}function me(e){return{t:`handoff-grant`,grant:e}}function he(e){return typeof e==`object`&&!!e&&e.t===`local-proof`&&typeof e.nonce==`string`}function S(e){return{admitted:!1,trust:`unproven`,reason:e}}function ge(e,t){if(t===void 0)return S(`no local-peer proof is configured for this channel`);if(!he(e))return S(`expected a local-proof frame carrying the rendezvous nonce`);try{return t.redeem(e.nonce)}catch(e){return S(`the rendezvous ledger could not decide: ${e instanceof Error?e.message:`unknown error`}`)}}function _e(e){return{t:`local-proof`,nonce:e}}function ve(e,t){try{e.send(t)}catch{}}function ye(e){try{e.close()}catch{}}function be(e,t,n){try{e?.(t,n)}catch{}}const C=Object.freeze({send:ve,close:ye,reportDeliveryError:be});function xe(e,t,n,r,i,a=u.startPairingHandshake){let o=a(e.cryptoContext,{secret:t,role:n,localFingerprint:e.localFingerprint,remoteFingerprint:e.remoteFingerprint,send:t=>C.send(e.channel,JSON.stringify(t)),...e.timeoutMs===void 0?{}:{timeoutMs:e.timeoutMs}});return o.result.then(r,i),o}function Se(e,t,n,r){let i=(0,u.startHostReconnect)(e.cryptoContext,{hostIdentityId:t.hostIdentityId,localFingerprint:e.localFingerprint,remoteFingerprint:e.remoteFingerprint,hostPrivateKey:t.hostPrivateKey,resolveDevicePublicKey:t.resolveDevicePublicKey,send:t=>C.send(e.channel,JSON.stringify(t)),...e.timeoutMs===void 0?{}:{timeoutMs:e.timeoutMs}});return i.result.then(n,r),i}function Ce(e){return(0,u.decodePairingFrame)(e).ok}function we(e){return(0,u.decodeReconnectFrame)(e).ok}function Te(e){return(0,u.decodeEnrollFrame)(e).ok}function Ee(e,t,n){let r=e.resumeBridge;if(r)return r.attach(t=>e.channel.send(t),{awaitResume:t,onDeliveryError:n,pendingBytes:()=>e.channel.bufferedAmount}),{onSessionMessage:e=>r.onClientMessage(e),cleanup:()=>r.detach()};let{onMessage:i,cleanup:a}=(e.createHandler??c.createSessionMessageHandler)({session:e.session,deliver:re(e.channel,n),maxFrameBytes:c.HISTORY_PAGE_MAX_BYTES,...e.personalUsageReporter?{personalUsageReporter:e.personalUsageReporter}:{},...e.usageReporter?{usageReporter:e.usageReporter}:{},...e.storedSessionUsageReporter?{storedSessionUsageReporter:e.storedSessionUsageReporter}:{},...e.surface?{surface:e.surface}:{},...e.commandSurfaceLocality?{commandSurfaceLocality:e.commandSurfaceLocality}:{}});return{onSessionMessage:i,cleanup:a}}var De=class{options;state;onSessionMessage;handlerCleanup;pairingController;reconnectController;pendingResult;pendingViaReconnect=!1;pendingDeviceId;pendingEnrollment;heldFrames=[];heldChars=0;approvalAbort;constructor(e){this.options=e,e.reconnect?this.state=`awaiting-mode`:(this.state=`pairing`,this.startFirstPair())}onInbound(e){if(this.state===`closed`)return;if(this.state===`accepted`){this.onSessionMessage?.(e);return}if(this.state===`operator-approval`){this.hold(e);return}let t;try{t=JSON.parse(e)}catch{return}if(this.state===`awaiting-mode`){we(t)&&t.t===`rc-hello`?(this.state=`reconnecting`,this.startReconnect(),this.reconnectController?.onFrame(t)):Ce(t)&&t.t===`pair-nonce`&&(this.state=`pairing`,this.startFirstPair(),this.pairingController?.onFrame(t));return}if(this.state===`pairing`){Ce(t)?this.pairingController?.onFrame(t):this.hold(e);return}if(this.state===`reconnecting`){we(t)?this.reconnectController?.onFrame(t):this.hold(e);return}if(this.state===`local-proof`){let e=ge(t,this.options.localPeer);this.options.localPeer?.onAdmission?.(e),e.admitted?this.accept(this.pendingResult,this.pendingViaReconnect):this.rejectAndClose();return}if(this.state===`handoff-grant`){this.judgeGrantFrame(t);return}if(this.state===`enrolling`){Te(t)?this.completeEnrollment(t.spki):this.hold(e);return}}cleanup(){this.state=`closed`,this.withdrawApproval(),this.handlerCleanup?.(),this.handlerCleanup=void 0,this.onSessionMessage=void 0}onChannelClosed(){this.state!==`accepted`&&this.state!==`closed`&&this.rejectAndClose()}withdrawApproval(){this.heldFrames=[],this.heldChars=0,this.approvalAbort?.abort(),this.approvalAbort=void 0}startFirstPair(){this.pairingController=xe(this.options,this.options.secret,this.options.role,e=>this.onFirstPairAccepted(e),()=>this.rejectAndClose(),this.options.startHandshake??u.startPairingHandshake)}startReconnect(){let e=this.options.reconnect;if(!e){this.rejectAndClose();return}this.reconnectController=Se(this.options,e,e=>{this.pendingDeviceId=e.deviceId,this.accept(void 0,!0)},()=>this.rejectAndClose())}onFirstPairAccepted(e){if(this.state!==`pairing`)return;this.pendingResult=e;let t=this.options.reconnect;if(!t){this.accept(e);return}this.state=`enrolling`,C.send(this.options.channel,JSON.stringify({t:`enroll-key`,spki:t.hostPublicSpki})),this.replayHeld()}completeEnrollment(e){if(this.state===`enrolling`){if(!this.options.reconnect){this.rejectAndClose();return}(async()=>{try{await(0,u.importPublicKey)(e);let t=await(0,u.deriveIdentityId)(e);if(this.state!==`enrolling`)return;this.pendingDeviceId=t,this.pendingEnrollment={deviceId:t,spki:e},this.accept(this.pendingResult)}catch{this.rejectAndClose()}})()}}accept(e,t=!1){if(this.state===`closed`||this.state===`accepted`)return;let n=de(this.options,this.state);if(n!==null){this.pendingResult=e??this.pendingResult,this.pendingViaReconnect=t,this.state=n,n===`operator-approval`&&this.askOperator(),this.replayHeld();return}let r=this.pendingEnrollment;if(this.pendingEnrollment=void 0,r!==void 0)try{this.options.reconnect?.onEnroll(r.deviceId,r.spki)}catch{this.rejectAndClose();return}let i=Ee(this.options,t,(e,t)=>this.handleSessionDeliveryError(e,t));this.onSessionMessage=i.onSessionMessage,this.handlerCleanup=i.cleanup,this.state=`accepted`,this.options.onAccept?.(e);let a=this.heldFrames;this.heldFrames=[],this.heldChars=0;for(let e of a){if(this.state!==`accepted`)return;this.onSessionMessage?.(e)}}replayHeld(){let e=this.heldFrames;this.heldFrames=[],this.heldChars=0;for(let t of e){if(this.state===`closed`)return;this.onInbound(t)}}hold(e){this.heldChars+=e.length,this.heldFrames.push(e),(this.heldFrames.length>32||this.heldChars>262144)&&this.rejectAndClose()}async askOperator(){let e=new AbortController;this.approvalAbort=e;let t={...this.pendingDeviceId===void 0?{}:{deviceId:this.pendingDeviceId},viaReconnect:this.pendingViaReconnect,signal:e.signal},n=!1;try{n=await this.options.connectionApproval?.approve(t)===!0}catch{n=!1}this.state!==`operator-approval`||e.signal.aborted||(this.approvalAbort=void 0,n?this.accept(this.pendingResult,this.pendingViaReconnect):this.rejectAndClose())}async judgeGrantFrame(e){let t=await pe(e,this.options.handoffGrant);this.state===`handoff-grant`&&(this.options.handoffGrant?.onAdmission?.(t),t.admitted?this.accept(this.pendingResult,this.pendingViaReconnect):this.rejectAndClose())}rejectAndClose(){this.state!==`closed`&&(this.state=`closed`,this.withdrawApproval(),C.close(this.options.channel),this.options.onReject?.())}handleSessionDeliveryError(e,t){this.state!==`closed`&&(this.state=`closed`,this.handlerCleanup?.(),this.handlerCleanup=void 0,this.onSessionMessage=void 0,C.reportDeliveryError(this.options.onDeliveryError,e,t),C.close(this.options.channel))}};function Oe(e){return Object.assign(Error(`WebRtcTransport ${e}.`),{name:`TransportLifecycleError`,code:e,transportName:`webrtc`})}var ke=class{options;generation=0;paired=!1;dropped=!1;constructor(e){this.options=e}reset(e){this.generation=e,this.paired=!1,this.dropped=!1}accept(e){e===this.generation&&(this.paired=!0)}handleDrop(e){e!==this.generation||!this.paired||this.dropped||(this.dropped=!0,this.options.cleanup(),this.options.onDropped())}handleFailure(e,t,n,r){if(t!==this.generation||this.dropped)return;let i=this.paired;i&&(this.dropped=!0);try{this.options.onDeliveryError(n,r)}catch{}this.options.cleanup();try{e.close()}catch{}i&&this.options.onDropped()}},Ae=class{options;name=`webrtc`;lifecycle=Object.freeze({kind:`service`});defaultEnabled=!1;optionsSchema={};session;peer;unsubscribeSignal;cleanupHandler;generation=0;localFingerprint;pairingGate;offerSent=!1;localCandidates=[];answered=!1;pendingFrames=[];stopAwaitingCertificate;deliveryLifecycle;constructor(e){if(this.options=e,this.deliveryLifecycle=new ke({cleanup:()=>{this.cleanupHandler?.(),this.pairingGate?.cleanup()},onDropped:()=>this.options.onDropped?.(),onDeliveryError:(e,t)=>this.options.onDeliveryError?.(e,t)}),this.options.secret&&this.options.open===!0)throw Error("WebRtcTransport: `secret` and `open: true` are contradictory. A pairing secret gates the data channel; `open` runs without a gate. Pass one.");if(this.options.secret===void 0||this.options.secret===``){if(this.options.open!==!0)throw Error('WebRtcTransport: no pairing `secret` and no explicit `open`. Pass a `secret` to gate the data channel, or `{ open: true, openReason: "…" }` to run without pairing on purpose.');(0,l.resolveAdmission)({open:!0,...this.options.openReason===void 0?{}:{openReason:this.options.openReason}})}}validateOptions(){return!0}attach(e){this.session=e}createPeer(){return new b({...this.options.iceServers?{iceServers:this.options.iceServers}:{},...this.options.forceTurn?{forceTurn:!0}:{},...this.options.loadDataChannel?{loadDataChannel:this.options.loadDataChannel}:{}})}wireSignaling(e,t,n,r){let i=this.options.signaling;e.onLocalCandidate(t=>{r===this.generation&&e===this.peer&&(this.offerSent?this.sendCandidate(t):this.localCandidates.length<64&&this.localCandidates.push(t))});let a=Promise.resolve();this.unsubscribeSignal=i.onSignal(i=>{r===this.generation&&(a=a.then(async()=>{if(r===this.generation&&e===this.peer){if(i.kind===`answer`){if(this.answered)return;this.answered=!0;let a=this.remoteFingerprintAlgorithm(t,i.data);if(this.options.secret&&a===void 0)return;let o=i.data?.sdp;if(typeof o!=`string`)return;e.acceptAnswer(o),a!==void 0&&this.awaitVerifiedCertificate(e,t,n,a,r)}else if(i.kind===`ice`){let t=je(i.data);t!==void 0&&e.addRemoteCandidate(t)}}}).catch(()=>{r===this.generation&&this.failPairing(t)}))})}sendCandidate(e){this.options.signaling.send({kind:`ice`,data:{candidate:e.candidate,sdpMid:e.mid,sdpMLineIndex:0}})}requireCurrentPeer(e,t){if(t!==this.generation||this.peer!==e)throw e.close(),Error(`WebRtcTransport startup was stopped.`)}async start(){let e=this.session;if(!e)throw Oe(`not-attached`);if(this.peer)throw Oe(`already-started`);let t=++this.generation;this.deliveryLifecycle.reset(t),this.answered=!1,this.offerSent=!1,this.localCandidates=[],this.pendingFrames=[];let n=this.createPeer();this.peer=n;let r=this.options.signaling,i=n.createDataChannel(`agent-session`);this.wireChannel(i,e,t),this.wireSignaling(n,i,e,t);let a=await n.createOffer();this.requireCurrentPeer(n,t),this.options.secret&&(this.localFingerprint=(0,u.extractDtlsFingerprint)(a)),r.send({kind:`offer`,data:{type:`offer`,sdp:a}}),this.offerSent=!0;for(let e of this.localCandidates.splice(0))this.sendCandidate(e)}remoteFingerprintAlgorithm(e,t){if(!this.options.secret)return;let n=t.sdp;try{if(typeof n!=`string`)throw Error(`answer carries no SDP`);return(0,u.extractDtlsFingerprintAttribute)(n).algorithm}catch{this.failPairing(e);return}}failPairing(e){e.close(),this.options.onPairingFailed?.()}awaitVerifiedCertificate(e,t,n,r,i){this.stopAwaitingCertificate=_(e,r,e=>{if(i!==this.generation)return;if(t.readyState===`open`){this.startPairing(t,n,e,i);return}let r=t.onStateChange(a=>{a===`open`&&i===this.generation&&(r(),this.startPairing(t,n,e,i))})},()=>{i===this.generation&&this.failPairing(t)})}startPairing(e,t,n,r){let i=this.options.secret;if(!i||!this.localFingerprint)return;this.pairingGate=new De({cryptoContext:this.options.cryptoContext,channel:{send:t=>e.send(t),close:()=>e.close()},session:t,secret:i,role:`initiator`,localFingerprint:this.localFingerprint,remoteFingerprint:n,onAccept:e=>{r===this.generation&&(this.deliveryLifecycle.accept(r),this.options.onPaired?.(e))},...this.options.onPairingFailed?{onReject:this.options.onPairingFailed}:{},...this.options.reconnect?{reconnect:this.options.reconnect}:{},...this.options.localPeer?{localPeer:this.options.localPeer}:{},...this.options.connectionApproval?{connectionApproval:this.options.connectionApproval}:{},...this.options.resumeBridge?{resumeBridge:this.options.resumeBridge}:{},...this.options.personalUsageReporter?{personalUsageReporter:this.options.personalUsageReporter}:{},...this.options.usageReporter?{usageReporter:this.options.usageReporter}:{},...this.options.storedSessionUsageReporter?{storedSessionUsageReporter:this.options.storedSessionUsageReporter}:{},surface:`remote`,commandSurfaceLocality:`remote`,onDeliveryError:(t,n)=>this.deliveryLifecycle.handleFailure(e,r,t,n)});let a=this.pairingGate;for(let e of this.pendingFrames.splice(0))a.onInbound(e)}wireChannel(e,t,n){if(this.options.secret){e.onMessage(e=>{n===this.generation&&(this.pairingGate?this.pairingGate.onInbound(e):this.pendingFrames.length<16&&this.pendingFrames.push(e))}),e.onStateChange(e=>{n===this.generation&&e===`closed`&&(this.pairingGate?.onChannelClosed(),this.deliveryLifecycle.handleDrop(n))}),this.cleanupHandler=()=>this.pairingGate?.cleanup();return}let{onMessage:r,cleanup:i}=(0,c.createSessionMessageHandler)({session:t,deliver:re(e,(t,r)=>this.deliveryLifecycle.handleFailure(e,n,t,r)),...this.options.personalUsageReporter?{personalUsageReporter:this.options.personalUsageReporter}:{},...this.options.usageReporter?{usageReporter:this.options.usageReporter}:{},...this.options.storedSessionUsageReporter?{storedSessionUsageReporter:this.options.storedSessionUsageReporter}:{},surface:`remote`,commandSurfaceLocality:`remote`,maxFrameBytes:c.HISTORY_PAGE_MAX_BYTES});this.cleanupHandler=i,e.onMessage(e=>{n===this.generation&&r(e)})}async stop(){this.generation+=1,this.cleanupHandler?.(),this.unsubscribeSignal?.(),this.cleanupHandler=void 0,this.unsubscribeSignal=void 0,this.pairingGate=void 0,this.localFingerprint=void 0,this.answered=!1,this.offerSent=!1,this.localCandidates=[],this.pendingFrames=[],this.stopAwaitingCertificate?.(),this.stopAwaitingCertificate=void 0,this.deliveryLifecycle.reset(this.generation),this.peer&&=(this.peer.close(),void 0),this.session=void 0}};function je(e){if(typeof e!=`object`||!e)return;let t=e;if(typeof t.candidate!=`string`||t.candidate.length===0)return;let n=typeof t.sdpMid==`string`?t.sdpMid:typeof t.sdpMLineIndex==`number`?String(t.sdpMLineIndex):`0`;return{candidate:t.candidate,mid:n}}function Me(){let e=[],t=[],n=!0;function r(e,t){return{send(e){n&&queueMicrotask(()=>{for(let n of t)n(e)})},onSignal(t){return e.push(t),()=>{let n=e.indexOf(t);n>=0&&e.splice(n,1)}},close(){n=!1,e.length=0}}}return[r(e,t),r(t,e)]}const Ne=new Set([`offer`,`answer`,`ice`]);function Pe(e){return new f.default(e)}var Fe=class{options;socket;handlers=[];outbox=[];joined=!1;closed=!1;constructor(e){this.options=e;let t=e.createSocket??Pe;this.socket=t(e.url),this.socket.on(`open`,()=>this.handleOpen()),this.socket.on(`message`,e=>this.handleMessage(e)),this.socket.on(`error`,e=>this.fail(e instanceof Error?e:Error(String(e)))),this.socket.on(`close`,()=>this.handleClose())}handleOpen(){this.socket.send(JSON.stringify({type:`join`,rendezvous:this.options.rendezvous}));for(let e of this.outbox)this.writeSignal(e);this.outbox.length=0}handleMessage(e){let t;try{t=JSON.parse(typeof e==`string`?e:String(e))}catch{return}if(typeof t!=`object`||!t)return;let n=t;if(n.type===`joined`){this.joined=!0,this.options.onReady?.();return}if(n.type===`error`){this.fail(Error(`signaling relay rejected the connection: ${String(n.reason)}`));return}if(n.type===`signal`&&typeof n.kind==`string`&&Ne.has(n.kind)){let e={kind:n.kind,data:n.data};for(let t of this.handlers)t(e)}}handleClose(){this.closed||this.joined||this.fail(Error(`signaling socket closed before the rendezvous was joined`))}fail(e){this.options.onError?.(e)}writeSignal(e){this.socket.send(JSON.stringify({type:`signal`,kind:e.kind,data:e.data}))}send(e){this.closed||(this.socket.readyState===1?this.writeSignal(e):this.outbox.push(e))}onSignal(e){return this.handlers.push(e),()=>{let t=this.handlers.indexOf(e);t>=0&&this.handlers.splice(t,1)}}close(){this.closed=!0,this.handlers.length=0,this.outbox.length=0,this.socket.close()}};const Ie=/^[A-Za-z0-9_-]{22}$/,Le=6e4;function w(e){return typeof e==`string`&&Ie.test(e)}function T(e,t){return typeof e==`string`&&e.length>0&&e.length<=t}function Re(e){if(typeof e!=`object`||!e||Array.isArray(e))return;let t=e;if(!(t.v!==1||!w(t.from))){if(t.kind===`hello`)return{v:1,kind:`hello`,from:t.from};if(!(!w(t.to)||!w(t.cid))){if(t.kind===`offer`||t.kind===`answer`)return T(t.sdp,49152)?{v:1,kind:t.kind,from:t.from,to:t.to,cid:t.cid,sdp:t.sdp}:void 0;if(t.kind===`ice`){let e=t.candidate;if(typeof e!=`object`||!e||Array.isArray(e))return;let n=e;return!T(n.candidate,2048)||n.sdpMid!==void 0&&!T(n.sdpMid,64)||n.sdpMLineIndex!==void 0&&!(typeof n.sdpMLineIndex==`number`&&Number.isInteger(n.sdpMLineIndex)&&n.sdpMLineIndex>=0&&n.sdpMLineIndex<64)?void 0:{v:1,kind:`ice`,from:t.from,to:t.to,cid:t.cid,candidate:{candidate:n.candidate,...n.sdpMid===void 0?{}:{sdpMid:n.sdpMid},...n.sdpMLineIndex===void 0?{}:{sdpMLineIndex:n.sdpMLineIndex}}}}}}}function ze(e){if(typeof e!=`object`||!e||Array.isArray(e))return;let t=e;if(!(t.t!==`mesh-msg`||typeof t.body!=`string`||t.body.length>6e4))return{t:`mesh-msg`,body:t.body}}var Be=class extends Error{end;stage;role;peer;channelClose;cause;constructor(e){let t=[`mesh link ended (${e.end}) during ${e.stage} as ${e.role}`];e.detail!==void 0&&t.push(e.detail),e.cause!==void 0&&t.push(e.cause instanceof Error?e.cause.message:String(e.cause));let n=e.peer;n!==void 0&&t.push(`connection ${n.state} [${n.history.join(` > `)}], ice ${n.ice??`?`}, gathering ${n.gathering??`?`}, candidates ${n.localCandidates} sent / ${n.remoteCandidates} applied, closed by ${n.closedBy??`the peer or the network`}${n.handlerError===void 0?``:` (${n.handlerError})`}`),e.channelClose!==void 0&&t.push(`channel ${e.channelClose}`),super(t.join(`; `)),this.name=`MeshLinkEndedError`,this.end=e.end,this.stage=e.stage,this.role=e.role,n!==void 0&&(this.peer=n),e.channelClose!==void 0&&(this.channelClose=e.channelClose),e.cause!==void 0&&(this.cause=e.cause)}};const Ve=`agent-file`,He=JSON.stringify({t:`mesh-admitted`});var Ue=class{options;state=`connecting`;peer;channel;localFingerprint;remoteFingerprint;tookRemoteDescription=!1;creatingPeer=!1;sentDescription=!1;localCandidates=[];remoteCandidates=0;handshake;fedProof=!1;held=[];handlers=new Set;endHandlers=new Set;fileChannels=new Set;fileHandlers=new Set;signalChain=Promise.resolve();stopAwaitingCertificate;timer;admissionResult;constructor(e){this.options=e,this.timer=setTimeout(()=>this.end(`timeout`),e.connectTimeoutMs)}get role(){return this.options.role}get admitted(){return this.state===`admitted`}get ended(){return this.isEnded()}isEnded(){return this.state===`ended`}get admission(){return this.state===`admitted`?this.admissionResult:void 0}get channelBinding(){if(this.state===`admitted`&&this.localFingerprint!==void 0&&this.remoteFingerprint!==void 0)return{localFingerprint:this.localFingerprint,remoteFingerprint:this.remoteFingerprint}}async offer(){if(!(this.options.role!==`offerer`||this.creatingPeer||this.isEnded())){this.creatingPeer=!0;try{let e=await this.createPeer();if(e===void 0)return;this.adoptChannel(e.createDataChannel(`agent-mesh`));let t=await e.createOffer();if(this.isEnded())return;this.localFingerprint=(0,u.extractDtlsFingerprint)(t),this.sendDescription({kind:`offer`,sdp:t})}catch(e){this.end(`signaling`,e)}}}onSignal(e){this.isEnded()||(this.signalChain=this.signalChain.then(()=>this.applySignal(e)).catch(e=>this.end(`signaling`,e)))}async applySignal(e){if(this.isEnded())return;if(e.kind===`ice`){if(!this.tookRemoteDescription||!this.peer||++this.remoteCandidates>64)return;this.peer.addRemoteCandidate({candidate:e.candidate.candidate,mid:e.candidate.sdpMid??String(e.candidate.sdpMLineIndex??0)});return}let t=this.options.role===`offerer`?`answer`:`offer`;if(e.kind!==t||this.tookRemoteDescription)return;this.tookRemoteDescription=!0;let n;try{n=(0,u.extractDtlsFingerprintAttribute)(e.sdp).algorithm}catch(e){this.end(`channel-binding`,e);return}if(this.options.role===`offerer`){let t=this.peer;if(!t)return;t.acceptAnswer(e.sdp),this.awaitCertificate(t,n);return}let r=await this.createPeer();if(r===void 0)return;let i=await r.acceptOffer(e.sdp);this.isEnded()||(this.localFingerprint=(0,u.extractDtlsFingerprint)(i),this.sendDescription({kind:`answer`,sdp:i}),this.awaitCertificate(r,n))}async createPeer(){let e=await this.options.createPeer();if(this.isEnded()){e.close();return}return this.peer=e,e.onLocalCandidate(e=>{if(this.isEnded())return;let t={kind:`ice`,candidate:{candidate:e.candidate,sdpMid:e.mid}};this.sentDescription?this.options.sendSignal(t):this.localCandidates.length<64&&this.localCandidates.push(t)}),e.onStateChange(e=>{(e===`failed`||e===`closed`)&&this.end(`closed`,void 0,`connection ${e}`)}),e.onDataChannel(e=>this.incomingChannel(e)),e}incomingChannel(e){if(this.options.role===`answerer`&&this.channel===void 0&&!this.isEnded()){this.adoptChannel(e);return}if(this.state!==`admitted`||e.label!==Ve||this.fileHandlers.size===0||this.fileChannels.size>=4){e.close();return}this.trackFileChannel(e);for(let t of this.fileHandlers)t(e)}trackFileChannel(e){this.fileChannels.add(e),e.onStateChange(t=>{t===`closed`&&this.fileChannels.delete(e)})}openFileChannel(){let e=this.peer;if(this.state!==`admitted`||e===void 0)return Promise.reject(Error(`mesh link is not admitted`));if(this.fileChannels.size>=4)return Promise.reject(Error(`too many file transfers are open on this link`));let t=e.createDataChannel(Ve);return this.trackFileChannel(t),new Promise((e,n)=>{if(t.readyState===`open`){e(t);return}let r=setTimeout(()=>{i(),t.close(),n(Error(`the file channel did not open`))},1e4),i=t.onStateChange(a=>{a!==`connecting`&&(clearTimeout(r),i(),a===`open`?e(t):n(Error(`the file channel closed before it opened`)))})})}onFileChannel(e){return this.fileHandlers.add(e),()=>this.fileHandlers.delete(e)}sendDescription(e){this.options.sendSignal(e),this.sentDescription=!0;for(let e of this.localCandidates.splice(0))this.options.sendSignal(e)}awaitCertificate(e,t){this.stopAwaitingCertificate=_(e,t,e=>{this.isEnded()||(this.remoteFingerprint=e,this.maybeStartHandshake())},e=>this.end(`channel-binding`,Error(e)))}adoptChannel(e){this.channel=e,e.onMessage(e=>this.inbound(e)),e.onStateChange(e=>{e===`open`?this.maybeStartHandshake():e===`closed`&&this.end(`closed`,void 0,`data channel closed`)}),e.readyState===`open`&&this.maybeStartHandshake()}maybeStartHandshake(){let e=this.channel;if(this.state!==`connecting`||this.handshake!==void 0||e===void 0||this.localFingerprint===void 0||this.remoteFingerprint===void 0||e.readyState!==`open`)return;let t;try{t=this.options.startHandshake({localFingerprint:this.localFingerprint,remoteFingerprint:this.remoteFingerprint,send:e=>this.write(JSON.stringify(e))})}catch(e){this.end(`handshake`,e);return}this.handshake=t,t.result.then(e=>this.confirm(e),e=>this.end(`handshake`,e));let n=this.held.splice(0);for(let e of n)this.feed(e)}inbound(e){if(!this.isEnded()){if(this.state===`admitted`){this.deliver(e);return}if(this.state===`confirming`){this.confirmed(e);return}if(this.handshake===void 0){this.hold(e);return}this.feed(e)}}hold(e){if(this.held.length>=16){this.end(`protocol`);return}this.held.push(e)}feed(e){if(this.fedProof){this.hold(e);return}let t;try{t=JSON.parse(e)}catch{t=e}typeof t==`object`&&t&&t.t===`dh-prove`&&(this.fedProof=!0),this.handshake?.onFrame(t)}confirm(e){if(this.state!==`connecting`)return;if(this.options.accepts!==void 0&&!this.options.accepts(e)){this.end(`handshake`,Error(`the admitted device is not the one this link is for`));return}this.state=`confirming`,this.admissionResult=e,this.write(He);let t=this.held.splice(0);for(let e of t)this.inbound(e)}confirmed(e){let t;try{t=JSON.parse(e)}catch{t=void 0}let n=this.admissionResult;if(n===void 0||typeof t!=`object`||!t||t.t!==`mesh-admitted`){this.end(`protocol`);return}clearTimeout(this.timer),this.state=`admitted`,this.options.onAdmitted(n)}deliver(e){let t;try{t=JSON.parse(e)}catch{t=void 0}let n=ze(t);if(n===void 0){this.end(`protocol`);return}for(let e of this.handlers)e(n.body)}write(e){try{this.channel?.send(e)}catch(e){this.end(`closed`,e)}}send(e){if(this.state!==`admitted`)throw Error(`mesh link is not admitted`);if(e.length>6e4)throw Error(`mesh message exceeds ${Le} characters`);this.write(JSON.stringify({t:`mesh-msg`,body:e}))}onMessage(e){return this.handlers.add(e),()=>this.handlers.delete(e)}onEnd(e){return this.endHandlers.add(e),()=>this.endHandlers.delete(e)}close(){this.end(`closed`,void 0,`closed by this side`)}get stage(){return this.state===`admitted`||this.state===`confirming`?this.state:this.handshake===void 0?this.remoteFingerprint===void 0?this.tookRemoteDescription?`connecting`:`signaling`:`awaiting-channel`:`handshake`}end(e,t,n){if(this.isEnded())return;let r=new Be({end:e,stage:this.stage,role:this.options.role,...n===void 0?{}:{detail:n},...this.peer===void 0?{}:{peer:this.peer.diagnostics()},...this.channel?.closeCause===void 0?{}:{channelClose:this.channel.closeCause},...t===void 0?{}:{cause:t}});this.state=`ended`,clearTimeout(this.timer),this.stopAwaitingCertificate?.(),this.held.length=0,this.handshake?.onFrame(void 0),this.channel?.close();for(let e of this.fileChannels)e.close();this.fileChannels.clear(),this.fileHandlers.clear();let i=this.peer;i&&setTimeout(()=>i.close(),250).unref?.(),this.options.onEnded(e,r);for(let t of this.endHandlers)t(e);this.endHandlers.clear(),this.handlers.clear()}};const E=554869826,D={Binding:1,Allocate:3,Refresh:4,Send:6,Data:7,CreatePermission:8,ChannelBind:9},O={Request:0,Indication:1,Success:2,Error:3},k={MappedAddress:1,Username:6,MessageIntegrity:8,ErrorCode:9,UnknownAttributes:10,ChannelNumber:12,Lifetime:13,XorPeerAddress:18,Data:19,Realm:20,Nonce:21,XorRelayedAddress:22,RequestedAddressFamily:23,EvenPort:24,RequestedTransport:25,DontFragment:26,MessageIntegritySha256:28,PasswordAlgorithm:29,Userhash:30,XorMappedAddress:32,ReservationToken:34,Priority:36,UseCandidate:37,Fingerprint:32808};function We(e,t){return e&15|(e&112)<<1|(e&3968)<<2|(t&1)<<4|(t&2)<<7}function Ge(e){return e.length>=20&&(e[0]&192)==0&&e.readUInt32BE(4)===554869826}function Ke(e){if(!Ge(e))return;let t=e.readUInt16BE(0),n=e.readUInt16BE(2);if(n%4!=0||20+n>e.length)return;let r=t&15|(t&224)>>1|(t&15872)>>2,i=(t&16)>>4|(t&256)>>7,a=[],o=20,s=20+n;for(;o<s;){if(o+4>s)return;let t=e.readUInt16BE(o),n=e.readUInt16BE(o+2);if(o+4+n>s)return;a.push({type:t,value:e.subarray(o+4,o+4+n),offset:o}),o+=4+n+(4-n%4)%4}if(o===s)return{method:r,cls:i,transactionId:Buffer.from(e.subarray(8,20)),attributes:a,raw:e.subarray(0,s)}}function A(e,t){return e.attributes.find(e=>e.type===t)?.value}function qe(e,t){return e.attributes.filter(e=>e.type===t).map(e=>e.value)}function Je(e){let t=e.attributes.findIndex(e=>e.type===k.MessageIntegrity);return t<0?e:{...e,attributes:e.attributes.slice(0,t+1)}}function Ye(e,t){if(e.length<8)return;let n=e[1],r=e.readUInt16BE(2)^E>>>16;if(n===1&&e.length===8){let t=e.readUInt32BE(4)^E;return{address:[t>>>24,t>>>16&255,t>>>8&255,t&255].join(`.`),port:r}}if(n===2&&e.length===20){let n=Buffer.alloc(16);n.writeUInt32BE(E,0),t.copy(n,4);let i=[];for(let t=0;t<16;t+=2)i.push(((e.readUInt16BE(4+t)^n.readUInt16BE(t))&65535).toString(16));return{address:i.join(`:`),port:r}}}function Xe(e){let[t=``,n=``]=e.split(`::`),r=t.length>0?t.split(`:`):[],i=e.includes(`::`)&&n.length>0?n.split(`:`):[],a=e.includes(`::`)?[...r,...Array(8-r.length-i.length).fill(`0`),...i]:r,o=Buffer.alloc(16);return a.forEach((e,t)=>o.writeUInt16BE(parseInt(e,16)&65535,t*2)),o}function j(e,t){let n=(e.port^E>>>16)&65535;if((0,m.isIPv4)(e.address)){let t=Buffer.alloc(8);t[1]=1,t.writeUInt16BE(n,2);let r=e.address.split(`.`).reduce((e,t)=>e<<8|Number(t),0);return t.writeUInt32BE((r^E)>>>0,4),t}if(!(0,m.isIPv6)(e.address))throw Error(`not an IP address: ${e.address}`);let r=Buffer.alloc(20);r[1]=2,r.writeUInt16BE(n,2);let i=Buffer.alloc(16);i.writeUInt32BE(E,0),t.copy(i,4);let a=Xe(e.address);for(let e=0;e<16;e+=1)r[4+e]=a[e]^i[e];return r}function Ze(e,t,n){return(0,p.createHash)(`md5`).update(`${e}:${t}:${n}`,`utf8`).digest()}function Qe(e,t){let n=e.attributes.find(e=>e.type===k.MessageIntegrity);if(n===void 0||n.value.length!==20)return!1;let r=Buffer.from(e.raw.subarray(0,n.offset));return r.writeUInt16BE(n.offset-20+24,2),(0,p.timingSafeEqual)((0,p.createHmac)(`sha1`,t).update(r).digest(),n.value)}const $e=(()=>{let e=new Uint32Array(256);for(let t=0;t<256;t+=1){let n=t;for(let e=0;e<8;e+=1)n=n&1?3988292384^n>>>1:n>>>1;e[t]=n>>>0}return e})();function et(e){let t=4294967295;for(let n of e)t=$e[(t^n)&255]^t>>>8;return(t^4294967295)>>>0}function M(e,t,n,r,i={}){let a=[],o=Buffer.alloc(20);o.writeUInt16BE(We(e,t),0),o.writeUInt32BE(E,4),n.copy(o,8,0,12),a.push(o);let s=(e,t)=>{let n=Buffer.alloc(4);n.writeUInt16BE(e,0),n.writeUInt16BE(t.length,2),a.push(n,t,Buffer.alloc((4-t.length%4)%4))};for(let e of r)s(e.type,e.value);let c=()=>Buffer.concat(a);if(i.integrityKey!==void 0){let e=c();e.writeUInt16BE(e.length-20+24,2),s(k.MessageIntegrity,(0,p.createHmac)(`sha1`,i.integrityKey).update(e).digest())}if(i.fingerprint!==!1){let e=c();e.writeUInt16BE(e.length-20+8,2);let t=Buffer.alloc(4);t.writeUInt32BE((et(e)^1398035790)>>>0,0),s(k.Fingerprint,t)}let l=c();if(l.writeUInt16BE(l.length-20,2),l.length>65535)throw Error(`STUN message too large`);return l}function tt(e,t){let n=Buffer.from(t,`utf8`),r=Buffer.alloc(4+n.length);return r[2]=Math.floor(e/100),r[3]=e%100,n.copy(r,4),r}function N(e){let t=Buffer.alloc(4);return t.writeUInt32BE(e>>>0,0),t}function nt(e){return e.length>=4&&(e[0]&192)==64}function rt(e){if(!nt(e))return;let t=e.readUInt16BE(0),n=e.readUInt16BE(2);if(!(4+n>e.length))return{channel:t,payload:e.subarray(4,4+n)}}function it(e,t){let n=Buffer.alloc(4);return n.writeUInt16BE(e,0),n.writeUInt16BE(t.length,2),Buffer.concat([n,t,Buffer.alloc((4-t.length%4)%4)])}const at={allocationsPerOwner:8,totalAllocations:64,bytesPerSecondPerOwner:1024*1024,maxLifetimeSeconds:3600,maxAllocationAgeMs:720*60*1e3,permissionsPerAllocation:32,channelsPerAllocation:32},ot={perSourcePerSecond:10,totalPerSecond:2e3},st=3e5,ct=new Set([k.MappedAddress,k.Username,k.MessageIntegrity,k.ErrorCode,k.ChannelNumber,k.Lifetime,k.XorPeerAddress,k.Data,k.Realm,k.Nonce,k.RequestedAddressFamily,k.RequestedTransport,k.MessageIntegritySha256,k.PasswordAlgorithm,k.XorMappedAddress,k.Priority,k.UseCandidate]);function P(e){return`${e.address}:${e.port}`}function lt(){for(let e of Object.values((0,h.networkInterfaces)()))for(let t of e??[])if(t.family===`IPv4`&&!t.internal)return t.address;return`127.0.0.1`}function ut(e){return e.startsWith(`127.`)||e===`::1`}function dt(e){let[t=0,n=0]=e.split(`.`).map(Number);return t===10||t===172&&n>=16&&n<=31||t===192&&n===168||t===169&&n===254||t===100&&n>=64&&n<=127}function ft(e,t){return n=>{if(!(0,m.isIPv4)(n))return!1;let r=Number(n.split(`.`)[0]);return r===0||r>=224?!1:r===127?e:t||!dt(n)}}async function pt(e,t){let n=(0,te.createSocket)(`udp4`);try{return await new Promise((r,i)=>{n.once(`error`,i),n.bind(e,t,()=>{n.off(`error`,i),r()})}),n}catch(e){try{n.close()}catch{}throw e}}async function F(e,t){try{return await pt(e,t)}catch{return}}function mt(e,t,n){let r=e instanceof Error?e.code:void 0,i=r===`EADDRINUSE`?`the port is taken`:r===`EADDRNOTAVAIL`?`${t} is not an address of this machine`:r===`EACCES`?`port ${n} needs privileges this process does not have`:gt(e).message;return Error(`the TURN relay cannot listen on UDP ${t}:${n}: ${i}`,{cause:e})}function ht(){let e=new Set;for(let t of Object.values((0,h.networkInterfaces)()))for(let n of t??[])e.add(n.address);return e}function I(e,t,n,r=1){let i=Math.max(0,n-e.at);return e.tokens=Math.min(Math.max(t,r),e.tokens+i/1e3*t),e.at=n,e.tokens>=r}function gt(e){return e instanceof Error?e:Error(String(e))}var _t=class e{socket;options;bindHost;relayAddress;allocations=new Map;buckets=new Map;quotas;realm;limits;answerBuckets=new Map;answerBudget;nonceSecret=(0,p.randomBytes)(32);ownAddresses=ht();allowPeer;sweeper;retained;closed=!1;constructor(e,t,n,r){this.socket=e,this.options=t,this.bindHost=n,this.relayAddress=r,this.quotas={...at,...t.quotas},this.realm=t.realm??`r`,this.limits={...ot,...t.unauthenticatedLimits},this.allowPeer=t.allowPeer??ft(ut(r),t.allowPrivatePeers??!0),e.on(`message`,(e,t)=>this.receive(e,t)),e.on(`error`,e=>t.onError?.(e)),this.sweeper=setInterval(()=>this.sweep(),5e3),this.sweeper.unref?.()}static async start(t){let n=Buffer.byteLength(t.realm??`r`);if(n===0||n>4)throw Error(`TURN realm must be 1 to 4 bytes`);let r=t.host??`0.0.0.0`,i=t.port??3478,a;try{a=await pt(i,r)}catch(e){throw mt(e,r,i)}let o=t.relayAddress??(r===`0.0.0.0`?lt():r);return new e(a,t,r,o)}get address(){let e=this.socket.address();return{address:this.bindHost===`0.0.0.0`?this.relayAddress:e.address,port:e.port}}allocationCount(e){if(e===void 0)return this.allocations.size;let t=0;for(let n of this.allocations.values())n.owner===e&&(t+=1);return t}retain(e){this.retained=new Set(e);for(let t of[...this.allocations.values()])e.has(t.owner)||this.remove(t);for(let t of[...this.buckets.keys()])e.has(t)||this.buckets.delete(t)}close(){if(this.closed)return Promise.resolve();this.closed=!0,clearInterval(this.sweeper);for(let e of[...this.allocations.values()])this.remove(e);return new Promise(e=>this.socket.close(()=>e()))}now(){return(this.options.now??Date.now)()}receive(e,t){if(this.closed)return;if(nt(e)){this.fromClientChannel(e,t);return}let n=Ke(e);if(n!==void 0){if(n.cls===O.Indication){n.method===D.Send&&this.fromClientSend(n,t);return}n.cls===O.Request&&this.request(n,t).catch(e=>this.options.onError?.(gt(e)))}}send(e,t){this.closed||this.socket.send(e,t.port,t.address,e=>{e&&this.options.onError?.(e)})}reply(e,t,n,r){let i=M(e.method,O.Success,e.transactionId,n,{...r===void 0?{}:{integrityKey:r}});return this.send(i,t),i}fail(e,t,n,r,i=[],a){let o=M(e.method,O.Error,e.transactionId,[{type:k.ErrorCode,value:tt(n,r)},...i],{...a===void 0?{}:{integrityKey:a}});this.send(o,t)}nonce(e){let t=Buffer.alloc(4);return t.writeUInt32BE(Math.floor(this.now()/1e3)>>>0,0),Buffer.concat([t,this.nonceMac(t,e)]).toString(`base64url`)}nonceMac(e,t){return(0,p.createHmac)(`sha256`,this.nonceSecret).update(e).update(P(t)).digest().subarray(0,8)}nonceValid(e,t){if(!/^[A-Za-z0-9_-]{16}$/.test(e))return!1;let n=Buffer.from(e,`base64url`),r=n.subarray(0,4);if(!(0,p.timingSafeEqual)(n.subarray(4),this.nonceMac(r,t)))return!1;let i=this.now()-r.readUInt32BE(0)*1e3;return i>=-6e4&&i<=6e5}answerUnauthenticated(e,t,n,r){let i=this.now(),a=this.answerBudget??={tokens:this.limits.totalPerSecond,at:i},o=this.answerBuckets.get(t.address)??{tokens:this.limits.perSourcePerSecond,at:i};if(this.answerBuckets.set(t.address,o),e.raw.length<28||!I(o,this.limits.perSourcePerSecond,i)||!I(a,this.limits.totalPerSecond,i))return;let s=M(e.method,n,e.transactionId,r(),{fingerprint:!1});s.length>e.raw.length||(--o.tokens,--a.tokens,this.send(s,t))}refuseUnauthenticated(e,t,n,r=()=>[]){this.answerUnauthenticated(e,t,O.Error,()=>[{type:k.ErrorCode,value:tt(n,``)},...r()])}challenge(e,t,n){this.refuseUnauthenticated(e,t,n,()=>[{type:k.Realm,value:Buffer.from(this.realm)},{type:k.Nonce,value:Buffer.from(this.nonce(t))}])}async authenticate(e,t,n){if(A(e,k.MessageIntegrity)===void 0){this.challenge(e,t,401);return}let r=A(e,k.Username)?.toString(`utf8`),i=A(e,k.Realm)?.toString(`utf8`),a=A(e,k.Nonce)?.toString(`utf8`);if(r===void 0||i===void 0||a===void 0){this.refuseUnauthenticated(e,t,400);return}if(i!==this.realm){this.challenge(e,t,401);return}if(!this.nonceValid(a,t)){this.challenge(e,t,438);return}if(n!==void 0){if(r!==n.username){this.refuseUnauthenticated(e,t,441);return}if(!Qe(e,n.integrityKey)){this.challenge(e,t,401);return}return{auth:{owner:n.owner,password:``},key:n.integrityKey,username:r}}let o;try{o=await this.options.authorize(r)}catch{o=void 0}if(this.closed)return;let s=o===void 0?void 0:Ze(r,this.realm,o.password);if(o===void 0||s===void 0||!Qe(e,s)){this.challenge(e,t,401);return}return{auth:o,key:s,username:r}}unknownAttributes(e){return e.attributes.map(e=>e.type).filter(e=>e<32768&&!ct.has(e))}async request(e,t){let n={address:t.address,port:t.port};if(e.method===D.Binding){this.answerUnauthenticated(e,n,O.Success,()=>[{type:k.XorMappedAddress,value:j(n,e.transactionId)}]);return}if(![D.Allocate,D.Refresh,D.CreatePermission,D.ChannelBind].includes(e.method)){this.refuseUnauthenticated(e,n,400);return}let r=this.allocations.get(P(n)),i=this.live(r)?r:void 0;if(e.method===D.Allocate&&i!==void 0&&i.transactionId.equals(e.transactionId)){i.response.length<=e.raw.length&&this.send(i.response,n);return}let a=await this.authenticate(e,n,i);a!==void 0&&await this.authenticatedRequest(Je(e),n,a)}async authenticatedRequest(e,t,n){let{key:r}=n,i=this.unknownAttributes(e);if(i.length>0){let n=Buffer.alloc(i.length*2);i.forEach((e,t)=>n.writeUInt16BE(e,t*2)),this.fail(e,t,420,`Unknown Attribute`,[{type:k.UnknownAttributes,value:n}],r);return}let a=this.allocations.get(P(t)),o=this.live(a)?a:void 0;if(e.method===D.Allocate){await this.allocate(e,t,n,o);return}if(o===void 0||o.owner!==n.auth.owner){this.fail(e,t,437,`Allocation Mismatch`,[],r);return}e.method===D.Refresh?this.refresh(e,t,o):e.method===D.CreatePermission?this.permit(e,t,o):this.bindChannel(e,t,o)}async allocate(e,t,n,r){let{auth:i,key:a,username:o}=n;if(r!==void 0){this.fail(e,t,437,`Allocation Mismatch`,[],a);return}let s=A(e,k.RequestedTransport);if(s===void 0||s.length!==4){this.fail(e,t,400,`Bad Request`,[],a);return}if(s[0]!==17){this.fail(e,t,442,`Unsupported Transport Protocol`,[],a);return}let c=A(e,k.RequestedAddressFamily);if(c!==void 0&&c[0]!==1){this.fail(e,t,440,`Address Family not Supported`,[],a);return}if(this.retained!==void 0&&!this.retained.has(i.owner)){this.fail(e,t,403,`Forbidden`,[],a);return}if(this.allocations.size>=this.quotas.totalAllocations){this.fail(e,t,508,`Insufficient Capacity`,[],a);return}if(this.allocationCount(i.owner)>=this.quotas.allocationsPerOwner){this.fail(e,t,486,`Allocation Quota Reached`,[],a);return}let l=await this.relayedSocket();if(l===void 0){this.fail(e,t,508,`Insufficient Capacity`,[],a);return}if(!this.closed&&this.retained!==void 0&&!this.retained.has(i.owner)){l.close(),this.fail(e,t,403,`Forbidden`,[],a);return}if(this.closed||this.allocations.has(P(t))||this.allocationCount(i.owner)>=this.quotas.allocationsPerOwner||this.allocations.size>=this.quotas.totalAllocations){l.close(),this.closed||this.fail(e,t,486,`Allocation Quota Reached`,[],a);return}let u=this.now(),d=this.grantedLifetime(e,u,u),f={key:P(t),client:t,owner:i.owner,username:o,integrityKey:a,transactionId:Buffer.from(e.transactionId),socket:l,relayed:{address:this.relayAddress,port:l.address().port},createdAt:u,expiresAt:u+d*1e3,permissions:new Map,channelsByNumber:new Map,channelsByPeer:new Map,response:Buffer.alloc(0)};l.on(`message`,(e,t)=>this.fromPeer(f,e,t)),l.on(`error`,e=>this.options.onError?.(e)),this.allocations.set(f.key,f),f.response=this.reply(e,t,[{type:k.XorRelayedAddress,value:j(f.relayed,e.transactionId)},{type:k.Lifetime,value:N(d)},{type:k.XorMappedAddress,value:j(t,e.transactionId)}],a)}async relayedSocket(){let e=this.options.relayPorts;if(e===void 0)return F(0,this.bindHost);let t=e.max-e.min+1;for(let n=0;n<Math.min(t,8);n+=1){let t=await F((0,p.randomInt)(e.min,e.max+1),this.bindHost);if(t!==void 0)return t}let n=new Set(this.allocationPorts());for(let t=e.min;t<=e.max;t+=1){if(n.has(t))continue;let e=await F(t,this.bindHost);if(e!==void 0)return e}}allocationPorts(){return[...this.allocations.values()].map(e=>e.relayed.port)}isServerItself(e){return e.port===this.socket.address().port&&(ut(e.address)||e.address===this.relayAddress||e.address===this.bindHost||this.bindHost===`0.0.0.0`&&this.ownAddresses.has(e.address))}grantedLifetime(e,t,n){let r=A(e,k.Lifetime),i=r!==void 0&&r.length===4?r.readUInt32BE(0):600,a=Math.floor((t+this.quotas.maxAllocationAgeMs-n)/1e3);return Math.max(0,Math.min(i,this.quotas.maxLifetimeSeconds,a))}refresh(e,t,n){let r=this.now(),i=this.grantedLifetime(e,n.createdAt,r);if(i===0){this.remove(n),this.reply(e,t,[{type:k.Lifetime,value:N(0)}],n.integrityKey);return}n.expiresAt=r+i*1e3,this.reply(e,t,[{type:k.Lifetime,value:N(i)}],n.integrityKey)}peerAddresses(e){let t=[];for(let n of qe(e,k.XorPeerAddress)){let r=Ye(n,e.transactionId);if(r===void 0)return;t.push(r)}return t.length>0?t:void 0}permit(e,t,n){let r=n.integrityKey,i=this.peerAddresses(e);if(i===void 0){this.fail(e,t,400,`Bad Request`,[],r);return}if(i.some(e=>!(0,m.isIPv4)(e.address))){this.fail(e,t,443,`Peer Address Family Mismatch`,[],r);return}if(i.some(e=>!this.allowPeer(e.address))){this.fail(e,t,403,`Forbidden`,[],r);return}let a=new Set(i.map(e=>e.address).filter(e=>!n.permissions.has(e)));if(n.permissions.size+a.size>this.quotas.permissionsPerAllocation){this.fail(e,t,508,`Insufficient Capacity`,[],r);return}let o=this.now()+st;for(let e of i)n.permissions.set(e.address,o);this.reply(e,t,[],r)}bindChannel(e,t,n){let r=n.integrityKey,i=A(e,k.ChannelNumber),a=this.peerAddresses(e),o=i!==void 0&&i.length===4?i.readUInt16BE(0):-1;if(o<16384||o>20479||a===void 0||a.length!==1){this.fail(e,t,400,`Bad Request`,[],r);return}let s=a[0];if(!(0,m.isIPv4)(s.address)){this.fail(e,t,443,`Peer Address Family Mismatch`,[],r);return}if(!this.allowPeer(s.address)){this.fail(e,t,403,`Forbidden`,[],r);return}let c=n.channelsByNumber.get(o),l=n.channelsByPeer.get(P(s));if(c!==void 0&&P(c.peer)!==P(s)||l!==void 0&&l.number!==o){this.fail(e,t,400,`Bad Request`,[],r);return}if(c===void 0&&n.channelsByNumber.size>=this.quotas.channelsPerAllocation||!n.permissions.has(s.address)&&n.permissions.size>=this.quotas.permissionsPerAllocation){this.fail(e,t,508,`Insufficient Capacity`,[],r);return}let u=this.now(),d=c??{number:o,peer:s,expiresAt:0};d.expiresAt=u+6e5,n.channelsByNumber.set(o,d),n.channelsByPeer.set(P(s),d),n.permissions.set(s.address,u+st),this.reply(e,t,[],r)}permitted(e,t){let n=e.permissions.get(t);return n!==void 0&&n>this.now()}spend(e,t){let n=this.now(),r=this.quotas.bytesPerSecondPerOwner,i=this.buckets.get(e)??{tokens:r,at:n};return this.buckets.set(e,i),I(i,r,n,t)?(i.tokens-=t,!0):!1}live(e){return e===void 0?!1:e.expiresAt>this.now()?!0:(this.remove(e),!1)}fromClientSend(e,t){let n=this.allocations.get(P(t));if(!this.live(n))return;let r=A(e,k.XorPeerAddress),i=A(e,k.Data);if(r===void 0||i===void 0)return;let a=Ye(r,e.transactionId);a===void 0||!this.permitted(n,a.address)||this.isServerItself(a)||this.spend(n.owner,i.length)&&n.socket.send(i,a.port,a.address)}fromClientChannel(e,t){let n=this.allocations.get(P(t));if(!this.live(n))return;let r=rt(e);if(r===void 0)return;let i=n.channelsByNumber.get(r.channel);i===void 0||i.expiresAt<=this.now()||this.permitted(n,i.peer.address)&&(this.isServerItself(i.peer)||this.spend(n.owner,r.payload.length)&&n.socket.send(r.payload,i.peer.port,i.peer.address))}fromPeer(e,t,n){if(this.allocations.get(e.key)!==e||!this.live(e)||!this.permitted(e,n.address)||!this.spend(e.owner,t.length))return;let r=e.channelsByPeer.get(P(n));if(r!==void 0&&r.expiresAt>this.now()){this.send(it(r.number,t),e.client);return}let i=(0,p.randomBytes)(12);this.send(M(D.Data,O.Indication,i,[{type:k.XorPeerAddress,value:j({address:n.address,port:n.port},i)},{type:k.Data,value:t}]),e.client)}remove(e){this.allocations.get(e.key)===e&&this.allocations.delete(e.key);try{e.socket.close()}catch{}}sweep(){let e=this.now();for(let[t,n]of this.answerBuckets)Math.abs(e-n.at)>=1e3&&this.answerBuckets.delete(t);for(let t of[...this.allocations.values()]){if(t.expiresAt<=e){this.remove(t);continue}for(let[n,r]of t.permissions)r<=e&&t.permissions.delete(n);for(let[n,r]of t.channelsByNumber)r.expiresAt>e||(t.channelsByNumber.delete(n),t.channelsByPeer.delete(P(r.peer)))}}};const vt=600*1e3,yt=3600*1e3,bt=/^(\d{1,12}):([A-Za-z0-9_-]{22})$/;function xt(e){return Buffer.from(e).toString(`base64url`)}async function St(e,t,n=vt){let r=Math.min(Math.max(n,1e3),yt),i=(await e.tag(`relay-user`,`outbound`,(0,u.rendezvousEpoch)(t))).slice(0,16),a=`${Math.floor((t+r)/1e3)}:${xt(i)}`;return{username:a,credential:await e.relayPassword(`outbound`,a)}}function Ct(e){return`turn:${e.host.includes(`:`)?`[${e.host}]`:e.host}:${e.port}?transport=udp`}async function wt(e,t,n,r){if(t.length===0)return[];let{username:i,credential:a}=await St(e,n,r);return t.map(e=>({urls:Ct(e),username:i,credential:a}))}var L=class extends Error{deviceId;need;constructor(e,t,n){let r=t===`relay-only`?`only relayed connections are allowed`:`no direct path was found (${n?.cause instanceof Error?n.cause.message:String(n?.cause)})`;super(`a relay device is needed to reach device ${e}: ${r}, and no paired device advertises a relay and no TURN server is configured. Run the relay on an always-on device, or configure a TURN server.`,n?.cause===void 0?void 0:{cause:n.cause}),this.name=`MeshRelayNeededError`,this.deviceId=e,this.need=t}},Tt=class e{server;now;peers=[];owners;constructor(e,t){this.server=e,this.now=t}static async start(t={}){let n=t.now??Date.now,r,i=await _t.start({...t.host===void 0?{}:{host:t.host},...t.port===void 0?{}:{port:t.port},...t.relayAddress===void 0?{}:{relayAddress:t.relayAddress},...t.relayPorts===void 0?{}:{relayPorts:t.relayPorts},...t.quotas===void 0?{}:{quotas:t.quotas},...t.allowPeer===void 0?{}:{allowPeer:t.allowPeer},...t.allowPrivatePeers===void 0?{}:{allowPrivatePeers:t.allowPrivatePeers},...t.onError===void 0?{}:{onError:t.onError},now:n,authorize:e=>r===void 0?Promise.resolve(void 0):r.authorize(e)});return r=new e(i,n),r}get endpoint(){let{address:e,port:t}=this.server.address;return{host:e,port:t}}allocationCount(e){return this.server.allocationCount(e)}declarePeers(e){this.peers=[...e],this.server.retain(new Set(e.map(e=>e.deviceId)))}async authorize(e){let t=bt.exec(e);if(t===null)return;let n=this.now(),r=Number(t[1])*1e3;if(r<=n||r-n>366e4)return;let i=(await this.tagOwners((0,u.rendezvousEpoch)(n))).get(t[2]);if(!(i===void 0||!this.peers.some(e=>e.deviceId===i.deviceId)))return{owner:i.deviceId,password:await i.rendezvous.relayPassword(`inbound`,e)}}tagOwners(e){let t=this.owners;if(t!==void 0&&t.epoch===e&&t.peers===this.peers)return t.byTag;let n=this.peers,r=(async()=>{let t=new Map;for(let r of n)for(let n of await r.rendezvous.lookupTags(`relay-user`,e))t.set(xt(n.slice(0,16)),r);return t})();return r.catch(()=>{this.owners?.byTag===r&&(this.owners=void 0)}),this.owners={epoch:e,peers:n,byTag:r},r}close(){return this.peers=[],this.server.close()}};const Et=2e4,Dt=1e3,Ot=3e3,kt=`mesh-lists`,At=`{"t":"${kt}"`;function jt(e){return{send:t=>e.send(t),onFrame:t=>e.onMessage(t),onClose:t=>e.readyState===`closed`?(queueMicrotask(t),()=>void 0):e.onStateChange(e=>{e===`closed`&&t()}),close:()=>e.close()}}var Mt=class{last;waiting;timer;run(e){let t=Date.now();if(this.last===void 0||t-this.last>=Dt){this.last=t,e();return}this.waiting=e,this.timer===void 0&&(this.timer=setTimeout(()=>{this.timer=void 0;let e=this.waiting;this.waiting=void 0,e!==void 0&&this.run(e)},Dt-(t-this.last)),this.timer.unref?.())}cancel(){this.timer!==void 0&&clearTimeout(this.timer),this.timer=void 0,this.waiting=void 0}};function Nt(){let e=new Uint8Array(16);return globalThis.crypto.getRandomValues(e),Buffer.from(e).toString(`base64url`)}function R(e,t){return t!==void 0&&t.seq>e.seq&&t.signingKeyId===e.signingKeyId}function Pt(e,t){return e===void 0?t:t===void 0?e:Math.max(e,t)}function Ft(e,t){let n=new Map;for(let r of[e.bySigningKey??{},t.bySigningKey??{}])for(let[e,t]of Object.entries(r)){let r=n.get(e)??{},i=Pt(r.rosterSeq,t.rosterSeq),a=Pt(r.revocationSeq,t.revocationSeq);n.set(e,{...i===void 0?{}:{rosterSeq:i},...a===void 0?{}:{revocationSeq:a}})}let r=Object.fromEntries(n),i=Pt(e.signingKeyRevocationSeq,t.signingKeyRevocationSeq);return{...i===void 0?{}:{signingKeyRevocationSeq:i},bySigningKey:r}}function It(e,t){let n=t.signingKeyCertificate.signingKeyId===e.signingKeyCertificate.signingKeyId;return{...t,...n&&R(t.roster,e.roster)?{roster:e.roster}:{},...n&&R(t.revocation,e.revocation)?{revocation:e.revocation}:{},...e.signingKeyRevocation.seq>t.signingKeyRevocation.seq?{signingKeyRevocation:e.signingKeyRevocation}:{},marks:Ft(e.marks,t.marks)}}function Lt(e,t){return t.signingKeyCertificate.signingKeyId===e.signingKeyCertificate.signingKeyId?t.roster.seq>e.roster.seq||t.revocation.seq>e.revocation.seq||t.signingKeyRevocation.seq>e.signingKeyRevocation.seq:!1}function Rt(e){if(e.startsWith(At))try{let t=JSON.parse(e);return typeof t==`object`&&t&&!Array.isArray(t)?t:void 0}catch{return{}}}var zt=class{options;instance=Nt();identity;sessionDescriptor;peers=new Map;byInbound=new Map;linkHandlers=new Set;refusalHandlers=new Set;waiters=new Set;unsubscribes=[];started=!1;stopped=!1;sync=Promise.resolve();constructor(e){this.options=e,this.identity=e.identity,this.sessionDescriptor=e.sessionDescriptor}get deviceId(){return this.identity.deviceCertificate.deviceId}async start(){if(this.started)throw Error(`DeviceMeshNode already started`);this.started=!0,this.unsubscribes.push(this.options.relay.onMessage((e,t)=>this.receive(e,t))),await this.syncPeers()}refresh(e){if(e.sessionDescriptor!==void 0&&(this.sessionDescriptor=e.sessionDescriptor),e.identity===void 0)return Promise.resolve();let t=this.identity;this.identity=It(t,e.identity);let n=this.syncPeers();return Lt(t,this.identity)&&n.then(()=>this.pushLists(),()=>void 0),n}pushLists(){if(this.stopped)return;let{roster:e,revocation:t,signingKeyRevocation:n}=this.identity,r=JSON.stringify({t:kt,roster:e,revocation:t,signingKeyRevocation:n});for(let e of this.peers.values())try{e.admitted?.exposed?.send(r)}catch{}}async receiveLists(e){let t=this.identity,n=(0,u.decodeDeviceRoster)(this.options.cryptoContext,e.roster),r=(0,u.decodeDeviceRevocationList)(this.options.cryptoContext,e.revocation),i=(0,u.decodeSigningKeyRevocation)(this.options.cryptoContext,e.signingKeyRevocation),a={...n.ok&&R(t.roster,n.value)?{roster:n.value}:{},...r.ok&&R(t.revocation,r.value)?{revocation:r.value}:{},...i.ok&&i.value.seq>t.signingKeyRevocation.seq?{signingKeyRevocation:i.value}:{}};if(Object.keys(a).length===0)return;let o=await(0,u.verifyDeviceChain)(this.options.cryptoContext,{masterPublicKey:t.masterPublicKey,signingKeyCert:t.signingKeyCertificate,deviceCert:t.deviceCertificate,roster:a.roster??t.roster,revocation:a.revocation??t.revocation,signingKeyRevocation:a.signingKeyRevocation??t.signingKeyRevocation,now:(this.options.now??Date.now)(),lastSeen:t.marks,required:{roster:!0,revocation:!0,signingKeyRevocation:!0},listExpiryGraceMs:1/0});if(!o.ok||this.stopped)return;let{rosterSeq:s,revocationSeq:c,signingKeyRevocationSeq:l}=o.accepted;this.adoptLists({...a,marks:{...a.signingKeyRevocation!==void 0&&l!==void 0?{signingKeyRevocationSeq:l}:{},bySigningKey:{[o.signingKeyId]:{...a.roster!==void 0&&s!==void 0?{rosterSeq:s}:{},...a.revocation!==void 0&&c!==void 0?{revocationSeq:c}:{}}}}})}syncPeers(){this.sync=this.sync.then(async()=>{if(this.stopped)return;let e=this.identity,t=e.deviceCertificate,n=new Set(e.revocation.revokedDeviceIds),r=new Map;for(let i of e.roster.devices)i.deviceId!==t.deviceId&&!n.has(i.deviceId)&&r.set(i.deviceId,i);for(let[e,t]of this.peers){let n=r.get(e);(n===void 0||n.kaKey!==t.device.kaKey||n.kaEpoch!==t.device.kaEpoch)&&this.drop(t)}let i=[];for(let[n,a]of r){if(this.peers.has(n))continue;let r,o;try{r=await(0,u.derivePairRendezvous)(this.options.cryptoContext,{ownKaPrivateKey:e.kaPrivateKey,own:t,peerDeviceId:n,lists:e}),o=await r.relayInbox()}catch{continue}let s={device:a,role:t.deviceId<a.deviceId?`offerer`:`answerer`,rendezvous:r,inbound:o.inbound,outbound:o.outbound,attempts:new Mt,replies:new Mt,relayFailures:0};this.peers.set(n,s),this.byInbound.set(o.inbound,s),i.push(s)}if(this.stopped)return;this.options.relayServer?.declarePeers([...this.peers.values()].map(e=>({deviceId:e.device.deviceId,rendezvous:e.rendezvous}))),this.options.relay.declarePresence([...this.byInbound.keys()]);let a=this.peerRoutes();this.options.relay.declarePeers?.(a),this.options.relays?.advertised?.(a,AbortSignal.timeout(Ot)).catch(()=>void 0);for(let e of i)this.hello(e)});let e=this.sync;return this.sync=e.catch(()=>void 0),e}drop(e){this.peers.delete(e.device.deviceId),this.byInbound.delete(e.inbound),e.attempts.cancel(),e.replies.cancel();let{pending:t,admitted:n}=e;if(e.pending=void 0,e.admitted=void 0,t?.link.close(),n?.link.close(),t!==void 0&&!this.stopped){let t={deviceId:e.device.deviceId,end:`closed`,error:Error(`peer device was revoked or is no longer in the roster`)};for(let e of this.refusalHandlers)e(t)}}roleFor(e){return this.peers.get(e)?.role}link(e){return this.peers.get(e)?.admitted?.exposed}connect(e,t=Et){if(this.stopped)return Promise.reject(Error(`device mesh node stopped`));let n=this.peers.get(e);if(n===void 0)return Promise.reject(Error(`not a rostered, unrevoked peer device`));let r=n.admitted?.exposed;return r===void 0?new Promise((r,i)=>{let a=()=>{clearTimeout(s),c(),l(),this.waiters.delete(o)},o=e=>{a(),i(e)},s=setTimeout(()=>o(Error(`peer device did not connect in time`)),t);s.unref?.();let c=this.onLink(t=>{t.admission.deviceId===e&&(a(),r(t))}),l=this.onRefusal(t=>{t.deviceId===e&&o(t.error instanceof Error?t.error:Error(`connection ${t.end}`))});this.waiters.add(o),this.hello(n)}):Promise.resolve(r)}onLink(e){return this.linkHandlers.add(e),()=>this.linkHandlers.delete(e)}onRefusal(e){return this.refusalHandlers.add(e),()=>this.refusalHandlers.delete(e)}stop(){if(!this.stopped){this.stopped=!0;for(let e of this.unsubscribes.splice(0))e();for(let e of[...this.peers.values()])this.drop(e);for(let e of[...this.waiters])e(Error(`device mesh node stopped`));this.linkHandlers.clear(),this.refusalHandlers.clear()}}hello(e){this.stopped||this.options.relay.send(e.outbound,{v:1,kind:`hello`,from:this.instance})}receive(e,t){if(this.stopped)return;let n=this.byInbound.get(e);if(n===void 0)return;let r=Re(t);if(r===void 0)return;if(r.kind===`hello`){this.onHello(n,r.from);return}if(r.to!==this.instance)return;if(r.kind===`offer`){this.onOffer(n,r);return}for(let e of[n.pending,n.admitted])if(e?.cid===r.cid&&e.remoteInstance===r.from){e.link.onSignal(z(r));return}let i=n.waitingOffer;r.kind===`ice`&&i?.cid===r.cid&&i.from===r.from&&i.ice.length<64&&i.ice.push(z(r))}serves(e,t){return e.admitted?.remoteInstance===t||e.pending?.remoteInstance===t}onHello(e,t){if(!this.serves(e,t)){if(e.role===`answerer`){e.replies.run(()=>this.hello(e));return}e.attempts.run(()=>{this.stopped||this.peers.get(e.device.deviceId)!==e||this.serves(e,t)||this.startAttempt(e,t,Nt()).link.offer()})}}onOffer(e,t){if(e.role!==`answerer`||e.admitted?.cid===t.cid||e.pending?.cid===t.cid)return;let n={cid:t.cid,from:t.from,ice:[]};e.waitingOffer=n,e.attempts.run(()=>{if(e.waitingOffer===n&&(e.waitingOffer=void 0),this.stopped||this.peers.get(e.device.deviceId)!==e||e.admitted?.cid===t.cid||e.pending?.cid===t.cid)return;let{link:r}=this.startAttempt(e,t.from,t.cid);r.onSignal(z(t));for(let e of n.ice)r.onSignal(e)})}startAttempt(e,t,n){let r=e.pending;e.pending=void 0,r?.link.close();let i=r=>{this.stopped||this.options.relay.send(e.outbound,{v:1,from:this.instance,to:t,cid:n,...r})},a,o=new Ue({role:e.role,createPeer:async()=>{let{stage:t,servers:n}=await this.relayStage(e);return a!==void 0&&(a.relayStage=t),this.createPeer(n)},sendSignal:i,startHandshake:t=>(0,u.startDeviceHandshake)(this.options.cryptoContext,{role:e.role===`offerer`?`initiator`:`responder`,identity:this.identity,sessionDescriptor:this.sessionDescriptor,...e.role===`offerer`?{expectedPeerDeviceId:e.device.deviceId}:{},localFingerprint:t.localFingerprint,remoteFingerprint:t.remoteFingerprint,locality:`another-host`,localPolicy:this.options.localPolicy,send:t.send,...this.options.fetchLatestLists===void 0?{}:{fetchLatestLists:this.options.fetchLatestLists},onListsAdopted:e=>this.adoptLists(e),...this.options.now===void 0?{}:{now:this.options.now},...this.options.handshakeTimeoutMs===void 0?{}:{timeoutMs:this.options.handshakeTimeoutMs}}),connectTimeoutMs:this.options.connectTimeoutMs??Et,accepts:t=>t.admission.deviceId===e.device.deviceId,onAdmitted:t=>this.admitted(e,o,t),onEnded:(t,n)=>this.ended(e,o,t,n)});return a={cid:n,remoteInstance:t,link:o},e.pending=a,a}adoptLists(e){let t=this.identity,n={...t,...R(t.roster,e.roster)?{roster:e.roster}:{},...R(t.revocation,e.revocation)?{revocation:e.revocation}:{},...e.signingKeyRevocation!==void 0&&e.signingKeyRevocation.seq>t.signingKeyRevocation.seq?{signingKeyRevocation:e.signingKeyRevocation}:{},marks:Ft(t.marks,e.marks)};this.refresh({identity:n}).catch(()=>void 0),this.options.onListsAdopted?.(e)}admitted(e,t,n){let r=e.pending;if(r===void 0||r.link!==t)return;if(n.admission.deviceId!==e.device.deviceId){t.close();return}let i=n.admission,a=t.channelBinding;if(a===void 0){t.close();return}let o=new ee.ConnectionAuthority({deviceId:i.deviceId,sessionId:i.sessionId,locality:i.locality,capabilities:i.capabilities},this.options.operatorApprover);t.onEnd(()=>o.close());let s=o.authorize(`message`);t.onMessage(e=>{let t=Rt(e);t!==void 0&&this.receiveLists(t).catch(()=>void 0)});let c={admission:i,result:n,channelBinding:a,authority:o,send:e=>t.send(e),onMessage:e=>t.onMessage(n=>{Rt(n)===void 0&&s.then(r=>{r.allowed&&!t.ended?e(n):t.close()})}),openFileChannel:async()=>jt(await t.openFileChannel()),onFileChannel:e=>t.onFileChannel(t=>e(jt(t))),onClose:e=>t.onEnd(()=>e()),close:()=>t.close()};r.exposed=c,e.relayFailures=0;let l=e.admitted;e.admitted=r,e.pending=void 0,l?.link.close(),this.options.relay.confirmPeer?.(i.deviceId);for(let e of this.linkHandlers)e(c)}ended(e,t,n,r){if(e.admitted?.link===t){e.admitted=void 0;return}if(e.pending?.link!==t)return;let i=e.pending.relayStage;e.pending=void 0;let a=r.stage===`connecting`&&(n===`timeout`||r.peer?.state===`failed`)&&r.peer?.history.includes(`connected`)!==!0,o=r;r.cause instanceof L?o=r.cause:a&&i===`direct`?o=new L(e.device.deviceId,`no-direct-path`,{cause:r}):a&&(e.relayFailures+=1);let s={deviceId:e.device.deviceId,end:n,error:o};for(let e of this.refusalHandlers)e(s)}async relayStage(e){let t=this.options.relays,n=[],r=await this.embeddedRelays(e);if(r.length>0&&n.push({stage:`embedded`,servers:r}),t?.configured!==void 0&&t.configured.length>0&&n.push({stage:`configured`,servers:t.configured}),n.length===0){if(t?.relayOnly===!0)throw new L(e.device.deviceId,`relay-only`);return{stage:`direct`,servers:[]}}return n[e.relayFailures%n.length]}peerRoutes(e){let t=[...this.peers.values()];return(e===void 0?t:[e,...t.filter(t=>t!==e)]).map(e=>({deviceId:e.device.deviceId,inbound:e.inbound,outbound:e.outbound,rendezvous:e.rendezvous}))}async embeddedRelays(e){let t=this.options.relays?.advertised;if(t===void 0)return[];let n;try{n=await t(this.peerRoutes(e),AbortSignal.timeout(Ot))}catch{return[]}let r=e.device.deviceId,i=[r,...[...n.keys()].filter(e=>e!==r)],a=(this.options.now??Date.now)(),o=[],s=0;for(let e of i){if(s>=2)break;let t=n.get(e),r=this.peers.get(e);t!==void 0&&t.length!==0&&r!==void 0&&(s+=1,o.push(...await wt(r.rendezvous,t.slice(0,3),a,this.options.relays?.credentialTtlMs)))}return o}createPeer(e){let t=[...this.options.iceServers??[],...e];return new b({...t.length>0?{iceServers:t}:{},...this.options.relays?.relayOnly===!0?{forceTurn:!0}:{},...this.options.loadDataChannel===void 0?{}:{loadDataChannel:this.options.loadDataChannel}})}};function z(e){return e.kind===`ice`?{kind:`ice`,candidate:{...e.candidate}}:{kind:e.kind,sdp:e.sdp}}function Bt(){let e=new Map;return{connect(){let t={messages:new Set,absents:new Set,topics:new Set,open:!0},n=()=>{for(let n of t.topics)e.get(n)===t&&e.delete(n);t.topics=new Set};return{declarePresence(r){if(t.open){n(),t.topics=new Set(r);for(let n of r)e.set(n,t)}},send(n,r){if(!t.open)return;let i=JSON.parse(JSON.stringify(r));queueMicrotask(()=>{let r=e.get(n);if(r===void 0||r===t||!r.open){for(let e of t.absents)e(n);return}for(let e of r.messages)e(n,i)})},onMessage(e){return t.messages.add(e),()=>t.messages.delete(e)},onAbsent(e){return t.absents.add(e),()=>t.absents.delete(e)},close(){t.open=!1,n(),t.messages.clear(),t.absents.clear()}}}}}var Vt=class{options;socket;messages=new Set;absents=new Set;outbox=[];topics;closed=!1;constructor(e){this.options=e;let t=e.createSocket??(e=>new f.default(e));this.socket=t(e.url),this.socket.on(`open`,()=>this.flush()),this.socket.on(`message`,e=>this.receive(e)),this.socket.on(`error`,e=>this.options.onError?.(e instanceof Error?e:Error(String(e)))),this.socket.on(`close`,()=>{this.closed||this.options.onError?.(Error(`signaling relay connection closed`))})}flush(){this.topics!==void 0&&this.write({type:`presence`,topics:this.topics});for(let e of this.outbox.splice(0))this.socket.send(e)}write(e){this.socket.send(JSON.stringify(e))}receive(e){let t;try{t=JSON.parse(typeof e==`string`?e:String(e))}catch{return}if(typeof t!=`object`||!t)return;let n=t;if(n.type===`message`&&typeof n.topic==`string`)for(let e of this.messages)e(n.topic,n.data);else if(n.type===`absent`&&typeof n.topic==`string`)for(let e of this.absents)e(n.topic);else n.type===`present`?this.options.onPresent?.():n.type===`error`&&this.options.onError?.(Error(`signaling relay refused a frame: ${String(n.reason)}`))}declarePresence(e){this.closed||(this.topics=[...e],this.socket.readyState===1&&this.write({type:`presence`,topics:this.topics}))}send(e,t){if(this.closed)return;let n=JSON.stringify({type:`message`,topic:e,data:t});this.socket.readyState===1?this.socket.send(n):this.outbox.length<256?this.outbox.push(n):this.options.onError?.(Error(`signaling relay is not reachable; message dropped`))}onMessage(e){return this.messages.add(e),()=>this.messages.delete(e)}onAbsent(e){return this.absents.add(e),()=>this.absents.delete(e)}close(){this.closed=!0,this.messages.clear(),this.absents.clear(),this.outbox.length=0,this.socket.close()}};function Ht(e){return{candidates:t=>Promise.resolve(e.recall(t.deviceId))}}function Ut(e,t){return e.host===t.host&&e.port===t.port}function Wt(e,t){return[{host:t.host,port:t.port},...e.filter(e=>!Ut(e,t))].slice(0,3)}function Gt(){let e=new Map,t;return{recall:t=>e.get(t)??[],remember:(t,n)=>{e.set(t,Wt(e.get(t)??[],n))},retain:t=>{let n=new Set(t);for(let t of[...e.keys()])n.has(t)||e.delete(t)},lastListenPort:()=>t,rememberListenPort:e=>{t=e}}}const Kt=/^[A-Za-z0-9_-]{43}$/,qt=/^[A-Za-z0-9_-]{22}$/,Jt=12e4,Yt=1008;function B(e){return(0,p.createHash)(`sha256`).update(`lan-address:${e}`).digest(`base64url`)}function Xt(e,t){return(0,p.createHmac)(`sha256`,e).update(`lan-present:${t}`).digest(`base64url`)}function Zt(e,t,n){if(typeof n!=`string`)return!1;let r=Buffer.from(Xt(e,t)),i=Buffer.from(n);return i.length===r.length&&(0,p.timingSafeEqual)(i,r)}function Qt(e,t){return new Promise((n,r)=>{let i=new f.WebSocketServer({port:e,...t===void 0?{}:{host:t},maxPayload:65536,perMessageDeflate:!1,verifyClient:e=>e.origin===void 0||e.origin===``}),a=e=>{i.close(),r(e)};i.once(`error`,a),i.once(`listening`,()=>{i.off(`error`,a),n(i)})})}function $t(e){let t;try{t=JSON.parse(String(e))}catch{return}if(typeof t!=`object`||!t||Array.isArray(t))return;let n=t;if(!(typeof n.type!=`string`||typeof n.to!=`string`||!Kt.test(n.to)))return n.type===`probe`?typeof n.nonce==`string`&&qt.test(n.nonce)?{type:n.type,to:n.to,nonce:n.nonce}:void 0:{type:n.type,to:n.to,data:n.data}}async function en(e={}){let t;try{t=await Qt(e.port??0,e.host)}catch(n){if(e.port===void 0||e.port===0)throw n;t=await Qt(0,e.host)}let n=t.address(),r=typeof n==`object`&&n?n.port:0,i=new Map,a=new Set;return t.on(`connection`,e=>{if(t.clients.size>32){e.close(Yt);return}let n=0,r=Date.now(),o=setTimeout(()=>e.close(),Jt);o.unref?.(),e.on(`close`,()=>clearTimeout(o)),e.on(`error`,()=>e.close()),e.on(`message`,t=>{let s=Date.now();if(s-r>1e4&&(r=s,n=0),n+=1,n>128){e.close(Yt);return}clearTimeout(o),o=setTimeout(()=>e.close(),Jt),o.unref?.();let c=$t(t);if(c===void 0)return;let l=i.get(c.to);if(l===void 0){e.send(JSON.stringify({type:`absent`,to:c.to}));return}if(c.type===`probe`&&c.nonce!==void 0){e.send(JSON.stringify({type:`present`,to:c.to,nonce:c.nonce,proof:Xt(l,c.nonce)}));return}if(c.type===`message`)for(let e of a)e(l,c.data)})}),{port:r,setPresence(e){i=new Map(e.map(e=>[B(e),e]))},onMessage(e){return a.add(e),()=>a.delete(e)},close(){a.clear(),i=new Map;for(let e of t.clients)e.terminate();return new Promise(e=>t.close(()=>e()))}}}const V=`_rdv._tcp.local`;function tn(){return(0,d.createRequire)(require("url").pathToFileURL(__filename).href)(`multicast-dns`)()}function nn(){let e=[];for(let t of Object.values((0,h.networkInterfaces)()))for(let n of t??[])n.internal||(n.family===`IPv4`||n.family===`IPv6`&&!n.address.startsWith(`fe80`))&&e.push(n.address);return e}function rn(e){let t=new Uint8Array(e);return globalThis.crypto.getRandomValues(t),Buffer.from(t).toString(`hex`)}function an(e){return Buffer.from(e.subarray(0,16)).toString(`hex`)}function on(e){return Math.max(8,Math.ceil(e/8)*8)}function H(e,t){return e.toLowerCase()===t.toLowerCase()}var sn=class{options;transport;routes=[];port;records;instances=new Set;timer;generation=0;closed=!1;epochCover;announced;lastAnswer;answerTimer;constructor(e={}){this.options=e}now(){return(this.options.now??Date.now)()}open(){if(!this.closed){if(this.transport!==void 0)return this.transport;try{let e=(this.options.createTransport??tn)();return e.on(`query`,e=>this.onQuery(e)),e.on(`error`,e=>this.options.onError?.(e)),this.transport=e,e}catch(e){this.closed=!0,this.options.onError?.(e instanceof Error?e:Error(String(e)));return}}}advertise(e,t){return this.routes=e,this.port=t,this.rebuild()}async rebuild(){let e=++this.generation,t=this.port;if(this.closed||t===void 0)return;let n=(0,u.rendezvousEpoch)(this.now()),r=await Promise.all(this.routes.map(e=>e.rendezvous.tag(`mdns`,`outbound`,n)));if(e!==this.generation||this.closed)return;this.epochCover?.epoch!==n&&(this.epochCover={epoch:n,padding:[],target:`${rn(8)}.local`});let{padding:i,target:a}=this.epochCover,o=on(r.length)-r.length;for(;i.length<o;)i.push(rn(16));let s=[...r.map(an),...i.slice(0,o)].sort(),c=JSON.stringify([n,t,s]),l=s.map(e=>({name:V,type:`PTR`,ttl:120,data:`${e}.${V}`})),d=[];for(let e of s){let n=`${e}.${V}`;d.push({name:n,type:`SRV`,ttl:120,data:{priority:0,weight:0,port:t,target:a}},{name:n,type:`TXT`,ttl:120,data:[]})}for(let e of(this.options.addresses??nn)())d.push({name:a,type:e.includes(`:`)?`AAAA`:`A`,ttl:120,data:e});this.records={answers:l,additionals:d},this.instances=new Set(s.map(e=>`${e}.${V}`.toLowerCase())),this.schedule(n),c!==this.announced&&(this.announced=c,this.open()?.respond(this.records))}schedule(e){this.timer!==void 0&&clearTimeout(this.timer);let t=Math.max(0,(e+1)*u.RENDEZVOUS_EPOCH_MS-this.now());this.timer=setTimeout(()=>{this.rebuild().catch(()=>void 0)},t),this.timer.unref?.()}onQuery(e){this.records===void 0||this.closed||(e.questions??[]).some(e=>H(e.name,`_rdv._tcp.local`)&&(e.type===`PTR`||e.type===`ANY`)||this.instances.has(e.name.toLowerCase()))&&this.answer()}answer(){if(this.answerTimer!==void 0)return;let e=this.options.minAnswerIntervalMs??500,t=this.lastAnswer===void 0?0:this.lastAnswer+e-this.now(),n=()=>{this.answerTimer=void 0,!(this.closed||this.records===void 0)&&(this.lastAnswer=this.now(),this.transport?.respond(this.records))};if(t<=0){n();return}this.answerTimer=setTimeout(n,t),this.answerTimer.unref?.()}async candidates(e,t){let n=this.open();if(n===void 0||t.aborted)return[];let r=(0,u.rendezvousEpoch)(this.now()),i=new Set((await e.rendezvous.lookupTags(`mdns`,r)).map(e=>`${an(e)}.${V}`));return t.aborted||this.closed?[]:new Promise(e=>{let r=[],a,o=()=>{clearTimeout(c),clearTimeout(a),t.removeEventListener(`abort`,o),n.removeListener(`response`,s),e(r)},s=(e,t)=>{let n=[...e.answers??[],...e.additionals??[]];for(let e of n){if(e.type!==`PTR`||!H(e.name,`_rdv._tcp.local`)||typeof e.data!=`string`||!i.has(e.data.toLowerCase()))continue;let a=n.find(t=>t.type===`SRV`&&H(t.name,e.data))?.data?.port;if(typeof a!=`number`||!Number.isInteger(a)||a<=0||a>65535)continue;let o=r.filter(e=>e.host===t.address);r.length<8&&o.length<2&&!o.some(e=>e.port===a)&&r.push({host:t.address,port:a})}r.length!==0&&a===void 0&&(a=setTimeout(o,this.options.answerGraceMs??200),a.unref?.())},c=setTimeout(o,this.options.lookupTimeoutMs??1e3);c.unref?.(),t.addEventListener(`abort`,o,{once:!0}),n.on(`response`,s),n.query({questions:[{name:V,type:`PTR`}]})})}close(){this.closed=!0,this.generation+=1,this.timer!==void 0&&clearTimeout(this.timer),this.answerTimer!==void 0&&clearTimeout(this.answerTimer),this.transport?.destroy(),this.transport=void 0}};function cn(){let e=new Set,t=[],n=(t,n,r)=>{let i=JSON.parse(JSON.stringify(n));queueMicrotask(()=>{for(let n of e)for(let e of r(n))e(i,{address:t.address})})};return{responses:t,transport(r){let i={address:r,queries:new Set,responses:new Set};return e.add(i),{on(e,t){e===`query`&&i.queries.add(t),e===`response`&&i.responses.add(t)},removeListener(e,t){i.responses.delete(t)},query(e){n(i,e,e=>e.queries)},respond(e){t.push(JSON.parse(JSON.stringify(e))),n(i,e,e=>e.responses)},destroy(){e.delete(i)}}}}}var ln=class{until=new Map;failures=new Map;has(e,t){let n=this.until.get(e);return n===void 0?!1:n>t?!0:(this.until.delete(e),!1)}fail(e,t,n){let r=(this.failures.get(e)??0)+1;this.failures.delete(e),this.failures.set(e,r);for(let e of this.failures.keys()){if(this.failures.size<=32)break;this.failures.delete(e),this.until.delete(e)}let i=Math.min(2**(r-1),16);this.until.set(e,t+n*i)}clear(){this.until.clear(),this.failures.clear()}};function un(e){if(typeof e!=`object`||!e)return!1;let t=e.kind;return t===`hello`||t===`offer`||t===`answer`}function dn(e){return`${e.host}:${e.port}`}function fn(){let e=new Uint8Array(16);return globalThis.crypto.getRandomValues(e),Buffer.from(e).toString(`base64url`)}function pn(e){return Buffer.from(e).toString(`base64url`)}function mn(e){return`ws://${e.host.includes(`:`)?`[${e.host}]`:e.host}:${e.port}`}function hn(e){try{let t=JSON.parse(String(e));return typeof t==`object`&&t?t:void 0}catch{return}}var gn=class{options;routes=new Map;byDevice=new Map;lanIn=new Map;messages=new Set;absents=new Set;unsubscribes=[];abort=new AbortController;sync=Promise.resolve();pendingPeers=0;waiting=[];timer;closed=!1;constructor(e){this.options=e;for(let e of this.carriers())this.unsubscribes.push(e.onMessage((e,t)=>this.deliver(e,t)),e.onAbsent(e=>this.absent(e)));this.unsubscribes.push(e.listener.onMessage((e,t)=>{let n=this.lanIn.get(e);n!==void 0&&this.deliver(n,t)}))}now(){return(this.options.now??Date.now)()}carriers(){return[...this.options.signaling??[],...this.options.relay===void 0?[]:[this.options.relay]]}deliver(e,t){if(!this.closed)for(let n of this.messages)n(e,t)}absent(e){if(!this.closed)for(let t of this.absents)t(e)}declarePresence(e){for(let t of this.carriers())t.declarePresence(e)}declarePeers(e){for(let t of this.carriers())t.declarePeers?.(e);this.pendingPeers+=1,this.sync=this.sync.then(()=>this.applyPeers(e)).catch(e=>{this.options.onError?.(e instanceof Error?e:Error(String(e)))}).finally(()=>{if(--this.pendingPeers,!(this.pendingPeers>0))for(let{topic:e,data:t}of this.waiting.splice(0))this.send(e,t)})}async applyPeers(e){if(this.closed)return;let t=(0,u.rendezvousEpoch)(this.now()),n=new Map,r=new Map;for(let i of e){let e=pn(await i.rendezvous.tag(`lan-inbox`,`outbound`,t));for(let e of await i.rendezvous.lookupTags(`lan-inbox`,t))n.set(pn(e),i.inbound);let a=this.routes.get(i.outbound),o=a!==void 0&&a.route.deviceId===i.deviceId?a:{route:i,lanOut:e,path:{kind:`unresolved`},avoid:new ln,avoidCarriers:new ln};o.route=i,o.lanOut=e,r.set(i.outbound,o)}if(!this.closed){for(let[e,t]of this.routes)r.get(e)!==t&&this.reset(t);this.routes.clear(),this.byDevice.clear();for(let[e,t]of r)this.routes.set(e,t),this.byDevice.set(t.route.deviceId,t);this.lanIn=n,this.options.listener.setPresence([...n.keys()]),this.cacheWrite(()=>this.options.cache?.retain(e.map(e=>e.deviceId))),await Promise.all((this.options.advertisers??[]).map(t=>t.advertise(e,this.options.listener.port))),!this.closed&&this.scheduleEpoch(t,e)}}scheduleEpoch(e,t){this.timer!==void 0&&clearTimeout(this.timer);let n=Math.max(0,(e+1)*u.RENDEZVOUS_EPOCH_MS-this.now());this.timer=setTimeout(()=>this.declarePeers(t),n),this.timer.unref?.()}confirmPeer(e){let t=this.byDevice.get(e),n=t?.path;if(!(t===void 0||n?.kind!==`direct`&&n?.kind!==`relay`)){if(clearTimeout(n.deadline),n.deadline=void 0,n.kind===`relay`){t.avoidCarriers.clear();return}t.avoid.clear(),this.cacheWrite(()=>this.options.cache?.remember(e,n.candidate))}}cacheWrite(e){try{e()}catch(e){this.options.onError?.(e instanceof Error?e:Error(String(e)))}}send(e,t){if(this.closed)return;if(this.pendingPeers>0){this.waiting.length<256?this.waiting.push({topic:e,data:t}):this.viaRelay(e,t);return}let n=this.routes.get(e);if(n===void 0){this.viaRelay(e,t);return}let r=n.path;if(r.kind===`direct`&&r.socket.readyState===1){this.sendDirect(n,r,t);return}if(r.kind===`relay`&&this.now()<r.until){this.viaCarrier(n,r,t);return}if(r.kind===`resolving`){r.queue.length<256?r.queue.push(t):this.viaRelay(e,t);return}r.kind===`direct`&&this.reset(n);let i=[t];n.path={kind:`resolving`,queue:i},this.resolve(n,i)}sendDirect(e,t,n){un(n)&&this.armDeadline(e,t),t.socket.send(JSON.stringify({type:`message`,to:B(e.lanOut),data:n}))}viaRelay(e,t){let n=this.carriers().at(-1);if(n===void 0){queueMicrotask(()=>this.absent(e));return}n.send(e,t)}viaCarrier(e,t,n){un(n)&&t.carrier!==this.carriers().at(-1)&&this.armDeadline(e,t),t.carrier.send(e.route.outbound,n)}async resolve(e,t){let n=new Set;for(let r of this.options.sources){if(this.closed||e.path.kind!==`resolving`)return;for(let i of await this.look(r,e.route)){let r=dn(i);if(n.size>=8)break;if(n.has(r)||e.avoid.has(r,this.now()))continue;n.add(r);let a=await this.probe(i,e.lanOut);if(a===void 0)continue;if(this.closed||e.path.kind!==`resolving`||this.routes.get(e.route.outbound)!==e){a.close();return}let o=this.useDirect(e,a,i);for(let n of t)this.sendDirect(e,o,n);return}}if(this.closed||e.path.kind!==`resolving`)return;this.fallBack(e);let r=e.path;for(let n of t)r.kind===`relay`?this.viaCarrier(e,r,n):this.viaRelay(e.route.outbound,n)}fallBack(e){let t=this.now(),n=this.carriers(),r=n.find(n=>!e.avoidCarriers.has(n,t))??n.at(-1);e.path=r===void 0?{kind:`unresolved`}:{kind:`relay`,until:t+this.recheckMs(),carrier:r}}recheckMs(){return this.options.relayRecheckMs??3e4}async look(e,t){let n=AbortSignal.timeout(e.timeoutMs??this.options.sourceTimeoutMs??1500),r=AbortSignal.any([n,this.abort.signal]);try{return await Promise.race([e.candidates(t,r),new Promise(e=>r.addEventListener(`abort`,()=>e([]),{once:!0}))])}catch{return[]}}probe(e,t){let n=B(t),r=fn();return new Promise(i=>{let a;try{a=(this.options.connect??(e=>new f.default(mn(e),{maxPayload:4096})))(e)}catch{i(void 0);return}let o=!1,s=e=>{o||(o=!0,clearTimeout(c),e||a.close(),i(e?a:void 0))},c=setTimeout(()=>s(!1),this.options.probeTimeoutMs??1500);c.unref?.(),a.on(`open`,()=>a.send(JSON.stringify({type:`probe`,to:n,nonce:r}))),a.on(`message`,e=>{let i=hn(e);if(i?.to===n){if(i.type===`absent`){s(!1);return}s(Zt(t,r,i.proof))}}),a.on(`error`,()=>s(!1)),a.on(`close`,()=>s(!1))})}armDeadline(e,t){t.deadline===void 0&&(t.deadline=setTimeout(()=>{e.path===t&&(t.kind===`direct`?e.avoid.fail(dn(t.candidate),this.now(),this.recheckMs()):e.avoidCarriers.fail(t.carrier,this.now(),this.recheckMs()),this.reset(e),this.fallBack(e))},this.options.admissionTimeoutMs??2e4),t.deadline.unref?.())}useDirect(e,t,n){let r={kind:`direct`,socket:t,candidate:n};e.path=r;let i=()=>{e.path===r&&this.reset(e)};return t.on(`close`,i),t.on(`error`,i),t.on(`message`,t=>{let n=hn(t);n?.type===`absent`&&n.to===B(e.lanOut)&&i()}),r}reset(e){let t=e.path;e.path={kind:`unresolved`},t.kind===`relay`&&clearTimeout(t.deadline),t.kind===`direct`&&(clearTimeout(t.deadline),t.socket.close())}onMessage(e){return this.messages.add(e),()=>this.messages.delete(e)}onAbsent(e){return this.absents.add(e),()=>this.absents.delete(e)}close(){if(!this.closed){this.closed=!0,this.abort.abort(),this.timer!==void 0&&clearTimeout(this.timer);for(let e of this.unsubscribes.splice(0))e();for(let e of this.routes.values())this.reset(e);this.routes.clear(),this.byDevice.clear(),this.messages.clear(),this.absents.clear(),this.waiting=[];for(let e of this.options.advertisers??[])e.close();this.options.listener.close().catch(()=>void 0)}}};async function _n(e={}){let t=e.cache??Gt(),n=t.lastListenPort(),r=await en({...n===void 0?{}:{port:n},...e.host===void 0?{}:{host:e.host}});try{t.rememberListenPort(r.port)}catch(t){e.onError?.(t instanceof Error?t:Error(String(t)))}let i=e.mdns===!1?void 0:new sn({...e.onError===void 0?{}:{onError:e.onError},...e.mdns}),a=e.internet?.dht,o=e.internet?.signaling??[];return new gn({...e.relay===void 0?{}:{relay:e.relay},...o.length>0?{signaling:o}:{},listener:r,sources:[Ht(t),...i===void 0?[]:[i],...a===void 0?[]:[a]],cache:t,advertisers:[...i===void 0?[]:[i],...a===void 0?[]:[a]],...e.onError===void 0?{}:{onError:e.onError}})}const vn=Uint8Array.from([48,46,2,1,0,48,5,6,3,43,101,112,4,34,4,32]),U=new TextEncoder,yn=new TextDecoder;function W(e){return e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength)}function bn(e){let t=atob(e.replace(/-/g,`+`).replace(/_/g,`/`)),n=new Uint8Array(t.length);for(let e=0;e<t.length;e+=1)n[e]=t.charCodeAt(e);return n}function G(e){let t=new Uint8Array(e.reduce((e,t)=>e+t.length,0)),n=0;for(let r of e)t.set(r,n),n+=r.length;return t}function xn(e,t){if(e.length!==t.length)return!1;let n=0;for(let r=0;r<e.length;r+=1)n|=e[r]^t[r];return n===0}async function Sn(e){if(e.length!==32)throw Error(`an Ed25519 seed is 32 bytes`);let t=await globalThis.crypto.subtle.importKey(`pkcs8`,W(G([vn,e])),{name:`Ed25519`},!0,[`sign`]),n=await globalThis.crypto.subtle.exportKey(`jwk`,t);if(typeof n.x!=`string`)throw Error(`Ed25519 public key unavailable`);return{publicKey:bn(n.x),sign:async e=>new Uint8Array(await globalThis.crypto.subtle.sign({name:`Ed25519`},t,W(e)))}}async function Cn(e,t,n){if(e.length!==32||n.length!==64)return!1;try{let r=await globalThis.crypto.subtle.importKey(`raw`,W(e),{name:`Ed25519`},!1,[`verify`]);return await globalThis.crypto.subtle.verify({name:`Ed25519`},r,W(n),W(t))}catch{return!1}}function K(e,t,n){let r=[];return e!==void 0&&e.length>0&&r.push(U.encode(`4:salt${e.length}:`),e),r.push(U.encode(`3:seqi${t}e1:v${n.length}:`),n),G(r)}async function wn(e,t,n,r){if(r.length>999)throw Error(`record value exceeds 999 bytes`);if(t!==void 0&&t.length>64)throw Error(`salt exceeds 64 bytes`);if(!Number.isSafeInteger(n)||n<0)throw Error(`seq must be a non-negative integer`);let i=await e.sign(K(t,n,r));return{k:e.publicKey,...t===void 0?{}:{salt:t},seq:n,v:r,sig:i}}async function q(e,t,n){return!xn(e.k,t)||!xn(e.salt??new Uint8Array,n??new Uint8Array)||e.v.length>999||!Number.isSafeInteger(e.seq)||e.seq<0?!1:Cn(t,K(n,e.seq,e.v),e.sig)}const Tn={hints:`bep44-salt`,revocation:`bep44-revocation-salt`};async function J(e){return new Uint8Array(await globalThis.crypto.subtle.digest(`SHA-256`,W(G(e))))}async function En(e,t,n,r,i=0){let[a,o]=await Promise.all([e.signingSeed(n,r,t),e.tag(Tn[t],n,r)]);if(i===0)return{key:await Sn(a),salt:o};let s=U.encode(`chunk`),c=Uint8Array.of(i),[l,u]=await Promise.all([J([s,a,c]),J([s,o,c])]);return{key:await Sn(l),salt:u}}async function Dn(e){let t=U.encode(JSON.stringify(e)),n=(await J([t])).subarray(0,8),r=Math.max(1,Math.ceil(t.length/854));if(r>8)throw Error(`device lists too large to publish as records`);return Array.from({length:r},(e,i)=>{let a=new Uint8Array(864).fill(32);return a[0]=r,a[1]=i,a.set(n,2),a.set(t.subarray(i*854,(i+1)*854),10),a})}function On(e){let t=e[0];if(e.length===864&&e[1]===0)return t!==void 0&&t>=1&&t<=8?t:void 0}function kn(e){let t=e.length,n=e[0]?.subarray(2,10),r=[];for(let[i,a]of e.entries()){if(a.length!==864||a[0]!==t||a[1]!==i||!An(a.subarray(2,10),n))return;r.push(a.subarray(10))}return Y(G(r))}function An(e,t){return t!==void 0&&e.length===t.length&&e.every((e,n)=>e===t[n])}function jn(e,t){let n=U.encode(JSON.stringify(e));if(n.length>t)throw Error(`record does not fit its fixed size`);let r=new Uint8Array(t).fill(32);return r.set(n),r}function Y(e){try{return JSON.parse(yn.decode(e))}catch{return}}function Mn(e,t){let n=[];for(let r of e){if(n.length>=t)break;r.host.length===0||r.host.length>64||n.push([r.host,r.port])}return n}function Nn(e,t=[]){let n=Mn(e,8),r=Mn(t,4);for(;;)try{return jn({v:1,c:n,...r.length>0?{t:r}:{}},640)}catch(e){if(n.length>0)n.pop();else if(r.length>0)r.pop();else throw e}}const Pn=/^[0-9A-Za-z.:%_-]{1,64}$/;function Fn(e){return Ln(e,`c`,8)}function In(e){return Ln(e,`t`,4)}function Ln(e,t,n){let r=Y(e);if(typeof r!=`object`||!r)return[];let i=r,a=i[t];if(i.v!==1||!Array.isArray(a))return[];let o=[];for(let e of a.slice(0,n)){if(!Array.isArray(e)||e.length!==2)continue;let[t,n]=e;typeof t!=`string`||!Pn.test(t)||typeof n!=`number`||!Number.isInteger(n)||n<1||n>65535||o.push({host:t,port:n})}return o}function Rn(e,t=Math.random){let n=t();return Math.floor((Number.isFinite(n)?Math.min(Math.max(n,0),1):0)*Math.max(0,e))}function zn(e){if(typeof e!=`object`||!e)return-1;let t=e.seq;return typeof t==`number`&&Number.isSafeInteger(t)?t:-1}function X(e){return e instanceof Error?e:Error(String(e))}var Bn=class{options;timeoutMs;scheduled=new Map;routes=[];listsFound;prefetchedEpoch;relaysFound=new Map;relayLookups=new Map;closed=!1;constructor(e){this.options=e,this.timeoutMs=e.lookupTimeoutMs??6e3}now(){return(this.options.now??Date.now)()}async candidates(e,t){let n=(0,u.rendezvousEpoch)(this.now()),r=await this.lookup(e,`hints`,n,t);t.aborted||this.rememberRelays(e,n,r);let i=[],a=new Set;for(let e of r.sort((e,t)=>t.epoch-e.epoch))for(let t of Fn(e.data)){let e=`${t.host}:${t.port}`;a.has(e)||(a.add(e),i.push(t))}return i}rememberRelays(e,t,n){let r=[...n].sort((e,t)=>t.epoch-e.epoch)[0],i=r===void 0?[]:In(r.data);this.relaysFound.set(e.deviceId,{epoch:t,checkedAt:this.now(),endpoints:i})}async relayAdverts(e,t){let n=this.now(),r=(0,u.rendezvousEpoch)(n),i=e.slice(0,16),a=[];for(let e of i){let t=this.relaysFound.get(e.deviceId);t!==void 0&&t.epoch===r&&(t.endpoints.length>0||n-t.checkedAt<12e4)||a.push(this.lookUpRelay(e,r))}if(a.length>0){let e=new Promise(e=>{t.aborted&&e(),t.addEventListener(`abort`,()=>e(),{once:!0})});await Promise.race([Promise.all(a),e])}let o=new Set(e.map(e=>e.deviceId));for(let e of[...this.relaysFound.keys()])o.has(e)||this.relaysFound.delete(e);let s=new Map;for(let e of i){let t=this.relaysFound.get(e.deviceId)?.endpoints??[];t.length>0&&s.set(e.deviceId,t)}return s}lookUpRelay(e,t){let n=this.relayLookups.get(e.deviceId);if(n!==void 0)return n;let r=AbortSignal.timeout(this.timeoutMs),i=this.lookup(e,`hints`,t,r).then(n=>{!r.aborted&&!this.closed&&this.rememberRelays(e,t,n)}).finally(()=>this.relayLookups.delete(e.deviceId));return this.relayLookups.set(e.deviceId,i),i}async lookup(e,t,n,r){let i=[n-1,n,n+1].flatMap(n=>this.options.stores.map(async i=>{let a=await this.read(i,e,t,n,0,r);return a===void 0?void 0:{epoch:n,data:a}}));return(await Promise.all(i)).filter(e=>e!==void 0)}async read(e,t,n,r,i,a){try{let o=await En(t.rendezvous,n,`inbound`,r,i),s=await e.get(o.key.publicKey,o.salt,a);if(s===void 0)return;let c=await t.rendezvous.openRecord(s,r,n);return c?.epoch===r?c.hints:void 0}catch{return}}async lookupLists(e,t,n){let r=[t-1,t,t+1].flatMap(t=>this.options.stores.map(async r=>{let i=await this.read(r,e,`revocation`,t,0,n),a=i===void 0?void 0:On(i);if(i===void 0||a===void 0)return;let o=await Promise.all(Array.from({length:a-1},(i,a)=>this.read(r,e,`revocation`,t,a+1,n)));if(!o.some(e=>e===void 0))return kn([i,...o])}));return(await Promise.all(r)).filter(e=>e!==void 0)}advertise(e,t){if(this.closed)return Promise.resolve();this.routes=e;let n=(0,u.rendezvousEpoch)(this.now()),r=new Set(e.map(e=>e.outbound));for(let[e,t]of this.scheduled)r.has(e)||(clearTimeout(t.timer),this.scheduled.delete(e));this.prefetchedEpoch!==n&&(this.prefetchedEpoch=n,this.findLists(AbortSignal.timeout(3e4)));let i=this.options.maxPublishJitterMs??9e4;for(let r of e){let e=this.scheduled.get(r.outbound);if(e!==void 0&&e.epoch===n&&e.port===t)continue;e!==void 0&&clearTimeout(e.timer);let a=setTimeout(()=>{this.scheduled.delete(r.outbound),this.publish(r,t)},Rn(i,this.options.random));a.unref?.(),this.scheduled.set(r.outbound,{timer:a,epoch:n,port:t})}return Promise.resolve()}async publish(e,t){if(this.closed)return;let n=this.now(),r=(0,u.rendezvousEpoch)(n),i=[];try{i.push({purpose:`hints`,chunk:0,plaintext:Nn(this.options.addresses().map(e=>({host:e,port:t})),this.options.relayEndpoints?.()??[])});let e=this.options.lists?.();if(e!==void 0){let t=await Dn({r:e.revocation,...e.signingKeyRevocation===void 0?{}:{s:e.signingKeyRevocation}});for(let[e,n]of t.entries())i.push({purpose:`revocation`,chunk:e,plaintext:n})}}catch(e){this.options.onError?.(X(e))}for(let{purpose:t,chunk:a,plaintext:o}of i)try{let i=await e.rendezvous.sealRecord(o,r,t),s=await En(e.rendezvous,t,`outbound`,r,a),c=await Promise.allSettled(this.options.stores.map(e=>e.put(s,i,n)));for(let e of c)e.status===`rejected`&&this.options.onError?.(X(e.reason))}catch(e){this.options.onError?.(X(e))}}async latestLists(e){let t=new Promise(t=>{e.aborted&&t(void 0),e.addEventListener(`abort`,()=>t(void 0),{once:!0})});return await Promise.race([this.findLists(e),t])??this.listsFound}async findLists(e){let t=(0,u.rendezvousEpoch)(this.now()),n=await Promise.all(this.routes.slice(0,16).map(n=>this.lookupLists(n,t,e))),r=[],i=[];for(let e of n){let t=[],n=[];for(let r of e){if(typeof r!=`object`||!r)continue;let e=r;e.r!==void 0&&t.push(e.r),e.s!==void 0&&n.push(e.s)}r.push(t),i.push(n)}let a=Un(r),o=Un(i),s=a.length===0&&o.length===0?void 0:{...a.length>0?{revocation:a}:{},...o.length>0?{signingKeyRevocation:o}:{}};return e.aborted||(this.listsFound=s),s}close(){if(!this.closed){this.closed=!0;for(let{timer:e}of this.scheduled.values())clearTimeout(e);this.scheduled.clear();for(let e of this.options.stores)e.close()}}};function Vn(e){let t=new Set;return e.filter(e=>{let n=JSON.stringify(e);return t.has(n)?!1:(t.add(n),!0)})}function Hn(e){return Vn(e).sort((e,t)=>zn(t)-zn(e))}function Un(e){let t=e.map(e=>Hn(e).slice(0,2)),n=[];for(let e=0;e<2;e+=1)n.push(...Hn(t.flatMap(t=>t.slice(e,e+1))));return Vn(n).slice(0,16)}function Wn(e){let t=``;for(let n of e)t+=n.toString(16).padStart(2,`0`);return t}function Gn(){let e=new Map,t=e=>e,n=(e,t)=>`${Wn(e)}/${Wn(t??new Uint8Array)}`;return{store:()=>({async put(t,r,i){let a=await wn(t.key,t.salt,Math.floor(i/1e3),r);if(!await q(a,a.k,a.salt))throw Error(`item refused`);let o=n(a.k,a.salt),s=e.get(o);if(s!==void 0&&s.seq>a.seq)throw Error(`item refused: older seq`);e.set(o,a)},async get(r,i){await Promise.resolve();let a=e.get(n(r,i)),o=a===void 0?void 0:t(a);if(o!==void 0)return await q(o,r,i)?o.v:void 0},close:()=>void 0}),items:()=>[...e.values()],serve:e=>{t=e}}}const Kn=`ybndrfg8ejkmcpqxot1uwisza345h769`;function qn(e){let t=``,n=0,r=0;for(let i of e)for(n=n<<8|i,r+=8;r>=5;)t+=Kn[n>>>r-5&31],r-=5;return r>0&&(t+=Kn[n<<5-r&31]),t}function Z(e){return Uint8Array.from([e>>>8&255,e&255])}function Jn(e,t){let n=G([...[`_r`,qn(e)].flatMap(e=>[Uint8Array.of(e.length),new TextEncoder().encode(e)]),Uint8Array.of(0)]),r=[];for(let e=0;e<t.length;e+=255){let n=t.subarray(e,e+255);r.push(Uint8Array.of(n.length),n)}t.length===0&&r.push(Uint8Array.of(0));let i=G(r);return G([Uint8Array.from([0,0,132,0,0,0,0,1,0,0,0,0]),n,Z(16),Z(1),Uint8Array.from([0,0,1,44]),Z(i.length),i])}function Yn(e){let t=t=>(e[t]??0)<<8|(e[t+1]??0);if(e.length<12)return;let n=t(4),r=t(6),i=12,a=()=>{for(let t=0;t<128;t+=1){let t=e[i];if(t===void 0)return!1;if(t===0)return i+=1,!0;if((t&192)==192)return i+=2,!0;i+=1+t}return!1};for(let e=0;e<n;e+=1){if(!a())return;i+=4}for(let n=0;n<r;n+=1){if(!a()||i+10>e.length)return;let n=t(i),r=t(i+8),o=i+10,s=o+r;if(s>e.length)return;if(n===16){let t=[],n=o;for(;n<s;){let r=e[n];if(n+1+r>s)return;t.push(e.subarray(n+1,n+1+r)),n+=1+r}return G(t)}i=s}}function Xn(e){let t=new Uint8Array(8);return new DataView(t.buffer).setBigUint64(0,BigInt(e)),t}function Zn(e){let t=e.length;for(;t>0&&e[t-1]===`/`;)--t;return e.slice(0,t)}function Qn(e){let t=e.fetch??globalThis.fetch.bind(globalThis),n=(e,t)=>`${Zn(e)}/${qn(t)}`;return{async put(r,i,a,o){let s=Jn(r.key.publicKey,i);if(s.length>999)throw Error(`record too large for a pkarr relay`);let c=Math.floor(a)*1e3,l=G([await r.key.sign(K(void 0,c,s)),Xn(c),s]);if(!(await Promise.allSettled(e.relays.map(async e=>{let i=await t(n(e,r.key.publicKey),{method:`PUT`,headers:{"content-type":`application/pkarr.org/relays#payload`},body:l.slice().buffer,...o===void 0?{}:{signal:o}});if(!i.ok)throw Error(`pkarr relay refused (${i.status})`)}))).some(e=>e.status===`fulfilled`))throw Error(`no pkarr relay took the record`)},async get(r,i,a){let o=await Promise.all(e.relays.map(async e=>{try{let i=await t(n(e,r),{signal:a});if(!i.ok)return;let o=new Uint8Array(await i.arrayBuffer());if(o.length<=72||o.length>1200)return;let s=o.subarray(0,64),c=Number(new DataView(o.buffer,o.byteOffset+64,8).getBigUint64(0)),l=o.slice(72);if(!Number.isSafeInteger(c)||!await Cn(r,K(void 0,c,l),s))return;let u=Yn(l);return u===void 0?void 0:{seq:c,value:u}}catch{return}})),s;for(let e of o)e!==void 0&&(s===void 0||e.seq>s.seq)&&(s=e);return s?.value},close:()=>void 0}}const $n=Uint8Array.from([48,42,48,5,6,3,43,101,112,3,33,0]),er=(e,t,n)=>{if(n.length!==32||e.length!==64)return!1;try{return(0,p.verify)(null,t,(0,p.createPublicKey)({key:Buffer.from(G([$n,n])),format:`der`,type:`spki`}),e)}catch{return!1}};async function tr(e){return new(await(import(`bittorrent-dht`))).default({verify:e})}function Q(e){return Buffer.from(e.buffer,e.byteOffset,e.byteLength)}function nr(e){if(e!==void 0)return new Promise((t,n)=>{e.aborted&&n(Error(`aborted`)),e.addEventListener(`abort`,()=>n(Error(`aborted`)),{once:!0})})}async function rr(e={}){let t=await(e.createDht??tr)(er),n=t=>e.onError?.(t);t.on(`error`,n),t.on(`warning`,n);let r=!1;return{async put(e,n,i,a){if(r)throw Error(`DHT store closed`);if(n.length>999)throw Error(`record value exceeds 999 bytes`);let o=await wn(e.key,e.salt,Math.floor(i/1e3),n),s=new Promise((n,r)=>{t.put({k:Q(o.k),salt:Q(e.salt),seq:o.seq,v:Q(o.v),sig:Q(o.sig)},(e,t,i)=>{e===null?i===0?r(Error(`no DHT node took the record`)):n():r(e)})}),c=nr(a);await(c===void 0?s:Promise.race([s,c]))},async get(e,n,i){if(r||i.aborted)return;let a=(0,p.createHash)(`sha1`).update(G([e,n])).digest(),o=new Promise(e=>{t.get(a,{salt:Q(n),cache:!1},(t,n)=>e(t===null?n:null))});try{let t=await Promise.race([o,nr(i)]);if(t?.v===void 0||t.k===void 0||t.sig===void 0)return;let r={k:new Uint8Array(t.k),salt:n,seq:t.seq??0,v:new Uint8Array(t.v),sig:new Uint8Array(t.sig)};return await q(r,e,n)?r.v:void 0}catch{return}},close(){r||(r=!0,t.destroy())}}}const ir=/^[0-9a-f]{64}$/,ar=/^[0-9a-f]{128}$/;function or(e){return 2e4+((e[0]??0)<<8|(e[1]??0))%1e4}function sr(e){let t=``;for(let n of e)t+=String.fromCharCode(n);return btoa(t)}function cr(e){try{let t=atob(e),n=new Uint8Array(t.length);for(let e=0;e<t.length;e+=1)n[e]=t.charCodeAt(e);return n}catch{return}}function lr(e){if(typeof e!=`object`||!e)return;let t=e;if(!(typeof t.id!=`string`||!ir.test(t.id))&&!(typeof t.pubkey!=`string`||!ir.test(t.pubkey))&&!(typeof t.sig!=`string`||!ar.test(t.sig))&&!(typeof t.kind!=`number`||!Number.isInteger(t.kind))&&!(typeof t.created_at!=`number`||!Number.isInteger(t.created_at))&&!(typeof t.content!=`string`||t.content.length>49152)&&!(!Array.isArray(t.tags)||t.tags.length!==0))return{id:t.id,pubkey:t.pubkey,sig:t.sig,kind:t.kind,created_at:t.created_at,content:t.content,tags:[]}}var ur=class{options;messages=new Set;absents=new Set;outbound=new Map;inbound=new Map;subscription;chain=Promise.resolve();seen=new Set;routes=[];epoch;timer;closed=!1;constructor(e){this.options=e}now(){return(this.options.now??Date.now)()}report(e){this.options.onError?.(e instanceof Error?e:Error(String(e)))}enqueue(e){this.chain=this.chain.then(e).catch(e=>this.report(e))}whenIdle(){return this.chain}declarePresence(){}declarePeers(e){this.enqueue(()=>this.derive(e))}async derive(e){if(this.closed)return;this.routes=e;let t=(0,u.rendezvousEpoch)(this.now()),n=new Map,r=new Map;for(let i of e){let e=await i.rendezvous.signingSeed(`outbound`,t,`signal`),a=or(await i.rendezvous.tag(`nostr-kind`,`outbound`,t));n.set(i.outbound,{route:i,epoch:t,secretKey:e,kind:a});for(let e of[t-1,t,t+1]){let t=await i.rendezvous.signingSeed(`inbound`,e,`signal`),n=or(await i.rendezvous.tag(`nostr-kind`,`inbound`,e));r.set((0,g.getPublicKey)(t),{route:i,epoch:e,kind:n})}}this.closed||(this.outbound=n,this.inbound=r,this.epoch=t,this.subscription?.close(),this.subscription=r.size===0?void 0:this.options.pool.subscribe({kinds:[...new Set([...r.values()].map(e=>e.kind))],authors:[...r.keys()],since:Math.floor(this.now()/1e3)-(this.options.maxEventAgeS??120)},e=>this.enqueue(()=>this.receive(e))),this.timer!==void 0&&clearTimeout(this.timer),this.timer=setTimeout(()=>this.declarePeers(this.routes),Math.max(0,(t+1)*u.RENDEZVOUS_EPOCH_MS-this.now())),this.timer.unref?.())}send(e,t){this.closed||this.enqueue(async()=>{if(this.closed)return;this.epoch!==void 0&&(0,u.rendezvousEpoch)(this.now())!==this.epoch&&await this.derive(this.routes);let n=this.outbound.get(e);if(n===void 0){for(let t of this.absents)t(e);return}let r=new TextEncoder().encode(JSON.stringify(t)).length;if(r>32768)throw Error(`signal too large for a Nostr event`);let i=jn(t,Math.ceil(r/512)*512),a=await n.route.rendezvous.sealRecord(i,n.epoch,`signal`),o=(0,g.finalizeEvent)({kind:n.kind,created_at:Math.floor(this.now()/1e3),tags:[],content:sr(a)},n.secretKey);if(!await this.options.pool.publish(o))throw Error(`no Nostr relay took the signal`)})}async receive(e){if(this.closed)return;let t=lr(e);if(t===void 0||this.seen.has(t.id))return;let n=this.inbound.get(t.pubkey);if(n===void 0||t.kind!==n.kind||Math.abs(Math.floor(this.now()/1e3)-t.created_at)>(this.options.maxEventAgeS??120)||!(0,g.verifyEvent)(t))return;this.remember(t.id);let r=cr(t.content);if(r===void 0)return;let i=await n.route.rendezvous.openRecord(r,n.epoch,`signal`);if(i?.epoch!==n.epoch)return;let a=Y(i.hints);if(!(a===void 0||this.closed))for(let e of this.messages)e(n.route.inbound,a)}remember(e){if(this.seen.add(e),this.seen.size<=2048)return;let t=this.seen.values().next().value;t!==void 0&&this.seen.delete(t)}onMessage(e){return this.messages.add(e),()=>this.messages.delete(e)}onAbsent(e){return this.absents.add(e),()=>this.absents.delete(e)}close(){this.closed||(this.closed=!0,this.timer!==void 0&&clearTimeout(this.timer),this.subscription?.close(),this.messages.clear(),this.absents.clear(),this.options.pool.close())}};function dr(e,t){return e.kinds.includes(t.kind)&&e.authors.includes(t.pubkey)}function fr(){let e=new Set,t=[],n=t=>{let n=JSON.parse(JSON.stringify(t));queueMicrotask(()=>{for(let t of[...e])dr(t.filter,n)&&t.onEvent(n)})};return{pool:()=>{let r=new Set;return{publish:e=>{let r=lr(e);return r===void 0||!(0,g.verifyEvent)(r)?Promise.resolve(!1):(t.push(JSON.parse(JSON.stringify(e))),n(e),Promise.resolve(!0))},subscribe:(t,n)=>{let i={filter:t,onEvent:n};return e.add(i),r.add(i),{close:()=>{e.delete(i),r.delete(i)}}},close:()=>{for(let t of r)e.delete(t);r.clear()}}},events:t,inject:e=>n(e)}}function pr(e){if(e.length===0)throw Error(`a Nostr relay pool needs at least one relay`);let t=new ne.SimplePool,n=[...e];return{publish:async e=>(await Promise.allSettled(t.publish(n,e))).some(e=>e.status===`fulfilled`),subscribe:(e,r)=>t.subscribeMany(n,{kinds:[...e.kinds],authors:[...e.authors],...e.since===void 0?{}:{since:e.since}},{onevent:e=>r(e)}),close:()=>t.destroy()}}const mr=[`wss://relay.damus.io`,`wss://nos.lol`,`wss://relay.primal.net`],hr=[`https://pkarr.pubky.app`,`https://pkarr.pubky.org`,`https://dns.iroh.link/pkarr`],gr=/^[A-Za-z0-9_-]{22}$/;var $=class extends Error{reason;constructor(e,t){super(`enrollment connection failed (${e})${t===void 0?``:`: ${t}`}`),this.name=`EnrollmentLinkError`,this.reason=e}};function _r(e,t){return typeof e==`string`&&e.length>0&&e.length<=t}function vr(e){if(typeof e!=`object`||!e||Array.isArray(e))return;let t=e;if(t.v!==1||typeof t.cid!=`string`||!gr.test(t.cid))return;let n=t.cid;if(t.kind===`offer`||t.kind===`answer`)return _r(t.sdp,49152)?{kind:t.kind,cid:n,sdp:t.sdp}:void 0;if(t.kind===`ice`){let e=t.candidate;if(typeof e!=`object`||!e||Array.isArray(e))return;let r=e;return!_r(r.candidate,2048)||!_r(r.mid,64)?void 0:{kind:`ice`,cid:n,candidate:{candidate:r.candidate,mid:r.mid}}}}function yr(){let e=new Uint8Array(16);return globalThis.crypto.getRandomValues(e),Buffer.from(e).toString(`base64url`)}var br=class{role;cid;options;onBound;onFailed;peer;channel;localFingerprint;remoteFingerprint;tookRemoteDescription=!1;sentDescription=!1;localCandidates=[];remoteCandidates=0;chain=Promise.resolve();stopAwaiting;timer;done=!1;early=[];frameHandlers=new Set;closeHandlers=new Set;constructor(e,t,n,r,i){this.role=e,this.cid=t,this.options=n,this.onBound=r,this.onFailed=i,this.timer=setTimeout(()=>this.fail(new $(`timeout`)),n.connectTimeoutMs??2e4)}async offer(){try{let e=this.createPeer();this.adopt(e.createDataChannel(`agent-enroll`));let t=await e.createOffer();if(this.done)return;this.localFingerprint=(0,u.extractDtlsFingerprint)(t),this.sendDescription({kind:`offer`,cid:this.cid,sdp:t})}catch(e){this.fail(new $(`signaling`,xr(e)))}}onSignal(e){this.done||(this.chain=this.chain.then(()=>this.apply(e)).catch(e=>this.fail(new $(`signaling`,xr(e)))))}async apply(e){if(this.done)return;if(e.kind===`ice`){if(this.peer===void 0||++this.remoteCandidates>64)return;this.peer.addRemoteCandidate(e.candidate);return}let t=this.role===`offerer`?`answer`:`offer`;if(e.kind!==t||this.tookRemoteDescription)return;this.tookRemoteDescription=!0;let n;try{n=(0,u.extractDtlsFingerprintAttribute)(e.sdp).algorithm}catch(e){this.fail(new $(`channel-binding`,xr(e)));return}if(this.role===`offerer`){let t=this.peer;if(t===void 0)return;t.acceptAnswer(e.sdp),this.awaitCertificate(t,n);return}let r=this.createPeer(),i=await r.acceptOffer(e.sdp);this.done||(this.localFingerprint=(0,u.extractDtlsFingerprint)(i),this.sendDescription({kind:`answer`,cid:this.cid,sdp:i}),this.awaitCertificate(r,n))}createPeer(){let e=new b({...this.options.iceServers===void 0?{}:{iceServers:this.options.iceServers},...this.options.loadDataChannel===void 0?{}:{loadDataChannel:this.options.loadDataChannel}});return this.peer=e,e.onLocalCandidate(e=>{if(this.done)return;let t={kind:`ice`,cid:this.cid,candidate:{candidate:e.candidate,mid:e.mid}};this.sentDescription?this.send(t):this.localCandidates.length<64&&this.localCandidates.push(t)}),e.onStateChange(e=>{(e===`failed`||e===`closed`)&&this.fail(new $(`closed`,`connection ${e}`))}),e.onDataChannel(e=>{this.role===`answerer`&&this.channel===void 0&&!this.done?this.adopt(e):e.close()}),e}send(e){this.options.relay.send(this.options.outbound,{v:1,...e})}sendDescription(e){this.send(e),this.sentDescription=!0;for(let e of this.localCandidates.splice(0))this.send(e)}awaitCertificate(e,t){this.stopAwaiting=_(e,t,e=>{this.remoteFingerprint=e,this.maybeBound()},e=>this.fail(new $(`channel-binding`,e)))}adopt(e){this.channel=e,e.onMessage(e=>this.inbound(e)),e.onStateChange(e=>{e===`open`?this.maybeBound():e===`closed`&&this.closed()}),e.readyState===`open`&&this.maybeBound()}inbound(e){if(e.length>262144){this.closeAll();return}if(this.frameHandlers.size===0){if(this.early.length>=16){this.closeAll();return}this.early.push(e);return}this.deliver(e)}deliver(e){let t;try{t=JSON.parse(e)}catch{t=void 0}for(let e of this.frameHandlers)e(t)}maybeBound(){let e=this.channel;if(this.done||e===void 0||e.readyState!==`open`)return;let t=this.localFingerprint,n=this.remoteFingerprint;t!==void 0&&n!==void 0&&(this.done=!0,clearTimeout(this.timer),this.stopAwaiting?.(),this.onBound({localFingerprint:t,remoteFingerprint:n,send:t=>{try{e.send(JSON.stringify(t))}catch{}},onFrame:e=>{this.frameHandlers.add(e);let t=this.early.splice(0);return t.length>0&&queueMicrotask(()=>t.forEach(e=>this.deliver(e))),()=>this.frameHandlers.delete(e)},onClose:t=>e.readyState===`closed`?(queueMicrotask(t),()=>void 0):(this.closeHandlers.add(t),()=>this.closeHandlers.delete(t)),close:()=>this.closeAll()}))}closed(){if(!this.done){this.fail(new $(`closed`,`data channel closed`));return}this.closeAll()}closeAll(){this.channel?.close();let e=this.peer;e!==void 0&&setTimeout(()=>e.close(),250).unref?.();let t=[...this.closeHandlers];this.closeHandlers.clear(),this.frameHandlers.clear();for(let e of t)e()}fail(e){this.done||(this.done=!0,clearTimeout(this.timer),this.stopAwaiting?.(),this.channel?.close(),this.peer?.close(),this.onFailed(e))}};function xr(e){return e instanceof Error?e.message:String(e)}function Sr(e){return new Promise((t,n)=>{let r=[],i=()=>{for(let e of r.splice(0))e()},a=new br(`offerer`,yr(),e,e=>{i(),t(e)},e=>{i(),n(e)});r.push(e.relay.onMessage((t,n)=>{if(t!==e.inbound)return;let r=vr(n);r!==void 0&&r.cid===a.cid&&a.onSignal(r)}),e.relay.onAbsent(t=>{t===e.outbound&&a.fail(new $(`absent`))})),e.relay.declarePresence([e.inbound]),a.offer()})}function Cr(e){let t,n=!1,r=e.relay.onMessage((r,i)=>{if(n||r!==e.inbound)return;let a=vr(i);if(a===void 0)return;if(t!==void 0){a.cid===t.cid&&t.onSignal(a);return}if(a.kind!==`offer`)return;let o=new br(`answerer`,a.cid,e,r=>{if(n){r.close();return}r.onClose(()=>{t===o&&(t=void 0)}),e.onChannel(r)},n=>{t===o&&(t=void 0),e.onAttemptFailed?.(n)});t=o,o.onSignal(a)});return e.relay.declarePresence([e.inbound]),{close:()=>{n||(n=!0,r(),t?.fail(new $(`closed`,`no longer listening`)))}}}exports.DEFAULT_MAX_PUBLISH_JITTER_MS=9e4,exports.DEFAULT_NOSTR_RELAYS=mr,exports.DEFAULT_PKARR_RELAYS=hr,exports.DEFAULT_RELAY_CREDENTIAL_TTL_MS=vt,exports.DEFAULT_TURN_QUOTAS=at,exports.DEFAULT_UNAUTHENTICATED_LIMITS=ot,exports.DeviceMeshNode=zt,exports.DiscoveringMeshRelay=gn,exports.EnrollmentLinkError=$,exports.MAX_CACHED_CANDIDATES=3,exports.MAX_MESH_MESSAGE_CHARS=Le,exports.MAX_RELAY_CREDENTIAL_TTL_MS=yt,exports.MESH_MDNS_SERVICE=V,exports.MeshDht=Bn,exports.MeshLinkEndedError=Be,exports.MeshMdns=sn,exports.MeshRelayNeededError=L,exports.MeshTurnRelay=Tt,exports.NostrMeshRelay=ur,exports.RtcChannel=y,exports.RtcPeer=b,exports.TurnServer=_t,exports.WebRtcTransport=Ae,exports.WsMeshRelayClient=Vt,exports.WsSignalingClient=Fe,exports.addressCacheSource=Ht,exports.createInMemoryItemNetwork=Gn,exports.createInMemoryMdnsBus=cn,exports.createInMemoryMeshAddressCache=Gt,exports.createInMemoryMeshRelayHub=Bt,exports.createInMemoryNostrHub=fr,exports.createInMemorySignalingPair=Me,exports.createNostrRelayPool=pr,exports.createPkarrRelayStore=Qn,exports.dialEnrollment=Sr,exports.handoffGrantFrame=me,exports.judgeHandoffGrant=pe,exports.listenForEnrollment=Cr,exports.loadDataChannel=oe,exports.localInterfaceAddresses=nn,exports.localProofFrame=_e,exports.meshRelayCredential=St,exports.meshRelayIceServers=wt,exports.paddedInstanceCount=on,exports.startLanMeshRelay=_n,exports.startMainlineDhtStore=rr,exports.startMeshLanListener=en;