openrtc 3.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +11 -0
  2. package/dist/{WasmBridge-FSGSSPWK.js → WasmBridge-JZGJHSSU.js} +1 -1
  3. package/dist/{chunk-IVH7EHAZ.js → chunk-C3TAFNG6.js} +1 -1
  4. package/dist/chunk-F3IZBMAT.js +1 -0
  5. package/dist/{chunk-3CV7SSY3.js → chunk-LTMH2AIS.js} +1 -1
  6. package/dist/{chunk-NIUTTTJS.js → chunk-R6J4PZDI.js} +1 -1
  7. package/dist/chunk-RSQCDTS2.js +1 -0
  8. package/dist/{chunk-5CWZ6GGD.js → chunk-W4IU7H7H.js} +1 -1
  9. package/dist/coreClient-BYWmk_1O.d.ts +309 -0
  10. package/dist/coreClient.d.ts +4 -250
  11. package/dist/coreClient.js +1 -1
  12. package/dist/deviceHandle-3P46T7SV.js +1 -0
  13. package/dist/{dist-XO466BRG.js → dist-FIVA6EPA.js} +0 -18
  14. package/dist/external-broadcast.d.ts +2 -2
  15. package/dist/external-broadcast.js +1 -1
  16. package/dist/index.d.ts +3 -3
  17. package/dist/index.js +1 -1
  18. package/dist/{ipcFactory-RUGRMNGB.js → ipcFactory-2MDPNX5M.js} +1 -1
  19. package/dist/native.d.ts +3 -3
  20. package/dist/native.js +1 -1
  21. package/dist/node.d.ts +3 -3
  22. package/dist/node.js +2 -2
  23. package/dist/openrtc-6RZZ7PEN.js +2 -0
  24. package/dist/openrtc_bg.wasm +0 -0
  25. package/dist/room-P5SHPIGF.js +1 -0
  26. package/dist/runtime/WasmRuntimeAdapter.js +1 -1
  27. package/dist/runtime/factories.js +1 -1
  28. package/dist/runtime/index.d.ts +2 -2
  29. package/dist/runtime/index.js +1 -1
  30. package/dist/server-browser.d.ts +2 -2
  31. package/dist/server.d.ts +2 -2
  32. package/dist/server.js +1 -1
  33. package/dist/service-node.d.ts +2 -2
  34. package/dist/service-node.js +1 -1
  35. package/dist/testing/native.d.ts +2 -2
  36. package/dist/testing/native.js +1 -1
  37. package/dist/testing.d.ts +2 -2
  38. package/dist/testing.js +1 -1
  39. package/dist/{types-DiFR_L_m.d.ts → types-BXYC9Q5H.d.ts} +5 -1
  40. package/native/darwin-arm64/openrtc-node-host +0 -0
  41. package/native/darwin-arm64/openrtc-node-host.manifest.json +4 -4
  42. package/native/darwin-x64/openrtc-node-host +0 -0
  43. package/native/darwin-x64/openrtc-node-host.manifest.json +4 -4
  44. package/native/linux-x64/openrtc-node-host +0 -0
  45. package/native/linux-x64/openrtc-node-host.manifest.json +4 -4
  46. package/package.json +1 -1
  47. package/dist/chunk-WZ2VUWTQ.js +0 -1
  48. package/dist/deviceHandle-KTPNRJSS.js +0 -1
  49. package/dist/openrtc-MG4DOSLP.js +0 -2
  50. package/dist/room-FFDNIK6N.js +0 -1
