openrtc 2.5.1 → 2.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +21 -1
  2. package/dist/{Connection-CTpuImO-.d.ts → Connection-CovQdc8E.d.ts} +30 -5
  3. package/dist/{DelegatingRuntimeAdapter-D67Ozqo3.d.ts → DelegatingRuntimeAdapter-3ykiNvyh.d.ts} +3 -2
  4. package/dist/{IpcRuntimeAdapter-Ddx0MtSI.d.ts → IpcRuntimeAdapter-BkM_1HyL.d.ts} +12 -2
  5. package/dist/NativeManagedBroadcastHost-WCQ6TPUU.js +1 -0
  6. package/dist/WasmBridge-LP7FHTHZ.js +1 -0
  7. package/dist/{assembly-DvfsYFCL.d.ts → assembly-C235UKSS.d.ts} +5 -3
  8. package/dist/{capabilities-CmzzxSvW.d.ts → capabilities-CdZpAKvE.d.ts} +1 -1
  9. package/dist/chunk-25CN4MLA.js +2 -0
  10. package/dist/chunk-42TNJH5S.js +1 -0
  11. package/dist/chunk-4CC6YIGG.js +1 -0
  12. package/dist/chunk-4J4F32QT.js +1 -0
  13. package/dist/chunk-CHT46RA7.js +2 -0
  14. package/dist/chunk-CNAW5BZ3.js +2 -0
  15. package/dist/chunk-P5GCLQHS.js +1 -0
  16. package/dist/chunk-VC7TGJFS.js +2 -0
  17. package/dist/{chunk-Z4KJHIV5.js → chunk-WMA4OMJL.js} +1 -1
  18. package/dist/{chunk-XTYALGJN.js → chunk-XMYBBLYK.js} +1 -1
  19. package/dist/coreClient.d.ts +3 -3
  20. package/dist/coreClient.js +1 -1
  21. package/dist/{dist-XO466BRG.js → dist-FIVA6EPA.js} +0 -18
  22. package/dist/index.d.ts +5 -5
  23. package/dist/index.js +1 -1
  24. package/dist/ipcFactory-2WMR4PH6.js +1 -0
  25. package/dist/native.d.ts +5 -5
  26. package/dist/native.js +1 -1
  27. package/dist/node.d.ts +9 -5
  28. package/dist/node.js +2 -2
  29. package/dist/openrtc-KERRTMSG.js +2 -0
  30. package/dist/openrtc_bg.wasm +0 -0
  31. package/dist/room-2MUFAJ4M.js +1 -0
  32. package/dist/runtime/WasmRuntimeAdapter.d.ts +3 -3
  33. package/dist/runtime/WasmRuntimeAdapter.js +1 -1
  34. package/dist/runtime/device-status.d.ts +1 -1
  35. package/dist/runtime/factories.d.ts +6 -5
  36. package/dist/runtime/factories.js +1 -1
  37. package/dist/runtime/index.d.ts +9 -9
  38. package/dist/runtime/index.js +1 -1
  39. package/dist/server-browser.d.ts +4 -4
  40. package/dist/server.d.ts +4 -4
  41. package/dist/server.js +1 -1
  42. package/dist/service-node.d.ts +5 -4
  43. package/dist/service-node.js +1 -1
  44. package/dist/testing/native.d.ts +4 -4
  45. package/dist/testing/native.js +1 -1
  46. package/dist/testing.d.ts +6 -4
  47. package/dist/testing.js +1 -1
  48. package/dist/transport/index.d.ts +2 -2
  49. package/dist/{types-Cyc-mPjk.d.ts → types-C6SMXBzJ.d.ts} +1 -1
  50. package/native/darwin-arm64/openrtc-node-host +0 -0
  51. package/native/darwin-arm64/openrtc-node-host.manifest.json +20 -0
  52. package/native/darwin-x64/openrtc-node-host +0 -0
  53. package/native/darwin-x64/openrtc-node-host.manifest.json +20 -0
  54. package/native/linux-x64/openrtc-node-host +0 -0
  55. package/native/linux-x64/openrtc-node-host.manifest.json +20 -0
  56. package/native/openrtc-node-host-signing-public.pem +3 -0
  57. package/package.json +3 -2
  58. package/dist/WasmBridge-ZXBCXBBM.js +0 -1
  59. package/dist/chunk-2K47N3QP.js +0 -2
  60. package/dist/chunk-EIJNERKZ.js +0 -1
  61. package/dist/chunk-FEF3DPPB.js +0 -1
  62. package/dist/chunk-GHAJW6SZ.js +0 -2
  63. package/dist/chunk-GTHSRQ7Y.js +0 -2
  64. package/dist/chunk-VTYVIKTM.js +0 -1
  65. package/dist/chunk-Z54XUIKZ.js +0 -1
  66. package/dist/ipcFactory-PRAJ7JP7.js +0 -1
  67. package/dist/openrtc-VCS6V3AN.js +0 -2
  68. package/dist/room-ULZ2FGWV.js +0 -1