@@ -0,0 +1 @@
1
+ import {b as b$3}from'./chunk-FKAQDDUM.js';import {b as b$1,a as a$2}from'./chunk-ZA44REGI.js';import {b as b$6,a as a$4,c}from'./chunk-F3IZBMAT.js';import {a as a$1,b as b$4}from'./chunk-O7Z6WLGA.js';import {b as b$2,a as a$3}from'./chunk-CCCYE3XN.js';import {d,a,e}from'./chunk-L7N4T2PX.js';import {d as d$1,b as b$5}from'./chunk-2GX6GB6L.js';function I(a,e,t,i){let n=JSON.stringify({__openrtc:2,capability:i,kind:a,name:e,value:t});if(n===void 0||!n.includes('"value":'))throw new Error("[OpenRTC] Messages must be JSON-serializable values.");return new TextEncoder().encode(n)}function B(a){let e;try{e=a instanceof Uint8Array?JSON.parse(new TextDecoder().decode(a)):a&&typeof a=="object"?a:{};}catch{return null}return e!=null&&e.__openrtc===2&&typeof e.capability=="string"&&e.capability.length>0&&e.capability.length<=192&&/^(?:devices|space|room|ticket):[A-Za-z0-9_.:@-]+$/.test(e.capability)&&(e.kind==="raw"||e.kind==="channel"||e.kind==="state")&&typeof e.name=="string"&&e.name.length>0&&e.name.length<=80&&/^[A-Za-z0-9_.:@-]+$/.test(e.name)&&Object.prototype.hasOwnProperty.call(e,"value")?e:null}var b="openrtc-peer-stream/1",de=32,ee=16,L=4294967295,he=/^[A-Za-z0-9][A-Za-z0-9._/+:-]{0,127}$/,ue=/^([0-9a-f]{64})-([0-9a-f]{64})$/i;function R(a){let e=a?.trim()??"";if(!he.test(e))throw new Error("[OpenRTC] stream protocol must be 1-128 safe ASCII characters.");return e}function x(a){let e=a?.trim()??"",t=ue.exec(e);return t?[t[1].toLowerCase(),t[2].toLowerCase()].sort().join("-"):e}function te(a){if(a===null||a===0)return null;if(!Number.isFinite(a)||a<0)throw new RangeError("[OpenRTC] datagram maximum age must be a non-negative finite number or null.");return Math.min(L,Math.ceil(a))}function ie(a){if(!Number.isSafeInteger(a)||a<1||a>L)throw new RangeError(`[OpenRTC] datagram buffer limits must be integers from 1 to ${L}.`);return a}var _=class{constructor(e,t){this.runtime=e;this.peerId=t;this.incomingAge=null;this.outgoingAge=null;this.incomingLimit=ee;this.outgoingLimit=ee;this.policyInstance=null;this.incomingWaiters=new Set;this.outgoingWaiters=new Set;this.outgoingAvailable=new Set;this.incomingError=null;this.receiveLoopStarted=false;this.sendLoop=null;this.closed=false;this.incomingClosed=false;this.outgoingClosed=false;this.maxDatagramSize=e.peerDatagramMaxSize?.()??1024,this.readable=new ReadableStream({pull:i=>this.pullIncoming(i),cancel:()=>this.closeIncoming()},{highWaterMark:0}),this.writable=new WritableStream({write:i=>this.enqueueOutgoing(i),close:async()=>{this.outgoingClosed=true,await this.sendLoop;},abort:()=>{this.outgoingClosed=true,this.policyInstance?.closeOutgoing(),this.wake(this.outgoingWaiters),this.wake(this.outgoingAvailable);}},{highWaterMark:1});}get incomingMaxAge(){return this.incomingAge}set incomingMaxAge(e){this.incomingAge=te(e),this.policy.setIncomingMaxAge(this.incomingAge??void 0,Date.now()),this.wake(this.incomingWaiters);}get outgoingMaxAge(){return this.outgoingAge}set outgoingMaxAge(e){this.outgoingAge=te(e),this.policy.setOutgoingMaxAge(this.outgoingAge??void 0);}get incomingMaxBufferedDatagrams(){return this.incomingLimit}set incomingMaxBufferedDatagrams(e){this.incomingLimit=ie(e),this.policy.setIncomingMaxBufferedDatagrams(this.incomingLimit);}get outgoingMaxBufferedDatagrams(){return this.outgoingLimit}set outgoingMaxBufferedDatagrams(e){this.outgoingLimit=ie(e),this.policy.setOutgoingMaxBufferedDatagrams(this.outgoingLimit),this.wake(this.outgoingWaiters);}getStats(){return this.policy.getStats(Date.now())}get policy(){if(!this.policyInstance){let e=this.runtime.createPeerDatagramPolicy;if(!e)throw new Error("[OpenRTC] Shared protected-datagram policy is unavailable in this runtime.");this.policyInstance=e();}return this.policyInstance}close(){this.closed||(this.closed=true,this.closeIncoming(),this.outgoingClosed=true,this.policyInstance?.closeOutgoing(),this.wake(this.outgoingWaiters),this.wake(this.outgoingAvailable));}async pullIncoming(e){for(this.receiveLoopStarted||(this.receiveLoopStarted=true,this.pumpIncoming());;){let t=this.policy.popIncoming(Date.now());if(t){e.enqueue(new Uint8Array(t));return}if(this.incomingError){e.error(this.incomingError);return}if(this.incomingClosed){e.close();return}await new Promise(i=>this.incomingWaiters.add(i));}}async pumpIncoming(){let e=this.runtime.receivePeerDatagram;if(!e){this.incomingError=new Error("[OpenRTC] Protected peer datagrams are unavailable in this runtime."),this.wake(this.incomingWaiters);return}try{for(;!this.incomingClosed;){let t=new Uint8Array(await e(this.peerId));if(this.incomingClosed)return;this.policy.pushIncoming(t,Date.now()),this.wake(this.incomingWaiters);}}catch(t){this.incomingClosed||(this.incomingError=t,this.wake(this.incomingWaiters));}}async enqueueOutgoing(e){if(this.closed||this.outgoingClosed)throw new Error("[OpenRTC] peer datagram stream is closed.");if(!(e instanceof Uint8Array)||e.byteLength>this.maxDatagramSize)throw new Error(`[OpenRTC] peer datagrams must be Uint8Array values up to ${this.maxDatagramSize} bytes.`);for(;!this.policy.pushOutgoing(e,Date.now())&&!this.closed;)await new Promise(t=>this.outgoingWaiters.add(t));if(this.closed||this.outgoingClosed)throw new Error("[OpenRTC] peer datagram stream is closed.");this.startSendLoop(),this.wake(this.outgoingAvailable);}startSendLoop(){this.sendLoop||this.closed||(this.sendLoop=this.pumpOutgoing());}async pumpOutgoing(){let e=this.runtime.sendPeerDatagram;if(!e){this.policy.closeOutgoing();return}for(;!this.closed;){let t=this.policy.popOutgoing(Date.now());if(!t){if(this.wake(this.outgoingWaiters),this.outgoingClosed)return;await new Promise(n=>this.outgoingAvailable.add(n));continue}this.wake(this.outgoingWaiters);let i=new Uint8Array(t.payload);try{await e(this.peerId,i,t.remainingMaxAgeMs??void 0)===!1?this.policy.recordExpiredOutgoing():this.policy.recordSent(i.byteLength);}catch{this.policy.recordSendFailure();}this.wake(this.outgoingWaiters);}}closeIncoming(){this.incomingClosed||(this.incomingClosed=true,this.policyInstance?.closeIncoming(),this.wake(this.incomingWaiters));}wake(e){for(let t of e)t();e.clear();}},S=class{constructor(){this.controller=null;this.closed=false;this.readable=new ReadableStream({start:e=>{this.controller=e;},cancel:()=>{this.closed=true,this.controller=null;}},{highWaterMark:de});}enqueue(e){return this.closed||!this.controller||(this.controller.desiredSize??0)<=0?false:(this.controller.enqueue(e),true)}close(){this.closed||(this.closed=true,this.controller?.close(),this.controller=null);}},F=class{constructor(e,t,i,n){this.client=e;this.peerId=t;this.capabilityKey=n;this.incomingBi=new S;this.incomingUni=new S;this.incomingBidirectionalStreams=this.incomingBi.readable;this.incomingUnidirectionalStreams=this.incomingUni.readable;this.closed=false;this.protocolHandlers=new Map;this.datagrams=new _(i,this.peerId);}async createBidirectionalStream(e){let t=R(e.protocol),i=await this.client.channels.openBi(this.peerId,b,{timeoutMs:e.timeoutMs,channelMetadata:{protocol:t,[a$3]:this.capabilityKey}});return {protocol:t,readable:i.readable,writable:i.writable}}async createUnidirectionalStream(e){let t=R(e.protocol);return (await this.client.channels.openUni(this.peerId,b,{timeoutMs:e.timeoutMs,channelMetadata:{protocol:t,[a$3]:this.capabilityKey}})).writable}accept(e,t){if(e.type==="bi"){let n=e.stream;if(!n.recv||!n.send)return false;let s={peerId:this.peerId,protocol:t,readable:n.recv,writable:n.send},r=this.protocolHandlers.get(t);if(r){try{r(s);}catch{s.readable.cancel("incoming-protocol-handler-failed").catch(()=>{}),s.writable.abort("incoming-protocol-handler-failed").catch(()=>{});}return true}return this.incomingBi.enqueue(s)||(s.readable.cancel("incoming-peer-stream-queue-full").catch(()=>{}),s.writable.abort("incoming-peer-stream-queue-full").catch(()=>{})),true}let i=e.stream;return !i||typeof i.getReader!="function"?false:(this.incomingUni.enqueue({peerId:this.peerId,protocol:t,readable:i})||i.cancel("incoming-peer-stream-queue-full").catch(()=>{}),true)}onProtocol(e,t){let i=R(e);if(this.protocolHandlers.has(i))throw new Error(`[OpenRTC] stream protocol '${i}' already has an owning consumer.`);return this.protocolHandlers.set(i,t),()=>{this.protocolHandlers.get(i)===t&&this.protocolHandlers.delete(i);}}close(){this.closed=true,this.datagrams.close(),this.protocolHandlers.clear(),this.incomingBi.close(),this.incomingUni.close();}},A=class{constructor(e,t){this.client=e;this.capabilityKey=t;this.peers=new Map;this.peerIdsByConnection=new Map;this.registered=false;this.observed=0;this.accepted=0;this.declined=0;this.lastResolution="none";try{e.channels.register({id:b,kind:"application-stream",ownership:"shared",peerModel:"device-first",routing:"stream-envelope",readiness:"settled-peer",promotionPolicy:"never",signalingPolicy:"hosted",delivery:"reliable",description:"Transport-agnostic protected peer streams"}),this.stopIncoming=e.channels.onIncomingChannel(b,i=>this.accept(i)),this.registered=!0;}catch{this.stopIncoming=()=>{};}}forPeer(e){let t=this.peers.get(e);return t||(t=new F(this.client,e,this.client.advanced.runtime,this.capabilityKey),this.peers.set(e,t)),t}onProtocol(e,t,i){return this.forPeer(e).onProtocol(t,i)}bindConnection(e,t){let i=x(e),n=t.trim();!i||!n||this.peerIdsByConnection.set(i,n);}unbindConnection(e){this.peerIdsByConnection.delete(x(e));}diagnostics(){return {registered:this.registered,peers:this.peers.size,boundConnections:this.peerIdsByConnection.size,observed:this.observed,accepted:this.accepted,declined:this.declined,lastResolution:this.lastResolution}}closePeer(e){let t=this.peers.get(e);if(t){t.close(),this.peers.delete(e);for(let[i,n]of this.peerIdsByConnection)n===e&&this.peerIdsByConnection.delete(i);}}close(){this.stopIncoming();for(let e of this.peers.values())e.close();this.peers.clear(),this.peerIdsByConnection.clear(),this.registered&&this.client.channels.unregister(b);}accept(e){if(this.observed+=1,e.channel?.metadata?.[a$3]!==this.capabilityKey)return this.declined+=1,false;let i=e.channel?.metadata?.protocol;if(typeof i!="string")return this.declined+=1,false;let n;try{n=R(i);}catch{return this.declined+=1,false}let r=this.resolveExistingPeer(e.remoteNodeId,e.connectionId)?.accept(e,n)??false;return r?this.accepted+=1:this.declined+=1,r}resolveExistingPeer(e,t=""){let i=x(t);if(i){let r=this.peerIdsByConnection.get(i);if(!r)return this.lastResolution="unbound-connection",null;let o=this.peers.get(r);return o?(this.lastResolution="connection",o):(this.lastResolution="unbound-connection",null)}let n=this.peers.get(e);if(n)return this.lastResolution="remote-peer",n;let s=this.client.peers.get(e)??this.client.peers.listConnected().find(r=>[r.peerId,r.deviceId,r.deviceIdHint,r.connectionId,...r.connectionIds].some(o=>o===e));if(s){let r=new Set([s.peerId,s.deviceId,s.deviceIdHint,s.connectionId,...s.connectionIds].filter(c=>typeof c=="string"&&c.length>0)),o=[...this.peers.entries()].filter(([c])=>r.has(c)).map(([,c])=>c);if(o.length===1)return this.lastResolution="peer-alias",o[0]}return this.lastResolution="none",null}};var w=new WeakMap;function pe(a){let e=w.get(a);if(!e||a.closed)throw new Error("[OpenRTC] Capability runtime is unavailable or already closed.");return e}function Be(a,e){if(w.has(a))throw new Error("[OpenRTC] Capability runtime is already registered.");return w.set(a,pe(e)),()=>{w.delete(a);}}function me(a){let e=a?.trim()??"";if(!/^pk_(?:live|test)_[0-9a-f]{40}$/.test(e))throw new Error("[OpenRTC] apiKey must be a public pk_live_ or pk_test_ key.");return e}function f(a){let e=a?.trim()??"";if(!e||e.length>160||!/^[A-Za-z0-9_.:@-]+$/.test(e))throw new Error("[OpenRTC] Capability id is invalid.");return e}var q=/^[A-Za-z0-9_.:@-]{1,160}$/,ve=/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,ne=2,G=8,ge=G;function ye(a){let e=typeof a=="string"?a.trim():"";if(!q.test(e))return null;let t=e.startsWith("device_")?e.slice(7):"";return ve.test(t)?t:e}function fe(a){let e=`openrtc:v2:device-id:${a}`,t,i=(()=>{try{return t=globalThis.localStorage,ye(t?.getItem(e))||crypto.randomUUID()}catch{return crypto.randomUUID()}})();try{t?.setItem(e,i);}catch{}return i}function re(a){let e=typeof a=="string"?a.trim():"";if(!q.test(e))throw new Error("[OpenRTC] The native host returned an invalid durable device ID.");return e}var se=250;function oe(a){if(a===void 0)return [];if(!Array.isArray(a))throw new Error("[OpenRTC] autoConnectExcludedDeviceIds must be an array.");let e=[...new Set(a.map(t=>{let i=typeof t=="string"?t.trim().toLowerCase():"";if(!q.test(i))throw new Error("[OpenRTC] autoConnectExcludedDeviceIds contains an invalid device ID.");return i}))].sort();if(e.length>se)throw new Error(`[OpenRTC] autoConnectExcludedDeviceIds supports at most ${se} devices.`);return e}function N(a){let e=b$1(a.token),t=typeof e.deviceKeyThumbprint=="string"?e.deviceKeyThumbprint.trim():"";if(!/^[A-Za-z0-9_-]{43}$/.test(t))throw new Error("[OpenRTC] Anonymous capability is missing its device-key binding.");return `anon_${t.slice(0,32)}`}var U=class{constructor(){this.descriptors=new Map;this.targets=new Map;}register(e){if(!e?.id?.trim())throw new Error("[OpenRTC] Channel id is required.");this.descriptors.set(e.id,{...e});for(let[t,i]of this.targets)t.channels.register({...e,delivery:e.delivery??i});return ()=>{this.descriptors.delete(e.id);for(let t of this.targets.keys())t.channels.unregister(e.id);}}list(){return [...this.descriptors.values()].map(e=>({...e}))}attach(e,t){this.targets.set(e,t);for(let i of this.descriptors.values())e.channels.register({...i,delivery:i.delivery??t});}detach(e){this.targets.delete(e);}};function ae(a$1){return d(a.TICKET_MESH_ALREADY_ACTIVE,`[OpenRTC] ticket:${a$1} is already active with different options.`,{retryable:false,plane:"admission"})}function le(a){return a.mesh===true?a.maxPeers??ge:a.maxPeers}function we(a){return JSON.stringify({identity:a.identity??(a.mesh===true?"session":null),maxPeers:le(a)??null,mesh:a.mesh===true,advancedFanout:a.advancedFanout===true})}function ce(a){let e=a?.trim()??"";if(!e||e.length>80||!/^[A-Za-z0-9_.:@-]+$/.test(e))throw new Error("[OpenRTC] Message name is invalid.");return e}var H=class{constructor(e,t,i){this.client=e;this.capabilityKey=t;this.rawConnections=new Map;this.logicalConnections=new Map;this.connectionListeners=new Map;this.rawListeners=new Map;this.closeListeners=new Map;this.channelListeners=new Map;this.stateListeners=new Map;this.remoteState=new Map;this.localState=new Map;this.stateSenders=new Map;this.stateReadyGenerations=new Map;this.mediaConnections=new Map;this.mediaRetirements=new Map;this.pendingRawConnections=new Map;this.connectionIdsByPeer=new Map;this.closed=false;this.cleanupComplete=false;this.closeAttempt=null;this.pendingStops=null;this.peerStreams=new A(e,t),this.stopMessage=e.onMessage((n,s)=>this.receive(n,s)),this.stopConnection=e.onConnection(n=>this.add(n)),this.stopDisconnection=e.onDisconnection(n=>this.remove(n)),e.getConnections().forEach(n=>this.add(n)),this.stopPeerLifecycle=e.peers.watchLifecycle(n=>this.observePeerLifecycle(n)),this.roomFanout=i?.create({client:e,capabilityKey:t,connections:()=>[...this.logicalConnections.values()].flatMap(({activeRaw:n})=>n?[n]:[]),deliver:(n,s,r)=>{let o=B(s);!o||o.capability!==this.capabilityKey||r!==void 0&&o.name!==r||r===void 0&&o.kind!=="channel"||this.deliverEnvelope(n,o);}});}state(e){if(this.assertOpen(),this.roomFanout?.isSparse())throw new Error("[OpenRTC] state() is not available in sparse gossip rooms; use a named channel with application-owned latest-state revisions.");let t=ce(e);return {set:i=>{this.assertOpen();let n=I("state",t,i,this.capabilityKey);if(this.localState.set(t,n),!this.roomFanout?.publishState(t,n))for(let{activeRaw:s}of this.logicalConnections.values())s&&this.sendState(s,t,n);},watch:i=>{this.assertOpen();let n=this.stateListeners.get(t);n||this.stateListeners.set(t,n=new Set);let s=(r,o)=>i({peerId:r,value:o});n.add(s);for(let[r,o]of this.remoteState)o.has(t)&&i({peerId:r,value:o.get(t)});return ()=>n?.delete(s)}}}channel(e){this.assertOpen();let t=ce(e),i=n=>I("channel",t,n,this.capabilityKey);return {send:async n=>{this.assertOpen();let s=i(n);await this.roomFanout?.sendChannel(t,s)||(this.assertOpen(),await Promise.all([...this.logicalConnections.values()].flatMap(({activeRaw:r})=>r?[this.sendPayload(r,s)]:[])));},sendTo:async(n,s)=>{this.assertOpen(),this.roomFanout?.assertTargetedSendAllowed();let r=this.logicalConnections.get(n)?.activeRaw;if(r){await this.sendPayload(r,i(s));return}throw d(a.DELIVERY_NOT_READY,`[OpenRTC] Peer '${n}' has no direct authorized route; sparse broadcasts never multi-hop targeted payloads.`,{retryable:true,plane:"delivery"})},onMessage:n=>{this.assertOpen();let s=this.channelListeners.get(t);s||this.channelListeners.set(t,s=new Set);let r=(o,c)=>n({peerId:o,message:c});return s.add(r),()=>s?.delete(r)}}}async sendPayload(e$1,t){try{await e$1.send(t);}catch(i){throw e(i)}}onConnection(e){this.assertOpen();let t=new Set;this.connectionListeners.set(e,t);for(let[i,n]of this.logicalConnections)n.activeRaw&&(t.add(i),e(n.view));return ()=>this.connectionListeners.delete(e)}assertOpen(){if(this.closed)throw new Error("[OpenRTC] Capability messages are closed.")}fence(){this.closed=true;}close(){if(this.cleanupComplete)return Promise.resolve();if(this.closeAttempt)return this.closeAttempt;this.closed=true;let e=this.releaseMessages();return this.closeAttempt=e,e.then(()=>{this.closeAttempt===e&&(this.closeAttempt=null);},()=>{this.closeAttempt===e&&(this.closeAttempt=null);}),e}async releaseMessages(){let e=[];this.pendingStops??(this.pendingStops=[()=>this.stopMessage(),()=>this.stopConnection(),()=>this.stopDisconnection(),()=>this.stopPeerLifecycle(),()=>this.roomFanout?.close()]),this.pendingStops=this.pendingStops.filter(i=>{try{return i(),!1}catch(n){return e.push(n),true}});let t=[];for(let i of this.logicalConnections.keys())try{t.push(this.retire(i));}catch(n){e.push(n);}this.pendingRawConnections.clear();try{this.peerStreams.close();}catch(i){e.push(i);}this.rawConnections.clear(),this.logicalConnections.clear(),this.connectionListeners.clear(),this.channelListeners.clear(),this.stateListeners.clear(),this.localState.clear(),this.remoteState.clear(),this.stateReadyGenerations.clear(),this.rawListeners.clear(),this.closeListeners.clear();for(let i of await Promise.allSettled(t))i.status==="rejected"&&e.push(i.reason);if(e.length===1)throw e[0];if(e.length)throw d(a.INTERNAL,"[OpenRTC] Capability message cleanup failed.",{cause:e,retryable:true,plane:"internal"});this.cleanupComplete=true;}add(e){if(this.closed)return;let t=this.rawConnections.get(e.id);if(t?.raw===e)return;t&&this.remove(t.raw);let i=e.remoteNodeId||e.id,n=this.mediaRetirements.get(i);if(n){let o={raw:e,peerId:i};this.pendingRawConnections.set(e.id,o),n.finally(()=>{this.closed||this.pendingRawConnections.get(e.id)!==o||(this.pendingRawConnections.delete(e.id),this.add(e));});return}this.rawConnections.set(e.id,{raw:e,peerId:i});let s=this.connectionIdsByPeer.get(i);s||this.connectionIdsByPeer.set(i,s=new Set),s.add(e.id),this.peerStreams.bindConnection(e.id,i);let r=this.logicalConnections.get(i);if(!r){let o=this.peerStreams.forPeer(i),c=new b$3(o,this.client.advanced.runtime,(d,h)=>this.peerStreams.onProtocol(i,d,h),()=>this.peerStreams.diagnostics());this.mediaConnections.set(i,c),r={activeRaw:e,rawIds:new Set,view:{id:i,peerId:i,streams:o,media:c,send:async d$1=>{let h=this.logicalConnections.get(i)?.activeRaw;if(!h)throw d(a.DELIVERY_NOT_READY,`[OpenRTC] Peer '${i}' is not connected.`,{retryable:true,plane:"delivery"});await this.sendPayload(h,I("raw","message",d$1,this.capabilityKey));},onMessage:d=>{let h=this.rawListeners.get(i);h||this.rawListeners.set(i,h=new Set);let v=d;return h.add(v),()=>h?.delete(v)},onClose:d=>{let h=this.closeListeners.get(i);return h||this.closeListeners.set(i,h=new Set),h.add(d),()=>h?.delete(d)}}},this.logicalConnections.set(i,r);}r.rawIds.add(e.id),r.activeRaw=e,this.observePeerLifecycle(this.client.peers.listConnected());for(let[o,c]of this.connectionListeners)c.has(i)||(c.add(i),o(r.view));for(let[o,c]of this.localState)this.sendState(e,o,c);}remove(e){if(this.pendingRawConnections.get(e.id)?.raw===e){this.pendingRawConnections.delete(e.id);return}let t=this.rawConnections.get(e.id);if(!t||t.raw!==e)return;this.rawConnections.delete(e.id),this.peerStreams.unbindConnection(e.id);let i=t.peerId,n=this.logicalConnections.get(i);if(n?.rawIds.delete(e.id),n?.activeRaw?.id===e.id){let o=[...n.rawIds],c=o[o.length-1];n.activeRaw=c?this.rawConnections.get(c)?.raw??null:null;}let s=this.connectionIdsByPeer.get(i);if(s?.delete(e.id),s?.size===0&&this.connectionIdsByPeer.delete(i),!n?.activeRaw){let o=this.remoteState.get(i);if(o){for(let c of o.keys())for(let l of this.stateListeners.get(c)??[])l(i,null);this.remoteState.delete(i);}}let r=this.stateSenders.get(e);if(r){for(let o of r.values())o.close();this.stateSenders.delete(e);}}observePeerLifecycle(e){for(let t of this.logicalConnections.keys()){let i=this.connectionIdsByPeer.get(t)??new Set,n=e.find(l=>l.peerId===t||l.connectionId===t||l.connectionIds.some(d=>i.has(d)));if(!n)continue;let s=n.status==="closed"&&n.logicalSessionTerminal===true&&n.routable!==true&&n.settledReady!==true;if(n.manualDisconnect||s){this.retire(t);continue}if(n.settledReady!==true||n.routable!==true){this.stateReadyGenerations.delete(t);continue}let r=n.transportStableId,o=n.transportGeneration,c=n.routeGeneration;if(Number.isSafeInteger(r)&&Number(r)>0&&Number.isSafeInteger(o)&&Number(o)>0&&Number.isSafeInteger(c)&&Number(c)>=0){let l=JSON.stringify([n.connectionId,n.generation,r,o,c]);if(this.stateReadyGenerations.get(t)!==l){this.stateReadyGenerations.set(t,l);let h=this.logicalConnections.get(t)?.activeRaw;if(h)for(let[v,u]of this.localState)this.sendState(h,v,u);}let d=this.mediaConnections.get(t);d&&d.observePhysicalGeneration({transportStableId:Number(r),transportGeneration:Number(o),routeGeneration:Number(c)}).catch(()=>{});}}}retire(e){let t=this.logicalConnections.get(e);if(!t)return this.mediaRetirements.get(e)??Promise.resolve();this.logicalConnections.delete(e),this.stateReadyGenerations.delete(e);for(let r of t.rawIds){let o=this.rawConnections.get(r)?.raw;if(this.rawConnections.delete(r),this.peerStreams.unbindConnection(r),!o)continue;let c=this.stateSenders.get(o);if(c){for(let l of c.values())l.close();this.stateSenders.delete(o);}}this.connectionIdsByPeer.delete(e);let i=this.remoteState.get(e);if(i){for(let r of i.keys())for(let o of this.stateListeners.get(r)??[])o(e,null);this.remoteState.delete(e);}let n=this.mediaConnections.get(e);this.mediaConnections.delete(e);let s=n?.close().catch(()=>{})??Promise.resolve();this.mediaRetirements.set(e,s),s.finally(()=>{this.mediaRetirements.get(e)===s&&this.mediaRetirements.delete(e);}),this.peerStreams.closePeer(e);for(let r of this.closeListeners.get(e)??[])r();this.closeListeners.delete(e),this.rawListeners.delete(e);for(let r of this.connectionListeners.values())r.delete(e);return s}receive(e,t){if(this.closed)return;this.add(e);let i=this.rawConnections.get(e.id)?.peerId??e.remoteNodeId??e.id;if(this.roomFanout?.receive(e,i,t))return;let n=B(t);if(!n){for(let s of this.rawListeners.get(i)??[])s(t);return}if(n.capability===this.capabilityKey){if(n.kind==="raw"){for(let s of this.rawListeners.get(i)??[])s(n.value);return}this.deliverEnvelope(i,n);}}deliverEnvelope(e,t){if(this.closed)return;if(t.kind==="raw"){for(let n of this.rawListeners.get(e)??[])n(t.value);return}if(t.kind==="channel"){for(let n of this.channelListeners.get(t.name)??[])n(e,t.value);return}let i=this.remoteState.get(e);i||this.remoteState.set(e,i=new Map),i.set(t.name,t.value);for(let n of this.stateListeners.get(t.name)??[])n(e,t.value);}sendState(e,t,i){let n=this.stateSenders.get(e);n||this.stateSenders.set(e,n=new Map);let s=n.get(t);s||(s=new a$1(r=>e.send(r)),n.set(t,s)),s.send(i).catch(()=>{});}},T=class{constructor(e,t,i,n,s){this.kind=e;this.id=t;this.client=i;this.onClosed=n;this.roomFanoutFactory=s;this.closed=false;this.retired=false;this.shutdownAttempt=null;w.set(this,i);}get peers(){return this.client.peers}get channels(){return this.client.channels}get diagnostics(){return this.client.diagnostics}state(e){return this.capabilityMessages().state(e)}channel(e){return this.capabilityMessages().channel(e)}onConnection(e){return this.capabilityMessages().onConnection(e)}projectRuntime(e){w.set(this,e);}setArchitecture(e){this.roomFanoutFactory?.setArchitecture(e);}close(){if(this.retired)return Promise.resolve();if(this.shutdownAttempt)return this.shutdownAttempt;this.fenceProductAccess();let e=this.releaseCapability();return this.shutdownAttempt=e,e.then(()=>{this.shutdownAttempt===e&&(this.shutdownAttempt=null);},()=>{this.shutdownAttempt===e&&(this.shutdownAttempt=null);}),e}beforeRuntimeShutdown(){}fenceProductAccess(){this.closed=true,this.messages?.fence();}async releaseCapability(){let e=[];try{this.beforeRuntimeShutdown();}catch(t){e.push(t);}try{await this.messages?.close();}catch(t){e.push(t);}try{await this.client.advanced.runtime.shutdown();}catch(t){e.push(t);}if(e.length===1)throw e[0];if(e.length)throw d(a.INTERNAL,"[OpenRTC] Capability cleanup failed.",{cause:e,retryable:true,plane:"internal"});this.onClosed(),w.delete(this),this.retired=true;}capabilityMessages(){if(this.closed)throw new Error("[OpenRTC] Capability is closed.");return this.messages??(this.messages=new H(this.client,b$2(this.kind,this.id).key,this.roomFanoutFactory))}},K=class extends T{constructor(t,i,n,s){super("space",t,i,n);this.delivery=s;this.kind="space";this.leave=()=>this.close();}},O=class extends T{constructor(t,i,n,s,r,o){super("ticket",t,i,n);this.token=s;this.ownsMesh=o;this.kind="ticket";this.closing=null;this.inviteListeners=new Set;this.stopInviteWatch=()=>{};this.meshStopped=false;if(this.currentInvite=r,o){let c=i.advanced.runtime;this.stopInviteWatch=c.watchTicketMeshInvite?.(t,l=>{this.closed||(this.currentInvite=l,this.inviteListeners.forEach(d=>d(l)));})??this.stopInviteWatch;}}get invite(){return this.closed?null:this.currentInvite}watchInvite(t){return this.closed?(t(null),()=>{}):(this.inviteListeners.add(t),t(this.currentInvite),()=>this.inviteListeners.delete(t))}async issuerNode(){if(this.closed)throw new Error("[OpenRTC] Capability is closed.");if(!this.ownsMesh)throw new Error("[OpenRTC] This ticket is not a mesh.");return this.client.advanced.runtime.ticketMeshIssuerNode(this.id)}get peers(){if(this.scopedPeers)return this.scopedPeers;let t=this.client.peers,i=`ticket:${this.id}`,n=r=>!this.closed&&r.scopes.includes(i)&&r.status==="connected"&&r.settledReady===true&&r.routable!==false&&r.logicalSessionTerminal!==true&&(!this.ownsMesh||this.client.advanced.runtime.isTicketMeshPeerReady(this.id,r)),s=(r,o)=>{let c=[],l=this.ownsMesh?this.client.advanced.runtime.watchTicketMeshPeers(this.id,()=>o(c.filter(n))):()=>{},d=t[r](h=>{c=h,o(h.filter(n));});return ()=>{d(),l();}};return this.scopedPeers={...t,watch:r=>s("watch",r),watchLifecycle:r=>s("watchLifecycle",r),get:r=>{let o=t.get(r);return o&&n(o)?o:void 0},listConnected:()=>t.listConnected().filter(n)}}get diagnostics(){if(this.scopedDiagnostics)return this.scopedDiagnostics;let t=this.client.diagnostics,i=`ticket:${this.id}`;return this.scopedDiagnostics={...t,capture:n=>c(s=>this.client.advanced.runtime.watchPeerStates(r=>s(this.closed?[]:r.filter(o=>o.scopes.includes(i)))),n),watchConnectionMetrics:n=>t.watchConnectionMetrics(s=>{n(this.closed?[]:s.filter(r=>r.scopes?.includes(i)));})}}close(){if(this.retired)return Promise.resolve();if(this.closing)return this.closing;this.fenceProductAccess();let t=this.closeOnce();return this.closing=t,t.catch(()=>{!this.retired&&this.closing===t&&(this.closing=null);}),t}async closeOnce(){this.ownsMesh&&!this.meshStopped&&(await this.client.advanced.runtime.closeTicketMesh(this.id),this.meshStopped=true),await super.close();}beforeRuntimeShutdown(){try{this.stopInviteWatch(),this.stopInviteWatch=()=>{};}finally{this.inviteListeners.clear();}}},D=class D{constructor(e,t){this.options=e;this.internals=t;this.diagnosticClientRef=++D.nextDiagnosticClient;this.nextDiagnosticOperation=0;this.channels=new U;this.broadcastSessions=new Set;this.broadcastPublishers=new Set;this.handles=new Set;this.activations=new Map;this.pendingCapabilityShutdowns=new Map;this.authorityCallableIds=new WeakMap;this.nextAuthorityCallableId=1;this.closed=false;this.closing=null;this.offline={support:async()=>(this.assertOpen(),this.internals.offlineSupport?.()??{provisioning:false,localMesh:false,cloudRequired:false,reason:"Browser-only OpenRTC cannot host the native LAN/Iroh offline runtime."}),createEnrollmentRequest:async e=>{if(this.assertOpen(),!this.internals.createOfflineEnrollmentRequest)throw new Error("[OpenRTC] Offline enrollment request signing requires a native Rust host.");return this.internals.createOfflineEnrollmentRequest({trustDomain:e.trustDomain,deviceId:await this.deviceId(),requestedRoles:e.requestedRoles})}};this.devices={localId:()=>(this.assertOpen(),this.deviceId()),start:(e={})=>{let t=e.auth??this.options.auth;return this.activateOnce("devices",JSON.stringify({autoConnect:e.autoConnect??"online",autoConnectExcludedDeviceIds:oe(e.autoConnectExcludedDeviceIds),maxPeers:e.maxPeers??null,advancedFanout:e.advancedFanout===true,profile:e.profile??null}),t,()=>this.startDevices(e))},listEnrolled:async(e={})=>{this.assertOpen();let t=e.auth??this.options.auth;if(!t)throw new Error("[OpenRTC] devices.listEnrolled() requires an auth provider.");let i=await(await this.controlPlane()).listEnrolledDevices(t,await this.deviceId()),{DeviceHandle:n}=await import('./deviceHandle-3P46T7SV.js');for(let s of this.handles)s instanceof n&&s.replaceEnrolledDevices(i);return i},revoke:async(e,t={})=>{this.assertOpen();let i=t.auth??this.options.auth;if(!i)throw new Error("[OpenRTC] devices.revoke() requires an auth provider.");let n=re(e),s=await this.deviceId();await(await this.controlPlane()).revokeDevice(i,s,n);let{DeviceHandle:r}=await import('./deviceHandle-3P46T7SV.js');for(let o of this.handles)o instanceof r&&o.removeEnrolledDevice(n);n===s&&this.retireAuthCapabilities(i);},revokeAll:async(e={})=>{this.assertOpen();let t=e.auth??this.options.auth;if(!t)throw new Error("[OpenRTC] devices.revokeAll() requires an auth provider.");if(await(await this.controlPlane()).revokeAllDevices(t,await this.deviceId(),e.exceptCurrent===true),e.exceptCurrent===true){let i=await this.deviceId(),{DeviceHandle:n}=await import('./deviceHandle-3P46T7SV.js');for(let s of this.handles)s instanceof n&&s.retainCurrentEnrolledDevice(i);}e.exceptCurrent!==true&&this.retireAuthCapabilities(t);}};this.spaces={join:(e,t={})=>this.activateOnce(`space:${f(e)}`,JSON.stringify({payload:t.payload??"reliable",identity:t.identity??null,maxPeers:t.maxPeers??null,advancedFanout:t.advancedFanout===true}),void 0,()=>this.joinSpace(e,t))};this.rooms={join:async(e,t={})=>(await import('./room-P5SHPIGF.js')).joinRoom(this,e,t)};this.tickets={issue:(e,t={})=>this.activateOnce(`ticket:${f(e)}`,we(t),void 0,()=>this.issueTicket(e,t),t.mesh===true?()=>ae(f(e)):void 0),join:e=>{let t=b$4(e);return t.mesh?this.activateOnce(`ticket:${f(t.id)}`,`join:${e}`,void 0,()=>this.joinTicket(e),()=>ae(f(t.id))):Promise.reject(d(a.TICKET_INVITE_INVALID,"[OpenRTC] This invitation does not describe a ticket mesh.",{retryable:false,plane:"admission"}))}};this.broadcasts={create:async e=>{this.assertOpen();let t=await this.broadcastHost();if(!t?.create)throw new Error("[OpenRTC] Managed broadcast creation is unavailable.");return t.create(e)},open:async e=>{this.assertOpen(),this.validateBroadcastGrant(e);let t=await this.broadcastHost();if(!t)throw new Error("[OpenRTC] Broadcast hosting is unavailable in this runtime.");return this.wrapBroadcastSession(await t.open(e))},subscribe:async e=>{this.assertOpen(),this.validateBroadcastGrant(e);let t=await this.broadcastHost();if(!t)throw new Error("[OpenRTC] Broadcast viewing is unavailable.");return this.wrapBroadcastSession(await t.open(e))},preparePublisher:async()=>{this.assertOpen();let e=await this.broadcastHost();if(!e?.preparePublisher)throw new Error("[OpenRTC] Broadcast publishing is unavailable in this runtime.");let t=await e.preparePublisher(),i=t.verificationKey.slice();if(i.byteLength!==32)throw await t.close(),new Error("[OpenRTC] Broadcast publisher key is invalid.");let n=false,s={verificationKey:i,open:async r=>{if(n)throw new Error("[OpenRTC] Broadcast publisher is closed.");return this.assertOpen(),this.validateBroadcastGrant(r),this.wrapBroadcastSession(await t.open(r))},close:async()=>{n||(n=true,await t.close(),this.broadcastPublishers.delete(s));}};return this.broadcastPublishers.add(s),s},renew:async(e,t={})=>{this.validateBroadcastGrant(e);let i=await this.broadcastHost();if(!i?.renew)throw new Error("[OpenRTC] Broadcast renewal is unavailable.");return i.renew(e,t.auth)},invite:async(e,t)=>{this.validateBroadcastGrant(e);let i=await this.broadcastHost();if(!i?.invite)throw new Error("[OpenRTC] Broadcast invitations are unavailable.");let{auth:n,...s}=t;return i.invite(e,s,n)},accept:async(e,t={})=>{if(!/^obi1\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(e))throw new Error("[OpenRTC] Broadcast invitation is invalid.");let i=await this.broadcastHost();if(!i?.accept)throw new Error("[OpenRTC] Broadcast invitation acceptance is unavailable.");return i.accept(e,t.auth)},revoke:async(e,t)=>{if(this.validateBroadcastGrant(e),!/^obi1\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(t.invite))throw new Error("[OpenRTC] Broadcast invitation is invalid.");let i=await this.broadcastHost();if(!i?.revoke)throw new Error("[OpenRTC] Broadcast revocation is unavailable.");await i.revoke(e,t.invite,t.auth);},leave:async(e,t={})=>{this.validateBroadcastGrant(e);let i=await this.broadcastHost();if(!i?.leave)throw new Error("[OpenRTC] Broadcast leave is unavailable.");await i.leave(e,t.auth);},close:async(e,t={})=>{this.validateBroadcastGrant(e);let i=await this.broadcastHost();if(!i?.closeGrant)throw new Error("[OpenRTC] Broadcast close is unavailable.");await i.closeGrant(e,t.auth);}};this.onClosed=e=>{this.handles.delete(e);for(let[t,i]of this.activations)i.handle===e&&this.activations.delete(t);};this.apiKey=me(e.apiKey);let i=e.trust?.browserPersistence??"session";if(i!=="session"&&i!=="persistent")throw new Error("[OpenRTC] Invalid browser identity persistence policy.");this.browserPersistence=i,this.appTag=`app_${this.apiKey.slice(-16)}`;}validateBroadcastGrant(e){if(typeof e!="string"||e.length<16||e.length>32768)throw new Error("[OpenRTC] Broadcast grant is invalid.")}broadcastHost(){return this.internals.broadcastHost?Promise.resolve(this.internals.broadcastHost):this.internals.broadcastHostFactory?this.broadcastHostPromise??(this.broadcastHostPromise=this.controlPlane().then(e=>this.internals.broadcastHostFactory({apiKey:this.apiKey,resolve:(t,i)=>e.resolveBroadcastAccess(t,i),manage:e.manageBroadcast.bind(e),deviceId:()=>this.deviceId(),defaultAuth:this.options.auth}))):Promise.resolve(void 0)}wrapBroadcastSession(e){let t=false,i={get id(){return e.id},get role(){return e.role},get state(){return e.state},media:e.media,getStats:()=>e.getStats(),close:async()=>{t||(t=true,this.broadcastSessions.delete(i),await e.close());}};return this.broadcastSessions.add(i),i}makeControlPlane(e){return Promise.all([import('./controlPlane-45AU3CSM.js'),e]).then(([{ControlPlane:t},i])=>new t(this.apiKey,this.internals.endpoints??a$2,i,this.options.trust?.attestation,{onAuthEpochChanged:n=>this.retireAuthCapabilities(n)},this.options.trust?.botVerification))}controlPlane(){return this.controlPlanePromise??(this.controlPlanePromise=this.makeControlPlane(this.internals.deviceKeyProvider?Promise.resolve(this.internals.deviceKeyProvider):import('./deviceKey-2NTRYCSR.js').then(({browserDeviceKeyProvider:e,createSessionDeviceKeyProvider:t})=>this.internals.platform!=="native"&&this.browserPersistence!=="persistent"?t():e)))}sessionPlane(){return this.sessionPlanePromise??(this.sessionPlanePromise=this.makeControlPlane(import('./deviceKey-2NTRYCSR.js').then(({createSessionDeviceKeyProvider:e})=>e())))}assertOpen(){if(this.closed)throw new Error("[OpenRTC] Client is closed.");if(this.closing)throw new Error("[OpenRTC] Client is closing.")}activateOnce(e,t,i,n,s){this.assertOpen();let r=this.activations.get(e);if(r){if(r.handle?.closed)throw new Error(`[OpenRTC] ${e} is closing; retry close() to finish retirement.`);if(r.fingerprint!==t||r.auth!==i)throw s?s():new Error(`[OpenRTC] ${e} is already active with different options.`);return r.promise}let o={fingerprint:t,auth:i},c=this.options.diagnostics?.logger,l=c?performance.now():0,d=c?++this.nextDiagnosticOperation:0,h=e.split(":",1)[0],v=["devices","space","room","ticket"].includes(h)?h:"custom",u=y=>{c&&b$6(c,Object.freeze({sdkVersion:a$4,clientRef:this.diagnosticClientRef,name:"capability.activation",operationRef:d,avenue:v,outcome:y,timestampMs:Date.now(),elapsedMs:performance.now()-l}));},g;try{g=this.pendingCapabilityShutdowns.has(e)?this.settlePendingCapabilityShutdown(e).then(n):n();}catch(y){throw u("started"),u("failed"),y}let z=g.then(y=>(o.handle=y,u("succeeded"),y)).catch(y=>{throw u("failed"),this.activations.get(e)===o&&this.activations.delete(e),y});return o.promise=z,this.activations.set(e,o),u("started"),z}retainPendingCapabilityShutdown(e,t){this.pendingCapabilityShutdowns.has(e)||this.pendingCapabilityShutdowns.set(e,t);}async settlePendingCapabilityShutdown(e){let t=this.pendingCapabilityShutdowns.get(e);t&&(await t(),this.pendingCapabilityShutdowns.get(e)===t&&this.pendingCapabilityShutdowns.delete(e));}authorityCallableId(e){let t=this.authorityCallableIds.get(e);if(t)return t;let i=this.nextAuthorityCallableId++;return this.authorityCallableIds.set(e,i),i}retireAuthCapabilities(e){for(let t of this.activations.values())t.auth===e&&t.promise.then(i=>i.close()).catch(()=>{});}async deviceId(){let e=this.internals.deviceIdProvider?await this.internals.deviceIdProvider(this.appTag):this.internals.platform!=="native"&&this.browserPersistence==="session"?this.sessionDeviceId??(this.sessionDeviceId=crypto.randomUUID()):fe(this.appTag);return re(e)}runtimeOptions(e){let t=this.options.transports,i=e.irohRelay&&t?.relay!==false,n=e.managedTurn&&t?.relay!==false,s=t?.privacy==="relay-only";if(s&&!i)throw new Error("[OpenRTC] transports.privacy: relay-only requires relay access.");let r=s?d$1(t?.priority?[...t.priority]:void 0,true):t?.priority?[...t.priority]:void 0,o=t?.webrtc,c=typeof o=="object"&&o.iceServers?.some(b$5)===true,l=!s||n||c;return {apiKey:this.apiKey,authMode:"external",discoveryMode:e.avenue?.kind==="user"?"user-scoped":"space",space:e.avenue?.id,localDeviceId:e.deviceId,deviceIdPersistence:"persistent",endpointIdPersistence:this.internals.platform==="native"?"persistent":"ephemeral",deviceName:e.deviceName?.trim()||void 0,coordinationPlatformType:e.devicePlatform?.trim()||void 0,initialAutoConnectExcludedDeviceIds:e.initialAutoConnectExcludedDeviceIds,nativeIdentityProvider:this.internals.platform==="native"&&e.nativeAuth?{providerId:e.nativeAuth.providerId,getSessionKey:async()=>e.nativeAuth.getSessionKey?.()??null,getAssertion:d=>e.nativeAuth.getAssertion(d)}:void 0,coordinationAvenueOverride:e.avenue,coordinationRoomGossipFanout:e.roomGossipFanout===true,coordinationRoomArchitecture:e.roomArchitecture,coordinationDevicePublicKeyX:e.devicePublicKeyX,coordinationDeviceSign:e.deviceSign,coordinationGateway:{endpoint:(this.internals.endpoints??a$2).gateway,environment:"production",grantProvider:e.grantProvider,onServiceError:this.options.onServiceError,testingAllowInsecureLoopback:this.internals.testingAllowInsecureLoopback},turnCredentialsProvider:n?e.turnProvider:void 0,transports:{relay:i,iroh:s?{relayOnly:true,relayTransportPolicy:"websocketRequired",localDiscovery:false,persistenceMode:this.internals.platform==="native"?"persistent":"ephemeral",...this.internals.irohTestRelayUrl?{testRelayUrl:this.internals.irohTestRelayUrl}:{}}:this.internals.irohTestRelayUrl?{testRelayUrl:this.internals.irohTestRelayUrl,persistenceMode:this.internals.platform==="native"?"persistent":"ephemeral"}:t?.iroh??true,webrtc:l?typeof o=="object"?s?{...o,privacyMode:true,useTurn:true,useDefaultIceServers:false}:o:o===true?s?{privacyMode:true,useTurn:true,useDefaultIceServers:false}:true:false:false,ble:t?.ble??false,moq:i?t?.moq??false:false,privacy:t?.privacy??"direct",optimizeFor:t?.optimizeFor??"balanced",priority:r},transportPriority:r}}async activate(e){let t=e.authority?null:e.controlPlane??await this.controlPlane(),i=this.options.transports?.relay!==false,n=e.source.irohRelay&&i,s=e.source.managedTurn&&i,r={irohRelay:n,managedTurn:s,moq:n&&!!this.options.transports?.moq,ble:this.options.transports?.ble===true,advancedFanout:e.architecture==="sparse"||e.advancedFanout===true,durableMembership:e.durableMembership===true},o=e.source,c=null,l=()=>e.authority?{userId:e.principalId}:{userId:e.principalId,token:o.token,tokenProvider:async()=>o.token,expiresAtMs:o.expiresAtMs},d=e.authority?.devicePublicKeyX??String((await t.deviceSigningPublicKey()).x??""),h=this.runtimeOptions({avenue:e.source.avenue,grantProvider:e.authority?.grantProvider??t.grantProvider(e.source,{maxPeers:e.maxPeers,features:r,architecture:e.architecture,roomDelivery:e.kind==="room"?e.defaultDelivery:void 0,deviceProfile:e.deviceName&&e.devicePlatform?{name:e.deviceName,platform:e.devicePlatform}:void 0,onSourceRenewed:async g=>{o={...o,...g},await c?.setAuth(l());}}),deviceId:e.deviceId,userId:e.principalId,roomGossipFanout:(e.kind==="room"||e.kind==="space")&&(e.architecture==="sparse"||e.advancedFanout===true),roomArchitecture:e.kind==="room"?e.architecture:void 0,devicePublicKeyX:d,deviceSign:e.authority?.deviceSign??(g=>t.signDeviceBytes(g)),irohRelay:e.source.irohRelay,managedTurn:e.source.managedTurn,turnProvider:s&&t?t.turnProvider(()=>o):void 0,deviceName:e.deviceName,devicePlatform:e.devicePlatform,initialAutoConnectExcludedDeviceIds:e.initialAutoConnectExcludedDeviceIds,nativeAuth:e.nativeAuth}),[v,{wrapAssembly:u}]=await Promise.all([this.internals.runtimeFactory(h),import('./coreClient.js')]);c=u(v,this.internals.platform==="native"?"native":"web"),await c.setAuth(l()),this.channels.attach(c,e.defaultDelivery??"reliable");try{await c.devices.startSession({browserTrustPersistence:this.browserPersistence,sessionKind:e.kind==="devices"?"app-user-device":"scoped-guest",scope:`v2:${e.kind}:${e.id}`,userId:e.principalId,localDeviceId:e.deviceId,metadata:e.deviceMetadata,autoConnectPolicy:e.autoConnect?"enabled":"disabled",presencePolicy:"online"});}catch(g){throw this.channels.detach(c),await c.advanced.runtime.shutdown().catch(()=>{}),g}return c}trackHandle(e){return this.handles.add(e),e}async startDevices(e={}){this.assertOpen();let t=oe(e.autoConnectExcludedDeviceIds),i=e.auth??this.options.auth;if(!i)throw new Error("[OpenRTC] devices.start() requires an auth provider.");let n=await this.deviceId(),{resolveDeviceProfile:s}=await import('./deviceProfile-CR2C7OYR.js'),r=s(e.profile,this.internals.platform==="native"?"native":"web"),o=await this.controlPlane(),c=await o.deviceCertificate(i,n,void 0,r),l=await this.activate({kind:"devices",id:c.principalId,source:c.source,principalId:c.principalId,deviceId:n,maxPeers:e.maxPeers,autoConnect:e.autoConnect!=="none",initialAutoConnectExcludedDeviceIds:t,advancedFanout:e.advancedFanout,deviceName:r.name,devicePlatform:r.platform,deviceMetadata:r.metadata,nativeAuth:i}),d=[];if(this.internals.platform!=="native")try{d=await o.listEnrolledDevices(i,n);}catch(g){throw this.channels.detach(l),await l.advanced.runtime.shutdown().catch(()=>{}),g}let{AuthenticatedDeviceRoster:h}=await import('./deviceRoster-EUF6BBF5.js'),{DeviceHandle:v}=await import('./deviceHandle-3P46T7SV.js'),u;return u=new v(c.principalId,l,()=>{this.channels.detach(l),this.onClosed(u);},new h(d)),this.handles.add(u),u}async joinSpace(e,t={}){this.assertOpen();let i=f(e),n=await(t.identity==="session"?this.sessionPlane():this.controlPlane()),s=await n.capability("space",i,t.maxPeers,t.advancedFanout),r=String(b$1(s.token).principalId),o=await this.activate({kind:"space",id:i,source:s,principalId:r,deviceId:N(s),maxPeers:t.maxPeers,autoConnect:true,defaultDelivery:t.payload??"reliable",advancedFanout:t.advancedFanout,controlPlane:n}),c;return c=new K(i,o,()=>{this.channels.detach(o),this.onClosed(c);},t.payload??"reliable"),this.handles.add(c),c}async openAuthorityRoom(e){return (await import('./room-P5SHPIGF.js')).openAuthorityRoom(this,e)}async issueTicket(e,t={}){this.assertOpen();let i=f(e);if(t.mesh===true&&t.advancedFanout===true)throw d(a.TICKET_MESH_INVALID_OPTIONS,"[OpenRTC] Ticket mesh cannot use advancedFanout.",{retryable:false,plane:"admission"});let n=le(t);if(t.mesh===true&&(!Number.isSafeInteger(n)||n<ne||n>G))throw d(a.TICKET_MESH_INVALID_OPTIONS,`[OpenRTC] Ticket mesh maxPeers must be an integer between ${ne} and ${G}.`,{retryable:false,plane:"admission"});let s=await(t.identity==="session"||t.mesh===true?this.sessionPlane():this.controlPlane()),r=await s.capability("ticket",i,n,t.advancedFanout),o=String(b$1(r.token).principalId),c=await this.activate({kind:"ticket",id:i,source:r,principalId:o,deviceId:N(r),maxPeers:n,autoConnect:false,advancedFanout:t.advancedFanout,controlPlane:s}),l=null;if(t.mesh===true)try{l=await c.advanced.runtime.issueTicketMesh(i,n);}catch(h){await this.shutdownFailedTicketActivation(i,c,h);}let d$1;return d$1=new O(i,c,()=>{this.channels.detach(c),this.onClosed(d$1);},r.token,l,t.mesh===true),this.handles.add(d$1),d$1}async joinTicket(e){this.assertOpen();let t=b$4(e);if(!t.mesh)throw d(a.TICKET_INVITE_INVALID,"[OpenRTC] This invitation does not describe a ticket mesh.",{retryable:false,plane:"admission"});let i=f(t.id),n=await this.sessionPlane(),s=await n.capability("ticket",i,t.maxPeers,false),r=String(b$1(s.token).principalId),o=await this.activate({kind:"ticket",id:i,source:s,principalId:r,deviceId:N(s),maxPeers:t.maxPeers,autoConnect:false,advancedFanout:false,controlPlane:n});try{await o.advanced.runtime.joinTicketMesh(e);}catch(l){await this.shutdownFailedTicketActivation(i,o,l);}let c;return c=new O(i,o,()=>{this.channels.detach(o),this.onClosed(c);},s.token,e,true),this.handles.add(c),c}async shutdownFailedTicketActivation(e,t,i){this.channels.detach(t);try{await t.advanced.runtime.shutdown();}catch(n){throw this.retainPendingCapabilityShutdown(`ticket:${e}`,()=>t.advanced.runtime.shutdown()),d(a.TICKET_MESH_UNAVAILABLE,"[OpenRTC] Ticket mesh startup failed and runtime teardown was not confirmed.",{retryable:true,plane:"coordination",cause:{startError:i,shutdownError:n}})}throw i}async close(){if(this.closed)return;if(this.closing)return this.closing;let e=this.closeOnce();this.closing=e;try{await e;}finally{this.closing===e&&(this.closing=null);}}async closeOnce(){await Promise.allSettled([...this.activations.values()].map(({promise:e})=>e)),await Promise.all([...this.handles].map(e=>e.close())),await Promise.all([...this.pendingCapabilityShutdowns.keys()].map(e=>this.settlePendingCapabilityShutdown(e))),await Promise.all([...this.broadcastSessions].map(e=>e.close())),await Promise.all([...this.broadcastPublishers].map(e=>e.close())),await Promise.all([this.controlPlanePromise,this.sessionPlanePromise].map(e=>e?.then(t=>t.dispose(),()=>{}))),this.activations.clear(),this.broadcastSessions.clear(),this.broadcastPublishers.clear(),await this.broadcastHostPromise?.then(e=>e?.close?.(),()=>{}),await this.internals.broadcastHost?.close?.(),await this.internals.close?.(),this.closed=true;}};D.nextDiagnosticClient=0;var E=D;function xe(a,e){return new E(a,e)}function Le(a,e){if(!(a instanceof E))throw new TypeError("[OpenRTC] ServiceNode requires a client created by this OpenRTC package.");return a.openAuthorityRoom(e)}export{I as a,B as b,pe as c,Be as d,f as e,re as f,N as g,T as h,xe as i,Le as j};
@@ -1,2 +1,2 @@
1
- import {j,d as d$1,c}from'./chunk-WZ2VUWTQ.js';var E=/^[A-Za-z0-9_.:@-]+$/,P=/^[A-Za-z0-9_-]{43}$/,C=/^[A-Za-z0-9_.:@-]+$/,k=/^[A-Za-z0-9._-]+$/,x=120*6e4,A=new TextEncoder;function d(r,e,t=160){let n=r.trim();if(!n||n.length>t||!E.test(n))throw new TypeError(`[OpenRTC] ${e} is invalid.`);return n}function h(r,e,t=Number.MAX_SAFE_INTEGER){if(!Number.isSafeInteger(r)||r<1||r>t)throw new RangeError(`[OpenRTC] ${e} must be a positive safe integer.`);return r}function K(r){let e="";for(let t of r)e+=String.fromCharCode(t);return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}async function g(r,e){let t=await r.publicJwk();if(t.kty!=="OKP"||t.crv!=="Ed25519"||typeof t.x!="string"||!P.test(t.x)||t.d!==void 0)throw new TypeError(`[OpenRTC] ${e} must return an Ed25519 public JWK.`);return {kty:"OKP",crv:"Ed25519",x:t.x}}async function y(r,e,t){let n=await r.sign(e);if(!(n instanceof Uint8Array)||n.byteLength!==64)throw new TypeError(`[OpenRTC] ${t} returned an invalid Ed25519 signature.`);return K(n)}function T(r){if(!/^pk_(?:live|test)_[A-Za-z0-9]+$/.test(r))throw new TypeError("[OpenRTC] apiKey is invalid.");return `app_${r.slice(-16)}`}function u(r){return r!==null&&typeof r=="object"&&!Array.isArray(r)?r:null}function v(r,e,t,n){if(typeof r!="string"||r.length<1||r.length>t||r!==r.trim()||n&&!n.test(r))throw new Error(`[OpenRTC] authority service grant ${e} is invalid.`);return r}function O(r){let e=v(r,"gatewayUrl",2048),t;try{t=new URL(e);}catch{throw new Error("[OpenRTC] authority service grant gatewayUrl is invalid.")}let n=t.protocol==="http:"&&["127.0.0.1","localhost","::1"].includes(t.hostname.toLowerCase());if(t.protocol!=="https:"&&!n||t.username||t.password||t.search||t.hash)throw new Error("[OpenRTC] authority service grant gatewayUrl is invalid.");return e}function N(r,e){let t=u(r),n=u(t?.avenue),i=u(t?.roomAuthority),a=u(i?.assignmentPublicKeyJwk),c=Date.now(),o=t?.expiresAtMs,s=t?.maxPeers;if(!t||t.protocolVersion!==2||t.architecture!=="authority"||n?.kind!=="room"||n.id!==e.roomId||i?.serviceId!==e.serviceId||i.generation!==e.generation||!Array.isArray(i.shardIds)||i.shardIds.length!==e.shardIds.length||i.shardIds.some((m,l)=>m!==e.shardIds[l])||a?.kty!=="OKP"||a.crv!=="Ed25519"||a.x!==e.assignmentPublicKeyX||!Number.isSafeInteger(o)||o<=c||o>c+x||!Number.isSafeInteger(s)||s<1||s>e.maxPeers)throw new Error("[OpenRTC] authority service grant response is inconsistent.");return {protocolVersion:2,gatewayUrl:O(t.gatewayUrl),routeKey:v(t.routeKey,"routeKey",256,C),token:v(t.token,"token",24e3,k),expiresAtMs:o,avenue:{kind:"room",id:e.roomId},maxPeers:s,architecture:"authority",roomAuthority:{serviceId:e.serviceId,generation:e.generation,shardIds:[...e.shardIds],assignmentPublicKeyJwk:{kty:"OKP",crv:"Ed25519",x:e.assignmentPublicKeyX}}}}var p=class{constructor(e){if(this.apiKey=e.apiKey,this.applicationTag=T(e.apiKey),typeof e.grantIssuer!="function")throw new TypeError("[OpenRTC] ServiceNode requires a browser-safe grantIssuer.");if(this.grantIssuer=e.grantIssuer,this.serviceId=d(e.serviceId,"serviceId",80),this.generation=h(e.generation,"generation"),this.shardIds=[...new Set(e.shardIds.map(t=>d(t,"shardId",80)))].sort(),this.shardIds.length<1||this.shardIds.length>64||this.shardIds.length!==e.shardIds.length)throw new RangeError("[OpenRTC] shardIds must contain 1..64 unique identifiers.");this.deviceId=d(e.deviceId,"deviceId"),this.deviceSigner=e.deviceSigner,this.assignmentSigner=e.assignmentSigner;}async requestGrant(e){let t=d(e.roomId,"roomId"),n=d(e.runtimeInstanceId,"runtimeInstanceId");if(!P.test(e.ticketFingerprint))throw new TypeError("[OpenRTC] ticketFingerprint is invalid.");e.maxPeers!==void 0&&h(e.maxPeers,"maxPeers",50);let i=await g(this.assignmentSigner,"assignmentSigner.publicJwk()"),a=await g(this.deviceSigner,"deviceSigner.publicJwk()"),c=crypto.randomUUID().replace(/-/g,""),o=Math.floor(Date.now()/1e3),s=["openrtc:v2:authority-service-grant",this.applicationTag,t,this.serviceId,String(this.generation),this.shardIds.join(","),i.x,n,c,o].join(":"),m={avenue:{kind:"room",id:t},serviceId:this.serviceId,generation:this.generation,shardIds:this.shardIds,assignmentPublicKeyJwk:i,deviceId:this.deviceId,runtimeInstanceId:n,ticketFingerprint:e.ticketFingerprint,deviceProof:{publicKeyJwk:a,nonce:c,issuedAt:o,signature:await y(this.deviceSigner,A.encode(s),"deviceSigner.sign()")},...e.maxPeers===void 0?{}:{maxPeers:e.maxPeers},...e.refreshGrant?{refreshGrant:e.refreshGrant}:{},features:e.features??{}},l=`authority_${crypto.randomUUID().replace(/-/g,"")}`,R=await this.grantIssuer({apiKey:this.apiKey,idempotencyKey:l,body:m});return N(R,{roomId:t,serviceId:this.serviceId,generation:this.generation,shardIds:this.shardIds,assignmentPublicKeyX:i.x,maxPeers:e.maxPeers??50})}async devicePublicKey(){return g(this.deviceSigner,"deviceSigner.publicJwk()")}async assignmentPublicKey(){return g(this.assignmentSigner,"assignmentSigner.publicJwk()")}async signDeviceBytes(e){return y(this.deviceSigner,e,"deviceSigner.sign()")}async signAssignment(e){let t=e.ttlMs??6e4;h(t,"ttlMs",2*6e4);let n=d(e.shardId,"shardId",80);if(!this.shardIds.includes(n))throw new RangeError("[OpenRTC] assignment shard is not owned by this service.");let i=e.priorityDeviceIds??[],a=e.relevantEntityIds??[];if(i.length>8||a.length>32)throw new RangeError("[OpenRTC] assignment exceeds the 8-edge or 32-entity bound.");let c=Date.now(),o={policyVersion:"room-authority-assignment-v1",serviceId:this.serviceId,generation:this.generation,revision:h(e.revision,"revision"),subjectDeviceId:d(e.subjectDeviceId,"subjectDeviceId"),shardId:n,priorityDeviceIds:i.map(s=>d(s,"priorityDeviceId")),relevantEntityIds:a.map(s=>d(s,"relevantEntityId")),issuedAtMs:c,expiresAtMs:c+t};if(new Set(o.priorityDeviceIds).size!==o.priorityDeviceIds.length||new Set(o.relevantEntityIds).size!==o.relevantEntityIds.length)throw new RangeError("[OpenRTC] assignment identifiers must be unique.");return {assignment:o,signature:await y(this.assignmentSigner,A.encode(JSON.stringify(o)),"assignmentSigner.sign()")}}},I=class{constructor(e,t,n){this.room=e;this.authority=t;this.onClosed=n;this.releaseRuntimeAlias=d$1(this,e);}get kind(){return this.room.kind}get id(){return this.room.id}get peers(){return this.room.peers}get channels(){return this.room.channels}get diagnostics(){return this.room.diagnostics}get closed(){return this.room.closed}get membership(){return this.room.membership}state(e){return this.room.state(e)}channel(e){return this.room.channel(e)}onConnection(e){return this.room.onConnection(e)}architecture(){return this.room.architecture()}onArchitectureChanged(e){return this.room.onArchitectureChanged(e)}authorityAssignment(){return this.room.authorityAssignment()}onAuthorityAssignmentChanged(e){return this.room.onAuthorityAssignmentChanged(e)}leave(){return this.retire(()=>this.room.leave())}close(){return this.retire(()=>this.room.close())}async publishAssignment(e){let t=await this.authority.signAssignment(e);return await c(this.room).advanced.runtime.publishAuthorityAssignment(t),t.assignment}retire(e){return this.retirement??(this.retirement=e().finally(()=>{this.releaseRuntimeAlias(),this.onClosed();}))}},S=class{constructor(e){this.options=e;this.rooms=new Map;this.connectionListeners=new Set;this.connectionCleanups=new Map;this.closed=false;if("secretKey"in e)throw new TypeError("[OpenRTC] ServiceNode never accepts secretKey; delegate short-lived grants.");this.authority=new p(e);}listen(e){if(this.closed)throw new Error("[OpenRTC] ServiceNode is closed.");let t=d(e,"roomId"),n=this.rooms.get(t);if(n)return n.promise;let i={};return i.promise=this.openRoom(t,()=>this.evictRoom(t,i)).catch(a=>{throw this.evictRoom(t,i),a}),this.rooms.set(t,i),i.promise}onConnection(e){if(this.connectionListeners.add(e),this.connectionListeners.size===1)for(let[t,n]of this.rooms)n.promise.then(i=>this.attachConnectionListener(t,i),()=>{});return ()=>{if(this.connectionListeners.delete(e),this.connectionListeners.size===0){for(let t of this.connectionCleanups.values())t();this.connectionCleanups.clear();}}}async close(){if(this.closed)return;this.closed=true;for(let t of this.connectionCleanups.values())t();this.connectionCleanups.clear();let e=await Promise.allSettled([...this.rooms.values()].map(t=>t.promise));await Promise.all(e.flatMap(t=>t.status==="fulfilled"?[t.value.close()]:[])),this.rooms.clear(),this.connectionListeners.clear();}async openRoom(e,t){let n=await this.options.client.devices.localId();if(n!==this.options.deviceId)throw new Error("[OpenRTC] ServiceNode deviceId must match the client installation.");let[i,a]=await Promise.all([this.authority.devicePublicKey(),this.authority.assignmentPublicKey()]),c=await j(this.options.client,{roomId:e,serviceId:this.options.serviceId,generation:this.options.generation,shardIds:this.options.shardIds,deviceId:n,maxPeers:this.options.maxPeers,irohRelay:this.options.irohRelay!==false,devicePublicKeyX:i.x,assignmentPublicKeyX:a.x,deviceSign:s=>this.authority.signDeviceBytes(s),grantProvider:async s=>{if(s.avenue.kind!=="room"||s.avenue.id!==e)throw new Error("[OpenRTC] ServiceNode grant request escaped its room.");if(s.deviceId!==n)throw new Error("[OpenRTC] ServiceNode grant request escaped its device.");return this.authority.requestGrant({roomId:e,runtimeInstanceId:s.runtimeInstanceId,ticketFingerprint:s.ticketFingerprint,maxPeers:this.options.maxPeers,refreshGrant:s.refreshGrant,features:{irohRelay:this.options.irohRelay!==false}})}}),o=new I(c,this.authority,t);return this.attachConnectionListener(e,o),o}evictRoom(e,t){this.rooms.get(e)===t&&(this.rooms.delete(e),this.connectionCleanups.get(e)?.(),this.connectionCleanups.delete(e));}attachConnectionListener(e,t){this.closed||this.connectionListeners.size===0||this.connectionCleanups.has(e)||this.connectionCleanups.set(e,t.onConnection(n=>{for(let i of this.connectionListeners)i({room:t,connection:n});}));}};
1
+ import {j,d as d$1,c}from'./chunk-RSQCDTS2.js';var E=/^[A-Za-z0-9_.:@-]+$/,P=/^[A-Za-z0-9_-]{43}$/,C=/^[A-Za-z0-9_.:@-]+$/,k=/^[A-Za-z0-9._-]+$/,x=120*6e4,A=new TextEncoder;function d(r,e,t=160){let n=r.trim();if(!n||n.length>t||!E.test(n))throw new TypeError(`[OpenRTC] ${e} is invalid.`);return n}function h(r,e,t=Number.MAX_SAFE_INTEGER){if(!Number.isSafeInteger(r)||r<1||r>t)throw new RangeError(`[OpenRTC] ${e} must be a positive safe integer.`);return r}function K(r){let e="";for(let t of r)e+=String.fromCharCode(t);return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}async function g(r,e){let t=await r.publicJwk();if(t.kty!=="OKP"||t.crv!=="Ed25519"||typeof t.x!="string"||!P.test(t.x)||t.d!==void 0)throw new TypeError(`[OpenRTC] ${e} must return an Ed25519 public JWK.`);return {kty:"OKP",crv:"Ed25519",x:t.x}}async function y(r,e,t){let n=await r.sign(e);if(!(n instanceof Uint8Array)||n.byteLength!==64)throw new TypeError(`[OpenRTC] ${t} returned an invalid Ed25519 signature.`);return K(n)}function T(r){if(!/^pk_(?:live|test)_[A-Za-z0-9]+$/.test(r))throw new TypeError("[OpenRTC] apiKey is invalid.");return `app_${r.slice(-16)}`}function u(r){return r!==null&&typeof r=="object"&&!Array.isArray(r)?r:null}function v(r,e,t,n){if(typeof r!="string"||r.length<1||r.length>t||r!==r.trim()||n&&!n.test(r))throw new Error(`[OpenRTC] authority service grant ${e} is invalid.`);return r}function O(r){let e=v(r,"gatewayUrl",2048),t;try{t=new URL(e);}catch{throw new Error("[OpenRTC] authority service grant gatewayUrl is invalid.")}let n=t.protocol==="http:"&&["127.0.0.1","localhost","::1"].includes(t.hostname.toLowerCase());if(t.protocol!=="https:"&&!n||t.username||t.password||t.search||t.hash)throw new Error("[OpenRTC] authority service grant gatewayUrl is invalid.");return e}function N(r,e){let t=u(r),n=u(t?.avenue),i=u(t?.roomAuthority),a=u(i?.assignmentPublicKeyJwk),c=Date.now(),o=t?.expiresAtMs,s=t?.maxPeers;if(!t||t.protocolVersion!==2||t.architecture!=="authority"||n?.kind!=="room"||n.id!==e.roomId||i?.serviceId!==e.serviceId||i.generation!==e.generation||!Array.isArray(i.shardIds)||i.shardIds.length!==e.shardIds.length||i.shardIds.some((m,l)=>m!==e.shardIds[l])||a?.kty!=="OKP"||a.crv!=="Ed25519"||a.x!==e.assignmentPublicKeyX||!Number.isSafeInteger(o)||o<=c||o>c+x||!Number.isSafeInteger(s)||s<1||s>e.maxPeers)throw new Error("[OpenRTC] authority service grant response is inconsistent.");return {protocolVersion:2,gatewayUrl:O(t.gatewayUrl),routeKey:v(t.routeKey,"routeKey",256,C),token:v(t.token,"token",24e3,k),expiresAtMs:o,avenue:{kind:"room",id:e.roomId},maxPeers:s,architecture:"authority",roomAuthority:{serviceId:e.serviceId,generation:e.generation,shardIds:[...e.shardIds],assignmentPublicKeyJwk:{kty:"OKP",crv:"Ed25519",x:e.assignmentPublicKeyX}}}}var p=class{constructor(e){if(this.apiKey=e.apiKey,this.applicationTag=T(e.apiKey),typeof e.grantIssuer!="function")throw new TypeError("[OpenRTC] ServiceNode requires a browser-safe grantIssuer.");if(this.grantIssuer=e.grantIssuer,this.serviceId=d(e.serviceId,"serviceId",80),this.generation=h(e.generation,"generation"),this.shardIds=[...new Set(e.shardIds.map(t=>d(t,"shardId",80)))].sort(),this.shardIds.length<1||this.shardIds.length>64||this.shardIds.length!==e.shardIds.length)throw new RangeError("[OpenRTC] shardIds must contain 1..64 unique identifiers.");this.deviceId=d(e.deviceId,"deviceId"),this.deviceSigner=e.deviceSigner,this.assignmentSigner=e.assignmentSigner;}async requestGrant(e){let t=d(e.roomId,"roomId"),n=d(e.runtimeInstanceId,"runtimeInstanceId");if(!P.test(e.ticketFingerprint))throw new TypeError("[OpenRTC] ticketFingerprint is invalid.");e.maxPeers!==void 0&&h(e.maxPeers,"maxPeers",50);let i=await g(this.assignmentSigner,"assignmentSigner.publicJwk()"),a=await g(this.deviceSigner,"deviceSigner.publicJwk()"),c=crypto.randomUUID().replace(/-/g,""),o=Math.floor(Date.now()/1e3),s=["openrtc:v2:authority-service-grant",this.applicationTag,t,this.serviceId,String(this.generation),this.shardIds.join(","),i.x,n,c,o].join(":"),m={avenue:{kind:"room",id:t},serviceId:this.serviceId,generation:this.generation,shardIds:this.shardIds,assignmentPublicKeyJwk:i,deviceId:this.deviceId,runtimeInstanceId:n,ticketFingerprint:e.ticketFingerprint,deviceProof:{publicKeyJwk:a,nonce:c,issuedAt:o,signature:await y(this.deviceSigner,A.encode(s),"deviceSigner.sign()")},...e.maxPeers===void 0?{}:{maxPeers:e.maxPeers},...e.refreshGrant?{refreshGrant:e.refreshGrant}:{},features:e.features??{}},l=`authority_${crypto.randomUUID().replace(/-/g,"")}`,R=await this.grantIssuer({apiKey:this.apiKey,idempotencyKey:l,body:m});return N(R,{roomId:t,serviceId:this.serviceId,generation:this.generation,shardIds:this.shardIds,assignmentPublicKeyX:i.x,maxPeers:e.maxPeers??50})}async devicePublicKey(){return g(this.deviceSigner,"deviceSigner.publicJwk()")}async assignmentPublicKey(){return g(this.assignmentSigner,"assignmentSigner.publicJwk()")}async signDeviceBytes(e){return y(this.deviceSigner,e,"deviceSigner.sign()")}async signAssignment(e){let t=e.ttlMs??6e4;h(t,"ttlMs",2*6e4);let n=d(e.shardId,"shardId",80);if(!this.shardIds.includes(n))throw new RangeError("[OpenRTC] assignment shard is not owned by this service.");let i=e.priorityDeviceIds??[],a=e.relevantEntityIds??[];if(i.length>8||a.length>32)throw new RangeError("[OpenRTC] assignment exceeds the 8-edge or 32-entity bound.");let c=Date.now(),o={policyVersion:"room-authority-assignment-v1",serviceId:this.serviceId,generation:this.generation,revision:h(e.revision,"revision"),subjectDeviceId:d(e.subjectDeviceId,"subjectDeviceId"),shardId:n,priorityDeviceIds:i.map(s=>d(s,"priorityDeviceId")),relevantEntityIds:a.map(s=>d(s,"relevantEntityId")),issuedAtMs:c,expiresAtMs:c+t};if(new Set(o.priorityDeviceIds).size!==o.priorityDeviceIds.length||new Set(o.relevantEntityIds).size!==o.relevantEntityIds.length)throw new RangeError("[OpenRTC] assignment identifiers must be unique.");return {assignment:o,signature:await y(this.assignmentSigner,A.encode(JSON.stringify(o)),"assignmentSigner.sign()")}}},I=class{constructor(e,t,n){this.room=e;this.authority=t;this.onClosed=n;this.releaseRuntimeAlias=d$1(this,e);}get kind(){return this.room.kind}get id(){return this.room.id}get peers(){return this.room.peers}get channels(){return this.room.channels}get diagnostics(){return this.room.diagnostics}get closed(){return this.room.closed}get membership(){return this.room.membership}state(e){return this.room.state(e)}channel(e){return this.room.channel(e)}onConnection(e){return this.room.onConnection(e)}architecture(){return this.room.architecture()}onArchitectureChanged(e){return this.room.onArchitectureChanged(e)}authorityAssignment(){return this.room.authorityAssignment()}onAuthorityAssignmentChanged(e){return this.room.onAuthorityAssignmentChanged(e)}leave(){return this.retire(()=>this.room.leave())}close(){return this.retire(()=>this.room.close())}async publishAssignment(e){let t=await this.authority.signAssignment(e);return await c(this.room).advanced.runtime.publishAuthorityAssignment(t),t.assignment}retire(e){return this.retirement??(this.retirement=e().finally(()=>{this.releaseRuntimeAlias(),this.onClosed();}))}},S=class{constructor(e){this.options=e;this.rooms=new Map;this.connectionListeners=new Set;this.connectionCleanups=new Map;this.closed=false;if("secretKey"in e)throw new TypeError("[OpenRTC] ServiceNode never accepts secretKey; delegate short-lived grants.");this.authority=new p(e);}listen(e){if(this.closed)throw new Error("[OpenRTC] ServiceNode is closed.");let t=d(e,"roomId"),n=this.rooms.get(t);if(n)return n.promise;let i={};return i.promise=this.openRoom(t,()=>this.evictRoom(t,i)).catch(a=>{throw this.evictRoom(t,i),a}),this.rooms.set(t,i),i.promise}onConnection(e){if(this.connectionListeners.add(e),this.connectionListeners.size===1)for(let[t,n]of this.rooms)n.promise.then(i=>this.attachConnectionListener(t,i),()=>{});return ()=>{if(this.connectionListeners.delete(e),this.connectionListeners.size===0){for(let t of this.connectionCleanups.values())t();this.connectionCleanups.clear();}}}async close(){if(this.closed)return;this.closed=true;for(let t of this.connectionCleanups.values())t();this.connectionCleanups.clear();let e=await Promise.allSettled([...this.rooms.values()].map(t=>t.promise));await Promise.all(e.flatMap(t=>t.status==="fulfilled"?[t.value.close()]:[])),this.rooms.clear(),this.connectionListeners.clear();}async openRoom(e,t){let n=await this.options.client.devices.localId();if(n!==this.options.deviceId)throw new Error("[OpenRTC] ServiceNode deviceId must match the client installation.");let[i,a]=await Promise.all([this.authority.devicePublicKey(),this.authority.assignmentPublicKey()]),c=await j(this.options.client,{roomId:e,serviceId:this.options.serviceId,generation:this.options.generation,shardIds:this.options.shardIds,deviceId:n,maxPeers:this.options.maxPeers,irohRelay:this.options.irohRelay!==false,devicePublicKeyX:i.x,assignmentPublicKeyX:a.x,deviceSign:s=>this.authority.signDeviceBytes(s),grantProvider:async s=>{if(s.avenue.kind!=="room"||s.avenue.id!==e)throw new Error("[OpenRTC] ServiceNode grant request escaped its room.");if(s.deviceId!==n)throw new Error("[OpenRTC] ServiceNode grant request escaped its device.");return this.authority.requestGrant({roomId:e,runtimeInstanceId:s.runtimeInstanceId,ticketFingerprint:s.ticketFingerprint,maxPeers:this.options.maxPeers,refreshGrant:s.refreshGrant,features:{irohRelay:this.options.irohRelay!==false}})}}),o=new I(c,this.authority,t);return this.attachConnectionListener(e,o),o}evictRoom(e,t){this.rooms.get(e)===t&&(this.rooms.delete(e),this.connectionCleanups.get(e)?.(),this.connectionCleanups.delete(e));}attachConnectionListener(e,t){this.closed||this.connectionListeners.size===0||this.connectionCleanups.has(e)||this.connectionCleanups.set(e,t.onConnection(n=>{for(let i of this.connectionListeners)i({room:t,connection:n});}));}};
2
2
  export{p as a,S as b};