package/README.md CHANGED
@@ -152,19 +152,39 @@ service.onConnection(({ connection }) => {
152
152
  await service.listen('world-42');
153
153
  ```
154
154
 
155
+ `maxPeers` counts everyone in the room, including the service. Node defaults to
156
+ eight; set a value from 1 through 50 explicitly when needed. Your app's approved
157
+ limit and available credits still apply, so a larger request can be denied.
158
+ Browser and standalone Rust grant requests may omit the value to use app policy.
159
+ These limits are not a promise of 50 simultaneous server connections or a
160
+ replacement for the remaining authority acceptance tests.
161
+
155
162
  The released package must contain the signed native artifact for the current
156
163
  `process.platform`/`process.arch`; a missing artifact fails closed. A reviewed
157
164
  source checkout can instead opt into `buildFromSource: true` with an absolute
158
165
  `sourceRoot`. The developer secret is sent only over the child's stdin, and
159
166
  the Node layer only demultiplexes bounded application messages and authority
160
167
  assignments. The Rust peer-session actor remains the sole lifecycle owner.
168
+ `connection.peerId` is the admitted remote endpoint ID, not an app account or
169
+ durable device ID. Room access alone does not grant those identities. Keep
170
+ `stateDirectory` across process restarts to retain the host's private keys.
171
+ Await `service.close()` before reusing that directory; it waits for the host
172
+ process to finish, not just acknowledge shutdown.
173
+ JSON and string messages use the same room-scoped envelope as browser
174
+ `Connection.send`; `onMessage` receives the application value, not the envelope.
175
+ Messages explicitly addressed to another room are discarded. Node byte payloads
176
+ (`Uint8Array`/`ArrayBuffer`) retain the lower-level native byte contract; use
177
+ JSON values for portable browser/Node application messages.
161
178
  This preview Node facade intentionally owns one room and exposes only
162
179
  message-oriented `send`/`onMessage`/`onClose` plus assignment publication; it
163
180
  does not yet claim the browser facade's streams, media, or full Room
164
181
  namespaces. Browser resolution of `openrtc/node` fails closed; browser code
165
182
  uses WASM plus delegated grants through `openrtc/service-node`. Native Rust
166
183
  uses `ControlPlane::join_authority_room` directly and does not require
167
- JavaScript.
184
+ JavaScript. Its `RoomAuthority::compose_client(builder)` method binds the
185
+ dedicated service-room client to the existing Rust peer-session owner before
186
+ endpoint initialization. Native hosts publish a room-scoped compound ticket;
187
+ attaching the signaling backend alone is not service startup.
168
188
 
169
189
  The authority surface remains preview-only until signed prebuilt artifacts and
170
190
  source-bound browser, Node, and native Rust authority E2E lanes pass.
@@ -184,6 +184,16 @@ interface ScopedChannelOptions {
184
184
  peerNodeId?: string;
185
185
  deviceId?: string | null;
186
186
  ticket?: string;
187
+ /**
188
+ * Product-issued bearer for a peer already known to Rust/WASM discovery.
189
+ * OpenRTC binds it to the owner-cached endpoint and presents it without
190
+ * projecting endpoint tickets through application state.
191
+ */
192
+ admissionToken?: string;
193
+ /** User avenue authorized to reveal the target device for this grant. */
194
+ admissionPeerUserId?: string;
195
+ admissionMaxConnections?: number;
196
+ admissionExpiresAtMs?: number;
187
197
  scope: RuntimePeerScope;
188
198
  channelId: string;
189
199
  timeoutMs?: number;
@@ -354,6 +364,18 @@ interface CoordinationSignalingStore {
354
364
  sendMessage(targetId: string, payload: string, state?: string, replyPayload?: string): Promise<string>;
355
365
  pollMessages(targetId: string): Promise<SignalingEnvelope[]>;
356
366
  watchFriendDevices(friendUserIds: string[], callback: (devices: Map<string, Device[]>) => void): () => void;
367
+ waitForFriendDevice(friendUserId: string, deviceId: string, timeoutMs?: number): Promise<Device>;
368
+ /**
369
+ * Supply authoritative native-session identity for read-only friend
370
+ * avenues when Rust owns the writable local presence socket.
371
+ */
372
+ setFriendObservationIdentity?(input: {
373
+ localNodeId: string;
374
+ ticket: string;
375
+ ttlMs: number;
376
+ metadata?: string;
377
+ deviceName?: string;
378
+ }): void;
357
379
  updateFriendTicket(friendTicket: string | null): Promise<void>;
358
380
  handleScopeChange(): Promise<void>;
359
381
  setHostAvailability?(input: {
@@ -837,7 +859,12 @@ interface NativeConnectResult {
837
859
  }
838
860
  interface NativeConnectParams {
839
861
  deviceId?: string | null;
840
- endpointTicket: string;
862
+ endpointTicket?: string;
863
+ admissionToken?: string;
864
+ admissionScope?: string;
865
+ admissionPeerUserId?: string;
866
+ admissionMaxConnections?: number;
867
+ admissionExpiresAtMs?: number;
841
868
  /** Total native dial/admission budget. The host command must enforce it. */
842
869
  timeoutMs?: number;
843
870
  }
@@ -1241,6 +1268,7 @@ interface ISignalingBackend {
1241
1268
  getPeerSession?(id: string): Promise<PeerSessionSnapshot | null>;
1242
1269
  listPeerSessions?(): Promise<PeerSessionSnapshot[]>;
1243
1270
  waitForSettledPeer?(id: string, timeoutMs?: number): Promise<PeerSessionSnapshot | null>;
1271
+ waitForSettledScope?(scope: string, timeoutMs?: number): Promise<PeerSessionSnapshot | null>;
1244
1272
  resolvePeerIdentity?(id: string): Promise<ResolvedPeerIdentity>;
1245
1273
  resolvePeerRecords?(id: string): Promise<ManagedConnectionRecord[]>;
1246
1274
  updateDevice(deviceId: string, updates: {
@@ -1322,10 +1350,7 @@ interface ISignalingBackend {
1322
1350
  retireOpenRtcMediaReceiver?(publicationId: string, mediaGeneration: number): void | Promise<void>;
1323
1351
  decodeOpenRtcMediaChunk?(encoded: Uint8Array): PortableMediaChunk | Promise<PortableMediaChunk>;
1324
1352
  decodeOpenRtcMediaControl?(encoded: Uint8Array): PortableMediaControl | Promise<PortableMediaControl>;
1325
- connectToDevice?(params: {
1326
- deviceId?: string | null;
1327
- endpointTicket: string;
1328
- }): Promise<NativeConnectResult>;
1353
+ connectToDevice?(params: NativeConnectParams): Promise<NativeConnectResult>;
1329
1354
  /**
1330
1355
  * Optional backchannel so a backend (e.g. WasmBridge) can access the narrow
1331
1356
  * facade surface needed to escalate runtime transport dials into registered
@@ -1,5 +1,5 @@
1
- import { K as DiscoveryMode, N as AuthMode, O as SignalingMode, Q as ClientOptions, T as ExplicitFileDataSendParams, U as ISignalingBackend, V as RuntimeIdentity, F as AuthContext, W as RoomMember, X as Device, Y as DeviceStatusSnapshot, k as PeerSessionSnapshot, n as ResolvedPeerIdentity, Z as ManagedConnectionRecord, _ as SignalingEnvelope, $ as DeviceEvent, a0 as DesiredPeerProjection, a1 as SignalingSession, a2 as SessionEvent, a3 as LocalDeviceInfo, a4 as NativeManagedSessionStartResult, g as ProtocolName, G as GrantScope, a5 as BackendPeerBiStream, a6 as BackendPeerUniStream, a7 as PortableMediaPublish, a8 as PortableMediaPublicationStart, a9 as PortableMediaSample, aa as PortableMediaChunk, ab as PortableMediaControl, ac as NativeConnectParams, ad as NativeConnectResult, ae as BackendConnectionState, af as NativePeerDataEvent } from './Connection-CTpuImO-.js';
2
- import { R as RuntimeCapabilities } from './capabilities-CmzzxSvW.js';
1
+ import { K as DiscoveryMode, N as AuthMode, O as SignalingMode, Q as ClientOptions, T as ExplicitFileDataSendParams, U as ISignalingBackend, V as RuntimeIdentity, F as AuthContext, W as RoomMember, X as Device, Y as DeviceStatusSnapshot, k as PeerSessionSnapshot, n as ResolvedPeerIdentity, Z as ManagedConnectionRecord, _ as SignalingEnvelope, $ as DeviceEvent, a0 as DesiredPeerProjection, a1 as SignalingSession, a2 as SessionEvent, a3 as LocalDeviceInfo, a4 as NativeManagedSessionStartResult, g as ProtocolName, G as GrantScope, a5 as BackendPeerBiStream, a6 as BackendPeerUniStream, a7 as PortableMediaPublish, a8 as PortableMediaPublicationStart, a9 as PortableMediaSample, aa as PortableMediaChunk, ab as PortableMediaControl, ac as NativeConnectParams, ad as NativeConnectResult, ae as BackendConnectionState, af as NativePeerDataEvent } from './Connection-CovQdc8E.js';
2
+ import { R as RuntimeCapabilities } from './capabilities-CdZpAKvE.js';
3
3
 
4
4
  /** Host-neutral configuration shared by browser/WASM and native/IPC adapters. */
5
5
  interface RuntimeBridgeOptions {
@@ -58,6 +58,7 @@ declare abstract class DelegatingRuntimeAdapter implements ISignalingBackend {
58
58
  getPeerSession(id: string): Promise<PeerSessionSnapshot | null>;
59
59
  listPeerSessions(): Promise<PeerSessionSnapshot[]>;
60
60
  waitForSettledPeer(id: string, timeoutMs?: number): Promise<PeerSessionSnapshot | null>;
61
+ waitForSettledScope(scope: string, timeoutMs?: number): Promise<PeerSessionSnapshot | null>;
61
62
  resolvePeerIdentity(id: string): Promise<ResolvedPeerIdentity>;
62
63
  resolvePeerRecords(id: string): Promise<ManagedConnectionRecord[]>;
63
64
  updateDevice(deviceId: string, updates: {
@@ -1,6 +1,6 @@
1
- import { R as RuntimeBridgeOptions, D as DelegatingRuntimeAdapter } from './DelegatingRuntimeAdapter-D67Ozqo3.js';
1
+ import { R as RuntimeBridgeOptions, D as DelegatingRuntimeAdapter } from './DelegatingRuntimeAdapter-3ykiNvyh.js';
2
2
  import { P as PlutoIpcBridge } from './ipc-DgzKqHH3.js';
3
- import { ae as BackendConnectionState, af as NativePeerDataEvent } from './Connection-CTpuImO-.js';
3
+ import { ae as BackendConnectionState, af as NativePeerDataEvent, X as Device } from './Connection-CovQdc8E.js';
4
4
 
5
5
  interface NativeIpcBridgeOptions extends RuntimeBridgeOptions {
6
6
  ipcBridge?: PlutoIpcBridge;
@@ -34,6 +34,7 @@ interface NativeProjectedStreamSource {
34
34
  incoming_streams(): Promise<ReadableStream<unknown>>;
35
35
  onStateChange(callback: (state: BackendConnectionState) => void): () => void;
36
36
  onPeerMessage(callback: (event: NativePeerDataEvent) => void): () => void;
37
+ onDevices(callback: (devices: Device[]) => void): () => void;
37
38
  isCurrentTransport(endpointId: string, transportStableId: bigint): Promise<boolean>;
38
39
  }
39
40
  type NativeRootProjectionEvent = {
@@ -48,17 +49,26 @@ type NativeRootProjectionEvent = {
48
49
  kind: 'stream';
49
50
  capabilityKeys: readonly string[];
50
51
  payload: unknown;
52
+ } | {
53
+ kind: 'devices';
54
+ capabilityKeys: readonly string[];
55
+ payload: {
56
+ identityId: string;
57
+ devices: Device[];
58
+ };
51
59
  };
52
60
  declare class NativeProjectionBroker {
53
61
  private host;
54
62
  private readonly consumers;
55
63
  private hostReader;
56
64
  private hostPump;
65
+ private consecutiveEstablishedFaults;
57
66
  private closed;
58
67
  register(capabilityKey: string, host: NativeProjectionHost): NativeProjectedStreamSource;
59
68
  unregister(capabilityKey: string): void;
60
69
  private subscribeState;
61
70
  private subscribePeerData;
71
+ private subscribeDevices;
62
72
  private requireConsumer;
63
73
  private currentHost;
64
74
  private incomingStreams;
@@ -0,0 +1 @@
1
+ import {b as b$1,a}from'./chunk-LLZT3MR6.js';import'./chunk-JPBW67B3.js';var p=64,w=50;function l(n,e){if(n instanceof Uint8Array)return n.slice();if(n instanceof ArrayBuffer)return new Uint8Array(n.slice(0));if(Array.isArray(n)&&n.every(r=>Number.isInteger(r)&&r>=0&&r<=255))return Uint8Array.from(n);throw new Error(`[OpenRTC] ${e} returned invalid binary data.`)}var u=class{constructor(e,r,t,i,o){this.bridge=e;this.handleId=r;this.onFailure=o;this.incoming=null;this.incomingWriters=new Map;this.sources=new Map;this.timer=null;this.closed=false;let s=i[0]??"",c={beginOpenRtcMediaPublication:async a=>{let d=await this.bridge.invoke("begin_openrtc_broadcast_publication",{handleId:this.handleId,sourceSlot:s,publicationId:a.publicationId||null,kind:a.kind,codec:a.codec,clockRate:a.clockRate,codedWidth:a.codedWidth??null,codedHeight:a.codedHeight??null,channels:a.channels??null});return {...d,control:l(d.control??[],"broadcast publication")}},encodeOpenRtcMediaSample:async a=>{if(!this.bridge.invokeRaw)throw new Error("[OpenRTC] Native broadcast requires binary IPC.");return await this.bridge.invokeRaw("publish_openrtc_broadcast_sample",a.payload,{"x-openrtc-broadcast-handle-id":this.handleId,"x-openrtc-publication-id":a.publicationId,"x-openrtc-timestamp-us":String(a.timestampUs),"x-openrtc-duration-us":String(a.durationUs),"x-openrtc-keyframe":String(a.keyframe),"x-openrtc-discardable":String(a.discardable)}),new Uint8Array},pauseOpenRtcMediaPublication:async a=>{await this.bridge.invoke("pause_openrtc_broadcast_publication",{handleId:this.handleId,publicationId:a});},retireOpenRtcMediaPublication:async a=>{await this.bridge.invoke("retire_openrtc_broadcast_publication",{handleId:this.handleId,publicationId:a});},retireOpenRtcMediaReceiver:async(a,d)=>{await this.bridge.invoke("retire_openrtc_broadcast_receiver",{handleId:this.handleId,publicationId:a,mediaGeneration:d});},decodeOpenRtcMediaControl:a=>this.decodeControl(a),decodeOpenRtcMediaChunk:a=>this.decodeChunk(a)},v={createBidirectionalStream:async()=>({protocol:"openrtc-media/1",readable:new ReadableStream({start(a){a.close();}}),writable:new WritableStream})};if(this.media=new b$1(v,c,(a,d)=>(this.incoming=d,()=>{this.incoming=null;})),["owner","publisher","processor"].includes(t)&&!s)throw new Error("[OpenRTC] Broadcast publisher grant has no source slot.");this.scheduleReceive(0);}addTrack(e,r){return this.media.addTrack(e,r)}removeTrack(e){return this.media.removeTrack(e)}onTrack(e){return this.media.onTrack(r=>e({...r,source:{id:this.sources.get(r.receiver.id)??"unknown"}}))}senders(){return this.media.senders()}receivers(){return this.media.receivers()}async close(){this.closed||(this.closed=true,this.timer&&clearTimeout(this.timer),this.timer=null,await Promise.all([...this.incomingWriters.values()].map(({writer:e})=>e.close().catch(()=>{}))),this.incomingWriters.clear(),this.sources.clear(),await this.media.close());}scheduleReceive(e){this.closed||(this.timer=setTimeout(()=>{this.receive();},e));}async receive(){if(!this.closed)try{let e=await this.bridge.invoke("receive_openrtc_broadcast_media",{handleId:this.handleId,max:p});for(let r of e)await this.accept(r);this.scheduleReceive(e.length===p?0:w);}catch(e){this.closed||this.onFailure(e);}}async accept(e){let r=e.publicationId;if(this.sources.set(r,e.sourceSlot),e.control){let i=this.incomingWriters.get(r);if(e.controlType==="stop"){i?.generation===e.mediaGeneration&&(this.incomingWriters.delete(r),await i.writer.close().catch(()=>{})),this.sources.delete(r);return}if(e.controlType!=="publish"||i&&i.generation>=e.mediaGeneration)return;i&&await i.writer.close().catch(()=>{});let o=new TransformStream,s=o.writable.getWriter();this.incomingWriters.set(r,{generation:e.mediaGeneration,writer:s}),this.incoming?.({peerId:e.sourceSlot,protocol:"openrtc-media/1",readable:o.readable,writable:new WritableStream}),await s.write(a(l(e.control,"broadcast control")));return}if(!e.media)return;let t=this.incomingWriters.get(r);!t||t.generation!==e.mediaGeneration||await t.writer.write(a(l(e.media,"broadcast media")));}async decodeControl(e){if(!this.bridge.invokeRaw)throw new Error("[OpenRTC] Native broadcast requires binary IPC.");return this.bridge.invokeRaw("decode_openrtc_media_control",e,{})}async decodeChunk(e){if(!this.bridge.invokeRaw)throw new Error("[OpenRTC] Native broadcast requires binary IPC.");let r=l(await this.bridge.invokeRaw("decode_openrtc_media_chunk",e,{}),"decode_openrtc_media_chunk");if(r.byteLength<4)throw new Error("[OpenRTC] Native media metadata is truncated.");let i=4+new DataView(r.buffer,r.byteOffset,4).getUint32(0,false);if(i>r.byteLength)throw new Error("[OpenRTC] Native media metadata is invalid.");return {...JSON.parse(new TextDecoder().decode(r.subarray(4,i))),payload:r.slice(i)}}},b=class{constructor(e,r){this.bridge=e;this.context=r;this.sessions=new Set;this.publishers=new Set;}open(e){return this.openNative(e)}async create(e){let r=e.auth??this.context.defaultAuth;if(!r)throw new Error("Managed broadcast creation requires authenticated control-plane access.");let t=await this.context.manage({action:"create",deviceId:await this.context.deviceId(),auth:r,create:e});if(!t)throw new Error("Managed broadcast creation returned no grant.");return t}async preparePublisher(){let e=await this.bridge.invoke("prepare_openrtc_broadcast_publisher"),r=l(e.verificationKey,"broadcast publisher");if(!e.handle||r.byteLength!==32)throw e.handle&&await this.bridge.invoke("release_openrtc_broadcast_publisher",{handle:e.handle}).catch(()=>{}),new Error("[OpenRTC] Native broadcast publisher is invalid.");let t=false,i={verificationKey:r,open:o=>{if(t)throw new Error("[OpenRTC] Broadcast publisher is closed.");return this.openNative(o,e.handle)},close:async()=>{t||(t=true,this.publishers.delete(i),await this.bridge.invoke("release_openrtc_broadcast_publisher",{handle:e.handle}));}};return this.publishers.add(i),i}renew(e,r){return this.manage("renew",r,{grant:e})}invite(e,r,t){return this.manage("invite",t,{grant:e,invitation:r})}accept(e,r){return this.manage("accept",r,{invite:e})}async revoke(e,r,t){await this.manage("revoke",t,{grant:e,invite:r});}async leave(e,r){await this.manage("leave",r,{grant:e});}async closeGrant(e,r){await this.manage("close",r,{grant:e});}async close(){await Promise.all([...this.sessions].map(e=>e.close())),await Promise.all([...this.publishers].map(e=>e.close()));}async manage(e,r,t){let i=r??this.context.defaultAuth;if(!i)throw new Error(`Managed broadcast ${e} requires authenticated control-plane access.`);return this.context.manage({action:e,deviceId:await this.context.deviceId(),auth:i,...t})}async openNative(e,r){let t=await this.bridge.invoke("open_openrtc_broadcast",{grantToken:e,issuerPublicKey:null,publisherSignerHandle:r??null,nowMs:Date.now()}),i=t.state,o=false,s=new u(this.bridge,t.handleId,t.role,t.sourceSlots??[],()=>{i="failed";}),c={id:t.id,role:t.role,get state(){return i},media:s,getStats:()=>this.bridge.invoke("get_openrtc_broadcast_stats",{handleId:t.handleId}),close:async()=>{o||(o=true,i="closed",await s.close(),await this.bridge.invoke("close_openrtc_broadcast",{handleId:t.handleId}),this.sessions.delete(c));}};return this.sessions.add(c),c}};export{b as NativeManagedBroadcastHost};
@@ -0,0 +1 @@
1
+ export{b as WasmBridge,a as loadBrowserWasmRuntimeModule}from'./chunk-P5GCLQHS.js';import'./chunk-AYHD4X2R.js';import'./chunk-25CN4MLA.js';import'./chunk-XMYBBLYK.js';import'./chunk-OT7IPLZE.js';import'./chunk-OWKAJPOI.js';import'./chunk-CNAW5BZ3.js';import'./chunk-CCCYE3XN.js';import'./chunk-N6LGTNUI.js';import'./chunk-JPBW67B3.js';import'./chunk-2GX6GB6L.js';
@@ -1,5 +1,5 @@
1
- import { h as RuntimePeerState, r as ConnectionState, l as PeerReadiness, i as PeerConnectOptions, j as Connection, I as IncomingStream, G as GrantScope, H as RuntimeClientOptions, U as ISignalingBackend, aw as RuntimeAuthIdentity, F as AuthContext, g as ProtocolName, L as LocalDeviceInfo, z as DeviceProfile, aj as BrowserProtocolStore, ak as NamespaceDescriptor, al as IrohMutationReceipt, am as IrohDocEntry, p as RuntimeDevice, M as ManagedOptions, u as ManagedSession, D as DeviceStatus, x as ConnectDeviceHooks, y as ConnectDeviceOptions, w as ConnectDeviceResult, v as DeviceConnectOptions, Z as ManagedConnectionRecord, k as PeerSessionSnapshot, n as ResolvedPeerIdentity, ax as RuntimeSession, ay as AppLimits, J as JoinRoomOptions, B as RuntimeRoomMember, az as ConnectionTarget, S as ScopedChannelOptions, q as ScopedLogicalChannel, o as PeerStreamOptions, ac as NativeConnectParams, ad as NativeConnectResult, A as RawConnection, C as ChannelDescriptor, T as ExplicitFileDataSendParams, aA as PresenceLoopOptions, b as RoomArchitectureSnapshot, c as RoomAuthorityAssignment, m as RuntimePeerHealth, s as ReadinessOptions, t as ConnectionEvent } from './Connection-CTpuImO-.js';
2
- import { R as RuntimeCapabilities, C as CapabilityProfile } from './capabilities-CmzzxSvW.js';
1
+ import { h as RuntimePeerState, r as ConnectionState, l as PeerReadiness, i as PeerConnectOptions, j as Connection, I as IncomingStream, G as GrantScope, H as RuntimeClientOptions, U as ISignalingBackend, aw as RuntimeAuthIdentity, F as AuthContext, g as ProtocolName, L as LocalDeviceInfo, z as DeviceProfile, aj as BrowserProtocolStore, ak as NamespaceDescriptor, al as IrohMutationReceipt, am as IrohDocEntry, p as RuntimeDevice, M as ManagedOptions, u as ManagedSession, D as DeviceStatus, x as ConnectDeviceHooks, y as ConnectDeviceOptions, w as ConnectDeviceResult, v as DeviceConnectOptions, Z as ManagedConnectionRecord, k as PeerSessionSnapshot, n as ResolvedPeerIdentity, ax as RuntimeSession, ay as AppLimits, J as JoinRoomOptions, B as RuntimeRoomMember, az as ConnectionTarget, S as ScopedChannelOptions, q as ScopedLogicalChannel, o as PeerStreamOptions, ac as NativeConnectParams, ad as NativeConnectResult, A as RawConnection, C as ChannelDescriptor, T as ExplicitFileDataSendParams, aA as PresenceLoopOptions, b as RoomArchitectureSnapshot, c as RoomAuthorityAssignment, m as RuntimePeerHealth, s as ReadinessOptions, t as ConnectionEvent } from './Connection-CovQdc8E.js';
2
+ import { R as RuntimeCapabilities, C as CapabilityProfile } from './capabilities-CdZpAKvE.js';
3
3
 
4
4
  /**
5
5
  * Coalesced peer reconciliation scheduler and full reconcile orchestration.
@@ -313,6 +313,7 @@ declare class RuntimeClient {
313
313
  private resolveManagedSessionUserId;
314
314
  private resolveManagedAutoConnectEnabled;
315
315
  private resolveManagedPresenceEnabled;
316
+ private resolveManagedTicketScope;
316
317
  private getEffectiveRuntimeUserId;
317
318
  private fetchAndApplyAppLimits;
318
319
  private resolvePeerStreamTarget;
@@ -466,7 +467,7 @@ declare class RuntimeClient {
466
467
  preserveBackendSession?: boolean;
467
468
  }): Promise<void>;
468
469
  private stopManagedSessionInternal;
469
- private rotateManagedUserDeviceGrant;
470
+ private rotateManagedGrant;
470
471
  listDevices(): Promise<RuntimeDevice[]>;
471
472
  listDeviceStatus(): Promise<DeviceStatus[]>;
472
473
  updateDevice(deviceId: string, updates: {
@@ -493,6 +494,7 @@ declare class RuntimeClient {
493
494
  getPeerSession(id: string): Promise<PeerSessionSnapshot | null>;
494
495
  listPeerSessions(): Promise<PeerSessionSnapshot[]>;
495
496
  waitForConnectedPeer(id: string, timeoutMs?: number): Promise<PeerSessionSnapshot | null>;
497
+ waitForConnectedScope(scope: string, timeoutMs?: number): Promise<PeerSessionSnapshot | null>;
496
498
  getPeerReadiness(id: string, timeoutMs?: number): Promise<PeerReadiness>;
497
499
  resolvePeerIdentity(id: string): Promise<ResolvedPeerIdentity>;
498
500
  resolveStreamPeer(remoteNodeId: string): Promise<ResolvedPeerIdentity>;
@@ -1,4 +1,4 @@
1
- import { g as ProtocolName, f as RouteOptimization } from './Connection-CTpuImO-.js';
1
+ import { g as ProtocolName, f as RouteOptimization } from './Connection-CovQdc8E.js';
2
2
 
3
3
  type RuntimeAdapterKind = 'browser-wasm' | 'native-ipc' | 'tauri-ipc' | 'unknown';
4
4
  type CapabilityMaturity = 'stable' | 'preview' | 'support-only' | 'unavailable';
@@ -0,0 +1,2 @@
1
+ import {b as b$1,d,l}from'./chunk-OT7IPLZE.js';import {a,c,e}from'./chunk-N6LGTNUI.js';import*as x from'tweetnacl';function kt(){throw new Error("[OpenRTC] The rollback-only Firebase auth host is not installed. OpenRTC 2.0 applications must supply an AuthProvider; legacy runtimes must import openrtc/auth explicitly.");}var Me="openrtc-trust";var oe="identity",R="managed-room-keys",I="managed-room-state";function Ee(){if(typeof globalThis.indexedDB>"u")throw new Error("[OpenRTC] Managed rooms require durable IndexedDB storage.");return globalThis.indexedDB}function ke(){return new Promise((t,e)=>{let n=Ee().open(Me,2);n.onupgradeneeded=()=>{let i=n.result;i.objectStoreNames.contains(oe)||i.createObjectStore(oe),i.objectStoreNames.contains(R)||i.createObjectStore(R),i.objectStoreNames.contains(I)||i.createObjectStore(I);},n.onsuccess=()=>t(n.result),n.onerror=()=>e(n.error??new Error("managed room database failed")),n.onblocked=()=>e(new Error("managed room database upgrade is blocked"));})}function W(t){return new Promise((e,n)=>{t.onsuccess=()=>e(t.result),t.onerror=()=>n(t.error??new Error("managed room storage failed"));})}function P(t){return new Promise((e,n)=>{t.oncomplete=()=>e(),t.onerror=()=>n(t.error??new Error("managed room storage failed")),t.onabort=()=>n(t.error??new Error("managed room storage aborted"));})}function _e(t,e,n){return `${t}:${e}:${n}`}function De(t,e){return `${t}:${e}`}function se(t){return new TextEncoder().encode(`openrtc-managed-room-state-v1:${t}`)}async function xe(t,e){let n=t.transaction(R,"readonly"),i=P(n),r=await W(n.objectStore(R).get(e));if(await i,r)return r;let o=await crypto.subtle.generateKey({name:"AES-GCM",length:256},false,["encrypt","decrypt"]),a=t.transaction(R,"readwrite"),s=P(a);a.objectStore(R).add(o,e);try{return await s,o}catch{let c=t.transaction(R,"readonly"),d=P(c),l=await W(c.objectStore(R).get(e));if(await d,!l)throw new Error("[OpenRTC] Managed room wrapping key could not be persisted.");return l}}function Ne(t){let e=t;return e?.schemaVersion===1&&e.wrappedKey instanceof Uint8Array&&e.wrappingNonce instanceof Uint8Array&&e.wrappingNonce.byteLength===12&&(e.sealedState===void 0||e.sealedState instanceof Uint8Array)?e:null}async function q(t,e,n){let i=await ke(),r=_e(t,e,n);try{let o=await xe(i,De(t,e)),a=i.transaction(I,"readonly"),s=P(a),c=Ne(await W(a.objectStore(I).get(r)));await s;let d,l;if(c){let u=await crypto.subtle.decrypt({name:"AES-GCM",iv:c.wrappingNonce,additionalData:se(r)},o,c.wrappedKey).catch(()=>{throw new Error("[OpenRTC] Managed room state key authentication failed.")});if(d=new Uint8Array(u),d.byteLength!==32)throw new Error("[OpenRTC] Managed room state key is invalid.");l=c;}else {d=crypto.getRandomValues(new Uint8Array(32));let u=crypto.getRandomValues(new Uint8Array(12)),f=new Uint8Array(await crypto.subtle.encrypt({name:"AES-GCM",iv:u,additionalData:se(r)},o,d));l={schemaVersion:1,wrappingNonce:u,wrappedKey:f};let y=i.transaction(I,"readwrite"),m=P(y);y.objectStore(I).add(l,r),await m;}return {wrappingKey:d,sealedState:l.sealedState,async persist(u){if(!(u instanceof Uint8Array)||u.byteLength===0)throw new Error("[OpenRTC] Managed room sealed state is invalid.");let f=i.transaction(I,"readwrite"),y=P(f);f.objectStore(I).put({...l,sealedState:u},r),await y,l={...l,sealedState:u};},close(){d.fill(0),i.close();}}}catch(o){throw i.close(),o}}var Oe=3e4,Ke=5*6e4,Le=3e4,He=100,Ue=48*1024,ae=12,Be=10*6e4,Fe=5*6e4,H=15e3,je=15e3,ze=1e3,ce=250;function de(t){let e=[...new Set(t.map(n=>String(n??"").trim().toLowerCase()).filter(Boolean))].sort();if(e.length>ce)throw new Error(`Coordination excluded-peer set exceeds ${ce} devices.`);return e}var We="openrtc.v2",qe="openrtc.auth.";function le(t){try{let e=t.split(".")[1];if(!e)return null;let n=e.replace(/-/g,"+").replace(/_/g,"/").padEnd(Math.ceil(e.length/4)*4,"="),i=JSON.parse(globalThis.atob(n));return typeof i.jti=="string"&&i.jti.length>0?i.jti:null}catch{return null}}var h=class extends Error{constructor(n,i,r){super(n);this.retryable=i;this.gatewayCode=r;this.name="CoordinationConnectError";this.code=a.COORDINATION_DISCONNECTED;this.plane="coordination";}},U=class extends Error{constructor(n,i,r){let o=e({code:n,message:i,retryable:r});super(`Coordination gateway ${n}: ${i}`);this.name="CoordinationGatewayProtocolError";this.code=o.code||n||a.COORDINATION_PROTOCOL,this.retryable=r,this.plane=o.plane;}};function ue(t){return t instanceof h&&/\bstale-budget\b/i.test(t.message)}function _(t){if(!t||typeof t!="object")return false;let e=t;return e.gatewayCode==="credential-revoked"||e.code==="credential-revoked"||e.reason==="device-certificate-revoked"}function pe(t){if(_(t))return true;if(typeof t!="object"||t===null)return false;let e=t;if(e.retryable===false)return true;let n=e.status??e.statusCode,i=typeof n=="number"?n:Number.NaN;if(Number.isInteger(i)&&i>=400&&i<500&&![408,425,429].includes(i))return true;let r=String(e.code??"");return ["functions/unauthenticated","functions/permission-denied","functions/invalid-argument","functions/failed-precondition","functions/resource-exhausted","unauthenticated","permission-denied","invalid-argument","failed-precondition","resource-exhausted"].includes(r)}function $e(t){let e=new Uint32Array(1);return crypto.getRandomValues(e),Math.max(1,Math.round(t*(.75+e[0]/4294967295*.5)))}function v(t){if(typeof crypto.randomUUID=="function")return `${t}:${crypto.randomUUID()}`;let e=new Uint8Array(16);crypto.getRandomValues(e);let n=Array.from(e,i=>i.toString(16).padStart(2,"0")).join("");return `${t}:${n}`}async function Ve(t){let e=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(t)),n="";for(let i of new Uint8Array(e))n+=String.fromCharCode(i);return btoa(n).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function k(t){if(!/^[A-Za-z0-9_-]+$/.test(t))throw new Error("[OpenRTC] Managed room payload encoding is invalid.");let e=t.replace(/-/g,"+").replace(/_/g,"/"),n=atob(e.padEnd(Math.ceil(e.length/4)*4,"="));return Uint8Array.from(n,i=>i.charCodeAt(0))}function Je(t,e,n){let i=new URL(t);if(i.search||i.hash||i.username||i.password)throw new Error("[OpenRTC] Coordination gateway endpoint must not contain credentials, query, or fragment.");if(i.protocol==="https:")i.protocol="wss:";else if(i.protocol==="http:")i.protocol="ws:";else if(i.protocol!=="wss:"&&i.protocol!=="ws:")throw new Error("[OpenRTC] Coordination gateway endpoint must use HTTPS/WSS.");return i.pathname=`${i.pathname.replace(/\/+$/,"")}/v${n}/connect/${e}`,i.toString()}function he(t){let e=new URL(t);return e.protocol==="wss:"&&(e.protocol="https:"),e.protocol==="ws:"&&(e.protocol="http:"),e.origin}var B=class t{constructor(e){this.options=e;this.runtimeInstanceId=v("runtime");this.socket=null;this.socketReady=false;this.activeGrantToken=null;this.activeGrantJti=null;this.activeAvenue=null;this.activeGrantExpiresAtMs=0;this.activeGrantProtocolVersion=1;this.leaseRefreshMode="off";this.pendingLeaseRefreshKey=null;this.authenticationRefreshTail=Promise.resolve();this.authenticationRefreshes=new Map;this.connectPromise=null;this.desiredPresence=null;this.friendObservationPresence=null;this.desiredExcludedPeers=[];this.devices=new Map;this.sparseMembers=new Map;this.sparseRoutes=new Map;this.pendingMembershipPageSnapshot=null;this.sparseTopologyRevision=0;this.roomArchitectureSnapshot=null;this.roomAuthorityAssignment=null;this.roomAuthorityAssignmentExpiry=null;this.roomEncryptionEpoch=0;this.managedWasmClient=null;this.peerAdmissionRuntime=null;this.peerAdmissionScope=null;this.peerAdmissionRevision=0;this.managedStateProvider=q;this.managedState=null;this.managedInitialization=null;this.managedActions=Promise.resolve();this.managedPublishQueue=[];this.managedPublishScheduled=false;this.managedMessageListeners=new Set;this.deviceListeners=new Set;this.architectureListeners=new Set;this.authorityAssignmentListeners=new Set;this.deviceStreams=new Set;this.sessionStreams=new Set;this.pendingAcks=new Map;this.pendingMessages=[];this.roomConnections=new Map;this.friendConnections=new Map;this.reconnectTimer=null;this.authRefreshTimer=null;this.keepaliveTimer=null;this.pendingAuthRefresh=null;this.budgetRenewalPromise=null;this.budgetRenewalEpoch=0;this.reconnectAttempt=0;this.reconnectOutageStartedAtMs=null;this.reconnectCircuitOpen=false;this.hostAvailable=true;this.connectionReadyWaiters=new Set;this.hostResumeReconnectPromise=null;this.lastHostResumeReconnectAtMs=0;this.desiredPresenceRevision=0;this.appliedPresenceRevision=0;this.stopped=false;this.credentialRevoked=false;if(this.initialExcludedPeers=de(e.initialExcludedPeers??[]),this.desiredExcludedPeers=[...this.initialExcludedPeers],e.gateway.environment!=="staging"&&e.gateway.environment!=="production")throw new Error("[OpenRTC] Coordination gateway environment is invalid.");let n=new URL(e.gateway.endpoint),i=n.hostname==="127.0.0.1"||n.hostname==="localhost"||n.hostname==="[::1]",r=n.protocol==="https:"||n.protocol==="wss:",o=e.gateway.testingAllowInsecureLoopback===true&&i&&(n.protocol==="http:"||n.protocol==="ws:");if(!r&&!o)throw new Error("[OpenRTC] Coordination gateway requires HTTPS/WSS.");if(n.username||n.password||n.search||n.hash)throw new Error("[OpenRTC] Coordination gateway credentials and parameters cannot be supplied in its URL.")}async updatePresence(e,n,i,r,o,a){let s=this.desiredPresence;if(i&&this.options.roomArchitecture==="authority"){let l=this.options.avenueOverride;if(l?.kind!=="room"||!this.peerAdmissionRuntime)throw new Error("[OpenRTC] Authority rooms require Rust peer admission support.");let u=`v2:room:${l.id}`;this.peerAdmissionRuntime.__requireScopePeerAdmission(u),this.peerAdmissionScope=u;}this.desiredPresence={localNodeId:e,ticket:n,online:i,ttlMs:r,metadata:o,deviceName:a?.trim()||this.options.getDefaultDeviceName()},(!s||s.localNodeId!==e||s.ticket!==n||s.online!==i||s.ttlMs!==r||s.metadata!==o||s.deviceName!==this.desiredPresence.deviceName)&&(this.desiredPresenceRevision+=1,this.reconnectCircuitOpen=false,this.reconnectAttempt=0,this.reconnectOutageStartedAtMs=null);for(let l of this.friendConnections.values())l.updatePresence(e,n,i,r,o,this.desiredPresence.deviceName).catch(()=>{});let d=this.desiredPresenceRevision;try{await this.ensureConnected();}catch(l){if(!(l instanceof h)||!l.retryable)throw l;await this.waitForConnectionReady();}this.appliedPresenceRevision>=d||(s&&s.ticket!==n&&await this.refreshAuthentication(),await this.sendOperation({v:1,type:"presence.upsert",idempotencyKey:v("presence"),ttlMs:r,device:this.gatewayDevice(this.desiredPresence)}),this.appliedPresenceRevision=Math.max(this.appliedPresenceRevision,d));}async setOffline(e){this.desiredPresence&&(this.desiredPresence.online=false,this.socket?.readyState===WebSocket.OPEN&&await this.sendOperation({v:1,type:"presence.offline",idempotencyKey:v("offline")}));}async reconnectAfterHostResume(){if(this.desiredPresence){if(this.hostResumeReconnectPromise)return this.hostResumeReconnectPromise;if(!(Date.now()-this.lastHostResumeReconnectAtMs<je)){this.lastHostResumeReconnectAtMs=Date.now(),this.hostResumeReconnectPromise=(async()=>{(this.socket?.readyState===WebSocket.OPEN||this.socketReady)&&this.stopSocket(),await this.ensureConnected();})();try{await this.hostResumeReconnectPromise;}finally{this.hostResumeReconnectPromise=null;}}}}setHostAvailability(e){let n=e.available&&!this.hostAvailable;this.hostAvailable=e.available;for(let i of this.roomConnections.values())i.setHostAvailability(e);for(let i of this.friendConnections.values())i.setHostAvailability(e);if(!e.available){this.reconnectTimer&&clearTimeout(this.reconnectTimer),this.reconnectTimer=null;return}n&&this.desiredPresence&&!this.socketReady&&!this.connectPromise&&!this.reconnectCircuitOpen&&!this.stopped&&this.ensureConnected().catch(i=>this.scheduleReconnect(i));}async updateDevice(e,n){if(e!==this.options.getLocalDeviceId())throw new Error("A coordination socket can update only its local device.");let i=n;if(n.excludedPeers!==void 0){let r=de(n.excludedPeers);this.desiredExcludedPeers=r,i={...n,excludedPeers:r};}await this.ensureConnected(),await this.sendOperation({v:1,type:"device.patch",idempotencyKey:v("device-patch"),patch:i});}async deleteDevice(e){if(this.options.credentialPurpose!=="device-control"&&(!this.socketReady||this.socket?.readyState!==WebSocket.OPEN)){let n=new t({...this.options,credentialPurpose:"device-control"});try{await n.deleteDevice(e);}finally{n.stopAuthActivity();}return}await this.ensureConnected();try{await this.sendOperation({v:1,type:"device.delete",idempotencyKey:v("device-delete"),targetDeviceId:e});}finally{this.options.credentialPurpose==="device-control"&&this.stopSocket();}}async cleanupStaleDevices(){}async searchDevices(e){return this.snapshot(e)}async listDevices(e){return this.snapshot(e)}onDevicesChange(e,n){let i=r=>e(n?r.filter(o=>o.nodeId!==n):r);return this.deviceListeners.add(i),i(this.snapshot()),this.desiredPresence&&this.ensureConnected().catch(()=>{}),()=>this.deviceListeners.delete(i)}onRoomArchitectureChange(e){return this.architectureListeners.add(e),this.roomArchitectureSnapshot&&e({...this.roomArchitectureSnapshot}),()=>this.architectureListeners.delete(e)}onRoomAuthorityAssignmentChange(e){return this.authorityAssignmentListeners.add(e),e(this.roomAuthorityAssignmentSnapshot()),()=>this.authorityAssignmentListeners.delete(e)}async publishAuthorityAssignment(e){await this.ensureConnected(),await this.sendOperation({v:1,type:"authority.assignment.publish",idempotencyKey:v("authority-assignment"),assignment:e.assignment,signature:e.signature});}setWasmClient(e){this.setManagedRoomRuntime(e,q);}setManagedRoomRuntime(e,n){let i=e;this.peerAdmissionRuntime=i&&typeof i.__requireScopePeerAdmission=="function"&&typeof i.__updateScopePeerAdmission=="function"?i:null;let r=e;this.managedWasmClient=r&&typeof r.__initManagedRoomGroup=="function"&&typeof r.__handleManagedRoomPreparePage=="function"&&typeof r.__handleManagedRoomArtifactChunk=="function"&&typeof r.__sealManagedRoomPayload=="function"&&typeof r.__openManagedRoomPayload=="function"&&typeof r.__forgetManagedRoomGroup=="function"?r:null,this.managedStateProvider=n,this.roomArchitectureSnapshot?.effective==="managed"&&this.enqueueManagedWork(()=>this.ensureManagedGroupInitialized());}onManagedRoomMessage(e){return this.managedMessageListeners.add(e),()=>this.managedMessageListeners.delete(e)}async publishManagedRoomMessage(e){return new Promise((n,i)=>{this.managedPublishQueue.push({input:e,resolve:n,reject:i}),!this.managedPublishScheduled&&(this.managedPublishScheduled=true,queueMicrotask(()=>{this.managedPublishScheduled=false,this.enqueueManagedWork(()=>this.flushManagedPublishBatch());}));})}async subscribeDevices(){let e=null;return new ReadableStream({start:n=>{e=n,this.deviceStreams.add(n);let i=this.snapshot().map(r=>({type:"added",device:r}));i.length>0&&n.enqueue(i);},cancel:()=>{e&&this.deviceStreams.delete(e),e=null;}})}async createSession(e){await this.ensureConnected(),await this.sendOperation({v:1,type:"session.put",idempotencyKey:v("session-put"),sessionId:e.connectionId,session:e,expiresAtMs:e.expiresAt??Date.now()+15*6e4});}async updateSession(e,n){await this.ensureConnected(),await this.sendOperation({v:1,type:"session.put",idempotencyKey:v("session-update"),sessionId:this.unscopedId(e),session:n,expiresAtMs:typeof n.expiresAt=="number"?n.expiresAt:Date.now()+15*6e4});}async subscribeSessions(e){let n=null;return new ReadableStream({start:i=>{n=i,this.sessionStreams.add(i);},cancel:()=>{n&&this.sessionStreams.delete(n),n=null;}})}async sendMessage(e,n,i,r){await this.ensureConnected();let o=v("signal");return await this.sendOperation({v:1,type:"signal.send",idempotencyKey:o,targetDeviceId:this.unscopedId(e),payload:n,state:i,replyPayload:r}),o}async pollMessages(e){return this.pendingMessages.splice(0,this.pendingMessages.length)}watchFriendDevices(e,n){let i=[...new Set(e.map(s=>s.trim()).filter(Boolean))];if(i.length>25)throw new RangeError(`watchFriendDevices accepts at most ${25} unique friend IDs per runtime.`);for(let s of i)if(s.length>128||s.includes("/"))throw new TypeError('Friend user IDs must be 1-128 characters and cannot contain "/".');let r={value:false},o=new Map,a=[];n(new Map);for(let s of i){if(!s||s===this.options.getCurrentUserId())continue;let c=this.friendConnection(s);a.push(c.onDevicesChange(d=>{if(r.value)return;let l=d.filter(u=>u.online);o.set(s,l),n(new Map(o));}));}return ()=>{r.value=true;for(let s of a)s();for(let s of i)this.friendConnections.get(s)?.stopAuthActivity(),this.friendConnections.delete(s);}}waitForFriendDevice(e,n,i=1e4){let r=e.trim(),o=n.trim();return !r||!o?Promise.reject(new Error("Capability-authorized device observation requires user and device ids.")):new Promise((a,s)=>{let c=()=>{},d=false,l=y=>{d||(d=true,clearTimeout(u),c(),y.error?s(y.error):a(y.device));},u=setTimeout(()=>l({error:new Error(`Timed out waiting for capability-authorized device ${o}`)}),Math.max(1,i));c=this.watchFriendDevices([r],y=>{let m=(y.get(r)??[]).find(T=>T.deviceId===o&&T.online&&typeof T.ticket=="string"&&T.ticket.trim().startsWith("endpoint"));m&&l({device:m});}),d&&c();})}setFriendObservationIdentity(e){this.friendObservationPresence={localNodeId:e.localNodeId,ticket:e.ticket,online:true,ttlMs:e.ttlMs,metadata:e.metadata,deviceName:e.deviceName?.trim()||this.options.getDefaultDeviceName()};for(let n of this.friendConnections.values())this.activateFriendConnection(n,this.friendObservationPresence);}async updateFriendTicket(e){await this.ensureConnected(),await this.sendOperation({v:1,type:"device.patch",idempotencyKey:v("friend-ticket"),patch:{friendTicket:e??""}});}async handleScopeChange(){this.stopSocket(),this.credentialRevoked=false,this.reconnectCircuitOpen=false,this.reconnectAttempt=0,this.reconnectOutageStartedAtMs=null,this.appliedPresenceRevision=0,this.devices.clear(),this.emitDevices();}stopAuthActivity(){this.stopped=true,this.friendObservationPresence=null,this.reconnectOutageStartedAtMs=null,this.stopSocket(),this.rejectConnectionReadyWaiters(new h("Coordination activity stopped before capability admission completed.",false)),this.desiredExcludedPeers=[...this.initialExcludedPeers];for(let e of this.pendingAcks.values())clearTimeout(e.timer),e.resolve();this.pendingAcks.clear();for(let e of this.managedPublishQueue.splice(0))e.reject(new Error("[OpenRTC] Managed room activity stopped."));if(this.devices.clear(),this.pendingMessages.splice(0,this.pendingMessages.length),this.managedState){try{this.managedWasmClient?.__forgetManagedRoomGroup(this.managedAvenueKey());}catch{}this.managedState.close(),this.managedState=null;}this.managedInitialization=null,this.managedMessageListeners.clear(),this.roomAuthorityAssignmentExpiry&&clearTimeout(this.roomAuthorityAssignmentExpiry),this.roomAuthorityAssignmentExpiry=null,this.roomAuthorityAssignment=null,this.authorityAssignmentListeners.clear(),this.emitDevices();for(let e of this.roomConnections.values())e.stopAuthActivity();this.roomConnections.clear();for(let e of this.friendConnections.values())e.stopAuthActivity();this.friendConnections.clear();}usesCoordinationGateway(){return true}async joinCoordinationRoom(e,n,i){let r=e.trim().toUpperCase(),o=this.roomConnections.get(r);o||(o=new t({...this.options,avenueOverride:{kind:"room",id:r}}),o.setHostAvailability({available:this.hostAvailable,reason:"parent-avenue-created"}),this.roomConnections.set(r,o));try{await o.updatePresence(n,i,!0,5*6e4,void 0,this.options.getDefaultDeviceName());}catch(a){if(!(a instanceof h)||!a.retryable)throw a;await o.waitForConnectionReady();}}async leaveCoordinationRoom(e){let n=e.trim().toUpperCase(),i=this.roomConnections.get(n);i&&(await i.setOffline(this.options.getLocalDeviceId()).catch(()=>{}),i.stopAuthActivity(),this.roomConnections.delete(n));}async getCoordinationRoomMembers(e){return this.requireRoomConnection(e).snapshot().map(i=>this.roomMember(i))}watchCoordinationRoomMembers(e,n){return this.requireRoomConnection(e).onDevicesChange(r=>n(r.map(o=>this.roomMember(o))))}async ensureConnected(){if(this.credentialRevoked)throw new h("Coordination credential revoked.",false,"credential-revoked");if(this.connectPromise)return this.connectPromise;if(!(this.socket?.readyState===WebSocket.OPEN&&this.socketReady)){if(!this.desiredPresence&&this.options.credentialPurpose!=="device-control")throw new Error("Coordination presence must be initialized before the gateway can connect.");if(!this.hostAvailable&&this.options.credentialPurpose!=="device-control")throw new h("Coordination reconnect is parked until the host is foregrounded and online.",true);if(this.reconnectCircuitOpen)throw new h("Coordination reconnect circuit is open until presence or scope changes.",false);if(this.reconnectTimer)throw new h("Coordination reconnect is already scheduled.",true);this.stopped=false,this.connectPromise=this.connect();try{await this.connectPromise;}catch(e){throw this.scheduleReconnect(e),e}finally{this.connectPromise=null;}}}async connect(){let e=this.desiredPresence??this.controlPresence(),n=this.desiredPresenceRevision,i=async()=>{let r=await this.mintGatewayCredential(e,false);await new Promise((o,a)=>{let s=new WebSocket(Je(r.gatewayUrl,r.routeKey,r.protocolVersion),[We,`${qe}${r.token}`]);this.socket=s;let c=false,d=false,l=null,u=()=>{d||s.readyState!==WebSocket.OPEN||(d=true,this.socketReady=true,this.appliedPresenceRevision=Math.max(this.appliedPresenceRevision,this.desiredPresence?n:0),clearTimeout(f),this.reconnectAttempt=0,this.reconnectOutageStartedAtMs=null,this.scheduleAuthRefresh(r.expiresAtMs,r.protocolVersion),this.resolveConnectionReadyWaiters(),o());},f=setTimeout(()=>{s.close(4408,"authentication timeout"),l=new h("Coordination gateway authentication timed out.",true),a(l);},H);s.onopen=()=>{s.send(JSON.stringify({v:1,type:"auth",token:r.token,socketLiveness:"ping-v1",device:this.gatewayDevice(e)}));},s.onmessage=y=>{if(y.data==="pong")return;let m;try{m=JSON.parse(String(y.data));}catch{s.close(4400,"invalid gateway frame"),d||(clearTimeout(f),a(new Error("Coordination gateway returned an invalid frame.")));return}if(m.type==="ready"&&!c&&this.socket===s&&(this.activeGrantToken=r.token,this.activeGrantJti=le(r.token),this.activeAvenue=r.avenue,this.activeGrantExpiresAtMs=r.expiresAtMs,this.activeGrantProtocolVersion=r.protocolVersion,this.leaseRefreshMode=m.leaseRefreshMode??"off",c=true,this.keepaliveTimer&&clearInterval(this.keepaliveTimer),this.keepaliveTimer=setInterval(()=>{if(this.socket===s&&s.readyState===WebSocket.OPEN)try{s.send("ping");}catch{s.close(4408,"gateway keepalive failed");}},3e4)),m.type==="error"&&!d){l=new h(`Coordination gateway ${m.code}: ${m.message}`,m.retryable,m.code),clearTimeout(f),a(l),s.close(4403,m.code);return}this.handleFrame(m,s);let T=m.type==="roster.snapshot"||m.type==="membership.snapshot"||m.type==="membership.page"&&this.pendingMembershipPageSnapshot===null;c&&(this.options.credentialPurpose==="device-control"||T)&&u();},s.onerror=()=>{d||(clearTimeout(f),l??(l=new h("Coordination gateway connection failed.",true)),a(l));},s.onclose=y=>{clearTimeout(f);let m=this.socket===s;m&&this.keepaliveTimer&&(clearInterval(this.keepaliveTimer),this.keepaliveTimer=null),m&&y.code===4403&&(!l||_(l))&&this.stopForCredentialRevocation(new h("Coordination credential revoked.",false,"credential-revoked")),d||(l??(l=new h(`Coordination gateway closed (${y.code}) before its initial projection.`,y.code!==4401&&y.code!==4403)),a(l)),this.socket===s&&(this.socket=null,this.socketReady=false),this.rejectPendingAcks("Coordination gateway connection closed.",s),this.rejectPendingAuthRefresh(new h("Coordination gateway closed during credential refresh.",y.code!==4401&&y.code!==4403),s),m&&!this.stopped&&this.desiredPresence&&y.code!==1e3&&!ue(l)&&this.scheduleReconnect(l??new h(`Coordination gateway closed (${y.code}).`,y.code!==4401));};});};try{await i();}catch(r){if(!ue(r))throw r;await i();}}async mintGatewayCredential(e,n){let r={avenue:await this.resolveAvenue(),deviceId:this.options.getLocalDeviceId(),runtimeInstanceId:this.runtimeInstanceId,ticketFingerprint:await Ve(e.ticket),purpose:this.options.credentialPurpose??"presence",idempotencyKey:v("credential")},o;try{if(!this.options.gateway.grantProvider)throw new h("OpenRTC 2.0 coordination requires a v2 gateway grant provider.",!1);o=await this.options.gateway.grantProvider({...r,...n&&this.activeGrantToken?{refreshGrant:this.activeGrantToken}:{}});}catch(s){throw s instanceof h?s:new h(s instanceof Error?s.message:"Coordination credential mint failed.",!pe(s),_(s)?"credential-revoked":void 0)}if(o.protocolVersion!==2)throw new h("Unsupported coordination gateway protocol.",false);let a=he(this.options.gateway.endpoint);if(he(o.gatewayUrl)!==a)throw new h("Coordination credential returned an unexpected gateway origin.",false);return o}handleFrame(e,n=this.socket){if(!(n&&n!==this.socket)){if(e.type==="error"&&e.code==="credential-revoked"){let i=new h(`Coordination gateway ${e.code}: ${e.message}`,false,e.code);this.rejectPendingAcks(i.message,n??void 0),this.rejectPendingAuthRefresh(i,n??void 0),this.stopForCredentialRevocation(i);return}if(e.type==="auth.refreshed"){let i=this.pendingAuthRefresh;i&&i.socket===n&&(clearTimeout(i.timer),this.pendingAuthRefresh=null,this.pendingLeaseRefreshKey=null,this.updateLocalDeviceExpiry(e.expiresAtMs),this.scheduleAuthRefresh(e.expiresAtMs,this.activeGrantProtocolVersion),i.resolve());}else if(e.type==="lease.refreshed"){let i=this.pendingAuthRefresh;if(i&&i.socket===n&&e.idempotencyKey===this.pendingLeaseRefreshKey){if(!Number.isSafeInteger(e.expiresAtMs)||e.expiresAtMs<=Date.now()){this.rejectPendingAuthRefresh(new h("Coordination lease refresh is already expired or invalid.",false),n);return}clearTimeout(i.timer),this.pendingAuthRefresh=null,this.pendingLeaseRefreshKey=null,this.activeGrantExpiresAtMs=e.expiresAtMs,this.updateLocalDeviceExpiry(e.expiresAtMs),this.scheduleAuthRefresh(e.expiresAtMs,this.activeGrantProtocolVersion),i.resolve();}}else if(e.type==="roster.snapshot"){this.sparseMembers.clear(),this.sparseRoutes.clear(),this.sparseTopologyRevision=0,this.devices.clear();for(let i of e.devices)this.devices.set(i.deviceId,this.toDevice(i));this.emitDevices();}else if(e.type==="membership.snapshot"){this.pendingMembershipPageSnapshot=null,this.sparseMembers.clear(),this.sparseRoutes.clear(),this.sparseTopologyRevision=0;for(let i of e.members)this.sparseMembers.set(i.deviceId,i);this.rebuildSparseDevices();}else if(e.type==="membership.page"){let i=/^[A-Za-z0-9:_-]{1,160}$/.test(e.snapshotId)&&Number.isSafeInteger(e.pageIndex)&&Number.isSafeInteger(e.pageCount)&&Number.isSafeInteger(e.memberCount)&&e.pageIndex>=0&&e.pageCount>=2&&e.pageCount<=50&&e.pageIndex<e.pageCount&&e.memberCount>100&&e.memberCount<=5e3&&e.members.length>0&&e.members.length<=100;e.pageIndex===0&&i&&(this.pendingMembershipPageSnapshot={snapshotId:e.snapshotId,nextPageIndex:0,pageCount:e.pageCount,memberCount:e.memberCount,members:new Map});let r=this.pendingMembershipPageSnapshot;if(!(i&&r!==null&&r.snapshotId===e.snapshotId&&r.nextPageIndex===e.pageIndex&&r.pageCount===e.pageCount&&r.memberCount===e.memberCount&&e.members.every(a=>a.deviceId.length>0&&!r.members.has(a.deviceId)))||!r){n?.close(4400,"invalid membership page");return}for(let a of e.members)r.members.set(a.deviceId,a);if(r.nextPageIndex+=1,r.nextPageIndex===r.pageCount){if(r.members.size!==r.memberCount){n?.close(4400,"incomplete membership pages");return}this.sparseMembers.clear(),this.sparseRoutes.clear(),this.sparseTopologyRevision=0;for(let a of r.members.values())this.sparseMembers.set(a.deviceId,a);this.pendingMembershipPageSnapshot=null,this.rebuildSparseDevices();}}else if(e.type==="membership.changed")e.operation==="delete"?this.sparseMembers.delete(e.member.deviceId):this.sparseMembers.set(e.member.deviceId,e.member),this.rebuildSparseDevices();else if(e.type==="topology.lease")this.acceptTopologyLease(e.lease);else if(e.type==="authority.assignment")this.acceptAuthorityAssignment(e.assignment,e.signature);else if(e.type==="presence.changed"){if(e.operation==="delete")this.devices.delete(e.device.deviceId),this.emitDeviceEvents([{type:"removed",deviceId:e.device.deviceId}]);else {let i=this.devices.has(e.device.deviceId),r=this.toDevice(e.device);this.devices.set(r.deviceId,r),this.emitDeviceEvents([{type:i?"modified":"added",device:r}]);}this.emitDevices();}else if(e.type==="signal.received")this.pendingMessages.length>=ze&&this.pendingMessages.shift(),this.pendingMessages.push({senderId:e.senderDeviceId,targetId:this.options.getLocalDeviceId(),payload:e.payload,state:e.state,replyPayload:e.replyPayload,timestamp:e.createdAtMs,appTag:this.options.appTag});else if(e.type==="managed.prepare.page"||e.type==="managed.commit.chunk.received"||e.type==="managed.received")this.enqueueManagedWork(()=>this.handleManagedFrame(e));else if(e.type==="session.changed"){let i=e.operation==="delete"?[{type:"removed",sessionId:e.sessionId}]:[{type:"modified",session:{...e.session??{},connectionId:e.sessionId}}];for(let r of this.sessionStreams)r.enqueue(i);}else if(e.type==="ack"){let i=this.pendingAcks.get(e.idempotencyKey);i&&i.socket===n&&(clearTimeout(i.timer),this.pendingAcks.delete(e.idempotencyKey),i.resolve());}else if(e.type==="error"){if(this.pendingAuthRefresh?.socket===n&&(!e.idempotencyKey||e.idempotencyKey===this.pendingLeaseRefreshKey)){let r=this.pendingAuthRefresh;clearTimeout(r.timer),this.pendingAuthRefresh=null,this.pendingLeaseRefreshKey=null,r.reject(new h(`Coordination gateway ${e.code}: ${e.message}`,e.retryable,e.code));return}let i=e.idempotencyKey?this.pendingAcks.get(e.idempotencyKey):null;i&&i.socket===n&&(clearTimeout(i.timer),this.pendingAcks.delete(e.idempotencyKey),i.reject(new U(e.code,e.message,e.retryable)));}}}enqueueManagedWork(e){let n=this.managedActions.then(e);this.managedActions=n.catch(i=>{console.error("[OpenRTC] Managed room owner rejected a gateway frame:",i),this.socket?.close(4400,"managed room state invalid");});}async flushManagedPublishBatch(){let e=this.managedPublishQueue.splice(0,He);if(e.length!==0)try{await this.ensureConnected(),await this.ensureManagedGroupInitialized();let n=this.roomArchitectureSnapshot,i=this.managedWasmClient,r=this.managedState;if(!n||n.effective!=="managed"||n.phase!=="settled"||this.roomEncryptionEpoch<1||!i||!r)throw new Error("[OpenRTC] Managed room encryption is not settled.");let o=[];for(let d of e){let l=await i.__sealManagedRoomPayload(this.managedAvenueKey(),BigInt(n.epoch),BigInt(this.roomEncryptionEpoch),d.input.messageId,d.input.channel,d.input.priority,d.input.zoneId,d.input.payload);o.push({item:d,sealedState:l.sealedState,envelope:{messageId:d.input.messageId,channel:d.input.channel,priority:d.input.priority,scope:d.input.zoneId?{kind:"zone",zoneId:d.input.zoneId}:{kind:"global"},ciphertext:l.payload}});}await r.persist(k(o[o.length-1].sealedState));let a=[],s=0,c=async()=>{if(a.length===0)return;let d=a;a=[],s=0,await this.sendOperation({v:1,type:"managed.publish",idempotencyKey:v("managed-publish"),architectureEpoch:n.epoch,encryptionEpoch:this.roomEncryptionEpoch,batch:d.map(({envelope:l})=>l)});for(let{item:l}of d)l.resolve();};for(let d of o){let l=d.envelope.ciphertext.length;a.length>0&&s+l>Ue&&await c(),a.push(d),s+=l;}await c();}catch(n){for(let i of e)i.reject(n);throw n}finally{this.managedPublishQueue.length>0&&!this.managedPublishScheduled&&(this.managedPublishScheduled=true,queueMicrotask(()=>{this.managedPublishScheduled=false,this.enqueueManagedWork(()=>this.flushManagedPublishBatch());}));}}managedAvenueKey(){let e=this.activeAvenue??this.options.avenueOverride;if(!e||e.kind!=="room"&&e.kind!=="space")throw new Error("[OpenRTC] Managed groups require an active room or space.");return `${e.kind}:${e.id}`}async ensureManagedGroupInitialized(){if(this.managedState)return;if(this.managedInitialization)return this.managedInitialization;let e=this.managedWasmClient;if(!e)throw new Error("[OpenRTC] This browser runtime has no managed-room Rust/WASM owner.");let n=this.managedAvenueKey(),i=(async()=>{let r=await this.managedStateProvider(this.options.appTag,this.options.getLocalDeviceId(),n),o=await e.__initManagedRoomGroup(n,this.options.getLocalDeviceId(),r.wrappingKey,r.sealedState);this.managedState=r,await this.executeManagedGroupActions([o]);})();this.managedInitialization=i;try{await i;}finally{this.managedInitialization===i&&(this.managedInitialization=null);}}async executeManagedGroupActions(e){for(let n of e)if(n.type==="persist-state"){let i=this.managedState;if(!i)throw new Error("[OpenRTC] Managed room state store is unavailable.");await i.persist(k(n.sealedState));}else n.type==="publish-key-package"?await this.sendOperation({v:1,type:"managed.key-package.publish",idempotencyKey:v("managed-key-package"),keyPackageHash:n.keyPackageHash,keyPackage:n.keyPackage}):n.type==="request-prepare-page"?await this.sendOperation({v:1,type:"managed.prepare.page.request",idempotencyKey:v("managed-prepare-page"),preparationId:n.preparationId,pageIndex:n.pageIndex}):n.type==="send-artifact-chunk"?await this.sendOperation({v:1,type:"managed.commit.chunk",idempotencyKey:v("managed-artifact"),...n.chunk}):n.type==="acknowledge-commit"&&await this.sendOperation({v:1,type:"managed.commit.ack",idempotencyKey:v("managed-commit-ack"),preparationId:n.preparationId,encryptionEpoch:n.encryptionEpoch,groupIdHash:n.groupIdHash});}async handleManagedFrame(e){await this.ensureManagedGroupInitialized();let n=this.managedWasmClient;if(!n)throw new Error("[OpenRTC] Managed room Rust/WASM owner is unavailable.");let i=this.managedAvenueKey();if(e.type==="managed.prepare.page"){await this.executeManagedGroupActions(await n.__handleManagedRoomPreparePage(i,e));return}if(e.type==="managed.commit.chunk.received"){await this.executeManagedGroupActions(await n.__handleManagedRoomArtifactChunk(i,e));return}let r=this.roomArchitectureSnapshot;if(!r||r.effective!=="managed"||r.phase!=="settled"||e.architectureEpoch!==r.epoch||e.encryptionEpoch!==this.roomEncryptionEpoch)throw new Error("[OpenRTC] Managed room delivery uses a stale room lease.");let o=[],a=null;for(let s of e.batch){let c=s.scope.kind==="zone"?s.scope.zoneId:void 0,d=await n.__openManagedRoomPayload(i,BigInt(e.architectureEpoch),BigInt(e.encryptionEpoch),s.messageId,s.channel,s.priority,c,k(s.ciphertext));a=d.sealedState,o.push({senderId:e.senderDeviceId,messageId:s.messageId,channel:s.channel,priority:s.priority,...c?{zoneId:c}:{},payload:k(d.payload)});}if(a){let s=this.managedState;if(!s)throw new Error("[OpenRTC] Managed room state store is unavailable.");await s.persist(k(a));}for(let s of o)for(let c of this.managedMessageListeners)c(s);}async sendOperation(e){this.budgetRenewalPromise&&await this.budgetRenewalPromise;let n=this.budgetRenewalEpoch;try{await this.sendOperationOnce(e);}catch(i){if(!(i instanceof U)||i.code!=="budget-renewal-required"&&i.code!==a.BUDGET_RENEWAL_REQUIRED||!i.retryable)throw i;this.budgetRenewalEpoch===n&&await this.renewBudget(),await this.sendOperationOnce(e);}}async sendOperationOnce(e){let n=this.socket;if(!n||n.readyState!==WebSocket.OPEN||!this.socketReady)throw new Error("Coordination gateway is not connected.");await new Promise((i,r)=>{let o=setTimeout(()=>{this.pendingAcks.get(e.idempotencyKey)?.timer===o&&this.pendingAcks.delete(e.idempotencyKey),r(new Error("Coordination gateway acknowledgement timed out."));},H);this.pendingAcks.set(e.idempotencyKey,{socket:n,resolve:i,reject:r,timer:o});try{n.send(JSON.stringify(e));}catch(a){clearTimeout(o),this.pendingAcks.delete(e.idempotencyKey),r(a instanceof Error?a:new Error(String(a)));}});}async renewBudget(){if(this.budgetRenewalPromise)return this.budgetRenewalPromise;let e=this.refreshAuthentication(true).then(()=>{this.budgetRenewalEpoch+=1;});this.budgetRenewalPromise=e;try{await e;}finally{this.budgetRenewalPromise===e&&(this.budgetRenewalPromise=null);}}async resolveAvenue(){if(this.options.avenueOverride)return this.options.avenueOverride;if((this.options.discoveryMode??"space")==="space"){let n=await this.options.resolveSpaceNamespaceId();if(!n)throw new Error("Space namespace is not available for coordination.");return {kind:"space",id:n}}let e=this.options.getCurrentUserId();if(!e)throw new Error("Authenticated user is required for coordination.");return {kind:"user",id:e}}gatewayDevice(e){return {deviceId:this.options.getLocalDeviceId(),runtimeInstanceId:this.runtimeInstanceId,nodeId:e.localNodeId,deviceName:e.deviceName,platformType:this.options.getPlatformType(),ticket:e.ticket,metadata:e.metadata,excludedPeers:this.desiredExcludedPeers,online:e.online}}controlPresence(){if(this.options.credentialPurpose!=="device-control")throw new Error("Coordination presence must be initialized before the gateway can connect.");return {localNodeId:this.options.getLocalDeviceId(),ticket:`openrtc-device-control:${this.runtimeInstanceId}`,online:false,ttlMs:0,deviceName:this.options.getDefaultDeviceName()}}toDevice(e){return this.options.normalizeDevice({...e,appTag:this.options.appTag,lastSeenAt:e.updatedAtMs,expiresAt:e.expiresAtMs},e.deviceId)}rebuildSparseDevices(){this.devices.clear();for(let e of this.sparseMembers.values()){let n=this.sparseRoutes.get(e.deviceId),i=n?{...e,...n}:{...e,runtimeInstanceId:"",nodeId:"",ticket:""};this.devices.set(e.deviceId,this.toDevice(i));}this.emitDevices();}acceptTopologyLease(e){if(e.topologyRevision<=this.sparseTopologyRevision)return;let n=this.activeAvenue,i=[...e.active,...e.backups],r=i.map(u=>u.deviceId),o=e.schemaVersion===1||this.validArchitectureLease(e.architecture),a=e.schemaVersion===1||this.validGroupEncryptionLease(e.groupEncryption,e.architecture),s=e.schemaVersion===2&&e.architecture.effectiveMode==="authority",c=e.schemaVersion===2?e.admissionPeers:void 0,d=!s||this.peerAdmissionScope!==null&&this.peerAdmissionRuntime!==null&&Array.isArray(c)&&c.length<=50&&new Set(c.map(u=>u.deviceId)).size===c.length&&c.every(u=>this.sparseMembers.get(u.deviceId)?.online&&u.deviceId!==this.options.getLocalDeviceId()&&/^[0-9a-f]{64}$/.test(u.nodeId));if(!((e.schemaVersion===1||e.schemaVersion===2)&&o&&a&&d&&Number.isSafeInteger(e.topologyRevision)&&e.topologyRevision>0&&(this.sparseTopologyRevision===0?e.previousTopologyRevision===void 0:e.previousTopologyRevision===this.sparseTopologyRevision)&&e.grantJti===this.activeGrantJti&&n!==null&&e.avenue.kind===n.kind&&e.avenue.id===n.id&&Number.isSafeInteger(e.expiresAtMs)&&e.expiresAtMs>Date.now()&&e.expiresAtMs<=this.activeGrantExpiresAtMs&&e.active.length<=16&&e.backups.length<=4&&i.length<=20&&new Set(r).size===r.length&&i.every(u=>u.online&&this.sparseMembers.has(u.deviceId)&&u.deviceId!==this.options.getLocalDeviceId()&&u.nodeId.trim().length>0&&u.ticket.trim().length>0))){this.socket?.close(4400,"invalid topology lease");return}if(s)try{this.peerAdmissionRuntime.__updateScopePeerAdmission(this.peerAdmissionScope,++this.peerAdmissionRevision,e.expiresAtMs,JSON.stringify(c.map(u=>u.nodeId)));}catch{this.socket?.close(4400,"invalid peer admission lease");return}if(e.schemaVersion===2){e.groupEncryption&&(this.roomEncryptionEpoch=e.groupEncryption.epoch);let u={requested:e.architecture.requestedMode,effective:e.architecture.effectiveMode,epoch:e.architecture.epoch,phase:e.architecture.phase,reason:e.architecture.reason,heldCreditsUsd:e.architecture.heldCreditsMicrousd/1e6,quoteExpiresAtMs:e.architecture.quoteExpiresAtMs},f=JSON.stringify(u)!==JSON.stringify(this.roomArchitectureSnapshot);if(this.roomArchitectureSnapshot=u,f)for(let y of this.architectureListeners)y({...u});if(u.effective!=="authority"&&this.roomAuthorityAssignment){this.roomAuthorityAssignmentExpiry&&(clearTimeout(this.roomAuthorityAssignmentExpiry),this.roomAuthorityAssignmentExpiry=null),this.roomAuthorityAssignment=null;for(let y of this.authorityAssignmentListeners)y(null);}u.effective==="managed"&&this.enqueueManagedWork(()=>this.ensureManagedGroupInitialized());}this.sparseTopologyRevision=e.topologyRevision,this.sparseRoutes.clear();for(let u of e.active)this.sparseRoutes.set(u.deviceId,{...u,topologyRole:"active",topologyRevision:e.topologyRevision});for(let u of e.backups)this.sparseRoutes.set(u.deviceId,{...u,topologyRole:"backup",topologyRevision:e.topologyRevision});this.rebuildSparseDevices();}acceptAuthorityAssignment(e,n){let i=this.roomAuthorityAssignment,r=this.options.getLocalDeviceId(),o=[e.serviceId,e.subjectDeviceId,e.shardId,...e.priorityDeviceIds,...e.relevantEntityIds];if(i&&e.generation===i.generation&&e.revision===i.revision){if(JSON.stringify({serviceId:e.serviceId,generation:e.generation,revision:e.revision,shardId:e.shardId,priorityDeviceIds:e.priorityDeviceIds,relevantEntityIds:e.relevantEntityIds,issuedAtMs:e.issuedAtMs,expiresAtMs:e.expiresAtMs})===JSON.stringify(i))return;this.socket?.close(4400,"invalid authority assignment");return}if(!(e.policyVersion==="room-authority-assignment-v1"&&this.roomArchitectureSnapshot?.effective==="authority"&&e.subjectDeviceId===r&&Number.isSafeInteger(e.generation)&&e.generation>0&&Number.isSafeInteger(e.revision)&&e.revision>0&&Number.isSafeInteger(e.issuedAtMs)&&Number.isSafeInteger(e.expiresAtMs)&&e.issuedAtMs<=Date.now()+3e4&&e.expiresAtMs>Date.now()&&e.expiresAtMs-e.issuedAtMs<=12e4&&e.priorityDeviceIds.length<=8&&e.relevantEntityIds.length<=32&&new Set(e.priorityDeviceIds).size===e.priorityDeviceIds.length&&new Set(e.relevantEntityIds).size===e.relevantEntityIds.length&&o.every(c=>/^[A-Za-z0-9_.:@-]{1,160}$/.test(c))&&/^[A-Za-z0-9_-]{86}$/.test(n)&&(!i||e.generation>i.generation||e.generation===i.generation&&e.revision>i.revision))){this.socket?.close(4400,"invalid authority assignment");return}this.roomAuthorityAssignment=Object.freeze({serviceId:e.serviceId,generation:e.generation,revision:e.revision,shardId:e.shardId,priorityDeviceIds:Object.freeze([...e.priorityDeviceIds]),relevantEntityIds:Object.freeze([...e.relevantEntityIds]),issuedAtMs:e.issuedAtMs,expiresAtMs:e.expiresAtMs}),this.roomAuthorityAssignmentExpiry&&clearTimeout(this.roomAuthorityAssignmentExpiry),this.roomAuthorityAssignmentExpiry=setTimeout(()=>{if(this.roomAuthorityAssignmentExpiry=null,this.roomAuthorityAssignment?.expiresAtMs===e.expiresAtMs){this.roomAuthorityAssignment=null;for(let c of this.authorityAssignmentListeners)c(null);}},Math.max(0,e.expiresAtMs-Date.now()));for(let c of this.authorityAssignmentListeners)c(this.roomAuthorityAssignmentSnapshot());}roomAuthorityAssignmentSnapshot(){let e=this.roomAuthorityAssignment;return !e||e.expiresAtMs<=Date.now()?null:{...e,priorityDeviceIds:[...e.priorityDeviceIds],relevantEntityIds:[...e.relevantEntityIds]}}validArchitectureLease(e){let n=this.roomArchitectureSnapshot?.epoch??0,i=new Set(["auto","mesh","sparse","managed","authority"]),r=new Set(["mesh","sparse","managed","authority"]),o=new Set(["size","traffic","latency","cost","capacity","manual","recovery"]);return e.policyVersion==="room-architecture-v1"&&Number.isSafeInteger(e.epoch)&&e.epoch>0&&e.epoch>=n&&(e.epoch===n||n===0||e.previousArchitectureEpoch===n)&&i.has(e.requestedMode)&&r.has(e.effectiveMode)&&(e.phase==="settled"||e.phase==="preparing")&&o.has(e.reason)&&Number.isSafeInteger(e.heldCreditsMicrousd)&&e.heldCreditsMicrousd>=0&&Number.isSafeInteger(e.quoteExpiresAtMs)&&e.quoteExpiresAtMs>0&&(e.reservationId===void 0||/^[A-Za-z0-9:_-]{1,160}$/.test(e.reservationId))}validGroupEncryptionLease(e,n){if(!e)return n.effectiveMode!=="managed"||n.phase==="preparing";let i=this.roomEncryptionEpoch;return e.policyVersion==="room-mls-v1"&&Number.isSafeInteger(e.epoch)&&e.epoch>0&&e.epoch>=i&&(e.epoch===i||i===0||e.previousEncryptionEpoch===i)&&(e.phase==="preparing"||e.phase==="settled")&&(n.effectiveMode!=="managed"||n.phase!=="settled"||e.phase==="settled")&&/^[A-Za-z0-9_.:@-]{1,160}$/.test(e.committerDeviceId)&&/^[A-Za-z0-9_-]{43}$/.test(e.groupIdHash)}snapshot(e){return [...this.devices.values()].filter(n=>!e||n.nodeId!==e).sort((n,i)=>n.deviceId.localeCompare(i.deviceId))}emitDevices(){let e=this.snapshot();for(let n of this.deviceListeners)n(e);}emitDeviceEvents(e){for(let n of this.deviceStreams)n.enqueue(e);}updateLocalDeviceExpiry(e){let n=this.options.getLocalDeviceId(),i=this.devices.get(n);if(!i||i.expiresAt===e)return;let r={...i,expiresAt:e};this.devices.set(n,r),this.emitDeviceEvents([{type:"modified",device:r}]),this.emitDevices();}scheduleAuthRefresh(e,n){this.authRefreshTimer&&clearTimeout(this.authRefreshTimer);let i=e-Date.now(),r=n===2?Ke:Oe,o=i>r+1e3;this.authRefreshTimer=setTimeout(()=>{if(this.authRefreshTimer=null,this.stopped)return;if(!o){this.stopSocket(false),this.scheduleReconnect(new h("Coordination credential crossed a billing boundary.",true));return}(n===2&&this.leaseRefreshMode==="active"?this.refreshLease():this.refreshAuthentication()).catch(s=>{this.stopSocket(false),this.scheduleReconnect(s);});},o?i-r:Math.max(1e3,i+1e3));}refreshAuthentication(e=false){let n=`${e?"issue":"refresh"}\0${this.desiredPresence?.ticket??""}`,i=this.authenticationRefreshes.get(n);if(i)return i;let r=this.authenticationRefreshTail.catch(()=>{}).then(()=>this.performAuthenticationRefresh(e));this.authenticationRefreshTail=r,this.authenticationRefreshes.set(n,r);let o=()=>{this.authenticationRefreshes.get(n)===r&&this.authenticationRefreshes.delete(n);};return r.then(o,o),r}async performAuthenticationRefresh(e){let n=this.socket,i=this.desiredPresence;if(!n||n.readyState!==WebSocket.OPEN||!this.socketReady||!i)throw new h("Coordination socket is unavailable for credential refresh.",true);if(this.pendingAuthRefresh)return this.pendingAuthRefresh.promise;let r=await this.mintGatewayCredential(i,!e);if(this.socket!==n||n.readyState!==WebSocket.OPEN||!this.socketReady)throw new h("Coordination socket changed while minting a credential refresh.",true);let o,a,s=new Promise((d,l)=>{o=d,a=l;}),c=setTimeout(()=>{this.pendingAuthRefresh?.timer===c&&(this.pendingAuthRefresh=null),a(new h("Coordination credential refresh timed out.",true));},H);this.pendingAuthRefresh={socket:n,promise:s,resolve:o,reject:a,timer:c};try{n.send(JSON.stringify({v:1,type:"auth.refresh",token:r.token}));}catch(d){this.rejectPendingAuthRefresh(new h(d instanceof Error?d.message:"Coordination credential refresh send failed.",true),n);}await s,this.activeGrantToken=r.token,this.activeGrantJti=le(r.token),this.activeAvenue=r.avenue,this.activeGrantExpiresAtMs=r.expiresAtMs,this.activeGrantProtocolVersion=r.protocolVersion;}refreshLease(){let e=`lease\0${this.desiredPresence?.ticket??""}`,n=this.authenticationRefreshes.get(e);if(n)return n;let i=this.authenticationRefreshTail.catch(()=>{}).then(()=>this.performLeaseRefresh());this.authenticationRefreshTail=i,this.authenticationRefreshes.set(e,i);let r=()=>{this.authenticationRefreshes.get(e)===i&&this.authenticationRefreshes.delete(e);};return i.then(r,r),i}async performLeaseRefresh(){let e=this.socket;if(!e||e.readyState!==WebSocket.OPEN||!this.socketReady)throw new h("Coordination socket is unavailable for lease refresh.",true);if(this.pendingAuthRefresh)return this.pendingAuthRefresh.promise;let n=v("lease"),i,r,o=new Promise((s,c)=>{i=s,r=c;}),a=setTimeout(()=>{this.pendingAuthRefresh?.timer===a&&(this.pendingAuthRefresh=null,this.pendingLeaseRefreshKey=null),r(new h("Coordination lease refresh timed out.",true));},H);this.pendingLeaseRefreshKey=n,this.pendingAuthRefresh={socket:e,promise:o,resolve:i,reject:r,timer:a};try{e.send(JSON.stringify({v:1,type:"lease.refresh",idempotencyKey:n}));}catch(s){this.rejectPendingAuthRefresh(new h(s instanceof Error?s.message:"Coordination lease refresh send failed.",true),e);}try{await o;}catch(s){if(this.stopped||_(s))throw s;await this.performAuthenticationRefresh(true);}}stopForCredentialRevocation(e){return _(e)?(this.credentialRevoked=true,this.reconnectCircuitOpen=true,this.stopAuthActivity(),true):false}scheduleReconnect(e){if(this.stopForCredentialRevocation(e)||this.reconnectTimer||this.reconnectCircuitOpen||this.stopped)return;if(!(e instanceof h?e.retryable:!pe(e))){this.reconnectCircuitOpen=true,this.rejectConnectionReadyWaiters(e instanceof Error?e:new h("Coordination reconnect circuit is open.",false));return}if(this.reconnectOutageStartedAtMs??(this.reconnectOutageStartedAtMs=Date.now()),!this.hostAvailable)return;let i=Math.min(this.reconnectAttempt,ae),r=Date.now()-this.reconnectOutageStartedAtMs>=Be,o=$e(r?Fe:d(i,250,Le));this.reconnectAttempt=Math.min(i+1,ae),this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.ensureConnected().catch(a=>this.scheduleReconnect(a));},o);}stopSocket(e=true){this.peerAdmissionScope&&this.peerAdmissionRuntime&&this.peerAdmissionRuntime.__updateScopePeerAdmission(this.peerAdmissionScope,++this.peerAdmissionRevision,0,"[]"),e&&this.reconnectTimer&&clearTimeout(this.reconnectTimer),this.authRefreshTimer&&clearTimeout(this.authRefreshTimer),this.reconnectTimer=null,this.keepaliveTimer&&clearInterval(this.keepaliveTimer),this.keepaliveTimer=null,this.authRefreshTimer=null,this.leaseRefreshMode="off",this.pendingLeaseRefreshKey=null,this.rejectPendingAuthRefresh(new h("Coordination credential refresh was canceled.",true));let n=this.socket;this.socket=null,this.socketReady=false,this.activeGrantJti=null,this.activeAvenue=null,this.activeGrantExpiresAtMs=0,this.sparseRoutes.clear(),this.sparseTopologyRevision=0,this.pendingMembershipPageSnapshot=null,this.sparseMembers.size>0&&this.rebuildSparseDevices(),n?.close(1e3,"coordination session stopped");}waitForConnectionReady(){return this.socket?.readyState===WebSocket.OPEN&&this.socketReady?Promise.resolve():this.stopped||this.reconnectCircuitOpen?Promise.reject(new h("Coordination reconnect circuit is unavailable.",false)):new Promise((e,n)=>{this.connectionReadyWaiters.add({resolve:e,reject:n});})}resolveConnectionReadyWaiters(){for(let e of this.connectionReadyWaiters)e.resolve();this.connectionReadyWaiters.clear();}rejectConnectionReadyWaiters(e){for(let n of this.connectionReadyWaiters)n.reject(e);this.connectionReadyWaiters.clear();}rejectPendingAuthRefresh(e,n){let i=this.pendingAuthRefresh;!i||n&&i.socket!==n||(clearTimeout(i.timer),this.pendingAuthRefresh=null,this.pendingLeaseRefreshKey=null,i.reject(e));}rejectPendingAcks(e,n){for(let[i,r]of this.pendingAcks)n&&r.socket!==n||(clearTimeout(r.timer),r.reject(new Error(e)),this.pendingAcks.delete(i));}unscopedId(e){let n=e.split("::");return n.length===2?n[1]:e}requireRoomConnection(e){let n=e.trim().toUpperCase(),i=this.roomConnections.get(n);if(!i)throw new Error(`Room ${n} is not joined through the coordination gateway.`);return i}friendConnection(e){let n=this.friendConnections.get(e);n||(n=new t({...this.options,avenueOverride:{kind:"user",id:e}}),n.setHostAvailability({available:this.hostAvailable,reason:"parent-avenue-created"}),this.friendConnections.set(e,n));let i=this.desiredPresence??this.friendObservationPresence;return !n.desiredPresence&&i&&this.activateFriendConnection(n,i),n}activateFriendConnection(e,n){e.updatePresence(n.localNodeId,n.ticket,n.online,n.ttlMs,n.metadata,n.deviceName).catch(()=>{});}roomMember(e){return {nodeId:e.nodeId??e.deviceId,userId:e.userId??"",ticket:e.ticket,joinedAt:Number(e.createdAt??e.lastSeenAt??Date.now()),lastSeenAt:Number(e.lastSeenAt??Date.now()),expiresAt:typeof e.expiresAt=="number"?e.expiresAt:void 0}}};var F=class{constructor(e){this.provider=e;this.cached=null;this.inFlight=null;this.refreshTimer=null;this.refreshRetryUsed=false;this.listeners=new Set;}async get(e=false){if(!this.provider)throw new Error("[OpenRTC] Native coordination requires coordinationGateway.nativeTrustTokenProvider; obtain tokens through a trusted backend without shipping the developer secret.");let n=Date.now();if(!e&&this.cached&&this.cached.expiresAtMs>n+3e4)return this.cached;if(this.inFlight)return this.inFlight;let i=(async()=>{let r=await this.provider(e),o=r?.token?.trim()??"",a=Number(r?.expiresAtMs),s=Date.now();if(!o||!Number.isFinite(a)||a<=s+3e4)throw new Error("[OpenRTC] Native trust token provider returned no usable short-lived token.");let c={token:o,expiresAtMs:a};return this.cached=c,this.refreshRetryUsed=false,this.notify(c),this.scheduleRefresh(c),c})();this.inFlight=i;try{return await i}finally{this.inFlight===i&&(this.inFlight=null);}}invalidate(){this.cached=null,this.clearRefreshTimer(),this.notify(null);}clear(){this.invalidate(),this.listeners.clear();}subscribe(e,n){return this.listeners.add(e),this.cached&&this.cached.expiresAtMs>Date.now()&&(n?.emitCurrent!==false&&e(this.cached),this.scheduleRefresh(this.cached)),()=>{this.listeners.delete(e),this.listeners.size===0&&this.clearRefreshTimer();}}notify(e){for(let n of this.listeners)n(e);}scheduleRefresh(e){if(this.clearRefreshTimer(),this.listeners.size===0)return;let n=Math.max(0,e.expiresAtMs-Date.now()-3e4);this.refreshTimer=setTimeout(()=>{this.refreshTimer=null,this.get(true).catch(()=>{if(this.listeners.size===0||this.refreshRetryUsed){this.invalidate();return}this.refreshRetryUsed=true,this.refreshTimer=setTimeout(()=>{this.refreshTimer=null,this.get(true).catch(()=>this.invalidate());},15e3);});},n);}clearRefreshTimer(){this.refreshTimer&&(clearTimeout(this.refreshTimer),this.refreshTimer=null);}};var ge=class{constructor(e){this.options=e;this.signaling=null;this.wasmClient=null;this.managedStateProvider=null;this.hostAvailability={available:true,reason:"initial"};this.nativeTrustTokens=e.gateway?new F(e.gateway.nativeTrustTokenProvider):null;}usesGateway(){return !!this.options.gateway}getSignaling(){if(this.options.signalingMode==="ticket-only")throw new Error('[openrtc] Managed signaling is disabled when signalingMode="ticket-only".');if(!this.options.gateway)throw new Error("[OpenRTC] Managed coordination requires coordinationGateway; the legacy direct Firebase data plane has been removed.");if(!this.signaling){this.signaling=new B({projectId:this.options.projectId,gateway:this.options.gateway,appTag:this.options.appTag,discoveryMode:this.options.discoveryMode,resolveSpaceNamespaceId:this.options.resolveSpaceNamespaceId,getCurrentUserId:this.options.getCurrentUserId,getAuthToken:this.options.getAuthToken,getAppCheckToken:this.options.getAppCheckToken,getLocalDeviceId:this.options.getLocalDeviceId,getDefaultDeviceName:this.options.getDefaultDeviceName,getPlatformType:this.options.getPlatformType,normalizeDevice:this.options.normalizeDevice,avenueOverride:this.options.avenueOverride,roomArchitecture:this.options.roomArchitecture,initialExcludedPeers:this.options.initialExcludedPeers,nativeTrustTokens:this.nativeTrustTokens});let e=this.signaling;this.managedStateProvider?e.setManagedRoomRuntime(this.wasmClient,this.managedStateProvider):e.setWasmClient(this.wasmClient),this.signaling.setHostAvailability?.(this.hostAvailability);}return this.signaling}setWasmClient(e){this.wasmClient=e,this.managedStateProvider=null,this.signaling?.setWasmClient(e);}setManagedRoomRuntime(e,n){this.wasmClient=e,this.managedStateProvider=n,this.signaling?.setManagedRoomRuntime(e,n);}setHostAvailability(e){this.hostAvailability=e,this.signaling?.setHostAvailability?.(e);}async reconnectAfterHostResume(){await this.signaling?.reconnectAfterHostResume?.();}async handleScopeChange(){await this.signaling?.handleScopeChange();}stopAuthActivity(){this.signaling?.stopAuthActivity();}async getNativeTrustToken(e=false){if(!this.nativeTrustTokens)throw new Error("[OpenRTC] Native trust tokens require a coordination gateway.");return this.nativeTrustTokens.get(e)}invalidateNativeTrustToken(){this.nativeTrustTokens?.invalidate();}subscribeNativeTrustToken(e,n){return this.nativeTrustTokens?.subscribe(e,n)??(()=>{})}};function Ye(){if(typeof globalThis<"u"&&globalThis.__OPENRTC_DEBUG__===true)return true;if(typeof localStorage<"u")try{return localStorage.getItem("openrtc:debug")==="1"}catch{return false}return false}function $(t,e,n){if(Ye()){if(typeof n>"u"){console[t](e);return}console[t](e,n);}}function Bt(t,e){$("debug",t,e);}function Ft(t,e){$("info",t,e);}function jt(t,e){$("log",t,e);}function ye(){return typeof window>"u"?false:!!(window.__TAURI_IPC__||window.__TAURI_INTERNALS__||window.__TAURI__||window.location.protocol==="tauri:"||window.location.hostname==="tauri.localhost")}var Qe="[OpenRTC][teardown-trace]";function Xe(){try{let t=globalThis;if(t.OPENRTC_TEARDOWN_TRACE===!0||t.localStorage?.getItem("OPENRTC_TEARDOWN_TRACE")==="1")return !0}catch{}return false}function qt(t,e={}){console.info(Qe,{kind:t,ts:new Date().toISOString(),...e}),Xe()&&console.info("[OpenRTC][teardown-trace:stack]",{kind:t,stack:new Error(`teardown: ${t}`).stack});}var z="trustedDevice",Ze="plutonium:e2ee:identity:v1",et="plutonium:e2ee:identity:session:v1",tt="openrtc-trust",C="identity",ve="transport-trust:v1",nt=2,me="managed-room-keys",fe="managed-room-state",it=1,b=null,D=null;function S(t){let e=atob(t),n=new Uint8Array(e.length);for(let i=0;i<e.length;i+=1)n[i]=e.charCodeAt(i);return n}function N(t){let e="";for(let n=0;n<t.length;n+=1)e+=String.fromCharCode(t[n]);return btoa(e)}async function V(t){let e=await crypto.subtle.digest("SHA-256",t),n=new Uint8Array(e);return Array.from(n).map(i=>i.toString(16).padStart(2,"0")).join("")}function rt(){return typeof sessionStorage>"u"?null:sessionStorage}function ot(){if(!(typeof localStorage>"u"))try{localStorage.removeItem(Ze);}catch{}}var j=null;async function be(){return j||(j=(async()=>{let t=globalThis.crypto?.subtle;if(!t||typeof t.generateKey!="function")return false;try{let e=await t.generateKey({name:"Ed25519"},!1,["sign","verify"]);return !!(e&&e.privateKey&&e.publicKey)}catch{return false}})(),j)}async function st(t){let e=await crypto.subtle.exportKey("raw",t);return new Uint8Array(e)}function at(){try{return typeof indexedDB<"u"?indexedDB:null}catch{return null}}function we(){let t=at();return t?new Promise(e=>{let n;try{n=t.open(tt,nt);}catch{e(null);return}n.onupgradeneeded=()=>{let i=n.result;i.objectStoreNames.contains(C)||i.createObjectStore(C),i.objectStoreNames.contains(me)||i.createObjectStore(me),i.objectStoreNames.contains(fe)||i.createObjectStore(fe);},n.onsuccess=()=>e(n.result),n.onerror=()=>e(null),n.onblocked=()=>e(null);}):Promise.resolve(null)}async function ct(){let t=await we();if(!t)return null;try{return await new Promise(e=>{let r=t.transaction(C,"readonly").objectStore(C).get(ve);r.onsuccess=()=>{let o=r.result;e(o&&o.privateKey&&o.publicKey?o:null);},r.onerror=()=>e(null);})}catch{return null}finally{t.close();}}async function dt(t){let e=await we();if(!e)return false;try{return await new Promise(n=>{let i=e.transaction(C,"readwrite");i.objectStore(C).put(t,ve),i.oncomplete=()=>n(!0),i.onerror=()=>n(!1),i.onabort=()=>n(!1);})}catch{return false}finally{e.close();}}async function Se(t,e){let n=await st(t.publicKey),i=await V(n),r=t.privateKey;return {publicKey:n,fingerprint:i,backend:"webcrypto-nonextractable",durable:e,privateKey:r,async signChallenge(o){let a=await crypto.subtle.sign({name:"Ed25519"},r,S(o));return N(new Uint8Array(a))}}}function lt(t,e,n){let i=t.secretKey;return {publicKey:t.publicKey,secretKey:i,fingerprint:e,backend:"tweetnacl",durable:n,async signChallenge(r){return ut(r,i)}}}function Yt(t=32){let e=crypto.getRandomValues(new Uint8Array(t));return N(e)}function ut(t,e){let n=x.sign.detached(S(t),e);return N(n)}function pt(t,e,n){try{return x.sign.detached.verify(S(t),S(e),S(n))}catch{return false}}async function Qt(t,e,n){let i=globalThis.crypto?.subtle;if(i&&typeof i.importKey=="function"&&typeof i.verify=="function")try{let r=await i.importKey("raw",S(n),{name:"Ed25519"},!1,["verify"]);return await i.verify({name:"Ed25519"},r,S(e),S(t))}catch{}return pt(t,e,n)}function Xt(t){return N(t)}function Zt(t){if(!t||!t.trim())return null;try{let e=JSON.parse(t),n=e&&typeof e=="object"&&!Array.isArray(e)?e[z]:null;if(!n||typeof n!="object"||Array.isArray(n))return null;let i=n,r=typeof i.version=="number"?i.version:null,o=typeof i.identityPublicKey=="string"?i.identityPublicKey:null,a=typeof i.identityFingerprint=="string"?i.identityFingerprint:null;return !r||!o||!a?null:{version:r,identityPublicKey:o,identityFingerprint:a}}catch{return null}}async function ht(){let t=await vt().catch(()=>null);return t?{version:it,identityPublicKey:N(t.publicKey),identityFingerprint:t.fingerprint}:null}async function en(t){let e=await ht();if(!e)return t??void 0;let n=typeof t=="string"?t.trim():"";if(!n)return JSON.stringify({[z]:e});try{let i=JSON.parse(n);if(i&&typeof i=="object"&&!Array.isArray(i))return JSON.stringify({...i,[z]:e})}catch{}return JSON.stringify({metadata:t,[z]:e})}function gt(){if(typeof window>"u")return null;let t=window.__TAURI_INTERNALS__;return !t||typeof t.invoke!="function"?null:t.invoke.bind(t)}async function yt(){if(typeof window>"u")return null;let t=gt();if(!ye()&&!t)return null;if(!t)throw new Error("[OpenRTC] Tauri transport trust requires the native signing provider, but Tauri invoke is unavailable.");try{let e=await t("openrtc_get_transport_trust_identity"),n=S(e.publicKeyBase64);if(n.byteLength!==x.sign.publicKeyLength)throw new Error("native transport trust public key has an invalid length");let i=await V(n);if(e.fingerprint!==i)throw new Error("native transport trust fingerprint does not match its public key");return {publicKey:n,fingerprint:i,backend:"native-provider",durable:!0,async signChallenge(r){return t("openrtc_sign_transport_trust_challenge",{challenge:r})}}}catch(e){let n=new Error("[OpenRTC] native transport trust provider failed; refusing WebCrypto fallback in Tauri.");throw n.cause=e,n}}function mt(){let t=rt();t&&t.removeItem(et);}async function ft(){if(ot(),mt(),b)return b;let t=await yt();if(t)return b=t,b;if(await be()){let e=await ct();if(e)return b=await Se(e,true),b}return null}async function vt(t={}){let e=await ft();if(e)return e;if(D)return D;let n=bt(t);D=n;try{return await n}finally{D===n&&(D=null);}}async function bt(t){if(b)return b;let e=t.ephemeral===true;if(await be())try{let n=await crypto.subtle.generateKey({name:"Ed25519"},!1,["sign","verify"]),i=!1;return e||(i=await dt(n)),b=await Se(n,i),b}catch{}if(!e)return console.warn("[OpenRTC][TRUST] Managed transport trust requires WebCrypto Ed25519 or native keychain; refusing extractable fallback storage"),null;try{let n=x.sign.keyPair(),i=await V(b$1(n.publicKey));return b=lt(n,i,!1),b}catch{return null}}var wt={managedSession:{nativeStartRetryWindowMs:12e4,nativeStartRetryMinDelayMs:400,nativeStartRetryMaxDelayMs:5e3,deviceStatusRefreshDebounceMs:50},browserAutoConnect:{scanDebounceMs:150,retryCooldownMs:2e3,settleGuardMs:1e4,retryMaxMs:8e3,nonInitiatorBaseGraceMs:2e3,nonInitiatorMaxGraceMs:16e3},nativeIpc:{authRequiredWaitMs:15e3,defaultBoundedCommandTimeoutMs:15e3,connectionEventSubscribeWindowMs:15e3,connectionEventRetryMinDelayMs:250,connectionEventRetryMaxDelayMs:1e3,tauriIpcNegativeCacheMs:2e3},browserIdentity:{ephemeralDeviceIdTtlMs:6e4}};function nn(){return wt}var St={adapter:"browser-wasm",productMaturity:{boundedRooms:"stable",serviceNodes:"preview",offlineEdge:"support-only",broadcast:"preview"},signaling:{coordinationGateway:true,nativeIpc:false,managedPresence:true},transport:{irohQuic:false,irohLan:false,webRtc:true,moq:true,ble:false,wasm:true},nativeProtocols:{productAlpn:false,irohDocs:false,irohBlobs:false,irohGossip:false},lifecycle:{managedSession:true,autoConnect:true,manualDisconnect:true,connectionStateEvents:true,peerSessions:true},transfers:{explicitFilePath:false,explicitFileData:true,history:false},fallback:{wasm:false}},Rt={adapter:"native-ipc",productMaturity:{boundedRooms:"stable",serviceNodes:"unavailable",offlineEdge:"unavailable",broadcast:"unavailable"},signaling:{coordinationGateway:true,nativeIpc:true,managedPresence:true},transport:{irohQuic:true,irohLan:false,webRtc:false,moq:false,ble:false,wasm:false},nativeProtocols:{productAlpn:true,irohDocs:true,irohBlobs:true,irohGossip:true},lifecycle:{managedSession:true,autoConnect:true,manualDisconnect:true,connectionStateEvents:true,peerSessions:true},transfers:{explicitFilePath:true,explicitFileData:true,history:true},fallback:{wasm:false}};function Re(t){return {adapter:t.adapter,productMaturity:t.productMaturity?{...t.productMaturity}:void 0,signaling:{...t.signaling},transport:{...t.transport},nativeProtocols:{...t.nativeProtocols},lifecycle:{...t.lifecycle},transfers:{...t.transfers},fallback:{...t.fallback}}}function on(t=globalThis){let e=Re(St),n=typeof t?.RTCPeerConnection=="function";return e.transport.webRtc=n,e}function G(t){return t?.compiled===true&&t.enabled===true}function sn(t,e=false){let n=Re(Rt),i=t?.transport;return n.productMaturity={...n.productMaturity,...t?.productMaturity},i&&(n.transport.irohQuic=G(i.irohQuic),n.transport.irohLan=G(i.irohLan),n.transport.webRtc=G(i.webRtc),n.transport.moq=G(i.moq),n.transport.ble=G(i.ble)),n.transport.wasm=false,n.fallback.wasm=e,n}function an(t){return {environment:t.adapter==="native-ipc"||t.adapter==="tauri-ipc"?"native":t.adapter==="browser-wasm"?"web":"unknown",productMaturity:t.productMaturity?{...t.productMaturity}:void 0,transports:{quic:t.transport.irohQuic,irohRelay:t.transport.irohQuic||t.adapter==="browser-wasm",irohLan:t.transport.irohLan,webRtc:t.transport.webRtc,moq:t.transport.moq,ble:t.transport.ble},lifecycle:{...t.lifecycle},storage:{localFileSystem:t.transfers.explicitFilePath,transferHistory:t.transfers.history},nativeProtocols:{...t.nativeProtocols}}}function Ie(t){if(t.errorCode)return t;let e=t.error||t.readinessReason;if(!e)return t;let n=c(e);return {...t,errorCode:n.errorCode,retryable:n.retryable,errorPlane:n.errorPlane}}function M(t){return !t||typeof t!="object"?{}:t instanceof Map?Object.fromEntries(t):t}function J(t){let e=M(t),n=M(e.device);if(!Object.keys(n).length)return e;let i={...n,...e};return delete i.device,i}function p(t,...e){for(let n of e){let i=t[n];if(typeof i=="string"&&i.trim().length>0)return i}}function w(t,...e){for(let n of e){let i=t[n];if(typeof i=="boolean")return i}}function g(t,...e){for(let n of e){let i=t[n];if(typeof i=="number"&&Number.isFinite(i))return i}}function A(t){if(typeof t=="number"&&Number.isFinite(t))return t;if(t instanceof Date){let e=t.getTime();return Number.isFinite(e)?e:void 0}if(typeof t=="string"){let e=Date.parse(t);return Number.isFinite(e)?e:void 0}if(t&&typeof t=="object"){let e=t;if(typeof e.toMillis=="function"){let i=e.toMillis();return Number.isFinite(i)?i:void 0}let n=typeof e.seconds=="number"?e.seconds:typeof e._seconds=="number"?e._seconds:void 0;if(n!==void 0&&Number.isFinite(n)){let i=typeof e.nanoseconds=="number"?e.nanoseconds:typeof e._nanoseconds=="number"?e._nanoseconds:0;return n*1e3+Math.floor((Number.isFinite(i)?i:0)/1e6)}}}function Y(...t){let e=t.map(A).filter(n=>typeof n=="number"&&Number.isFinite(n));return e.length?Math.max(...e):void 0}function Q(t){if(typeof t!="string")return;let e=t.trim().toLowerCase();return e==="online"||e==="idle"||e==="offline"?e:void 0}function Ae(t){let e=Q("presenceStatus"in t?t.presenceStatus:void 0),n="presenceUpdatedAt"in t?A(t.presenceUpdatedAt):void 0,i="presenceExpiresAt"in t?A(t.presenceExpiresAt):void 0,r=n??Y(t.lastSeenAt,t.updatedAt,t.createdAt),o=i??A(t.expiresAt),a=e;a||(t.online?r!==void 0&&r+3e5<=Date.now()?a="idle":a="online":a="offline");let s=typeof t.ticket=="string"?t.ticket.trim():"",c="connectable"in t&&typeof t.connectable=="boolean"?t.connectable:a==="online"&&s.length>0;return {presenceStatus:a,presenceUpdatedAt:r,presenceExpiresAt:o,connectable:c}}function Te(t){return l(t)}function E(t,...e){return Te(p(t,...e))}function K(t){if(!Array.isArray(t))return;let e=Array.from(new Set(t.map(Te).filter(n=>!!n)));return e.length?e:void 0}function Pe(t){let e=M(t),n={webrtc:g(e,"webrtc"),iroh:g(e,"iroh"),irohLan:g(e,"irohLan","iroh_lan"),irohRelay:g(e,"irohRelay","iroh_relay"),ble:g(e,"ble"),moq:g(e,"moq")};return Object.values(n).some(i=>i!==void 0)?n:void 0}function pn(t){return (t.discoveryMode??"space")==="space"&&typeof t.apiKey=="string"&&t.apiKey.trim().length>0&&typeof t.spaceKey=="string"&&t.spaceKey.trim().length>0}function hn(t,e,n){return n?true:(typeof t.appTag=="string"?t.appTag:typeof t.tag=="string"?t.tag:void 0)===e}function It(t,e){let n=J(t),i=p(n,"deviceId","device_id")||e||"",r=p(n,"nodeId","node_id")||"",o=p(n,"ticket")||"";return {deviceId:i,deviceName:p(n,"deviceName","device_name")||"Unknown Device",online:!!n.online,ticket:o,friendTicket:p(n,"friendTicket","friend_ticket"),presenceStatus:Q(p(n,"presenceStatus","presence_status","livenessStatus","liveness_status")),presenceUpdatedAt:g(n,"presenceUpdatedAt","presence_updated_at")??Y(n.presenceUpdatedAt,n.presence_updated_at,n.lastSeenAt,n.last_seen_at,n.updatedAt,n.updated_at,n.createdAt,n.created_at),presenceExpiresAt:g(n,"presenceExpiresAt","presence_expires_at")??A(n.presenceExpiresAt??n.presence_expires_at)??A(n.expiresAt??n.expires_at),connectable:w(n,"connectable"),kind:p(n,"kind"),nodeId:r||void 0,devicePublicKeyJwk:n.devicePublicKeyJwk??n.device_public_key_jwk,platformType:p(n,"platformType","platform_type"),capabilities:n.capabilities||void 0,sessionId:p(n,"sessionId","session_id"),userId:p(n,"userId","user_id"),lastSeenAt:n.lastSeenAt??n.last_seen_at,expiresAt:n.expiresAt??n.expires_at,createdAt:n.createdAt??n.created_at,updatedAt:n.updatedAt??n.updated_at,metadata:p(n,"metadata"),excludedPeers:X(n.excludedPeers??n.excluded_peers),availableTransports:K(n.availableTransports??n.available_transports),transports:K(n.transports),topologyRole:n.topologyRole==="active"||n.topologyRole==="backup"?n.topologyRole:void 0,topologyRevision:Number.isSafeInteger(n.topologyRevision)&&Number(n.topologyRevision)>0?Number(n.topologyRevision):void 0}}function X(t){return Array.isArray(t)?t.filter(e=>typeof e=="string"):[]}function At(t){let e=Ae(t);return {...t,...e,connectionStatus:"connectionStatus"in t&&typeof t.connectionStatus=="string"?t.connectionStatus:t.online?"online":"disconnected",settledReady:"settledReady"in t&&typeof t.settledReady=="boolean"?t.settledReady:false,readinessState:"readinessState"in t&&typeof t.readinessState=="string"?t.readinessState:void 0,readinessReason:"readinessReason"in t&&typeof t.readinessReason=="string"?t.readinessReason:void 0,peerHealth:"peerHealth"in t&&typeof t.peerHealth=="string"?t.peerHealth:"unknown",peerId:"peerId"in t&&typeof t.peerId=="string"?t.peerId:void 0,promotionEligible:"promotionEligible"in t&&typeof t.promotionEligible=="boolean"?t.promotionEligible:true,scopes:"scopes"in t?X(t.scopes):[],connectionId:"connectionId"in t&&typeof t.connectionId=="string"?t.connectionId:void 0,deviceIdHint:"deviceIdHint"in t&&typeof t.deviceIdHint=="string"?t.deviceIdHint:void 0,transportStableId:"transportStableId"in t&&typeof t.transportStableId=="number"?t.transportStableId:"transportStableId"in t?t.transportStableId??null:void 0,transportGeneration:"transportGeneration"in t&&typeof t.transportGeneration=="number"?t.transportGeneration:void 0,routeGeneration:"routeGeneration"in t&&typeof t.routeGeneration=="number"?t.routeGeneration:void 0,activeTransport:"activeTransport"in t?t.activeTransport:void 0,parallelTransport:"parallelTransport"in t?t.parallelTransport:void 0,availableTransports:"availableTransports"in t?K(t.availableTransports):"transports"in t?K(t.transports):void 0,latencyMs:"latencyMs"in t&&typeof t.latencyMs=="number"?t.latencyMs:void 0,latencyByTransport:"latencyByTransport"in t?Pe(t.latencyByTransport):void 0}}function O(t,e){return e===void 0?true:e===null?t==null:t==null||t===e}function Ce(t,e){let n=O(t.connectionId,e.connectionId)&&O(t.nodeId,e.nodeId)&&O(t.transportStableId,e.transportStableId)&&O(t.transportGeneration,e.transportGeneration)&&O(t.routeGeneration,e.routeGeneration),i=(r,o)=>r!==void 0?r:n?o:void 0;return {inheritsSnapshot:n,fields:{connectionId:i(e.connectionId??void 0,t.connectionId),transportStableId:i(e.transportStableId,t.transportStableId),transportGeneration:i(e.transportGeneration,t.transportGeneration),routeGeneration:i(e.routeGeneration,t.routeGeneration),activeTransport:i(e.activeTransport,t.activeTransport),parallelTransport:i(e.parallelTransport,t.parallelTransport),latencyMs:n?t.latencyMs:void 0,latencyByTransport:n?t.latencyByTransport:void 0}}}var Tt={connectionId:void 0,transportStableId:null,transportGeneration:void 0,routeGeneration:void 0,activeTransport:void 0,parallelTransport:void 0,latencyMs:void 0,latencyByTransport:void 0};function Pt(t,e,n){let i=Ce(t,{connectionId:e.activeConnectionId,nodeId:e.nodeId,transportStableId:e.transportStableId,transportGeneration:e.transportGeneration,routeGeneration:e.routeGeneration,activeTransport:e.activeTransport,parallelTransport:e.parallelTransport}),r=n?n({connectionId:e.activeConnectionId??void 0,deviceId:e.deviceId??void 0,deviceIdHint:e.deviceIdHint??void 0,nodeId:e.nodeId??void 0}):t.promotionEligible??true;if(!r)return {...t,peerHealth:e.health??t.peerHealth,peerId:e.peerId??t.peerId,promotionEligible:r,scopes:e.scopes?.length?[...e.scopes]:t.scopes,nodeId:e.nodeId===void 0?t.nodeId:e.nodeId??void 0,deviceIdHint:e.deviceIdHint??t.deviceIdHint,...i.fields,readinessReason:e.readinessReason??t.readinessReason};let o=e.status??t.connectionStatus,a=typeof o=="string"?o.trim().toLowerCase():"",s=a==="failed"||a==="closed"||a==="disconnected",d=typeof e.readinessState=="string"&&e.readinessState.trim().length>0?e.readinessState==="routable":e.settledReady===true,l=t.settledReady===true||t.readinessState==="routable";if(i.inheritsSnapshot&&l&&!s&&!d)return {...t,peerHealth:e.health??t.peerHealth,peerId:e.peerId??t.peerId,promotionEligible:r,scopes:e.scopes?.length?[...e.scopes]:t.scopes,nodeId:e.nodeId===void 0?t.nodeId:e.nodeId??void 0,deviceIdHint:e.deviceIdHint??t.deviceIdHint,...i.fields,readinessReason:e.readinessReason??t.readinessReason};let u=s?false:d,f=d&&!s&&(a==="connecting"||a==="connected")?"connected":o,y=d?"routable":e.readinessState??(i.inheritsSnapshot?t.readinessState:void 0),m=u?e.readinessReason??"peer-session-settled":e.readinessReason??(i.inheritsSnapshot?t.readinessReason:void 0);return {...t,connectionStatus:f,settledReady:u,readinessState:y,readinessReason:m,peerHealth:e.health??t.peerHealth,peerId:e.peerId??t.peerId,promotionEligible:r,scopes:e.scopes?.length?[...e.scopes]:t.scopes,nodeId:e.nodeId===void 0?t.nodeId:e.nodeId??void 0,deviceIdHint:e.deviceIdHint??t.deviceIdHint,...i.fields}}function Ct(t,e){let n=Ce(t,{connectionId:e.connectionId,nodeId:e.nodeId,transportStableId:e.transportStableId,transportGeneration:e.transportGeneration,routeGeneration:e.routeGeneration,activeTransport:e.activeTransport,parallelTransport:e.parallelTransport});if(e.promotionEligible===false)return {...t,peerHealth:e.health??t.peerHealth,peerId:e.peerId??t.peerId,promotionEligible:false,nodeId:e.nodeId??t.nodeId,deviceIdHint:e.deviceIdHint??t.deviceIdHint,...n.fields,scopes:e.scopes?.length?[...e.scopes]:t.scopes};let i=e.status??t.connectionStatus,r=typeof i=="string"?i.trim().toLowerCase():"",o=r==="failed"||r==="closed"||r==="disconnected",a=t.settledReady===true||t.readinessState==="routable",s=e.routable===false;if(n.inheritsSnapshot&&a&&o&&!s)return {...t,peerHealth:t.peerHealth??e.health,peerId:t.peerId??e.peerId,promotionEligible:e.promotionEligible??t.promotionEligible??true,connectionId:t.connectionId??e.connectionId,deviceIdHint:t.deviceIdHint??e.deviceIdHint,scopes:t.scopes?.length?t.scopes:e.scopes??t.scopes};if(a&&o)return {...t,connectionStatus:i,settledReady:false,readinessState:void 0,readinessReason:e.error??t.readinessReason,peerHealth:e.health??t.peerHealth,peerId:e.peerId??t.peerId,promotionEligible:e.promotionEligible??t.promotionEligible??true,deviceIdHint:e.deviceIdHint??t.deviceIdHint,...Tt,scopes:e.scopes?.length?[...e.scopes]:t.scopes};let c=e.routable===true||e.protocolState==="routable";if(n.inheritsSnapshot&&a&&!o&&!c)return {...t,peerHealth:t.peerHealth??e.health,peerId:t.peerId??e.peerId,promotionEligible:e.promotionEligible??t.promotionEligible??true,connectionId:t.connectionId??e.connectionId,deviceIdHint:t.deviceIdHint??e.deviceIdHint,transportStableId:t.transportStableId??e.transportStableId,transportGeneration:t.transportGeneration??e.transportGeneration,routeGeneration:t.routeGeneration??e.routeGeneration,activeTransport:t.activeTransport??e.activeTransport,parallelTransport:t.parallelTransport===void 0?e.parallelTransport:t.parallelTransport,scopes:t.scopes?.length?t.scopes:e.scopes??t.scopes};let d=e.transportState==="connected"&&e.health==="healthy",l=o?false:c,u=!o&&(c||d)&&(r==="connecting"||r==="connected"||e.transportState==="connected")?"connected":i,f=l?"routable":(e.routable===false&&e.protocolState?e.protocolState:void 0)??(n.inheritsSnapshot?t.readinessState:void 0)??(e.status==="connecting"?e.transportState==="connected"?"transport-only":"connecting":void 0),y=l?(n.inheritsSnapshot?t.readinessReason:void 0)??(e.routable===true?"peer-projection-routable":void 0):(e.routable===false&&e.error?e.error:void 0)??(n.inheritsSnapshot?t.readinessReason:void 0)??(e.status==="connecting"?e.transportState==="connected"?"peer-projection-transport-ready":"peer-projection-connecting":void 0);return {...t,connectionStatus:u,settledReady:l,readinessState:f,readinessReason:y,peerHealth:e.health??t.peerHealth,peerId:e.peerId??t.peerId,promotionEligible:e.promotionEligible??t.promotionEligible??true,nodeId:e.nodeId??t.nodeId,deviceIdHint:e.deviceIdHint??t.deviceIdHint,...n.fields,scopes:e.scopes?.length?[...e.scopes]:t.scopes}}function Mt(t){let{device:e,session:n=null,peer:i=null,isPromotionEligible:r}=t,o=At(e);return n&&(o=Pt(o,n,r)),i&&(o=Ct(o,i)),Ie(o)}function gn(t){let e=J(t),n=It(e),i=Q(p(e,"presenceStatus","presence_status","livenessStatus","liveness_status")),r=Ae({...n,...i?{presenceStatus:i}:{},presenceUpdatedAt:g(e,"presenceUpdatedAt","presence_updated_at")??Y(e.presenceUpdatedAt,e.presence_updated_at,e.lastSeenAt,e.last_seen_at,e.updatedAt,e.updated_at,e.createdAt,e.created_at),presenceExpiresAt:g(e,"presenceExpiresAt","presence_expires_at")??A(e.presenceExpiresAt??e.presence_expires_at)??A(e.expiresAt??e.expires_at),connectable:w(e,"connectable")}),o={...n,...r,connectionStatus:p(e,"connectionStatus","connection_status")||"disconnected",settledReady:w(e,"settledReady","settled_ready")??false,readinessState:p(e,"readinessState","readiness_state")??void 0,readinessReason:p(e,"readinessReason","readiness_reason")??void 0,peerHealth:p(e,"peerHealth","peer_health")||"unknown",peerId:p(e,"peerId","peer_id"),scopes:X(e.scopes),connectionId:p(e,"connectionId","connection_id"),deviceIdHint:p(e,"deviceIdHint","device_id_hint"),transportStableId:g(e,"transportStableId","activeTransportStableId","active_transport_stable_id")??void 0,transportGeneration:g(e,"transportGeneration","transport_generation")??void 0,routeGeneration:g(e,"routeGeneration","route_generation")??void 0,activeTransport:E(e,"activeTransport","active_transport"),parallelTransport:E(e,"parallelTransport","parallel_transport")??null,availableTransports:K(e.availableTransports??e.available_transports),latencyMs:g(e,"latencyMs","latency_ms"),latencyByTransport:Pe(e.latencyByTransport??e.latency_by_transport)};return Mt({device:o})}function yn(t){let e=J(t);return Ie({peerId:p(e,"peerId","peer_id")||"",deviceId:p(e,"deviceId","device_id"),deviceIdHint:p(e,"deviceIdHint","device_id_hint"),nodeId:p(e,"nodeId","node_id"),activeConnectionId:p(e,"activeConnectionId","active_connection_id"),candidates:Array.isArray(e.candidates)?e.candidates.filter(n=>typeof n=="string"):Array.isArray(e.candidateConnectionIds)?e.candidateConnectionIds.filter(n=>typeof n=="string"):Array.isArray(e.candidate_connection_ids)?e.candidate_connection_ids.filter(n=>typeof n=="string"):[],status:p(e,"status")||"disconnected",health:p(e,"health")||"unknown",settledReady:w(e,"settledReady","settled_ready")??false,readinessState:p(e,"readinessState","readiness_state")??void 0,transportStableId:g(e,"transportStableId","activeTransportStableId","active_transport_stable_id")??void 0,transportGeneration:g(e,"transportGeneration","transport_generation")??void 0,routeGeneration:g(e,"routeGeneration","route_generation")??void 0,activeTransport:E(e,"activeTransport","active_transport"),parallelTransport:E(e,"parallelTransport","parallel_transport")??null,replacementPending:w(e,"replacementPending","replacement_pending")??void 0,logicalSessionTerminal:w(e,"logicalSessionTerminal","logical_session_terminal")??false,lastTransitionAtMs:g(e,"lastTransitionAtMs","lastLifecycleTransitionAtMs","last_lifecycle_transition_at_ms")??void 0,readinessReason:p(e,"readinessReason","readiness_reason")??void 0,transitionCount:g(e,"transitionCount","transition_count")??void 0,connectTransitions:g(e,"connectTransitions","connectingTransitionCount","connecting_transition_count")??void 0,replacementCount:g(e,"replacementCount","replacement_count")??void 0,retireCount:g(e,"retireCount","retire_count")??void 0,lastDisconnectReason:p(e,"lastDisconnectReason","last_disconnect_reason")??void 0,lastReconnectReason:p(e,"lastReconnectReason","last_reconnect_reason")??void 0,scopes:Array.isArray(e.scopes)?e.scopes.filter(n=>typeof n=="string"):[],lastSeenAtMs:typeof e.lastSeenAtMs=="number"?e.lastSeenAtMs:typeof e.last_seen_at_ms=="number"?e.last_seen_at_ms:0,error:p(e,"error"),errorCode:p(e,"errorCode","error_code")??void 0,retryable:w(e,"retryable")??void 0,errorPlane:p(e,"errorPlane","error_plane")??void 0})}function mn(t){let e=M(t);return {connectionId:typeof e.connectionId=="string"?e.connectionId:"",nodeId:typeof e.nodeId=="string"?e.nodeId:null,deviceId:typeof e.deviceId=="string"?e.deviceId:null,deviceIdHint:typeof e.deviceIdHint=="string"?e.deviceIdHint:null,endpointId:typeof e.endpointId=="string"?e.endpointId:null,transportGeneration:typeof e.transportGeneration=="number"?e.transportGeneration:0,routeGeneration:typeof e.routeGeneration=="number"?e.routeGeneration:void 0,transportStableId:typeof e.transportStableId=="number"?e.transportStableId:null,transportSource:typeof e.transportSource=="string"?e.transportSource:null,lastTransportChangeAtMs:typeof e.lastTransportChangeAtMs=="number"?e.lastTransportChangeAtMs:0,lastRouteChangeAtMs:typeof e.lastRouteChangeAtMs=="number"?e.lastRouteChangeAtMs:void 0,state:typeof e.state=="string"?e.state:"pending",statusReason:typeof e.statusReason=="string"?e.statusReason:null,transitionCount:typeof e.transitionCount=="number"?e.transitionCount:void 0,connectTransitions:typeof e.connectTransitions=="number"?e.connectTransitions:void 0,replacementCount:typeof e.replacementCount=="number"?e.replacementCount:void 0,retireCount:typeof e.retireCount=="number"?e.retireCount:void 0,lastDisconnectReason:typeof e.lastDisconnectReason=="string"?e.lastDisconnectReason:void 0,lastReconnectReason:typeof e.lastReconnectReason=="string"?e.lastReconnectReason:void 0,createdAtMs:typeof e.createdAtMs=="number"?e.createdAtMs:0,updatedAtMs:typeof e.updatedAtMs=="number"?e.updatedAtMs:0}}function fn(t){let e=M(t);return {peerId:typeof e.peerId=="string"?e.peerId:null,deviceId:typeof e.deviceId=="string"?e.deviceId:null,deviceIdHint:typeof e.deviceIdHint=="string"?e.deviceIdHint:null,nodeId:typeof e.nodeId=="string"?e.nodeId:null}}function Et(t){switch(t){case "connected":return "connected";case "connecting":return "connecting";case "failed":return "failed";default:return "closed"}}function vn(t){let e=t.activeConnectionId||t.candidates[0]||null;if(!e)return null;let n=Et(t.status),i=n==="connected"?"connected":n==="connecting"?"connecting":"closed",r=n==="connected"?t.settledReady?"routable":"transport-only":n==="connecting"?"connecting":"closed";return {connectionId:e,deviceId:t.deviceId??null,deviceIdHint:t.deviceIdHint??null,remoteNodeId:t.nodeId??null,state:n,transportState:i,protocolState:r,routable:!!t.settledReady,readinessState:t.readinessState,readinessReason:t.readinessReason,transportGeneration:t.transportGeneration,routeGeneration:t.routeGeneration,transportStableId:t.transportStableId,activeTransport:t.activeTransport,parallelTransport:t.parallelTransport??null,replacementInProgress:t.replacementPending,logicalSessionTerminal:t.logicalSessionTerminal===true,lastTransitionAtMs:t.lastTransitionAtMs,transitionCount:t.transitionCount,connectTransitions:t.connectTransitions,replacementCount:t.replacementCount,retireCount:t.retireCount,lastDisconnectReason:t.lastDisconnectReason??void 0,lastReconnectReason:t.lastReconnectReason??void 0,updatedAt:t.lastSeenAtMs,error:t.error??void 0}}function bn(t){let e=M(t),n=p(e,"connectionId","connection_id");if(!n)return null;let i=p(e,"state")||"connecting",r=g(e,"createdAt","created_at")??g(e,"updatedAt","updated_at")??Date.now(),o=g(e,"updatedAt","updated_at")??r;return {connectionId:n,deviceId:p(e,"deviceId","device_id"),deviceIdHint:p(e,"deviceIdHint","device_id_hint"),remoteNodeId:p(e,"remoteNodeId","remote_node_id"),state:i,transportState:p(e,"transportState","transport_state")??(i==="connected"?"connected":i==="connecting"?"connecting":"closed"),protocolState:p(e,"protocolState","protocol_state")??(i==="connected"?"routable":i==="connecting"?"connecting":"closed"),routable:w(e,"routable")??false,logicalSessionTerminal:w(e,"logicalSessionTerminal","logical_session_terminal")??false,readinessState:p(e,"readinessState","readiness_state")??void 0,readinessReason:p(e,"readinessReason","readiness_reason")??void 0,transportGeneration:g(e,"transportGeneration","transport_generation")??void 0,routeGeneration:g(e,"routeGeneration","route_generation")??void 0,transportStableId:g(e,"transportStableId","activeTransportStableId","active_transport_stable_id")??void 0,activeTransport:E(e,"activeTransport","active_transport"),parallelTransport:E(e,"parallelTransport","parallel_transport")??null,replacementInProgress:w(e,"replacementInProgress","replacement_in_progress")??void 0,lastTransitionAtMs:g(e,"lastTransitionAtMs","lastLifecycleTransitionAtMs","last_lifecycle_transition_at_ms")??void 0,transitionCount:g(e,"transitionCount","transition_count")??void 0,connectTransitions:g(e,"connectTransitions","connectingTransitionCount","connecting_transition_count")??void 0,replacementCount:g(e,"replacementCount","replacement_count")??void 0,retireCount:g(e,"retireCount","retire_count")??void 0,lastDisconnectReason:p(e,"lastDisconnectReason","last_disconnect_reason")??void 0,lastReconnectReason:p(e,"lastReconnectReason","last_reconnect_reason")??void 0,error:p(e,"error")??void 0,createdAt:r,updatedAt:o}}function wn(t,e){return t?t.connectionId===e.connectionId&&(t.deviceId??null)===(e.deviceId??null)&&(t.deviceIdHint??null)===(e.deviceIdHint??null)&&(t.remoteNodeId??null)===(e.remoteNodeId??null)&&t.state===e.state&&(t.transportState??null)===(e.transportState??null)&&(t.protocolState??null)===(e.protocolState??null)&&!!t.routable==!!e.routable&&(t.activeTransport??null)===(e.activeTransport??null)&&(t.parallelTransport??null)===(e.parallelTransport??null)&&(t.transportStableId??null)===(e.transportStableId??null)&&(t.transportGeneration??null)===(e.transportGeneration??null)&&(t.routeGeneration??null)===(e.routeGeneration??null)&&!!t.replacementInProgress==!!e.replacementInProgress&&!!t.logicalSessionTerminal==!!e.logicalSessionTerminal&&(t.transitionCount??null)===(e.transitionCount??null)&&(t.connectTransitions??null)===(e.connectTransitions??null)&&(t.replacementCount??null)===(e.replacementCount??null)&&(t.retireCount??null)===(e.retireCount??null)&&(t.lastDisconnectReason??null)===(e.lastDisconnectReason??null)&&(t.lastReconnectReason??null)===(e.lastReconnectReason??null)&&(t.error??null)===(e.error??null):false}
2
+ export{Mt as A,gn as B,yn as C,mn as D,fn as E,vn as F,bn as G,wn as H,kt as a,ge as b,Ye as c,Bt as d,Ft as e,jt as f,ye as g,qt as h,Yt as i,Qt as j,Xt as k,Zt as l,en as m,vt as n,wt as o,nn as p,St as q,Rt as r,Re as s,on as t,sn as u,an as v,J as w,pn as x,hn as y,It as z};
@@ -0,0 +1 @@
1
+ import {b as b$1,a as a$1}from'./chunk-ZA44REGI.js';import {b as b$3}from'./chunk-LLZT3MR6.js';import {a}from'./chunk-DUY34MGT.js';import {b as b$2,a as a$2}from'./chunk-CCCYE3XN.js';import {d as d$1,a as a$3}from'./chunk-N6LGTNUI.js';import {d,b as b$4}from'./chunk-2GX6GB6L.js';function I(o,e,t,i){let n=JSON.stringify({__openrtc:2,capability:i,kind:o,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(o){let e;try{e=o instanceof Uint8Array?JSON.parse(new TextDecoder().decode(o)):o&&typeof o=="object"?o:{};}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",se=32,Y=16,U=4294967295,ce=/^[A-Za-z0-9][A-Za-z0-9._/+:-]{0,127}$/,le=/^([0-9a-f]{64})-([0-9a-f]{64})$/i;function A(o){let e=o?.trim()??"";if(!ce.test(e))throw new Error("[OpenRTC] stream protocol must be 1-128 safe ASCII characters.");return e}function k(o){let e=o?.trim()??"",t=le.exec(e);return t?[t[1].toLowerCase(),t[2].toLowerCase()].sort().join("-"):e}function ee(o){if(o===null||o===0)return null;if(!Number.isFinite(o)||o<0)throw new RangeError("[OpenRTC] datagram maximum age must be a non-negative finite number or null.");return Math.min(U,Math.ceil(o))}function te(o){if(!Number.isSafeInteger(o)||o<1||o>U)throw new RangeError(`[OpenRTC] datagram buffer limits must be integers from 1 to ${U}.`);return o}var L=class{constructor(e,t){this.runtime=e;this.peerId=t;this.incomingAge=null;this.outgoingAge=null;this.incomingLimit=Y;this.outgoingLimit=Y;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=ee(e),this.policy.setIncomingMaxAge(this.incomingAge??void 0,Date.now()),this.wake(this.incomingWaiters);}get outgoingMaxAge(){return this.outgoingAge}set outgoingMaxAge(e){this.outgoingAge=ee(e),this.policy.setOutgoingMaxAge(this.outgoingAge??void 0);}get incomingMaxBufferedDatagrams(){return this.incomingLimit}set incomingMaxBufferedDatagrams(e){this.incomingLimit=te(e),this.policy.setIncomingMaxBufferedDatagrams(this.incomingLimit);}get outgoingMaxBufferedDatagrams(){return this.outgoingLimit}set outgoingMaxBufferedDatagrams(e){this.outgoingLimit=te(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();}},O=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:se});}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 O;this.incomingUni=new O;this.incomingBidirectionalStreams=this.incomingBi.readable;this.incomingUnidirectionalStreams=this.incomingUni.readable;this.closed=false;this.protocolHandlers=new Map;this.datagrams=new L(i,this.peerId);}async createBidirectionalStream(e){let t=A(e.protocol),i=await this.client.channels.openBi(this.peerId,b,{timeoutMs:e.timeoutMs,channelMetadata:{protocol:t,[a$2]:this.capabilityKey}});return {protocol:t,readable:i.readable,writable:i.writable}}async createUnidirectionalStream(e){let t=A(e.protocol);return (await this.client.channels.openUni(this.peerId,b,{timeoutMs:e.timeoutMs,channelMetadata:{protocol:t,[a$2]:this.capabilityKey}})).writable}accept(e,t){if(e.type==="bi"){let n=e.stream;if(!n.recv||!n.send)return false;let r={peerId:this.peerId,protocol:t,readable:n.recv,writable:n.send},a=this.protocolHandlers.get(t);if(a){try{a(r);}catch{r.readable.cancel("incoming-protocol-handler-failed").catch(()=>{}),r.writable.abort("incoming-protocol-handler-failed").catch(()=>{});}return true}return this.incomingBi.enqueue(r)||(r.readable.cancel("incoming-peer-stream-queue-full").catch(()=>{}),r.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=A(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();}},D=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=k(e),n=t.trim();!i||!n||this.peerIdsByConnection.set(i,n);}unbindConnection(e){this.peerIdsByConnection.delete(k(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$2]!==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=A(i);}catch{return this.declined+=1,false}let a=this.resolveExistingPeer(e.remoteNodeId,e.connectionId)?.accept(e,n)??false;return a?this.accepted+=1:this.declined+=1,a}resolveExistingPeer(e,t=""){let i=k(t);if(i){let a=this.peerIdsByConnection.get(i);if(!a)return this.lastResolution="unbound-connection",null;let s=this.peers.get(a);return s?(this.lastResolution="connection",s):(this.lastResolution="unbound-connection",null)}let n=this.peers.get(e);if(n)return this.lastResolution="remote-peer",n;let r=this.client.peers.get(e)??this.client.peers.listConnected().find(a=>[a.peerId,a.deviceId,a.deviceIdHint,a.connectionId,...a.connectionIds].some(s=>s===e));if(r){let a=new Set([r.peerId,r.deviceId,r.deviceIdHint,r.connectionId,...r.connectionIds].filter(c=>typeof c=="string"&&c.length>0)),s=[...this.peers.entries()].filter(([c])=>a.has(c)).map(([,c])=>c);if(s.length===1)return this.lastResolution="peer-alias",s[0]}return this.lastResolution="none",null}};var _={"identity.assertion.exchange":25692e-8,"identity.monthly-active-principal":110352e-9,"capability.issue":212346e-9,"device.enroll":218946e-9,"gateway.grant.issue":202146e-9,"gateway.grant.refresh":200346e-9,"security.attestation.verify":29694e-8,"room.create":388056e-9,"room.join":209946e-9,"room.leave":200346e-9,"broadcast.control":271938e-9,"broadcast.delivery":.1,"coordination.connection.open":58164e-8,"coordination.credential.refresh":367734e-9,"coordination.lease.refresh":27987e-8,"coordination.presence.upsert":27771e-8,"coordination.presence.offline":27171e-8,"coordination.signal.send":27771e-8,"coordination.managed.publish":473688e-9,"coordination.managed.keypackage.publish":271908e-9,"coordination.managed.commit.chunk":295182e-9,"coordination.managed.commit.ack":271908e-9,"coordination.managed.control":.001122582,"coordination.managed.prepare.page":26718e-8,"coordination.authority.assignment":370866e-9,"coordination.session.put":27771e-8,"coordination.session.delete":27171e-8,"coordination.usage.ingest":197088e-9};var y=new WeakMap;function de(o){let e=y.get(o);if(!e||o.closed)throw new Error("[OpenRTC] Capability runtime is unavailable or already closed.");return e}function xe(o,e){if(y.has(o))throw new Error("[OpenRTC] Capability runtime is already registered.");return y.set(o,de(e)),()=>{y.delete(o);}}function ue(o){let e=o?.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 T(o){let e=o?.trim()??"";if(!e||e.length>160||!/^[A-Za-z0-9_.:@-]+$/.test(e))throw new Error("[OpenRTC] Capability id is invalid.");return e}var z=/^[A-Za-z0-9_.:@-]{1,160}$/,he=/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;function me(o){let e=typeof o=="string"?o.trim():"";if(!z.test(e))return null;let t=e.startsWith("device_")?e.slice(7):"";return he.test(t)?t:e}function pe(o){let e=`openrtc:v2:device-id:${o}`,t,i=(()=>{try{return t=globalThis.localStorage,me(t?.getItem(e))||crypto.randomUUID()}catch{return crypto.randomUUID()}})();try{t?.setItem(e,i);}catch{}return i}function ie(o){let e=typeof o=="string"?o.trim():"";if(!z.test(e))throw new Error("[OpenRTC] The native host returned an invalid durable device ID.");return e}var ne=250;function re(o){if(o===void 0)return [];if(!Array.isArray(o))throw new Error("[OpenRTC] autoConnectExcludedDeviceIds must be an array.");let e=[...new Set(o.map(t=>{let i=typeof t=="string"?t.trim().toLowerCase():"";if(!z.test(i))throw new Error("[OpenRTC] autoConnectExcludedDeviceIds contains an invalid device ID.");return i}))].sort();if(e.length>ne)throw new Error(`[OpenRTC] autoConnectExcludedDeviceIds supports at most ${ne} devices.`);return e}function oe(o){let e=b$1(o.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 N=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);}},K=class{constructor(e){this.options=e;this.total=0;this.warned=false;}get sessionCreditsUsd(){return this.total}estimate(e){let t=e.units??1,i=Number.isFinite(t)?Math.max(0,t):0;return {creditsUsd:(_[e.operation]??0)*i,estimated:true}}estimateRoom(e){let t=G(e.maxMembers,"maxMembers",1,Number.MAX_SAFE_INTEGER);if(t>50)throw f(`[OpenRTC] Room architecture is unavailable for ${t} members in this release; the limit is 50.`);let i=G(e.durationSeconds,"durationSeconds",1,744*60*60),n=G(e.maxPayloadBytes,"maxPayloadBytes",0,1048576),r=ge(e.maxMessagesPerSecond,"maxMessagesPerSecond",0,1e4),a=ve(e.architecture),s=ye(a,t,e.delivery),l=fe(s,t)*r*i*n/1e9,d=Math.floor(i/3300),u=h("capability.issue")+h("gateway.grant.issue")+h("room.join")+h("coordination.connection.open")+h("coordination.presence.upsert")+h("room.leave")+h("coordination.presence.offline")+d*h("coordination.lease.refresh"),m=t*u,v=r*i,p=Math.max(0,Math.ceil(t/4)-1),P=s==="managed"?v*h("coordination.managed.publish")+t*h("coordination.managed.keypackage.publish")+t*h("coordination.managed.commit.ack")+t*h("coordination.managed.commit.chunk")+h("coordination.managed.control")+p*h("coordination.managed.prepare.page"):s==="authority"?t*Math.ceil(i/120)*h("coordination.authority.assignment"):0,g=l*h("broadcast.delivery");return {architecture:a,effectiveArchitecture:s,creditsUsd:Math.ceil((m+P+g)*1e12)/1e12,estimated:true,expiresAtMs:Date.now()+5*6e4,assumptions:["Every declared member obtains one capability and gateway grant, joins once, publishes presence, and retires once during the quote window.",`Each continuously connected member is quoted for ${d} successful 55-minute lease renewal${d===1?"":"s"}.`,"Room-wide payload is conservatively quoted as fully hosted or relayed.","Payload delivery uses the published customer value of $0.10 per decimal GB.",s==="managed"?"Managed control assumes initial group setup, maximum-size KeyPackage paging, bounded artifact chunks, exactly one room-wide transition settlement, and one protected publish per declared message.":s==="authority"?"Authority control assumes one signed assignment per member every two minutes.":"Direct application payloads do not add hosted fanout operations.",s==="authority"?"Developer service-node hosting is external and is not included in OpenRTC credits.":"Unused reservations are released when authoritative settlement completes."]}}assertCanSpend(e,t=1){let i=this.options?.maxSessionCreditsUsd;if(i===void 0||this.total+this.estimate({operation:e,units:t}).creditsUsd<=i)return;let r={sessionCreditsUsd:this.total,operation:e,estimated:true,thresholdCreditsUsd:i,kind:"session-limit"};throw this.options?.onWarning?.(r),new Error("[OpenRTC] The client-side session credit limit was reached.")}record(e,t=1){let i=this.estimate({operation:e,units:t}).creditsUsd;this.total+=i;let n={sessionCreditsUsd:this.total,operation:e,estimated:true};this.options?.onUsage?.(n);let r=this.options?.warnAtSessionCreditsUsd;!this.warned&&r!==void 0&&this.total>=r&&(this.warned=true,this.options?.onWarning?.({...n,thresholdCreditsUsd:r,kind:"warning"}));}};function ve(o){return o??"auto"}function G(o,e,t,i){if(!Number.isSafeInteger(o)||o<t||o>i)throw new RangeError(`[OpenRTC] ${e} must be an integer from ${t} to ${i}.`);return o}function ge(o,e,t,i){if(!Number.isFinite(o)||o<t||o>i)throw new RangeError(`[OpenRTC] ${e} must be between ${t} and ${i}.`);return o}function h(o){let e=_[o];if(!Number.isFinite(e)||e<=0)throw new Error(`[OpenRTC] Room quote is unavailable because ${o} has no current customer-credit price.`);return e}function ye(o,e,t){if(o==="mesh"){if(e>16)throw f("[OpenRTC] Fixed mesh is limited to 16 members in this release.");return o}if(o==="sparse"){if(e>50)throw f("[OpenRTC] Fixed sparse is limited to 50 members in this release.");if(t!=="latest-state")throw f("[OpenRTC] Sparse room quotes require latest-state delivery.");return o}if(o==="managed")throw f("[OpenRTC] Managed room architecture is unavailable in this release.");if(o==="authority")return o;if(e<=8)return "mesh";if(t==="latest-state"&&e<=50)return "sparse";throw f(`[OpenRTC] Reliable automatic room architecture is unavailable for ${e} members in this release.`)}function f(o){return d$1(a$3.ROOM_ARCHITECTURE_UNAVAILABLE,o,{retryable:false,plane:"admission"})}function fe(o,e){if(e<=1)return 0;if(o!=="sparse")return e-1;let t=Math.min(4,e-1),i=e*t/2;return Math.max(e-1,i*2-(e-1))}function ae(o){let e=o?.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.mediaConnections=new Map;this.mediaRetirements=new Map;this.pendingRawConnections=new Map;this.connectionIdsByPeer=new Map;this.closed=false;this.peerStreams=new D(e,t),this.stopMessage=e.onMessage((n,r)=>this.receive(n,r)),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,r,a)=>{let s=B(r);!s||s.capability!==this.capabilityKey||a!==void 0&&s.name!==a||a===void 0&&s.kind!=="channel"||this.deliverEnvelope(n,s);}});}state(e){if(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=ae(e);return {set:i=>{let n=I("state",t,i,this.capabilityKey);if(this.localState.set(t,n),!this.roomFanout?.publishState(t,n))for(let{activeRaw:r}of this.logicalConnections.values())r&&this.sendState(r,t,n);},watch:i=>{let n=this.stateListeners.get(t);n||this.stateListeners.set(t,n=new Set);let r=(a,s)=>i({peerId:a,value:s});n.add(r);for(let[a,s]of this.remoteState)s.has(t)&&i({peerId:a,value:s.get(t)});return ()=>n?.delete(r)}}}channel(e){let t=ae(e),i=n=>I("channel",t,n,this.capabilityKey);return {send:async n=>{let r=i(n);await this.roomFanout?.sendChannel(t,r)||await Promise.all([...this.logicalConnections.values()].flatMap(({activeRaw:a})=>a?[a.send(r)]:[]));},sendTo:async(n,r)=>{this.roomFanout?.assertTargetedSendAllowed();let a=this.logicalConnections.get(n)?.activeRaw;if(a){await a.send(i(r));return}throw new Error(`[OpenRTC] Peer '${n}' has no direct authorized route; sparse broadcasts never multi-hop targeted payloads.`)},onMessage:n=>{let r=this.channelListeners.get(t);r||this.channelListeners.set(t,r=new Set);let a=(s,c)=>n({peerId:s,message:c});return r.add(a),()=>r?.delete(a)}}}onConnection(e){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)}async close(){if(this.closed)return;this.closed=true,this.stopMessage(),this.stopConnection(),this.stopDisconnection(),this.stopPeerLifecycle(),this.roomFanout?.close();let e=[...this.logicalConnections.keys()].map(t=>this.retire(t));this.pendingRawConnections.clear(),this.peerStreams.close(),this.rawConnections.clear(),this.connectionListeners.clear(),this.channelListeners.clear(),this.stateListeners.clear(),this.localState.clear(),await Promise.allSettled(e);}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 s={raw:e,peerId:i};this.pendingRawConnections.set(e.id,s),n.finally(()=>{this.closed||this.pendingRawConnections.get(e.id)!==s||(this.pendingRawConnections.delete(e.id),this.add(e));});return}this.rawConnections.set(e.id,{raw:e,peerId:i});let r=this.connectionIdsByPeer.get(i);r||this.connectionIdsByPeer.set(i,r=new Set),r.add(e.id),this.peerStreams.bindConnection(e.id,i);let a=this.logicalConnections.get(i);if(!a){let s=this.peerStreams.forPeer(i),c=new b$3(s,this.client.advanced.runtime,(d,u)=>this.peerStreams.onProtocol(i,d,u),()=>this.peerStreams.diagnostics());this.mediaConnections.set(i,c),a={activeRaw:e,rawIds:new Set,view:{id:i,peerId:i,streams:s,media:c,send:async d=>{let u=this.logicalConnections.get(i)?.activeRaw;if(!u)throw new Error(`[OpenRTC] Peer '${i}' is not connected.`);await u.send(I("raw","message",d,this.capabilityKey));},onMessage:d=>{let u=this.rawListeners.get(i);u||this.rawListeners.set(i,u=new Set);let m=d;return u.add(m),()=>u?.delete(m)},onClose:d=>{let u=this.closeListeners.get(i);return u||this.closeListeners.set(i,u=new Set),u.add(d),()=>u?.delete(d)}}},this.logicalConnections.set(i,a);}a.rawIds.add(e.id),a.activeRaw=e,this.observePeerLifecycle(this.client.peers.listConnected());for(let[s,c]of this.connectionListeners)c.has(i)||(c.add(i),s(a.view));for(let[s,c]of this.localState)this.sendState(e,s,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 s=[...n.rawIds],c=s[s.length-1];n.activeRaw=c?this.rawConnections.get(c)?.raw??null:null;}let r=this.connectionIdsByPeer.get(i);if(r?.delete(e.id),r?.size===0&&this.connectionIdsByPeer.delete(i),!n?.activeRaw){let s=this.remoteState.get(i);if(s){for(let c of s.keys())for(let l of this.stateListeners.get(c)??[])l(i,null);this.remoteState.delete(i);}}let a=this.stateSenders.get(e);if(a){for(let s of a.values())s.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 r=n.status==="closed"&&n.logicalSessionTerminal===true&&n.routable!==true&&n.settledReady!==true;if(n.manualDisconnect||r){this.retire(t);continue}if(n.settledReady!==true||n.routable!==true)continue;let a=n.transportStableId,s=n.transportGeneration,c=n.routeGeneration;if(Number.isSafeInteger(a)&&Number(a)>0&&Number.isSafeInteger(s)&&Number(s)>0&&Number.isSafeInteger(c)&&Number(c)>=0){let l=this.mediaConnections.get(t);l&&l.observePhysicalGeneration({transportStableId:Number(a),transportGeneration:Number(s),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);for(let a of t.rawIds){let s=this.rawConnections.get(a)?.raw;if(this.rawConnections.delete(a),this.peerStreams.unbindConnection(a),!s)continue;let c=this.stateSenders.get(s);if(c){for(let l of c.values())l.close();this.stateSenders.delete(s);}}this.connectionIdsByPeer.delete(e);let i=this.remoteState.get(e);if(i){for(let a of i.keys())for(let s of this.stateListeners.get(a)??[])s(e,null);this.remoteState.delete(e);}let n=this.mediaConnections.get(e);this.mediaConnections.delete(e);let r=n?.close().catch(()=>{})??Promise.resolve();this.mediaRetirements.set(e,r),r.finally(()=>{this.mediaRetirements.get(e)===r&&this.mediaRetirements.delete(e);}),this.peerStreams.closePeer(e);for(let a of this.closeListeners.get(e)??[])a();this.closeListeners.delete(e),this.rawListeners.delete(e);for(let a of this.connectionListeners.values())a.delete(e);return r}receive(e,t){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 r of this.rawListeners.get(i)??[])r(t);return}if(n.capability===this.capabilityKey){if(n.kind==="raw"){for(let r of this.rawListeners.get(i)??[])r(n.value);return}this.deliverEnvelope(i,n);}}deliverEnvelope(e,t){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 r=n.get(t);r||(r=new a(a=>e.send(a)),n.set(t,r)),r.send(i).catch(()=>{});}},C=class{constructor(e,t,i,n,r){this.kind=e;this.id=t;this.client=i;this.onClosed=n;this.roomFanoutFactory=r;this.closed=false;y.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)}setArchitecture(e){this.roomFanoutFactory?.setArchitecture(e);}async close(){if(!this.closed){this.closed=true,await this.messages?.close();try{await this.client.advanced.runtime.shutdown();}finally{y.delete(this),this.onClosed();}}}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))}},w=class extends C{constructor(t,i,n,r){super("devices",t,i,n);this.roster=r;this.kind="devices";this.localId=()=>this.client.devices.localId();this.localInfo=()=>this.client.devices.localInfo();this.list=async()=>this.roster.mergeDevices(await this.client.devices.list());this.listWithStatus=async()=>this.roster.mergeStatus(await this.client.devices.listWithStatus());this.watch=t=>this.client.devices.watch(i=>t(this.roster.mergeDevices(i)));this.connect=this.client.devices.connect;this.disconnect=this.client.devices.disconnect;let a=i.devices.list,s=i.devices.listWithStatus,c=i.devices.watch,l=i.devices.watchWithStatus,d=g=>(this.roster.reconcileLiveSnapshot(g),g),u=async()=>this.roster.mergeDevices(d(await a())),m=async()=>this.roster.mergeStatus(await s()),v=g=>c(M=>g(this.roster.mergeDevices(d(M)))),p=g=>l(M=>g(this.roster.mergeStatus(M))),P=Object.create(i);Object.defineProperties(P,{listDevices:{value:u,enumerable:false},listDeviceStatus:{value:m,enumerable:false},watchDevices:{value:v,enumerable:false},watchDeviceStatus:{value:p,enumerable:false},devices:{value:{...i.devices,list:u,listWithStatus:m,watch:v,watchWithStatus:p},enumerable:true}}),y.set(this,P),this.stopRosterSync=c(d);}replaceEnrolledDevices(t){this.roster.replace(t);}removeEnrolledDevice(t){this.roster.remove(t);}retainCurrentEnrolledDevice(t){this.roster.retain(t);}async close(){this.stopRosterSync(),await super.close();}},q=class extends C{constructor(t,i,n,r){super("space",t,i,n);this.delivery=r;this.kind="space";this.leave=()=>this.close();}},W=class extends C{constructor(t,i,n,r){super("ticket",t,i,n);this.token=r;this.kind="ticket";}},E=class{constructor(e,t){this.options=e;this.internals=t;this.channels=new N;this.broadcastSessions=new Set;this.broadcastPublishers=new Set;this.handles=new Set;this.activations=new Map;this.authorityCallableIds=new WeakMap;this.nextAuthorityCallableId=1;this.closed=false;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:re(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());for(let n of this.handles)n instanceof w&&n.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=ie(e),r=await this.deviceId();await(await this.controlPlane()).revokeDevice(i,r,n);for(let a of this.handles)a instanceof w&&a.removeEnrolledDevice(n);n===r&&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();for(let n of this.handles)n instanceof w&&n.retainCurrentEnrolledDevice(i);}e.exceptCurrent!==true&&this.retireAuthCapabilities(t);}};this.spaces={join:(e,t={})=>this.activateOnce(`space:${T(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-2MUFAJ4M.js')).joinRoom(this,e,t)};this.tickets={issue:(e,t={})=>this.activateOnce(`ticket:${T(e)}`,JSON.stringify({identity:t.identity??null,maxPeers:t.maxPeers??null,advancedFanout:t.advancedFanout===true}),void 0,()=>this.issueTicket(e,t))};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,r={verificationKey:i,open:async a=>{if(n)throw new Error("[OpenRTC] Broadcast publisher is closed.");return this.assertOpen(),this.validateBroadcastGrant(a),this.wrapBroadcastSession(await t.open(a))},close:async()=>{n||(n=true,await t.close(),this.broadcastPublishers.delete(r));}};return this.broadcastPublishers.add(r),r},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,...r}=t;return i.invite(e,r,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=ue(e.apiKey),this.appTag=`app_${this.apiKey.slice(-16)}`,this.usage=new K(e.usage);}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-IIPEJ77Q.js'),e]).then(([{ControlPlane:t},i])=>new t(this.apiKey,this.internals.endpoints??a$1,i,this.options.trust?.attestation,{beforeLogicalOperation:n=>this.usage.assertCanSpend(n),onLogicalOperation:n=>this.usage.record(n),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-EIMDBAQS.js').then(({browserDeviceKeyProvider:e})=>e)))}sessionPlane(){return this.sessionPlanePromise??(this.sessionPlanePromise=this.makeControlPlane(import('./deviceKey-EIMDBAQS.js').then(async({createDeviceKey:e})=>{let t=await e();return {getOrCreate:async()=>t}})))}assertOpen(){if(this.closed)throw new Error("[OpenRTC] Client is closed.")}activateOnce(e,t,i,n){this.assertOpen();let r=this.activations.get(e);if(r){if(r.fingerprint!==t||r.auth!==i)throw new Error(`[OpenRTC] ${e} is already active with different options.`);return r.promise}let a={fingerprint:t,auth:i},s=n().then(c=>(a.handle=c,c)).catch(c=>{throw this.activations.get(e)===a&&this.activations.delete(e),c});return a.promise=s,this.activations.set(e,a),s}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):pe(this.appTag);return ie(e)}runtimeOptions(e){let t=this.options.transports,i=e.irohRelay&&t?.relay!==false,n=e.managedTurn&&t?.relay!==false,r=t?.privacy==="relay-only";if(r&&!i)throw new Error("[OpenRTC] transports.privacy: relay-only requires relay access.");let a=r?d(t?.priority?[...t.priority]:void 0,true):t?.priority?[...t.priority]:void 0,s=t?.webrtc,c=typeof s=="object"&&s.iceServers?.some(b$4)===true,l=!r||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$1).gateway,environment:"production",grantProvider:e.grantProvider,testingAllowInsecureLoopback:this.internals.testingAllowInsecureLoopback},turnCredentialsProvider:n?e.turnProvider:void 0,transports:{relay:i,iroh:r?{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 s=="object"?r?{...s,privacyMode:true,useTurn:true,useDefaultIceServers:false}:s:s===true?r?{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:a},transportPriority:a}}async activate(e){let t=e.authority?null:e.controlPlane??await this.controlPlane(),i=this.options.transports?.relay!==false,n=e.source.irohRelay&&i,r=e.source.managedTurn&&i,a={irohRelay:n,managedTurn:r,moq:n&&!!this.options.transports?.moq,ble:this.options.transports?.ble===true,advancedFanout:e.architecture==="sparse"||e.advancedFanout===true,durableMembership:e.durableMembership===true},s=e.source,c=null,l=()=>e.authority?{userId:e.principalId}:{userId:e.principalId,token:s.token,tokenProvider:async()=>s.token,expiresAtMs:s.expiresAtMs},d=e.authority?.devicePublicKeyX??String((await t.deviceSigningPublicKey()).x??""),u=this.runtimeOptions({avenue:e.source.avenue,grantProvider:e.authority?.grantProvider??t.grantProvider(e.source,{maxPeers:e.maxPeers,features:a,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 p=>{s={...s,...p},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??(p=>t.signDeviceBytes(p)),irohRelay:e.source.irohRelay,managedTurn:e.source.managedTurn,turnProvider:r&&t?t.turnProvider(()=>s):void 0,deviceName:e.deviceName,devicePlatform:e.devicePlatform,initialAutoConnectExcludedDeviceIds:e.initialAutoConnectExcludedDeviceIds,nativeAuth:e.nativeAuth}),[m,{wrapAssembly:v}]=await Promise.all([this.internals.runtimeFactory(u),import('./coreClient.js')]);c=v(m,this.internals.platform==="native"?"native":"web"),await c.setAuth(l()),this.channels.attach(c,e.defaultDelivery??"reliable");try{this.usage.assertCanSpend("coordination.connection.open"),await c.devices.startSession({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(p){throw this.channels.detach(c),await c.advanced.runtime.shutdown().catch(()=>{}),p}return this.usage.record("coordination.connection.open"),c}trackHandle(e){return this.handles.add(e),e}async startDevices(e={}){this.assertOpen();let t=re(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:r}=await import('./deviceProfile-CR2C7OYR.js'),a=r(e.profile,this.internals.platform==="native"?"native":"web"),s=await this.controlPlane(),c=await s.deviceCertificate(i,n,void 0,a),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:a.name,devicePlatform:a.platform,deviceMetadata:a.metadata,nativeAuth:i}),d=[];if(this.internals.platform!=="native")try{d=await s.listEnrolledDevices(i,n);}catch(v){throw this.channels.detach(l),await l.advanced.runtime.shutdown().catch(()=>{}),v}let{AuthenticatedDeviceRoster:u}=await import('./deviceRoster-EUF6BBF5.js'),m;return m=new w(c.principalId,l,()=>{this.channels.detach(l),this.onClosed(m);},new u(d)),this.handles.add(m),m}async joinSpace(e,t={}){this.assertOpen();let i=T(e),n=await(t.identity==="session"?this.sessionPlane():this.controlPlane()),r=await n.capability("space",i,t.maxPeers,t.advancedFanout),a=String(b$1(r.token).principalId),s=await this.activate({kind:"space",id:i,source:r,principalId:a,deviceId:oe(r),maxPeers:t.maxPeers,autoConnect:true,defaultDelivery:t.payload??"reliable",advancedFanout:t.advancedFanout,controlPlane:n}),c;return c=new q(i,s,()=>{this.channels.detach(s),this.onClosed(c);},t.payload??"reliable"),this.handles.add(c),c}async openAuthorityRoom(e){return (await import('./room-2MUFAJ4M.js')).openAuthorityRoom(this,e)}async issueTicket(e,t={}){this.assertOpen();let i=T(e),n=await(t.identity==="session"?this.sessionPlane():this.controlPlane()),r=await n.capability("ticket",i,t.maxPeers,t.advancedFanout),a=String(b$1(r.token).principalId),s=await this.activate({kind:"ticket",id:i,source:r,principalId:a,deviceId:oe(r),maxPeers:t.maxPeers,autoConnect:false,advancedFanout:t.advancedFanout,controlPlane:n}),c;return c=new W(i,s,()=>{this.channels.detach(s),this.onClosed(c);},r.token),this.handles.add(c),c}async close(){if(!this.closed){this.closed=true;try{await Promise.all([...this.handles].map(e=>e.close()));}finally{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?.();}}}};function Be(o,e){return new E(o,e)}function ke(o,e){if(!(o instanceof E))throw new TypeError("[OpenRTC] ServiceNode requires a client created by this OpenRTC package.");return o.openAuthorityRoom(e)}export{I as a,B as b,de as c,xe as d,T as e,ie as f,oe as g,C as h,Be as i,ke as j};