@@ -0,0 +1,309 @@
1
+ import { P as PolicySnapshot, a as PeerReconciliationStats, R as RuntimeClient, b as PlutoRuntimeAssembly } from './assembly-BEMgeExQ.js';
2
+ import { k as RuntimePeerState, l as PeerConnectOptions, m as Connection, n as PeerSessionSnapshot, o as PeerReadiness, p as RuntimePeerHealth, q as ResolvedPeerIdentity, C as ChannelDescriptor, r as PeerStreamOptions, I as IncomingStream, s as ScopedChannelOptions, t as RuntimeDevice, u as ScopedLogicalChannel, v as ConnectionState, w as ReadinessOptions, x as ConnectionEvent, d as TransferPeerDemandRequest, f as TransferPeerDemandStatus, M as ManagedOptions, y as ManagedSession, D as DeviceStatus, z as DeviceConnectOptions, A as ConnectDeviceResult, B as ConnectDeviceHooks, F as ConnectDeviceOptions, L as LocalDeviceInfo, G as DeviceProfile, H as RawConnection, J as JoinRoomOptions, K as RuntimeRoomMember, N as GrantScope, O as AuthContext, Q as RuntimeClientOptions } from './Connection-BZ6piJsh.js';
3
+ import { R as RuntimeCapabilities, C as CapabilityProfile } from './capabilities-fJ11v3xA.js';
4
+
5
+ interface DiagnosticPeer {
6
+ /** Capture-local alias. Full user/device/node/connection IDs are excluded. */
7
+ peerRef: string;
8
+ state: 'connected' | 'connecting' | 'disconnected' | 'failed' | 'closed' | 'unknown';
9
+ admission: 'unknown' | 'pending' | 'admitted' | 'rejected' | 'expired';
10
+ ready: boolean;
11
+ readinessCode: string;
12
+ scopeKinds: readonly string[];
13
+ transportGeneration: number | null;
14
+ routeGeneration: number | null;
15
+ transportStableId: number | null;
16
+ transport: string;
17
+ hasError: boolean;
18
+ }
19
+ interface DiagnosticEvent {
20
+ sequence: number;
21
+ timestampMs: number;
22
+ elapsedMs: number;
23
+ level: 'debug' | 'info' | 'warn';
24
+ name: 'peer.changed' | 'peer.removed';
25
+ peer: Readonly<DiagnosticPeer>;
26
+ }
27
+ interface DiagnosticBundle {
28
+ schemaVersion: 1;
29
+ sdkVersion: string;
30
+ startedAtMs: number;
31
+ stopped: boolean;
32
+ droppedEvents: number;
33
+ /** Peers beyond this capture's 64 distinct peer limit are not recorded. */
34
+ peerLimitReached: boolean;
35
+ events: readonly DiagnosticEvent[];
36
+ }
37
+ interface DiagnosticCaptureOptions {
38
+ /** Default 256, maximum 1024 events. Oldest events are evicted. */
39
+ maxEvents?: number;
40
+ /** Optional host logger/breadcrumb adapter. Exceptions cannot fault peers. */
41
+ logger?: (event: Readonly<DiagnosticEvent>) => void | Promise<void>;
42
+ }
43
+ interface DiagnosticCapture {
44
+ /** Local in-memory copy. The caller owns saving or uploading it. */
45
+ snapshot(): DiagnosticBundle;
46
+ /** Unsubscribe. Retains the bounded capture for subsequent snapshot calls. */
47
+ stop(): void;
48
+ }
49
+ /** Constructor-level logging covers failures before an avenue handle exists. */
50
+ interface DiagnosticOperationEvent {
51
+ sdkVersion: string;
52
+ /** SDK-realm client alias; pair with operationRef for local correlation. */
53
+ clientRef: number;
54
+ name: 'capability.activation';
55
+ operationRef: number;
56
+ avenue: 'devices' | 'space' | 'room' | 'ticket' | 'custom';
57
+ outcome: 'started' | 'succeeded' | 'failed';
58
+ timestampMs: number;
59
+ elapsedMs: number;
60
+ }
61
+
62
+ type ChannelConnectOptions = Omit<ScopedChannelOptions, 'scope' | 'deviceId' | 'ticket'> & {
63
+ /**
64
+ * Device selected from `client.devices.*`. Passing the device object lets
65
+ * OpenRTC reuse its current ticket for native and ticket-gated routes.
66
+ */
67
+ device?: string | RuntimeDevice;
68
+ deviceId?: string | null;
69
+ ticket?: string;
70
+ /**
71
+ * Logical channel lifecycle scope. Most app channels should use the default
72
+ * `session`; pass a custom scope only when you intentionally manage peer
73
+ * lifecycle separately from the channel.
74
+ */
75
+ scope?: ScopedChannelOptions['scope'];
76
+ };
77
+ type DeviceSessionOptions = Omit<ManagedOptions, 'platform'> & {
78
+ /**
79
+ * Runtime host for the managed user-device session. Normal apps can omit
80
+ * this: `OpenRTC(...)` defaults to `web`, and `OpenRTC.native(...)` defaults
81
+ * to `native`.
82
+ */
83
+ platform?: ManagedOptions['platform'];
84
+ };
85
+ interface DeviceNamespace {
86
+ requestTransferPeer(request: TransferPeerDemandRequest): Promise<TransferPeerDemandStatus>;
87
+ transferPeerDemandStatus(id: string, generation: number): Promise<TransferPeerDemandStatus | null>;
88
+ releaseTransferPeer(id: string, generation: number): Promise<boolean>;
89
+ setTransferPeerBudget(budget: number, generation: number): Promise<void>;
90
+ startSession(options?: DeviceSessionOptions): Promise<ManagedSession>;
91
+ stopSession(options?: {
92
+ preserveBackendSession?: boolean;
93
+ }): Promise<void>;
94
+ list(): Promise<RuntimeDevice[]>;
95
+ listWithStatus(): Promise<DeviceStatus[]>;
96
+ watch(callback: (devices: RuntimeDevice[]) => void): () => void;
97
+ watchWithStatus(callback: (devices: DeviceStatus[]) => void): () => void;
98
+ connect(device: string | RuntimeDevice, options?: DeviceConnectOptions): Promise<ConnectDeviceResult>;
99
+ /**
100
+ * @deprecated Use `devices.connect()`. Retry and route recovery are owned by
101
+ * OpenRTC; legacy consumer-provided connection hooks are ignored.
102
+ */
103
+ connectWithRetry(device: string | RuntimeDevice, hooks: ConnectDeviceHooks, options: ConnectDeviceOptions): Promise<ConnectDeviceResult>;
104
+ disconnect(deviceId: string): Promise<void>;
105
+ update(deviceId: string, updates: {
106
+ deviceName?: string;
107
+ capabilities?: RuntimeDevice['capabilities'];
108
+ metadata?: string;
109
+ }): Promise<void>;
110
+ delete(deviceId: string): Promise<void>;
111
+ localId(): Promise<string | null>;
112
+ localInfo(): Promise<LocalDeviceInfo | null>;
113
+ localProfile(options?: {
114
+ deviceName?: string;
115
+ localDeviceId?: string | null;
116
+ platform?: 'native' | 'web';
117
+ userId?: string | null;
118
+ }): Promise<DeviceProfile>;
119
+ updateLocalName(deviceName: string): Promise<LocalDeviceInfo | null>;
120
+ }
121
+ interface PeerNamespace {
122
+ watch(callback: (peers: RuntimePeerState[]) => void): () => void;
123
+ watchLifecycle(callback: (peers: RuntimePeerState[]) => void): () => void;
124
+ get(id: string): RuntimePeerState | undefined;
125
+ listConnected(): RuntimePeerState[];
126
+ connect(options: PeerConnectOptions): Promise<Connection>;
127
+ disconnect(id: string, scope?: string): Promise<void>;
128
+ forceDisconnect(id: string): Promise<void>;
129
+ session(id: string): Promise<PeerSessionSnapshot | null>;
130
+ sessions(): Promise<PeerSessionSnapshot[]>;
131
+ waitConnected(id: string, timeoutMs?: number): Promise<PeerSessionSnapshot | null>;
132
+ readiness(id: string, timeoutMs?: number): Promise<PeerReadiness>;
133
+ health(id: string): Promise<RuntimePeerHealth>;
134
+ identity(id: string): Promise<ResolvedPeerIdentity>;
135
+ addScope(id: string, scope?: string): RuntimePeerState | undefined;
136
+ releaseScope(id: string, scope?: string): RuntimePeerState | undefined;
137
+ scopes(id: string): string[];
138
+ refresh(): Promise<RuntimePeerState[]>;
139
+ }
140
+ interface ChannelNamespace {
141
+ register(descriptor: ChannelDescriptor): void;
142
+ unregister(channelId: string): void;
143
+ list(): ChannelDescriptor[];
144
+ openBi(id: string, channelId: string, options?: Omit<PeerStreamOptions, 'channelId'>): Promise<{
145
+ connection: Connection;
146
+ readable: ReadableStream<Uint8Array>;
147
+ writable: WritableStream<Uint8Array>;
148
+ }>;
149
+ openUni(id: string, channelId: string, options?: Omit<PeerStreamOptions, 'channelId'>): Promise<{
150
+ connection: Connection;
151
+ writable: WritableStream<Uint8Array>;
152
+ }>;
153
+ onIncoming(callback: (stream: IncomingStream) => boolean | void): () => void;
154
+ onIncomingChannel(channelId: string, callback: (stream: IncomingStream & {
155
+ channel: NonNullable<IncomingStream['channel']>;
156
+ }) => boolean | void): () => void;
157
+ connect(options: ChannelConnectOptions): Promise<ScopedLogicalChannel>;
158
+ connectScoped(options: ScopedChannelOptions): Promise<ScopedLogicalChannel>;
159
+ }
160
+ interface RoomNamespace {
161
+ create(roomId?: string): Promise<string>;
162
+ join(roomId: string, options?: JoinRoomOptions): Promise<Connection[]>;
163
+ leave(roomId: string): Promise<void>;
164
+ watch(roomId: string, callback: (members: RuntimeRoomMember[]) => void): () => void;
165
+ members(roomId: string): Promise<RuntimeRoomMember[]>;
166
+ }
167
+ interface TicketNamespace {
168
+ raw(): Promise<string>;
169
+ share(options?: {
170
+ maxConnections?: number;
171
+ }): Promise<string>;
172
+ grant(scope: GrantScope, options?: {
173
+ maxConnections?: number;
174
+ }): Promise<string>;
175
+ revoke(scope: GrantScope): Promise<string[]>;
176
+ }
177
+ interface DiagnosticsNamespace {
178
+ /** Opt-in bounded local timeline. Does not collect credentials or payloads. */
179
+ capture(options?: DiagnosticCaptureOptions): DiagnosticCapture;
180
+ status(): Promise<{
181
+ runtime: 'tauri' | 'browser' | 'unknown';
182
+ wasmLoaded: boolean;
183
+ localNodeId?: string;
184
+ userId?: string;
185
+ }>;
186
+ policy(): PolicySnapshot;
187
+ capabilities(): RuntimeCapabilities;
188
+ capabilityProfile(): CapabilityProfile;
189
+ /** SDK-owned local metrics observer. No application pings or coordination reads. */
190
+ watchConnectionMetrics(callback: (states: readonly ConnectionState[]) => void): () => void;
191
+ connectionStates(): Promise<ConnectionState[]>;
192
+ onStateChange(callback: (state: ConnectionState) => void): Promise<() => void> | (() => void);
193
+ connections(): Connection[];
194
+ applicationReadyConnections(options?: ReadinessOptions): Connection[];
195
+ onConnection(callback: (connection: Connection) => void): () => void;
196
+ onDisconnection(callback: (connection: Connection) => void): () => void;
197
+ onConnectionEvent(callback: (event: ConnectionEvent) => void): () => void;
198
+ forceReconnect(): void;
199
+ peerReconciliation(): Readonly<PeerReconciliationStats>;
200
+ }
201
+ interface AdvancedNamespace {
202
+ readonly runtime: RuntimeClient;
203
+ readonly assembly: PlutoRuntimeAssembly;
204
+ nodeId(): Promise<string>;
205
+ nodeIdFromTicket(ticket: string): Promise<string | null>;
206
+ endpointTicket(): Promise<string>;
207
+ connectRaw(target: {
208
+ ticket: string;
209
+ timeoutMs?: number;
210
+ }): Promise<RawConnection>;
211
+ openBi(nodeId: string): Promise<{
212
+ readable: ReadableStream<Uint8Array>;
213
+ writable: WritableStream<Uint8Array>;
214
+ }>;
215
+ openUni(nodeId: string): Promise<WritableStream<Uint8Array>>;
216
+ isConnected(nodeId: string): Promise<boolean>;
217
+ disconnectNode(nodeId: string): Promise<void>;
218
+ excludeAutoConnect(deviceId: string, excluded: boolean): Promise<void>;
219
+ notifyNetworkChange(reason?: string): Promise<void>;
220
+ }
221
+ /**
222
+ * Client extends RuntimeClient with auth helpers that were
223
+ * previously only available on PlutoRuntimeAssembly.
224
+ *
225
+ * This is the unified type returned by OpenRTC() and OpenRTC.native().
226
+ */
227
+ interface Client extends RuntimeClient {
228
+ readonly devices: DeviceNamespace;
229
+ readonly peers: PeerNamespace;
230
+ readonly channels: ChannelNamespace;
231
+ readonly rooms: RoomNamespace;
232
+ readonly tickets: TicketNamespace;
233
+ readonly diagnostics: DiagnosticsNamespace;
234
+ readonly advanced: AdvancedNamespace;
235
+ /** @deprecated Use setAuth() instead */
236
+ setAuthContext(context: AuthContext | null): Promise<void>;
237
+ /** Set auth context for the runtime */
238
+ setAuth(context: AuthContext | null): Promise<void>;
239
+ /** Sync Pluto-hosted auth to the runtime */
240
+ syncPlutoAuth(options?: {
241
+ userId?: string | null;
242
+ forceRefresh?: boolean;
243
+ }): Promise<void>;
244
+ /** Bind Pluto auth host to auto-sync on token changes */
245
+ bindPlutoAuthHost(): () => void;
246
+ /** Sign in via Pluto SSO */
247
+ signIn(): Promise<void>;
248
+ /** Sign out and clear auth context */
249
+ signOut(): Promise<void>;
250
+ /**
251
+ * @deprecated Use `client.devices.startSession(...)` for the public
252
+ * user-device avenue lifecycle. This top-level method remains for
253
+ * RuntimeClient compatibility and advanced integrations.
254
+ */
255
+ startManagedSession(options: ManagedOptions): Promise<ManagedSession>;
256
+ /**
257
+ * @deprecated Use `client.devices.stopSession(...)` for the public
258
+ * user-device avenue lifecycle.
259
+ */
260
+ stopManagedSession(options?: {
261
+ preserveBackendSession?: boolean;
262
+ }): Promise<void>;
263
+ /** @deprecated Use `client.rooms.create(...)`. */
264
+ createRoom(roomId?: string): Promise<string>;
265
+ /** @deprecated Use `client.rooms.join(...)`. */
266
+ joinRoom(roomId: string, options?: JoinRoomOptions): Promise<Connection[]>;
267
+ /** @deprecated Use `client.rooms.leave(...)`. */
268
+ leaveRoom(roomId: string): Promise<void>;
269
+ /** @deprecated Use `client.rooms.watch(...)`. */
270
+ watchRoom(roomId: string, callback: (members: RuntimeRoomMember[]) => void): () => void;
271
+ /** @deprecated Use `client.rooms.members(...)`. */
272
+ getRoomMembers(roomId: string): Promise<RuntimeRoomMember[]>;
273
+ /** @deprecated Use `client.tickets.raw(...)`. */
274
+ getInvite(): Promise<string>;
275
+ /** @deprecated Use `client.tickets.raw(...)`. */
276
+ getTicket(): Promise<string>;
277
+ /** @deprecated Use `client.tickets.share(...)` or `client.tickets.grant(...)`. */
278
+ getTicketWithToken(scope: GrantScope, maxConnections?: number): Promise<string>;
279
+ /** @deprecated Use `client.tickets.revoke(...)`. */
280
+ revokeTokensByScope(scope: GrantScope): Promise<string[]>;
281
+ /** @deprecated Use `client.peers.connect(...)`. */
282
+ connectPeer(options: PeerConnectOptions): Promise<Connection>;
283
+ /** @deprecated Use `client.peers.connect(...)`. */
284
+ connectTo(options: PeerConnectOptions): Promise<Connection>;
285
+ /** @deprecated Use `client.peers.waitConnected(...)`. */
286
+ waitForConnectedPeer(id: string, timeoutMs?: number): Promise<PeerSessionSnapshot | null>;
287
+ /** @deprecated Use `client.channels.connect(...)`; use `client.channels.connectScoped(...)` only for custom lifecycle scopes. */
288
+ connectScopedChannel(options: ScopedChannelOptions): Promise<ScopedLogicalChannel>;
289
+ /** @deprecated Use `client.channels.openBi(...)`. */
290
+ openPeerBi(id: string, options?: PeerStreamOptions): Promise<{
291
+ connection: Connection;
292
+ readable: ReadableStream<Uint8Array>;
293
+ writable: WritableStream<Uint8Array>;
294
+ }>;
295
+ /** @deprecated Use `client.channels.openUni(...)`. */
296
+ openPeerUni(id: string, options?: PeerStreamOptions): Promise<{
297
+ connection: Connection;
298
+ writable: WritableStream<Uint8Array>;
299
+ }>;
300
+ /**
301
+ * Access to the underlying PlutoRuntimeAssembly for backward compatibility.
302
+ * @deprecated Access methods directly on the client instead.
303
+ */
304
+ readonly runtime: RuntimeClient;
305
+ }
306
+ declare function resolveOptions(options: RuntimeClientOptions): RuntimeClientOptions;
307
+ declare function wrapAssembly(assembly: PlutoRuntimeAssembly, defaultManagedSessionPlatform: ManagedOptions['platform']): Client;
308
+
309
+ export { type AdvancedNamespace as A, type ChannelNamespace as C, type DiagnosticsNamespace as D, type PeerNamespace as P, type RoomNamespace as R, type TicketNamespace as T, type DeviceNamespace as a, type DiagnosticOperationEvent as b, type DiagnosticBundle as c, type DiagnosticCapture as d, type DiagnosticCaptureOptions as e, type DiagnosticEvent as f, type DiagnosticPeer as g, type Client as h, type ChannelConnectOptions as i, type DeviceSessionOptions as j, resolveOptions as r, wrapAssembly as w };