openrtc 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +26 -3
  2. package/dist/DelegatingRuntimeAdapter-CjHzBEBA.d.ts +180 -0
  3. package/dist/{IpcRuntimeAdapter-CT-W0Mtp.d.ts → IpcRuntimeAdapter-CtckyMol.d.ts} +2 -1
  4. package/dist/auth/index.js +1 -1
  5. package/dist/auth/internal.js +1 -1
  6. package/dist/chunk-3VTF5RKW.js +1 -0
  7. package/dist/chunk-JXGKO7SX.js +1 -0
  8. package/dist/chunk-MFT6SOZ6.js +3 -0
  9. package/dist/chunk-SGZWR63E.js +1 -0
  10. package/dist/chunk-VARALO7G.js +1 -0
  11. package/dist/chunk-WOHFM6DI.js +2 -0
  12. package/dist/chunk-YHJOXD46.js +2 -0
  13. package/dist/{factories-0TxDPMeu.d.ts → factories-CwZiIRg1.d.ts} +412 -226
  14. package/dist/index.d.ts +100 -6
  15. package/dist/index.js +2 -1
  16. package/dist/openrtc_bg.wasm +0 -0
  17. package/dist/runtime/WasmRuntimeAdapter.d.ts +2 -1
  18. package/dist/runtime/WasmRuntimeAdapter.js +1 -1
  19. package/dist/runtime/index.d.ts +205 -391
  20. package/dist/runtime/index.js +1 -1
  21. package/dist/runtime/tauri.d.ts +5 -6
  22. package/dist/runtime/tauri.js +1 -1
  23. package/dist/transport/index.d.ts +11 -0
  24. package/dist/transport/index.js +1 -0
  25. package/dist/{DelegatingRuntimeAdapter-CW8d78dZ.d.ts → types-DyCGvj9l.d.ts} +200 -170
  26. package/package.json +12 -10
  27. package/dist/chunk-4MH42GUI.js +0 -2
  28. package/dist/chunk-CQAKCS2S.js +0 -4
  29. package/dist/chunk-D54VGRRH.js +0 -1
  30. package/dist/chunk-DIQYFAGL.js +0 -2
  31. package/dist/chunk-PZ25OCVG.js +0 -2
  32. package/dist/chunk-UVASANPG.js +0 -1
  33. package/wasm/README.md +0 -64
  34. package/wasm/openrtc.d.ts +0 -320
  35. package/wasm/openrtc.js +0 -2290
  36. package/wasm/openrtc_bg.wasm +0 -0
  37. package/wasm/openrtc_bg.wasm.d.ts +0 -113
  38. package/wasm/package.json +0 -16
@@ -1 +0,0 @@
1
- import {w,v}from'./chunk-PZ25OCVG.js';var n=class extends w{constructor(e){super(new v(e));}setWasmClient(e){this.unwrap().setWasmClient(e);}};export{n as a};
@@ -1,2 +0,0 @@
1
- import {p,w,v,t,s,b,u,i,k,a as a$1,l as l$1,m,n,o}from'./chunk-PZ25OCVG.js';import {a,e}from'./chunk-4MH42GUI.js';function y(p,e="native runtime"){if(!p||typeof p!="object")throw new Error(`[openrtc] ${e} requires a valid IPC bridge object.`);if(typeof p.invoke!="function")throw new Error(`[openrtc] ${e} IPC bridge is missing invoke(command, args).`);if(typeof p.listen!="function")throw new Error(`[openrtc] ${e} IPC bridge is missing listen(event, handler).`);return p}var D=null;async function H(){return D||(D=(async()=>{let p="openrtc-tauri",e="../../../tauri/src/runtime/ipc";try{return await import(p)}catch(t){try{return await import(e)}catch(i){let r=new Error("[openrtc] Native support now lives in the first-party `openrtc-tauri` package. Install `openrtc-tauri` (and `@tauri-apps/api`) or pass an explicit IPC bridge to OpenRTC.native(...).");throw r.cause={packageError:t,workspaceError:i},r}}})()),D}function q(){let p=null,e=async()=>(p||(p=H().then(t=>y(t.createTauriIpcBridge(),"openrtc-tauri"))),p);return {async invoke(t,i){return (await e()).invoke(t,i)},async listen(t,i){return (await e()).listen(t,i)},async isAvailable(){try{let t=await e();return typeof t.isAvailable=="function"?!!await t.isAvailable():!0}catch{return false}}}}var l=class l{constructor(e){this.subscriptionNonce=0;this.lastSyncedAuthToken=null;this.cachedLocalDeviceId=null;this.cachedLocalDeviceName=null;this.tauriCoreAvailability=null;this.tauriCoreAvailabilityValue=null;this.tauriCoreAvailabilityCheckedAtMs=0;this.authSyncInFlight=null;this.lastNativeAuthSyncAtMs=0;this.hasLoggedMissingAuthForDevices=false;this.nativeRtdbPresenceScope=null;this.nativeRtdbTicketVersion=0;this.lastNativePresenceTicket=null;this.nativeRtdbPresenceDisabledForSession=false;this.fallback=new v(e),this.app=this.fallback.app,this.auth=this.fallback.auth,this.appTag=this.fallback.tag,this.options=this.fallback.getResolvedOptions(),this.transportOptions=e.transports,this.strictMode=e.strictMode===true,this.turnCredentialsProvider=e.turnCredentialsProvider,this.allowWasmFallback=e.allowWasmFallback??false,this.ipcBridge=y(e.ipcBridge??q(),"NativeIpcBridge");}get currentUser(){return this.fallback.currentUser}get tag(){return this.fallback.tag}getRuntimeCapabilities(){let e=t(s);return e.fallback.wasm=this.allowWasmFallback,e}setWasmClient(e){if(!this.allowWasmFallback){let t="[NativeIpcBridge][NATIVE-GUARD] Refusing WasmClient attachment because native IPC is authoritative and WASM fallback is disabled.";throw console.error(t,{capabilities:this.getRuntimeCapabilities()}),new Error(t)}this.fallback.setWasmClient(e);}onAuthChange(e){return this.fallback.onAuthChange(e)}checkForSSOToken(){return this.fallback.checkForSSOToken()}waitForAuth(){return this.fallback.waitForAuth()}signInAnonymously(){return this.fallback.signInAnonymously()}getTurnCredentials(){return this.fallback.getTurnCredentials()}cleanupStaleDevices(){return this.fallback.cleanupStaleDevices()}sendMessage(e,t,i,r){return this.fallback.sendMessage(e,t,i,r)}pollMessages(e){return this.fallback.pollMessages(e)}createSession(e){return this.fallback.createSession(e)}updateSession(e,t){return this.fallback.updateSession(e,t)}openPeerBi(e,t){return this.fallback.openPeerBi(e,t)}openPeerUni(e,t){return this.fallback.openPeerUni(e,t)}isConnected(e){return this.fallback.isConnected(e)}getAuthContext(){return this.fallback.getAuthContext()}getCurrentUserId(){return this.fallback.getCurrentUserIdForScope()}resolveNativeAuthScopedUserId(e){return this.currentUser?.id??this.getAuthContext()?.userId??e??null}resolveWebLogicalDeviceId(){return this.fallback.getResolvedWebLogicalDeviceId()}normalizeDevice(e,t){return this.fallback.normalizeDeviceRecord(e,t)}matchesTag(e){return this.fallback.matchesLegacyOrCurrentTag(e)}buildNativeRtdbScope(e){if((this.options.discoveryMode??"personal")==="personal")return null;let i=e??this.getCurrentUserId();return i?{kind:"user-scoped",appTag:this.appTag,userId:i}:null}async syncNativeRtdbPresenceTicket(e){if(this.nativeRtdbPresenceDisabledForSession)return;let t=this.buildNativeRtdbScope(),i=await this.resolveLocalDeviceId();if(!(!t||!i))try{if(!this.fallback.rtdbPresence||!this.nativeRtdbPresenceScope){await this.fallback.registerRtdbPresence(t,i,this.nativeRtdbTicketVersion),this.nativeRtdbPresenceScope=t,this.lastNativePresenceTicket=e,b("[NativeIpcBridge][RTDB] registered native presence ticket state",{deviceId:i,ticketVersion:this.nativeRtdbTicketVersion,ticketFingerprint:u(e)});return}let a=this.lastNativePresenceTicket!==e;(this.nativeRtdbPresenceScope.kind!==t.kind||t.kind==="user-scoped"&&this.nativeRtdbPresenceScope.kind==="user-scoped"&&(this.nativeRtdbPresenceScope.appTag!==t.appTag||this.nativeRtdbPresenceScope.userId!==t.userId))&&(await this.fallback.registerRtdbPresence(t,i,this.nativeRtdbTicketVersion),this.nativeRtdbPresenceScope=t),a&&(this.nativeRtdbTicketVersion+=1,await this.fallback.rtdbPresence?.bumpTicketVersion(t,i,this.nativeRtdbTicketVersion),b("[NativeIpcBridge][RTDB] bumped native ticketVersion after managed ticket change",{deviceId:i,ticketVersion:this.nativeRtdbTicketVersion,ticketFingerprint:u(e)})),this.nativeRtdbPresenceScope=t,this.lastNativePresenceTicket=e;}catch(r){this.nativeRtdbPresenceDisabledForSession=true,this.nativeRtdbPresenceScope=null,this.lastNativePresenceTicket=null,console.warn("[NativeIpcBridge][RTDB] native RTDB presence mirror unavailable; continuing with Firestore/native presence.",r);}}async markNativeRtdbOffline(){if(!this.nativeRtdbPresenceScope)return;let e=await this.resolveLocalDeviceId();if(e)try{await this.fallback.rtdbPresence?.markOffline(this.nativeRtdbPresenceScope,e,this.nativeRtdbTicketVersion),b("[NativeIpcBridge][RTDB] marked native presence offline",{deviceId:e,ticketVersion:this.nativeRtdbTicketVersion});}catch(t){console.warn("[NativeIpcBridge][RTDB] failed to mark native presence offline:",t);}finally{this.nativeRtdbPresenceScope=null,this.nativeRtdbTicketVersion=0,this.lastNativePresenceTicket=null,this.nativeRtdbPresenceDisabledForSession=false;}}normalizeNativeIceServer(e){let t=e.urls,i=Array.isArray(t)?t.filter(r=>typeof r=="string"&&r.trim().length>0):typeof t=="string"&&t.trim().length>0?[t]:[];return i.length===0?null:{urls:i,username:typeof e.username=="string"&&e.username.trim().length>0?e.username:void 0,credential:typeof e.credential=="string"&&e.credential.trim().length>0?e.credential:void 0}}filterNativeStunServers(e){return e.map(t=>({...t,urls:t.urls.filter(i=>!i.startsWith("stun:"))})).filter(t=>t.urls.length>0)}nativeIceServerHasTurnUrl(e){return e.urls.some(t=>t.startsWith("turn:")||t.startsWith("turns:"))}async loadNativeTurnIceServers(){if(typeof this.turnCredentialsProvider!="function")return [];let e=await this.turnCredentialsProvider().catch(t=>(console.warn("[NativeIpcBridge] TURN credential provider failed:",t),null));return !e||!Array.isArray(e.iceServers)?[]:e.iceServers.map(t=>this.normalizeNativeIceServer(t)).filter(t=>!!t)}async buildNativeTransportConfigPayload(){let e=this.transportOptions;if(!e)return null;let t=null;if(e.webrtc===true||e.webrtc&&typeof e.webrtc=="object"){let r=e.webrtc===true?null:e.webrtc,a=Array.isArray(r?.iceServers)?r.iceServers.map(u=>this.normalizeNativeIceServer(u)).filter(u=>!!u):[],n=this.strictMode||r?.privacyMode===true;(this.strictMode||r?.privacyMode===true||r?.useTurn===true)&&(a=[...a,...await this.loadNativeTurnIceServers()]),n&&(a=this.filterNativeStunServers(a));let s=a.some(u=>this.nativeIceServerHasTurnUrl(u)),c=n&&s;n&&!s&&console.warn("[NativeIpcBridge] Relay-only WebRTC requested, but no TURN servers are configured; using ICE policy all"),(a.length>0||c)&&(t={iceServers:a.length>0?a:void 0,privacyMode:c});}let i=null;if(e.moq&&typeof e.moq=="object"){let r=typeof e.moq.relayUrl=="string"&&e.moq.relayUrl.trim().length>0?e.moq.relayUrl:void 0;r&&(i={relayUrl:r});}return !t&&!i?null:{webrtc:t,moq:i}}isTauriEnv(){return a()}sleep(e){return new Promise(t=>setTimeout(t,e))}nextConnectionEventRetryDelayMs(e){let t=l.CONNECTION_EVENT_RETRY_MIN_DELAY_MS*Math.pow(2,Math.max(0,e-1));return Math.min(l.CONNECTION_EVENT_RETRY_MAX_DELAY_MS,t)}async clearNativeAuthRelay(e){if(await this.canUseTauriIpc())try{await this.invokeIpc("desktop_set_pluto_auth_token",{authToken:null,refreshToken:null}),this.lastSyncedAuthToken=null,this.lastNativeAuthSyncAtMs=0,b(`[NativeIpcBridge] cleared native auth relay (${e})`);}catch(t){console.warn(`[NativeIpcBridge] failed clearing native auth relay (${e}):`,t);}}async canUseTauriIpc(){return this.ipcBridge?typeof this.ipcBridge.isAvailable=="function"?!!await this.ipcBridge.isAvailable():true:typeof window>"u"?false:this.tauriCoreAvailabilityValue===true?true:this.tauriCoreAvailabilityValue===false&&Date.now()-this.tauriCoreAvailabilityCheckedAtMs<l.TAURI_IPC_NEGATIVE_CACHE_MS?false:(this.tauriCoreAvailability||(this.tauriCoreAvailability=(async()=>{try{if(this.isTauriEnv())return this.tauriCoreAvailabilityValue=!0,this.tauriCoreAvailabilityCheckedAtMs=Date.now(),!0;try{return await this.invokeIpc("rtc_native_status"),b("[NativeIpcBridge] Resolved Tauri IPC via rtc_native_status probe"),this.tauriCoreAvailabilityValue=!0,this.tauriCoreAvailabilityCheckedAtMs=Date.now(),!0}catch(e){let t=String(e?.message??e??"");return t.includes("__TAURI_INTERNALS__")||t.includes("Cannot read properties of undefined")||t.includes("window is not defined")?(this.tauriCoreAvailabilityValue=!1,this.tauriCoreAvailabilityCheckedAtMs=Date.now(),!1):(b("[NativeIpcBridge] Tauri IPC probe reached native layer (command-level error acceptable)"),this.tauriCoreAvailabilityValue=!0,this.tauriCoreAvailabilityCheckedAtMs=Date.now(),!0)}}catch{return this.tauriCoreAvailabilityValue=false,this.tauriCoreAvailabilityCheckedAtMs=Date.now(),false}})().finally(()=>{this.tauriCoreAvailability=null;})),this.tauriCoreAvailability)}async invokeIpc(e,t,i){let r=this.ipcBridge.invoke(e,t),a=i?.timeoutMs??l.MANAGED_SESSION_IPC_TIMEOUT_MS;return a===null||a<=0?r:this.withTimeout(r,a,e)}withTimeout(e,t,i){let r=null,a=new Promise((n,o)=>{r=setTimeout(()=>{o(new Error(`${i} timeout after ${t}ms`));},t);});return Promise.race([e,a]).finally(()=>{r&&clearTimeout(r);})}isRetryableManagedSessionStartError(e){let t=(e instanceof Error?e.message:String(e??"")).toLowerCase();return t?!!(t.includes("start_rtc_managed_session")&&t.includes("timeout after")||t.includes("callback")&&t.includes("id")||t.includes("channel closed")||t.includes("ipc channel closed")):false}async listenIpc(e,t){return this.ipcBridge.listen(e,i=>{t({payload:i});})}async shouldUseTauriSignaling(){if(await this.canUseTauriIpc())return true;if(this.allowWasmFallback)return false;throw new Error("[pluto-rtc] Tauri runtime adapter requires native IPC, but it is unavailable.")}async signInWithPluto(){if(!await this.canUseTauriIpc()){await this.fallback.signInWithPluto();return}let e$1=await this.invokeIpc("rtc_sign_in_with_pluto"),t=typeof e$1?.customToken=="string"?e$1.customToken.trim():"";if(!t)throw new Error("[pluto-rtc] Native Pluto SSO did not return a custom token.");await e().signInWithCustomTokenValue(t),await this.ensureNativeAuth("pluto-sso",{requireToken:true,maxWaitMs:1e4});}async setAuthContext(e){if(await this.fallback.setAuthContext(e),!e?.token)await this.markNativeRtdbOffline(),await this.clearNativeAuthRelay("setAuthContext");else if(!await this.ensureNativeAuth("setAuthContext",{requireToken:true,maxWaitMs:l.AUTH_REQUIRED_WAIT_MS}))throw new Error("Native auth token unavailable for setAuthContext")}async signOut(){await this.fallback.signOut(),await this.markNativeRtdbOffline(),await this.clearNativeAuthRelay("signOut");}async stopAuthScopedActivity(e){let t=this.resolveNativeAuthScopedUserId(e?.userId??null),i$1=await this.shouldUseTauriSignaling();if(i("NativeIpcBridge.stopAuthScopedActivity",{userId:t,useTauri:i$1}),i$1)try{await Promise.allSettled([this.revokeSessionTokensByScope("user-device"),this.invokeIpc("stop_rtc_presence_loop"),this.invokeIpc("stop_rtc_auto_connect"),t?this.invokeIpc("set_rtc_offline",{userId:t}):Promise.resolve()]);}catch(r){console.warn("[NativeIpcBridge] Failed to stop native auth-scoped RTC activity:",r);}await this.markNativeRtdbOffline(),await this.fallback.stopAuthScopedActivity({userId:t});}async ensureNativeAuthOnce(e,t){if(!await this.canUseTauriIpc())return true;if(this.authSyncInFlight)return this.authSyncInFlight;let i=(async()=>{try{if(!this.currentUser)return console.warn(`[NativeIpcBridge] auth sync skipped (${e}): no current user`),!t;let r=Date.now()-this.lastNativeAuthSyncAtMs>=480*1e3,a=this.currentUser?.getToken?await this.currentUser.getToken(r):null,o=this.getAuthContext()?.refreshToken??this.auth?.currentUser?.refreshToken??null;if(!a)return console.warn(`[NativeIpcBridge] auth sync skipped (${e}): missing token for user ${this.currentUser?.id}`),!t;if(a===this.lastSyncedAuthToken)return !0;let s=await Promise.allSettled([this.invokeIpc("desktop_set_pluto_auth_token",{authToken:a,refreshToken:o})]);return s[0]?.status==="rejected"?(console.warn(`[NativeIpcBridge] desktop auth relay failed (${e}):`,s[0].reason),!1):(this.lastSyncedAuthToken=a,this.lastNativeAuthSyncAtMs=Date.now(),b(`[NativeIpcBridge] auth token relayed to native runtime (${e}) user_id=${this.currentUser?.id}`),!0)}catch(r){return console.error("[NativeIpcBridge] auth sync failed:",r),false}})();this.authSyncInFlight=i;try{return await i}finally{this.authSyncInFlight===i&&(this.authSyncInFlight=null);}}async ensureNativeAuth(e="runtime",t){if(!await this.canUseTauriIpc())return true;let i=t?.requireToken??false,r=t?.maxWaitMs??(i?l.AUTH_REQUIRED_WAIT_MS:0),a=t?.pollMs??250,n=Date.now()+Math.max(0,r);for(;;){if(await this.ensureNativeAuthOnce(e,i))return true;if(!i||Date.now()>=n)return false;await this.sleep(a);}}async resolveLocalDeviceId(){if(this.cachedLocalDeviceId)return this.cachedLocalDeviceId;if(await this.canUseTauriIpc())try{let t=await this.invokeIpc("get_rtc_local_device_info"),i=typeof t?.device_id=="string"?t.device_id:"",r=typeof t?.device_name=="string"?t.device_name.trim():"";if(i)return this.cachedLocalDeviceId=i,r&&(this.cachedLocalDeviceName=r),i}catch(t){console.warn("[NativeIpcBridge] get_rtc_local_device_info failed:",t);}let e=this.resolveWebLogicalDeviceId();return this.cachedLocalDeviceId=e,e}async resolveLocalDeviceName(){if(this.cachedLocalDeviceName)return this.cachedLocalDeviceName;if(await this.canUseTauriIpc())try{let e=await this.invokeIpc("get_rtc_local_device_info"),t=typeof e?.device_name=="string"?e.device_name.trim():"";if(t){let i=this.normalizeNativeDeviceName(t);return this.cachedLocalDeviceName=i,i}}catch(e){console.warn("[NativeIpcBridge] get_rtc_local_device_info failed:",e);}return this.defaultDeviceNameFallback()}normalizeNativeDeviceName(e){let t=e.trim();if(!t)return this.defaultDeviceNameFallback();if(t==="Desktop Device"){let i=this.defaultDeviceNameFallback();if(i!=="Desktop Device")return i}return t}defaultDeviceNameFallback(){if(typeof window>"u"||typeof navigator>"u")return "Desktop Device";let e=navigator.userAgent||"";return /iPhone|iPad|iPod/i.test(e)?"iPhone":/Android/i.test(e)?"Android":"Desktop Device"}inferNativePlatformTypeFallback(){if(typeof window>"u"||typeof navigator>"u")return "desktop";if(!this.isTauriEnv())return "web";let e=navigator.userAgent||"";return /iPhone|iPad|iPod|Android|Mobile/i.test(e)?"mobile":"desktop"}withPresenceMetadata(e,t){try{let i=e?JSON.parse(e):{};return JSON.stringify({...i,deviceId:t,plutoVersion:"0.1.0-desktop"})}catch{return JSON.stringify({deviceId:t,plutoVersion:"0.1.0-desktop",rawMetadata:e})}}async searchDevices(e){if(await this.shouldUseTauriSignaling()){if(!await this.ensureNativeAuth("searchDevices",{requireToken:true,maxWaitMs:l.AUTH_REQUIRED_WAIT_MS}))throw new Error("Native auth token unavailable for searchDevices");let i=await this.invokeIpc("search_rtc_devices",{userId:this.currentUser?.id});if(Array.isArray(i?.devices)){let r=i.devices.map(a=>this.normalizeDevice(a));return e&&(r=r.filter(a=>a.ticket!==e&&a.deviceId!==e&&a.nodeId!==e)),r}throw typeof i?.message=="string"?new Error(String(i.message)):new Error("Unexpected response for search_rtc_devices")}return this.fallback.searchDevices(e)}async listDevicesWithStatus(){if(await this.shouldUseTauriSignaling()){if(!await this.ensureNativeAuth("listDevicesWithStatus",{requireToken:true,maxWaitMs:l.AUTH_REQUIRED_WAIT_MS}))throw new Error("Native auth token unavailable for listDevicesWithStatus");let t=await this.invokeIpc("search_rtc_devices_with_status",{userId:this.currentUser?.id});if(Array.isArray(t?.devices)){let i=t.devices.filter(n=>this.matchesTag(n)).map(n=>k(n)),r=await this.resolveLocalDeviceId().catch(()=>null),a=!!r&&i.some(n=>n.deviceId===r);return a$1("[NativeIpcBridge] listDevicesWithStatus result",{count:i.length,localDeviceId:r,selfIncluded:a,devices:i.map(n=>({deviceId:n.deviceId,deviceName:n.deviceName,online:!!n.online,connectionStatus:n.connectionStatus,settledReady:!!n.settledReady,peerHealth:n.peerHealth,scopes:n.scopes,connectionId:n.connectionId??null,deviceIdHint:n.deviceIdHint??null,nodeId:n.nodeId??null,activeTransport:n.activeTransport??null,parallelTransport:n.parallelTransport??null}))}),r&&!a&&a$1("[NativeIpcBridge] native status snapshot excludes local device by design",{localDeviceId:r,count:i.length}),i}throw typeof t?.message=="string"?new Error(String(t.message)):new Error("Unexpected response for search_rtc_devices_with_status")}return this.fallback.listDevicesWithStatus()}async getPeerSession(e){if(await this.shouldUseTauriSignaling()){let t=await this.invokeIpc("get_rtc_peer_session",{id:e});return !t||typeof t!="object"?null:l$1(t)}return this.fallback.getPeerSession(e)}async listPeerSessions(){if(await this.shouldUseTauriSignaling()){let e=await this.invokeIpc("list_rtc_peer_sessions");return (Array.isArray(e)?e:[]).map(t=>l$1(t))}return this.fallback.listPeerSessions()}async waitForSettledPeer(e,t){if(await this.shouldUseTauriSignaling()){let i=typeof t=="number"?Math.max(l.MANAGED_SESSION_IPC_TIMEOUT_MS,t+1e3):l.MANAGED_SESSION_IPC_TIMEOUT_MS,r=await this.invokeIpc("wait_for_rtc_settled_peer",{id:e,timeoutMs:t},{timeoutMs:i});return !r||typeof r!="object"?null:l$1(r)}return this.fallback.waitForSettledPeer(e,t)}async resolvePeerConnectionRecords(e){if(await this.shouldUseTauriSignaling()){let t=await this.invokeIpc("resolve_rtc_peer_connection_records",{id:e});return (Array.isArray(t)?t:[]).map(i=>m(i))}return this.fallback.resolvePeerConnectionRecords(e)}async resolvePeerIdentity(e){if(await this.shouldUseTauriSignaling()){let t=await this.invokeIpc("resolve_rtc_peer_identity",{id:e});return n(t)}return this.fallback.resolvePeerIdentity(e)}async setOffline(e){if(await this.shouldUseTauriSignaling())try{if(!await this.ensureNativeAuth("setOffline",{requireToken:!0,maxWaitMs:l.AUTH_REQUIRED_WAIT_MS}))throw new Error("Native auth token unavailable for setOffline");let i=this.getCurrentUserId();await this.invokeIpc("set_rtc_offline",{userId:i}),await this.markNativeRtdbOffline();return}catch(t){console.warn("[NativeIpcBridge] set_rtc_offline failed:",t);}return this.fallback.setOffline(e)}async updateDevice(e,t){if(await this.shouldUseTauriSignaling()){if(!await this.ensureNativeAuth("updateDevice",{requireToken:true,maxWaitMs:l.AUTH_REQUIRED_WAIT_MS}))throw new Error("Native auth token unavailable for updateDevice");let a=this.getCurrentUserId();if(!a)throw new Error("updateDevice requires authenticated user scope");try{await this.invokeIpc("update_rtc_device",{userId:a,deviceId:e,deviceName:t.deviceName??null,capabilities:t.capabilities??null,metadata:t.metadata??null});return}catch(n){throw console.warn("[NativeIpcBridge] update_rtc_device failed:",n),n instanceof Error?n:new Error(String(n))}}return this.fallback.updateDevice(e,t)}async deleteDevice(e){if(await this.shouldUseTauriSignaling()){if(!await this.ensureNativeAuth("deleteDevice",{requireToken:true,maxWaitMs:l.AUTH_REQUIRED_WAIT_MS}))throw new Error("Native auth token unavailable for deleteDevice");let r=this.getCurrentUserId();if(!r)throw new Error("deleteDevice requires authenticated user scope");try{await this.invokeIpc("delete_rtc_device",{userId:r,deviceId:e});return}catch(a){throw console.warn("[NativeIpcBridge] delete_rtc_device failed:",a),a instanceof Error?a:new Error(String(a))}}return this.fallback.deleteDevice(e)}async getLocalDeviceInfo(){if(!await this.canUseTauriIpc()){let e=await this.getLocalDeviceId?.();return e?{deviceId:e,deviceName:this.defaultDeviceNameFallback(),platformType:this.inferNativePlatformTypeFallback()}:null}try{let e=await this.invokeIpc("get_rtc_local_device_info"),t=typeof e?.device_id=="string"?e.device_id.trim():"";return t?{deviceId:t,deviceName:this.normalizeNativeDeviceName(typeof e?.device_name=="string"?e.device_name:""),platformType:typeof e?.platform_type=="string"?e.platform_type:this.inferNativePlatformTypeFallback(),capabilities:e?.capabilities??void 0,lastSeenAt:typeof e?.last_seen_at=="string"?e.last_seen_at:void 0}:null}catch(e){return console.warn("[NativeIpcBridge] getLocalDeviceInfo failed:",e),null}}async updateLocalDeviceName(e){if(!await this.canUseTauriIpc())return null;try{let t=await this.invokeIpc("update_rtc_local_device_name",{deviceName:e}),i=typeof t?.device_id=="string"?t.device_id.trim():"";return i?(this.cachedLocalDeviceName=this.normalizeNativeDeviceName(e),{deviceId:i,deviceName:this.cachedLocalDeviceName,platformType:typeof t?.platform_type=="string"?t.platform_type:this.inferNativePlatformTypeFallback(),capabilities:t?.capabilities??void 0,lastSeenAt:typeof t?.last_seen_at=="string"?t.last_seen_at:void 0}):null}catch(t){return console.warn("[NativeIpcBridge] updateLocalDeviceName failed:",t),null}}async startManagedSessionNative(e){if(!await this.shouldUseTauriSignaling())throw new Error("[pluto-rtc] Native IPC unavailable for startManagedSessionNative().");if(!await this.ensureNativeAuth("startManagedSessionNative",{requireToken:true,maxWaitMs:l.AUTH_REQUIRED_WAIT_MS}))throw new Error("Native auth token unavailable for startManagedSessionNative");let i=this.resolveNativeAuthScopedUserId(e.userId);if(!i)throw new Error("Native managed session startup requires a runtime auth-scoped user id.");i!==e.userId&&console.info("[NativeIpcBridge][managed-session][user-id-remap]",{requestedUserId:e.userId,runtimeUserId:this.currentUser?.id??this.getAuthContext()?.userId??null,effectiveUserId:i}),console.info("[NativeIpcBridge][managed-session][start-request]",{requestedUserId:e.userId,runtimeUserId:this.currentUser?.id??this.getAuthContext()?.userId??null,effectiveUserId:i,deviceName:e.deviceName??null,localDeviceId:e.localDeviceId??null,presence:e.presence!==false,autoConnect:e.autoConnect!==false,hasMetadata:typeof e.metadata=="string"&&e.metadata.trim().length>0});let r=await this.buildNativeTransportConfigPayload(),a={userId:i,deviceName:e.deviceName??null,localDeviceId:e.localDeviceId??null,metadata:e.metadata??null,...r?{transports:r}:{},autoConnect:e.autoConnect!==false,presence:e.presence!==false,apiKey:this.options.apiKey??null},n=null,o=null;for(let h=1;h<=l.MANAGED_SESSION_IPC_MAX_ATTEMPTS;h+=1)try{n=await this.invokeIpc("start_rtc_managed_session",a,{timeoutMs:l.MANAGED_SESSION_IPC_TIMEOUT_MS}),o=null;break}catch(f){o=f;let w=this.isRetryableManagedSessionStartError(f),T=l.MANAGED_SESSION_IPC_MAX_ATTEMPTS-h;if(console.warn("[NativeIpcBridge][managed-session][ipc-attempt-failed]",{attempt:h,retryable:w,remaining:T,message:f instanceof Error?f.message:String(f)}),!w||T<=0)throw f;await this.ensureNativeAuth("startManagedSessionNative-retry",{requireToken:true,maxWaitMs:5e3}),await this.sleep(250*h);}if(!n&&o)throw o instanceof Error?o:new Error(String(o));let s=typeof n?.ticket=="string"&&n.ticket.trim().length>0?n.ticket.trim():null;s&&e.presence!==false&&await this.syncNativeRtdbPresenceTicket(s);let c=n?.localDevice&&typeof n.localDevice=="object"?n.localDevice:n?.local_device&&typeof n.local_device=="object"?n.local_device:null,d=c?{deviceId:typeof c.deviceId=="string"?c.deviceId:typeof c.device_id=="string"?c.device_id:"",deviceName:this.normalizeNativeDeviceName(typeof c.deviceName=="string"?c.deviceName:typeof c.device_name=="string"?c.device_name:""),platformType:typeof c.platformType=="string"?c.platformType:typeof c.platform_type=="string"?c.platform_type:"desktop",capabilities:c.capabilities??void 0,lastSeenAt:typeof c.lastSeenAt=="string"?c.lastSeenAt:typeof c.last_seen_at=="string"?c.last_seen_at:void 0}:null,u={localNodeId:typeof n?.localNodeId=="string"?n.localNodeId:typeof n?.local_node_id=="string"?n.local_node_id:null,ticket:s,ticketScope:typeof n?.ticketScope=="string"?n.ticketScope:typeof n?.ticket_scope=="string"?n.ticket_scope:null,presenceStarted:typeof n?.presenceStarted=="boolean"?n.presenceStarted:!!n?.presence_started,autoConnectStarted:typeof n?.autoConnectStarted=="boolean"?n.autoConnectStarted:!!n?.auto_connect_started,localDevice:d?.deviceId?d:null};return console.info("[NativeIpcBridge][managed-session][ipc-started]",{requestedUserId:e.userId,runtimeUserId:this.currentUser?.id??this.getAuthContext()?.userId??null,effectiveUserId:i,localNodeId:u.localNodeId,ticketScope:u.ticketScope,presenceStarted:u.presenceStarted,autoConnectStarted:u.autoConnectStarted,localDeviceId:u.localDevice?.deviceId??null}),u}async reconcileNativeManagedSession(e){if(!await this.shouldUseTauriSignaling())return null;if(!await this.ensureNativeAuth("reconcileNativeManagedSession",{requireToken:true,maxWaitMs:l.AUTH_REQUIRED_WAIT_MS}))throw new Error("Native auth token unavailable for reconcileNativeManagedSession");return this.invokeIpc("reconcile_mobile_rtc_after_resume",{reason:e?.reason??"frontend"})}async getManagedNodeId(e){let t=e?.initializeIfMissing??true;console.info("[NativeIpcBridge][getManagedNodeId] enter",{initializeIfMissing:t});let i=await this.canUseTauriIpc();if(console.info("[NativeIpcBridge][getManagedNodeId] canUseTauriIpc",{canUse:i}),!i)return null;try{console.info("[NativeIpcBridge][getManagedNodeId] invoking get_iroh_node_id");let r=await this.invokeIpc("get_iroh_node_id");if(console.info("[NativeIpcBridge][getManagedNodeId] get_iroh_node_id returned",{existing:r}),r||!t)return r;console.info("[NativeIpcBridge][getManagedNodeId] invoking start_iroh_node");let a=await this.invokeIpc("start_iroh_node");return console.info("[NativeIpcBridge][getManagedNodeId] start_iroh_node returned",{started:a}),a}catch(r){if(console.warn("[NativeIpcBridge] getManagedNodeId failed:",r),!t)return null;throw r}}async getEndpointTicket(){if(!await this.canUseTauriIpc())throw new Error("[pluto-rtc] getEndpointTicket requires native IPC in Tauri runtime.");return this.invokeIpc("get_iroh_endpoint_ticket")}async connectToDevice(e){if(!await this.canUseTauriIpc())throw new Error("[pluto-rtc] connectToDevice requires native IPC in Tauri runtime.");return this.options.authMode!=="anonymous"?await this.ensureNativeAuth("connectToDevice",{requireToken:true,maxWaitMs:l.AUTH_REQUIRED_WAIT_MS}):b("[NativeIpcBridge] connectToDevice using anonymous native ticket path"),this.invokeIpc("connect_to_device",{deviceId:e.deviceId??null,endpointTicket:e.endpointTicket})}async registerSessionToken(e,t,i){await this.canUseTauriIpc()&&await this.invokeIpc("register_session_token",{token:e,scope:t,maxConnections:i});}async getEndpointTicketWithToken(e,t){if(!await this.canUseTauriIpc())return null;try{return await this.invokeIpc("get_endpoint_ticket_with_token",{scope:e,maxConnections:t})}catch{return null}}async validateSessionToken(e,t){if(!await this.canUseTauriIpc())return null;try{return await this.invokeIpc("validate_session_token",{token:e,connectionId:t??null})}catch{return null}}async revokeSessionTokensByScope(e){if(i("NativeIpcBridge.revokeSessionTokensByScope",{grantScope:e}),!await this.canUseTauriIpc())return [];try{return await this.invokeIpc("revoke_session_tokens_by_scope",{scope:e})}catch{return []}}async disconnectDevice(e){if(!await this.canUseTauriIpc())throw new Error("[pluto-rtc] disconnectDevice requires native IPC in Tauri runtime.");await this.invokeIpc("disconnect_device",{deviceId:e});}async setAutoConnectExcluded(e,t){await this.canUseTauriIpc()&&await this.invokeIpc("set_auto_connect_excluded",{deviceId:e,excluded:t});}onDevicesChange(e,t){let i=false,r=new Map,a=null,n=false,o=()=>{let d=Array.from(r.values());t&&(d=d.filter(u=>u.ticket!==t&&u.deviceId!==t&&u.nodeId!==t)),e(d);},s=async()=>{if(!await this.shouldUseTauriSignaling()){console.warn("[NativeIpcBridge] onDevicesChange falling back to wasm signaling (Tauri IPC unavailable)"),c=this.fallback.onDevicesChange(e,t);return}for(;!i;)try{let u=Date.now()+15e3,h=this.getCurrentUserId();for(;!i&&!h&&Date.now()<u&&(this.hasLoggedMissingAuthForDevices||(this.hasLoggedMissingAuthForDevices=!0,b("[NativeIpcBridge] onDevicesChange waiting for authenticated user before subscription")),h=this.getCurrentUserId(),!h);)await this.sleep(250);if(!h){!i&&!n&&(console.warn("[NativeIpcBridge] onDevicesChange could not resolve authenticated user; keeping subscription in retry mode"),e([]),n=!0),await this.sleep(1e3);continue}if(!await this.ensureNativeAuth("onDevicesChange",{requireToken:!0,maxWaitMs:Math.max(0,u-Date.now())})){!i&&!n&&(console.warn("[NativeIpcBridge] onDevicesChange timed out waiting for auth token; keeping subscription in retry mode"),e([]),n=!0),await this.sleep(1e3);continue}this.hasLoggedMissingAuthForDevices=!1,n=!1,b(`[NativeIpcBridge] onDevicesChange starting subscription user_id=${h}`);let w=await this.searchDevices(t);r.clear();for(let b of w)r.set(b.deviceId,b);for(o(),a=(await this.subscribeDevices(h)).getReader();!i;){let{done:b,value:R}=await a.read();if(b||!R)break;for(let I of R){if(I.type==="removed"){r.delete(I.deviceId);continue}let C=I.device?.deviceId;if(!this.matchesTag(I.device??{})){C&&r.delete(C);continue}let S=this.normalizeDevice(I.device);S.deviceId&&r.set(S.deviceId,S);}o();}}catch(d){i||(console.error("[NativeIpcBridge] onDevicesChange stream failed; retrying subscription:",d),await this.sleep(1e3));}finally{if(a){try{await a.cancel();}catch{}a=null;}}},c=()=>{i=true,a&&(a.cancel(),a=null);};return s(),()=>c()}async subscribeDevices(e){if(await this.shouldUseTauriSignaling()){if(!await this.ensureNativeAuth("subscribeDevices",{requireToken:true,maxWaitMs:l.AUTH_REQUIRED_WAIT_MS}))throw new Error("Native auth token unavailable for subscribeDevices");let i=`sub-${Math.random().toString(36).substring(2,11)}`,r=null,a=null,n=false,o=async()=>{if(!n&&(n=true,r&&(await Promise.resolve(r()),r=null),a)){try{await a();}catch{}a=null;}};return new ReadableStream({start:async s=>{b(`[NativeIpcBridge] subscribeDevices request start user_id=${e} request_id=${i}`),r=await this.listenIpc("rtc-device-events",c=>{if(n)return;let d=c.payload;if(d.requestId===i){if(d.type==="deviceEvents"){let u=Array.isArray(d.events)?d.events.length:0;a$1(`[NativeIpcBridge] subscribeDevices event batch request_id=${i} count=${u}`);try{s.enqueue(d.events);}catch{o();}}else if(d.type==="error"&&(console.warn(`[NativeIpcBridge] subscribeDevices stream error request_id=${i}: ${d.message}`),!n)){try{s.error(d.message);}catch{}o();}}}),a=async()=>{await this.invokeIpc("stop_rtc_subscription",{requestId:i});};try{await this.invokeIpc("start_rtc_device_subscription",{requestId:i,userId:e});}catch(c){try{s.error(c);}catch{}await o();}},cancel:async()=>{b(`[NativeIpcBridge] subscribeDevices request stop request_id=${i}`),await o();}})}return this.fallback.subscribeDevices(e)}async subscribeSessions(e){if(await this.shouldUseTauriSignaling()){if(!await this.ensureNativeAuth("subscribeSessions",{requireToken:true,maxWaitMs:l.AUTH_REQUIRED_WAIT_MS}))throw new Error("Native auth token unavailable for subscribeSessions");let i=`sub-${Math.random().toString(36).substring(2,11)}`,r=await this.resolveLocalDeviceId()||e,a=null,n=null,o=false,s=async()=>{if(!o&&(o=true,a&&(await Promise.resolve(a()),a=null),n)){try{await n();}catch{}n=null;}};return new ReadableStream({start:async c=>{a=await this.listenIpc("rtc-session-events",d=>{if(o)return;let u=d.payload;if(u.requestId===i){if(u.type==="sessionEvents")try{c.enqueue(u.events);}catch{s();}else if(u.type==="error"&&!o){try{c.error(u.message);}catch{}s();}}}),n=async()=>{await this.invokeIpc("stop_rtc_subscription",{requestId:i});};try{await this.invokeIpc("start_rtc_session_subscription",{requestId:i,localDeviceId:r});}catch(d){try{c.error(d);}catch{}await s();}},cancel:async()=>{await s();}})}return this.fallback.subscribeSessions(e)}async getLocalDeviceId(){return this.resolveLocalDeviceId()}async updatePresence(e,t,i=true,r=3e5,a){if(await this.shouldUseTauriSignaling())try{if(!await this.ensureNativeAuth("updatePresence",{requireToken:!0,maxWaitMs:l.AUTH_REQUIRED_WAIT_MS}))throw new Error("Native auth token unavailable for updatePresence");let o=this.resolveNativeAuthScopedUserId(),s=await this.resolveLocalDeviceId(),c=await this.resolveLocalDeviceName();await this.invokeIpc("update_rtc_presence",{userId:o,deviceName:c,ticket:t,metadata:this.withPresenceMetadata(a,s)}),await this.syncNativeRtdbPresenceTicket(t);return}catch(n){console.warn("[NativeIpcBridge] update_rtc_presence failed:",n);}return this.fallback.updatePresence(e,t,i,r,a)}startAutoConnect(e,t){(async()=>{try{if(!await this.shouldUseTauriSignaling()){console.error("[NativeIpcBridge] startAutoConnect requires native Rust signaling; IPC unavailable");return}let i=await this.resolveLocalDeviceId()||t;await this.startAutoConnectOnce(e,i);}catch(i){console.warn("[NativeIpcBridge] startAutoConnect failed:",i);}})();}forceReconnectSnapshot(){(async()=>{if(!await this.shouldUseTauriSignaling()){console.error("[NativeIpcBridge] forceReconnectSnapshot requires native Rust signaling; IPC unavailable");return}try{await this.invokeIpc("force_rtc_reconnect_snapshot");}catch(e){console.warn("[NativeIpcBridge] force_rtc_reconnect_snapshot failed:",e);}})();}startPresenceLoop(e,t,i,r,a){(async()=>{try{if(!await this.shouldUseTauriSignaling()){console.warn("[NativeIpcBridge] startPresenceLoop falling back to wasm signaling (Tauri IPC unavailable)"),this.fallback.startPresenceLoop(e,t,i,r,a);return}let n=await this.resolveLocalDeviceId(),o=this.shouldUseResolvedDeviceName(i)?await this.resolveLocalDeviceName():i.trim(),s=this.withPresenceMetadata(a,n);await this.startPresenceLoopOnce(e,t,o,r,s),await this.syncNativeRtdbPresenceTicket(r);}catch(n){console.warn("[NativeIpcBridge] startPresenceLoop failed:",n);}})();}async startAutoConnectOnce(e,t){if(!await this.shouldUseTauriSignaling())throw new Error("[pluto-rtc] Native IPC unavailable for startAutoConnectOnce().");if(!await this.ensureNativeAuth("startAutoConnect",{requireToken:true,maxWaitMs:l.AUTH_REQUIRED_WAIT_MS}))throw new Error("Native auth token unavailable for startAutoConnect");let r=this.resolveNativeAuthScopedUserId(e);if(!r)throw new Error("Native auto-connect requires a runtime auth-scoped user id.");await this.invokeIpc("start_rtc_auto_connect",{userId:r,localDeviceId:t});}async startPresenceLoopOnce(e,t,i,r,a){if(!await this.shouldUseTauriSignaling())throw new Error("[pluto-rtc] Native IPC unavailable for startPresenceLoopOnce().");if(console.info("[NativeIpcBridge][presence][start-request]",{userId:e,localNodeId:t,deviceName:i,hasMetadata:typeof a=="string"&&a.trim().length>0,hasCompoundTicket:typeof r=="string"&&r.includes(".")}),!await this.ensureNativeAuth("startPresenceLoop",{requireToken:true,maxWaitMs:l.AUTH_REQUIRED_WAIT_MS}))throw new Error("Native auth token unavailable for startPresenceLoop");let o=this.resolveNativeAuthScopedUserId(e);if(!o)throw new Error("Native presence loop requires a runtime auth-scoped user id.");console.info("[NativeIpcBridge][presence][auth-ready]",{requestedUserId:e,runtimeUserId:this.currentUser?.id??this.getAuthContext()?.userId??null,effectiveUserId:o,localNodeId:t}),await this.invokeIpc("start_rtc_presence_loop",{userId:o,localNodeId:t,deviceName:i,ticket:r,metadata:a,apiKey:this.options.apiKey??null}),console.info("[NativeIpcBridge][presence][ipc-started]",{requestedUserId:e,effectiveUserId:o,localNodeId:t,deviceName:i});}shouldUseResolvedDeviceName(e){let t=e.trim();return t.length===0||t==="Unknown Device"||t==="Desktop Device"}async sendExplicitFilePath(e,t,i=""){if(b("[NativeIpcBridge] sendExplicitFilePath start",{connectionId:e,filePath:t,transferId:i||null,authMode:this.options.authMode}),await this.canUseTauriIpc()){this.options.authMode!=="anonymous"?await this.ensureNativeAuth("sendExplicitFilePath"):b("[NativeIpcBridge] sendExplicitFilePath using anonymous native path");let r=await this.invokeIpc("send_file",{connectionId:e,filePath:t,transferId:i});return b("[NativeIpcBridge] sendExplicitFilePath completed",{connectionId:e,transferId:i||null,result:r}),r}return this.fallback.sendExplicitFilePath(e,t,i)}async sendExplicitFileData(e){if(b("[NativeIpcBridge] sendExplicitFileData start",{connectionId:e.connectionId??null,connectionRemoteNodeId:e.connection?.remoteNodeId??null,remoteNodeId:e.remoteNodeId??null,transferId:e.transferId??null,fileName:e.file.name,fileSize:e.file.size,authMode:this.options.authMode}),await this.canUseTauriIpc()){this.options.authMode!=="anonymous"?await this.ensureNativeAuth("sendExplicitFileData"):b("[NativeIpcBridge] sendExplicitFileData using anonymous native path");let t=e.connectionId||e.connection?.deviceId||e.connection?.remoteNodeId||e.remoteNodeId||"";if(!t)throw new Error("sendExplicitFileData requires a settled peer identifier in native runtime");let i=new Uint8Array(await e.file.arrayBuffer());await this.invokeIpc("send_file_data",{connectionId:t,filename:e.file.name,data:Array.from(i),transferId:e.transferId}),b("[NativeIpcBridge] sendExplicitFileData completed",{connectionId:t,transferId:e.transferId??null,fileName:e.file.name,fileSize:e.file.size});return}return this.fallback.sendExplicitFileData(e)}async getConnectionStates(){if(await this.canUseTauriIpc())try{this.options.authMode!=="anonymous"&&await this.ensureNativeAuth("getConnectionStates");let e=await this.invokeIpc("list_rtc_connection_states");return (Array.isArray(e)?e:[]).map(t=>o(t)).filter(t=>!!t)}catch(e){return console.warn("[NativeIpcBridge] Failed to fetch native connection states:",e),[]}return []}async onConnectionStateChange(e){let t=false,i=null,r=Date.now(),a=0,n=()=>{let o=i;o&&Promise.resolve(o());};for(;!t&&Date.now()-r<=l.CONNECTION_EVENT_SUBSCRIBE_WINDOW_MS;){if(a+=1,!await this.canUseTauriIpc()){await this.sleep(this.nextConnectionEventRetryDelayMs(a));continue}i=await this.listenIpc("connection-state-changed",o$1=>{let s=o(o$1?.payload);s&&(a$1("[NativeIpcBridge] connection-state-changed trigger",{connectionId:s.connectionId,deviceId:s.deviceId??null,deviceIdHint:s.deviceIdHint??null,remoteNodeId:s.remoteNodeId??null,state:s.state,transportState:s.transportState??null,protocolState:s.protocolState??null,routable:s.routable??null,activeTransport:s.activeTransport??null,parallelTransport:s.parallelTransport??null}),e(s),this.getConnectionStates().then(c=>{c.forEach(d=>e(d));}).catch(c=>{console.warn("[NativeIpcBridge] Failed to refresh Rust-owned connection states after trigger:",c);}));});try{let o=await this.getConnectionStates();o.length>0&&a$1("[NativeIpcBridge] replaying current native connection states",o.map(s=>({connectionId:s.connectionId,deviceId:s.deviceId??null,deviceIdHint:s.deviceIdHint??null,remoteNodeId:s.remoteNodeId??null,state:s.state,transportState:s.transportState??null,protocolState:s.protocolState??null,routable:s.routable??null}))),o.forEach(s=>e(s));}catch(o){console.warn("[NativeIpcBridge] Failed to replay native connection states after event subscription:",o);}return ()=>{t=true,n();}}return ()=>{t=true,n();}}async onIncomingNativeMessage(e){if(!await this.canUseTauriIpc())return ()=>{};let t=await this.listenIpc("iroh://message",i=>{if(i?.payload?.data&&i.payload.streamId==="main")try{let r=new Uint8Array(i.payload.data);if(r.length<2||r[0]!==0)return;let n=r.slice(1),o=new TextDecoder().decode(n),s=JSON.parse(o);e(i.payload.connectionId,i.payload.remoteNodeId??null,s);}catch{}});return typeof t=="function"?t:()=>{}}async getTransferHistory(e=50){return await this.canUseTauriIpc()?this.invokeIpc("get_transfer_history",{limit:e}):[]}async deleteTransferJob(e){await this.canUseTauriIpc()&&await this.invokeIpc("delete_transfer_job",{jobId:e});}};l.AUTH_REQUIRED_WAIT_MS=p.nativeIpc.authRequiredWaitMs,l.MANAGED_SESSION_IPC_TIMEOUT_MS=p.nativeIpc.managedSessionIpcTimeoutMs,l.MANAGED_SESSION_IPC_MAX_ATTEMPTS=p.nativeIpc.managedSessionIpcMaxAttempts,l.CONNECTION_EVENT_SUBSCRIBE_WINDOW_MS=p.nativeIpc.connectionEventSubscribeWindowMs,l.CONNECTION_EVENT_RETRY_MIN_DELAY_MS=p.nativeIpc.connectionEventRetryMinDelayMs,l.CONNECTION_EVENT_RETRY_MAX_DELAY_MS=p.nativeIpc.connectionEventRetryMaxDelayMs,l.TAURI_IPC_NEGATIVE_CACHE_MS=p.nativeIpc.tauriIpcNegativeCacheMs;var _=l;var V=class extends w{constructor(e){let t=y(e.bridge,"IpcRuntimeAdapter");super(new _({...e,ipcBridge:t,allowWasmFallback:e.allowWasmFallback??false}));}};
2
- export{q as a,V as b};
@@ -1,2 +0,0 @@
1
- import {b as b$1,e}from'./chunk-4MH42GUI.js';import {getFirestore,connectFirestoreEmulator,getDoc,serverTimestamp,setDoc,updateDoc,deleteDoc,collection,doc,getDocs,query,where,limit,onSnapshot,getDocFromServer}from'firebase/firestore';import {httpsCallable,getFunctions}from'firebase/functions';import {getDatabase,connectDatabaseEmulator,ref,onDisconnect,serverTimestamp as serverTimestamp$1,set,onValue}from'firebase/database';var ze="[OpenRTC][teardown-trace]";function $e(){try{let s=globalThis;if(s.OPENRTC_TEARDOWN_TRACE===!0||s.localStorage?.getItem("OPENRTC_TEARDOWN_TRACE")==="1")return !0}catch{}return false}function le(s,e={}){console.info(ze,{kind:s,ts:new Date().toISOString(),...e}),$e()&&console.info("[OpenRTC][teardown-trace:stack]",{kind:s,stack:new Error(`teardown: ${s}`).stack});}var C={managedSession:{nativeStartRetryWindowMs:12e4,nativeStartRetryMinDelayMs:400,nativeStartRetryMaxDelayMs:5e3,reconciliationIntervalMs:3e4,deviceStatusRefreshDebounceMs:150},browserAutoConnect:{scanDebounceMs:150,retryCooldownMs:2e3,settleGuardMs:1e4,retryMaxMs:3e4,nonInitiatorBaseGraceMs:2e3,nonInitiatorMaxGraceMs:16e3},nativeIpc:{authRequiredWaitMs:15e3,managedSessionIpcTimeoutMs:6e4,managedSessionIpcMaxAttempts:2,connectionEventSubscribeWindowMs:15e3,connectionEventRetryMinDelayMs:250,connectionEventRetryMaxDelayMs:1e3,tauriIpcNegativeCacheMs:2e3},browserIdentity:{ephemeralDeviceIdTtlMs:6e4}};function Dt(){return C}var F={adapter:"browser-wasm",signaling:{firestore:true,nativeIpc:false,rtdbPresence:true},transport:{irohQuic:true,webRtcUpgrade:true,nativeWebRtc:false,wasm:true},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",signaling:{firestore:true,nativeIpc:true,rtdbPresence:true},transport:{irohQuic:true,webRtcUpgrade:true,nativeWebRtc:true,wasm:false},lifecycle:{managedSession:true,autoConnect:true,manualDisconnect:true,connectionStateEvents:true,peerSessions:true},transfers:{explicitFilePath:true,explicitFileData:true,history:true},fallback:{wasm:false}};function N(s){return {adapter:s.adapter,signaling:{...s.signaling},transport:{...s.transport},lifecycle:{...s.lifecycle},transfers:{...s.transfers},fallback:{...s.fallback}}}var ue=new Set;function W(s,e){ue.has(s)||(ue.add(s),console.warn(e));}function Ve(s){return s.allowAnonymousHostedDefaults===true}function je(s){return /^pk_(live|test)_[0-9a-f]{40}$/.test(s)}async function ge(s,e){let t=`${s}:${e}`,i=new TextEncoder().encode(t),r=await crypto.subtle.digest("SHA-256",i);return Array.from(new Uint8Array(r)).map(d=>d.toString(16).padStart(2,"0")).join("")}function ee(s){let e=typeof s.apiKey=="string"?s.apiKey.trim():"";if(e)return je(e)||W(`invalid-api-key:${e.slice(0,10)}`,"[pluto-rtc] The provided `apiKey` does not match the expected format (pk_live_... or pk_test_...). Create an app at https://api.openrtc.app/developer."),`app_${e.slice(-16)}`;if(!Ve(s))throw new Error("[openrtc] `apiKey` is required. If you intentionally need the old shared hosted fallback for a controlled demo or test, set `allowAnonymousHostedDefaults: true` explicitly.");return W("no-api-key","[pluto-rtc] No `apiKey` provided. Operating on the legacy shared hosted namespace because `allowAnonymousHostedDefaults` is enabled explicitly. Create an app at https://api.openrtc.app/developer."),"app_anonymous"}function fe(s){return s.authMode?s.authMode:("apiKey"in s&&"spaceKey"in s&&typeof s.apiKey=="string"&&s.apiKey.trim().length>0&&typeof s.spaceKey=="string"&&s.spaceKey.trim().length>0||W("default-auth-mode","[pluto-rtc] `authMode` is not set; defaulting to `anonymous` for compatibility."),"anonymous")}function he(s){let e=typeof s.projectId=="string"?s.projectId.trim():"";return e||(W("default-project-id","[pluto-rtc] `projectId` is not set; defaulting to the built-in PlutoRTC Firebase project."),b$1)}function pe(s){return s.trim().replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")}function ve(s){let e="storagePrefix"in s&&typeof s.storagePrefix=="string"?pe(s.storagePrefix):"";return e||pe(ee(s))||"default"}function L(s){if(!s)return null;let e=2166136261;for(let t=0;t<s.length;t+=1)e^=s.charCodeAt(t),e=Math.imul(e,16777619);return `fp-${(e>>>0).toString(16).padStart(8,"0")}`}function Qe(s){try{let e=s.replace(/-/g,"+").replace(/_/g,"/"),t=(4-e.length%4)%4,n=e+"=".repeat(t);if(typeof atob=="function")return JSON.parse(atob(n));let i=globalThis.Buffer;if(i)return JSON.parse(i.from(n,"base64").toString("utf8"))}catch{return null}return null}function U(s){let e=typeof s=="string"?s.trim():"";if(!e)return {present:false};let t=e.lastIndexOf("."),n=t>=0?e.slice(0,t):e,i=t>=0?e.slice(t+1):null,r=i?Qe(i):null,o=r&&typeof r.t=="string"&&r.t.trim().length>0?r.t.trim():null,a=r&&typeof r.s=="string"&&r.s.trim().length>0?r.s.trim():null,d=r&&typeof r.m=="number"&&Number.isFinite(r.m)?r.m:null;return {present:true,irohFingerprint:L(n),tokenFingerprint:L(o),tokenSuffixFingerprint:L(i),scope:a,maxConnections:d}}var K=class K{constructor(e){this.hooks=e;this.deviceListeners=new Map;this.devicesById=new Map;this.staleDeviceOfflineWrites=new Set;this.nextListenerIdSeed={value:1};this.activeDeviceScopeKey=null;this.activeDeviceUnsubscribe=null;this.deviceWatchGeneration=0;this.rtdbPresence=null;this.rtdbScope=null;this.rtdbPresenceMap={};this.rtdbUnsubscribe=null;this.knownTicketVersions=new Map;}get options(){return this.hooks.options}setRtdbPresence(e,t){this.rtdbUnsubscribe&&(this.rtdbUnsubscribe(),this.rtdbUnsubscribe=null),this.rtdbPresence=e,this.rtdbScope=t,this.rtdbPresenceMap={},this.knownTicketVersions.clear();}stopRtdbPresence(){this.rtdbUnsubscribe?.(),this.rtdbUnsubscribe=null,this.rtdbPresence=null,this.rtdbScope=null,this.rtdbPresenceMap={},this.knownTicketVersions.clear();}stopAuthScopedActivity(){this.stopRtdbPresence(),this.stopDeviceWatch({clearDevices:true});}async searchDevices(e){let n=(await this.readCurrentDeviceSnapshot()).filter(i=>i.online);return e?this.filterDevices(n,e):n}async listDevices(e){let t=await this.readCurrentDeviceSnapshot();return e?this.filterDevices(t,e):t}async subscribeDevices(){let e=await this.hooks.getDevicesCollectionRef();if(!e)return new ReadableStream({start(n){n.close();}});let t=null;return new ReadableStream({start:n=>{t=onSnapshot(e,i=>{let r=Date.now(),o=[];for(let a of i.docChanges()){let d=this.toDevice(a.doc,r);if(a.type==="removed"){o.push({type:"removed",deviceId:a.doc.id});continue}if(!d){o.push({type:"removed",deviceId:a.doc.id});continue}o.push({type:a.type==="added"?"added":"modified",device:d});}o.length>0&&n.enqueue(o);},i=>{console.warn("[BrowserDeviceDiscovery] subscribeDevices snapshot error:",{message:i?.message,code:i?.code});try{n.close();}catch{}});},cancel:()=>{t?.(),t=null;}})}onDevicesChange(e,t){let n=this.nextListenerIdSeed.value++;return this.deviceListeners.set(n,{callback:e,excludeNodeId:t}),this.emitDevicesToListener(n),this.ensureDeviceWatch(),()=>{this.deviceListeners.delete(n),this.deviceListeners.size===0&&this.stopDeviceWatch({clearDevices:true});}}async handleScopeChange(){let e=this.deviceListeners.size>0;this.stopDeviceWatch({clearDevices:true}),e&&await this.ensureDeviceWatch();}async cleanupStaleDevices(){let e=await this.hooks.getDevicesCollectionRef();if(!e)return;let t=await getDocs(e),n=Date.now();await Promise.allSettled(t.docs.map(async i=>{let r=i.data(),o=this.isDeviceExpired(r,n),a=r.online===true;if(o&&!a){await deleteDoc(i.ref);return}let d=this.toMillis(r.updatedAt)??this.toMillis(r.lastSeenAt)??0;!a||!d||d+3e5>n||await updateDoc(i.ref,{online:false,updatedAt:serverTimestamp(),expiresAt:n+2592e6});}));}async refreshDeviceForAutoConnect(e){let t=e.trim();if(!t)return null;let n=await this.hooks.getDevicesCollectionRef();if(!n)return this.devicesById.get(t)??null;let i=doc(n,t),r=this.devicesById.get(t)??null,o="server",a=null;try{a=await getDocFromServer(i);}catch(g){o="cache",console.warn("[BrowserDeviceDiscovery][auto-connect][refresh] getDocFromServer failed; falling back to getDoc",{deviceId:t,error:g}),a=await getDoc(i).catch(()=>null);}if(!a?.exists())return this.devicesById.delete(t),console.info("[BrowserDeviceDiscovery][auto-connect][refresh] device doc missing during refresh",{deviceId:t,source:o,previousTicket:U(r?.ticket)}),this.emitDevicesToAll(),null;let d=typeof a.data=="function"?a.data():null,c=this.deviceFromSnapshot(t,d,Date.now());if(!c)return this.devicesById.delete(t),console.info("[BrowserDeviceDiscovery][auto-connect][refresh] refreshed device doc was filtered out",{deviceId:t,source:o,previousTicket:U(r?.ticket)}),this.emitDevicesToAll(),null;let l=this.rtdbPresenceMap[t],u=l?{...c,online:l.online}:c;this.devicesById.set(t,u);let h=(r?.ticket??null)!==(u.ticket??null);return console.info("[BrowserDeviceDiscovery][auto-connect][refresh]",{deviceId:t,source:o,ticketChanged:h,previousTicket:U(r?.ticket),refreshedTicket:U(u.ticket),previousNodeId:r?.nodeId??null,refreshedNodeId:u.nodeId??null}),this.emitDevicesToAll(),u}stopDeviceWatch(e){this.deviceWatchGeneration+=1,this.activeDeviceUnsubscribe?.(),this.activeDeviceUnsubscribe=null,this.activeDeviceScopeKey=null,e?.clearDevices&&(this.devicesById.clear(),this.emitDevicesToAll());}emitDevicesToAll(){for(let e of this.deviceListeners.keys())this.emitDevicesToListener(e);}emitDevicesToListener(e){let t=this.deviceListeners.get(e);if(!t)return;let n=Array.from(this.devicesById.values()),i=t.excludeNodeId?this.filterDevices(n,t.excludeNodeId):n;t.callback(i);}filterDevices(e,t){return e.filter(n=>n.ticket!==t&&n.deviceId!==t&&n.nodeId!==t)}async readCurrentDeviceSnapshot(){let e=await this.hooks.getDevicesCollectionRef();if(!e)return [];let t=await getDocs(e),n=Date.now(),i=[];for(let r of t.docs){let o=r.data();if(this.isDeviceExpired(o,n)){o.online===true&&await this.markStaleDeviceOffline(r,o,n);continue}if(!this.options.matchesTag(o))continue;let a=this.options.normalizeDevice({...o,deviceId:o.deviceId??r.id},r.id);a?.deviceId&&i.push(a);}return i}toDevice(e,t){return this.deviceFromSnapshot(e.id,e.data(),t,e)}deviceFromSnapshot(e,t,n,i){if(!t)return null;if(this.isDeviceExpired(t,n))return t.online===true&&i&&this.markStaleDeviceOffline(i,t,n),null;if(!this.options.matchesTag(t))return null;let r=this.options.normalizeDevice({...t,deviceId:t.deviceId??e},e);return r.deviceId?r:null}async markStaleDeviceOffline(e,t,n){let i=typeof t.deviceId=="string"&&t.deviceId.trim().length>0?t.deviceId:e.id,r=e.ref?.path||i;if(!(!r||this.staleDeviceOfflineWrites.has(r))){this.staleDeviceOfflineWrites.add(r);try{let o=await this.hooks.resolveDeviceRef(i);if(!o)return;await updateDoc(o,{online:!1,updatedAt:serverTimestamp(),expiresAt:n+2592e6});}catch(o){console.warn("[BrowserDeviceDiscovery] failed to mark stale device offline:",o);}finally{this.staleDeviceOfflineWrites.delete(r);}}}isDeviceExpired(e,t){let n=this.toMillis(e.expiresAt);if(typeof n=="number")return n<=t;let i=e.online===true?3e5:2592e6,r=this.toMillis(e.updatedAt);if(typeof r=="number")return r+i<=t;let o=this.toMillis(e.lastSeenAt);return typeof o=="number"?o+i<=t:false}toMillis(e){if(typeof e=="number"&&Number.isFinite(e))return e;if(typeof e=="string"){let t=Date.parse(e);return Number.isNaN(t)?void 0:t}if(e instanceof Date)return e.getTime();if(e&&typeof e=="object"&&typeof e.toMillis=="function")return e.toMillis()}async ensureDeviceWatch(){if(this.deviceListeners.size===0)return;let e=await this.hooks.getDevicesCollectionRef(),t=e?.path??null;if(!e||!t){this.devicesById.clear(),this.emitDevicesToAll();return}if(!(this.activeDeviceUnsubscribe&&this.activeDeviceScopeKey===t)){if(this.stopDeviceWatch({clearDevices:true}),this.rtdbPresence&&this.rtdbScope){await this.ensureDeviceWatchRtdb(e,t);return}this.startFirestoreDeviceWatch(e,t);}}startFirestoreDeviceWatch(e,t){let n=++this.deviceWatchGeneration;this.activeDeviceScopeKey=t,this.activeDeviceUnsubscribe=onSnapshot(e,i=>{if(n!==this.deviceWatchGeneration)return;let r=Date.now();this.devicesById.clear();for(let o of i.docs){let a=this.toDevice(o,r);a&&this.devicesById.set(a.deviceId,a);}this.emitDevicesToAll();},i=>{if(n!==this.deviceWatchGeneration)return;let r=i?.code,o=String(i?.message??"");if((r==="permission-denied"||r==="PERMISSION_DENIED"||/permission.?denied/i.test(o)||/missing or insufficient permissions/i.test(o))&&!this.options.auth.currentUser){console.warn("[BrowserDeviceDiscovery] device watch permission-denied before auth; retrying after auth establishes"),this.stopDeviceWatch({clearDevices:false}),setTimeout(()=>{n===this.deviceWatchGeneration&&this.options.auth.currentUser&&this.ensureDeviceWatch();},500);return}console.warn("[BrowserDeviceDiscovery] device watch failed:",i);});}async ensureDeviceWatchRtdb(e,t){let n=++this.deviceWatchGeneration;this.activeDeviceScopeKey=t;let i;try{i=await this.withTimeout(getDocs(e),K.RTDB_ROSTER_READ_TIMEOUT_MS,"RTDB-backed device roster read timed out");}catch(c){if(n!==this.deviceWatchGeneration)return;console.warn("[BrowserDeviceDiscovery] RTDB-backed device watch setup failed; falling back to Firestore listener:",c),this.startFirestoreDeviceWatch(e,t);return}if(n!==this.deviceWatchGeneration)return;let r=Date.now();this.devicesById.clear();let o=i.docs;for(let c of o){let l=this.toDevice(c,r);l&&this.devicesById.set(l.deviceId,l);}let a=this.rtdbPresence,d=this.rtdbScope;this.rtdbUnsubscribe&&this.rtdbUnsubscribe();try{this.rtdbUnsubscribe=a.onPresenceChange(d,c=>{if(n!==this.deviceWatchGeneration)return;this.rtdbPresenceMap=c;let l=[];for(let[u,h]of Object.entries(c)){let g=this.knownTicketVersions.get(u)??-1;h.ticketVersion!==g&&(this.knownTicketVersions.set(u,h.ticketVersion),g!==-1&&l.push(u));}this.applyRtdbOverlay(),l.length>0&&this.refetchDeviceTickets(l,e,n);});}catch(c){if(n!==this.deviceWatchGeneration)return;console.warn("[BrowserDeviceDiscovery] RTDB presence subscription setup failed; falling back to Firestore listener:",c),this.startFirestoreDeviceWatch(e,t);return}this.activeDeviceUnsubscribe=()=>{this.rtdbUnsubscribe?.(),this.rtdbUnsubscribe=null;},this.emitDevicesToAll();}withTimeout(e,t,n){let i=null;return new Promise((r,o)=>{i=setTimeout(()=>{i=null,o(new Error(n));},t),e.then(a=>{i&&clearTimeout(i),r(a);},a=>{i&&clearTimeout(i),o(a);});})}applyRtdbOverlay(){for(let[e,t]of this.devicesById){let n=this.rtdbPresenceMap[e];n&&t.online!==n.online&&this.devicesById.set(e,{...t,online:n.online});}this.emitDevicesToAll();}async refetchDeviceTickets(e,t,n){await Promise.allSettled(e.map(async i=>{try{let r=doc(t,i),o=await getDoc(r);if(n!==this.deviceWatchGeneration)return;if(!o.exists()){this.devicesById.delete(i);return}let a=this.deviceFromSnapshot(i,typeof o.data=="function"?o.data():null,Date.now());if(a){let d=this.rtdbPresenceMap[i];this.devicesById.set(i,d?{...a,online:d.online}:a);}else this.devicesById.delete(i);}catch(r){console.warn("[BrowserDeviceDiscovery] refetch device ticket failed:",r);}})),n===this.deviceWatchGeneration&&this.emitDevicesToAll();}};K.RTDB_ROSTER_READ_TIMEOUT_MS=5e3;var G=K;var z=class{constructor(e){this.ctx=e;this.friendDeviceUnsubscribes=new Map;this.firestore=getFirestore(e.app);}watchFriendDevices(e,t){if(this.usesPersonalSpaceMode())return ()=>{};let n=new Map,i=new Set(e);for(let[r,o]of this.friendDeviceUnsubscribes)i.has(r)||(o(),this.friendDeviceUnsubscribes.delete(r),n.delete(r));for(let r of e){if(this.friendDeviceUnsubscribes.has(r))continue;let o=`apps/${this.ctx.appTag}/users/${r}/devices`,a=collection(this.firestore,o),d=onSnapshot(a,c=>{let l=[];c.forEach(u=>{let h=u.data();if(!h||h.kind!=="device"||!this.ctx.matchesTag(h))return;let g=this.ctx.normalizeDevice(h,u.id);g.online&&l.push(g);}),n.set(r,l),t(new Map(n));},c=>{console.warn("[BrowserFriendDiscovery] friend device watch failed:",{friendUid:r,message:c?.message,code:c?.code});});this.friendDeviceUnsubscribes.set(r,d);}return ()=>{for(let[,r]of this.friendDeviceUnsubscribes)r();this.friendDeviceUnsubscribes.clear();}}async updateFriendTicket(e){let t=await this.ctx.resolveOrCreateLocalDeviceRef();t&&await updateDoc(t,{friendTicket:e??null});}usesPersonalSpaceMode(){return this.ctx.usesPersonalSpaceMode?this.ctx.usesPersonalSpaceMode():(this.ctx.discoveryMode??"personal")==="personal"&&typeof this.ctx.apiKey=="string"&&this.ctx.apiKey.trim().length>0&&typeof this.ctx.spaceKey=="string"&&this.ctx.spaceKey.trim().length>0}};var ct="createSignalingSession",V=class{constructor(e){this.ctx=e;}async createSession(e){if(this.shouldUseHostedSessionCallable()){await this.createHostedSession(e);return}let t=await this.ctx.getSessionsCollectionRef();if(!t)throw new Error("createSession requires an active browser signaling namespace");let n=doc(t,e.connectionId),i=Date.now(),r=600*1e3;await setDoc(n,{appTag:e.appTag??this.ctx.appTag,connectionId:e.connectionId,initiator:e.initiator??this.ctx.getCurrentUserId(),target:e.target??this.ctx.getCurrentUserId(),initiatorDeviceId:e.initiatorDeviceId,targetDeviceId:e.targetDeviceId,connectionType:e.connectionType??null,state:e.state,offer:e.offer?JSON.stringify(e.offer):null,offerE2ee:e.offerE2ee?JSON.stringify(e.offerE2ee):null,answer:e.answer?JSON.stringify(e.answer):null,answerE2ee:e.answerE2ee?JSON.stringify(e.answerE2ee):null,iceCandidates:Array.isArray(e.iceCandidates)?JSON.stringify(e.iceCandidates):null,initiatorNodeId:e.initiatorNodeId??null,targetNodeId:e.targetNodeId??null,initiatorEndpointAddr:e.initiatorEndpointAddr??null,targetEndpointAddr:e.targetEndpointAddr??null,intent:e.intent??null,createdAt:e.createdAt??i,updatedAt:i,expiresAt:i+r},{merge:true});}async updateSession(e,t){let n=await this.ctx.getSessionsCollectionRef();if(!n)throw new Error("updateSession requires an active browser signaling namespace");let i=doc(n,this.ctx.parseScopedId(e)),r={};if(t&&typeof t=="object"){for(let[o,a]of Object.entries(t))if(a!==void 0){if(a===null||typeof a=="string"||typeof a=="number"||typeof a=="boolean"){r[o]=a;continue}r[o]=JSON.stringify(a);}}Object.keys(r).length!==0&&(r.updatedAt=Date.now(),await updateDoc(i,r));}async sendMessage(e,t,n,i){let r=await this.ctx.getMessagesCollectionRef();if(!r)throw new Error("sendMessage requires an active browser signaling namespace");let o=this.createDocumentId(),a=doc(r,o),d=this.ctx.getCurrentUserId()??this.ctx.getLocalDeviceId(),c=Date.now(),l=1440*60*1e3;return await setDoc(a,{appTag:this.ctx.appTag,senderId:d,targetId:e,payload:t,state:n??null,replyPayload:i??null,timestamp:c,expiresAt:c+l}),a.path}async pollMessages(e){let t=await this.ctx.getMessagesCollectionRef();if(!t)return [];let n=await getDocs(query(t,where("targetId","==",e),limit(50))),i=[];for(let r of n.docs){let o=r.data(),a=typeof o.senderId=="string"?o.senderId:"",d=typeof o.targetId=="string"?o.targetId:"",c=typeof o.payload=="string"?o.payload:"";!a||!d||!c||i.push({senderId:a,targetId:d,payload:c,state:typeof o.state=="string"?o.state:void 0,replyPayload:typeof o.replyPayload=="string"?o.replyPayload:void 0,timestamp:this.ctx.toMillis(o.timestamp),_documentId:r.id});}return i.sort((r,o)=>(r.timestamp??0)-(o.timestamp??0)),await Promise.allSettled(i.map(async r=>{await deleteDoc(doc(t,r._documentId));})),i.map(({_documentId:r,...o})=>o)}async subscribeSessions(e){let t=await this.ctx.getSessionsCollectionRef(),n=this.ctx.parseScopedId(e);if(!t||!n)return new ReadableStream({start(a){a.close();}});let i=null,r=null,o=false;return new ReadableStream({start:a=>{let d={initiator:new Set,target:new Set},c=new Map,l=(u,h)=>{if(o)return;let g=[];for(let f of h.docChanges()){let v=f.doc.id;if(f.type==="removed"){d[u].delete(v),!(d.initiator.has(v)||d.target.has(v))&&c.delete(v)&&g.push({type:"removed",sessionId:v});continue}let m=this.toSession(f.doc.id,f.doc.data());if(!m)continue;d[u].add(v);let I=c.has(v);c.set(v,m),g.push({type:I?"modified":"added",session:m});}g.length>0&&a.enqueue(g);};i=onSnapshot(query(t,where("initiatorDeviceId","==",n)),u=>l("initiator",u),u=>{o||a.error(u);}),r=onSnapshot(query(t,where("targetDeviceId","==",n)),u=>l("target",u),u=>{o||a.error(u);});},cancel:()=>{o=true,i?.(),r?.(),i=null,r=null;}})}shouldUseHostedSessionCallable(){return (this.ctx.discoveryMode??"personal")!=="personal"&&!!this.ctx.getCurrentUserId()}async createHostedSession(e){await httpsCallable(getFunctions(this.ctx.app),ct)({...e,appTag:e.appTag??this.ctx.appTag,initiator:e.initiator??this.ctx.getCurrentUserId()??void 0,target:e.target??this.ctx.getCurrentUserId()??void 0});}toSession(e,t){let n=typeof t.initiatorDeviceId=="string"?t.initiatorDeviceId:"",i=typeof t.targetDeviceId=="string"?t.targetDeviceId:"";return !n&&!i?null:{connectionId:typeof t.connectionId=="string"?t.connectionId:e,initiator:typeof t.initiator=="string"?t.initiator:"",target:typeof t.target=="string"?t.target:"",initiatorDeviceId:n,targetDeviceId:i,connectionType:typeof t.connectionType=="string"?t.connectionType:void 0,offer:this.parseMaybeJson(t.offer),offerE2ee:this.parseMaybeJson(t.offerE2ee),answer:this.parseMaybeJson(t.answer),answerE2ee:this.parseMaybeJson(t.answerE2ee),iceCandidates:Array.isArray(t.iceCandidates)?t.iceCandidates:[],initiatorNodeId:typeof t.initiatorNodeId=="string"?t.initiatorNodeId:void 0,targetNodeId:typeof t.targetNodeId=="string"?t.targetNodeId:void 0,initiatorEndpointAddr:typeof t.initiatorEndpointAddr=="string"?t.initiatorEndpointAddr:void 0,targetEndpointAddr:typeof t.targetEndpointAddr=="string"?t.targetEndpointAddr:void 0,intent:typeof t.intent=="string"?t.intent:void 0,appTag:typeof t.appTag=="string"?t.appTag:this.ctx.appTag,createdAt:this.ctx.toMillis(t.createdAt),expiresAt:this.ctx.toMillis(t.expiresAt),state:typeof t.state=="string"?t.state:""}}parseMaybeJson(e){if(typeof e!="string")return e;try{return JSON.parse(e)}catch{return e}}createDocumentId(){return `${Date.now()}-${Math.random().toString(36).slice(2,10)}`}};function pt(s){return typeof s=="object"&&s!==null&&"code"in s&&s.code==="not-found"}var j=class{constructor(e){this.options=e;this.namespaceRootPromise=null;this.firestore=getFirestore(e.app);try{let t=globalThis?.__OPENRTC_FIRESTORE_EMULATOR_HOST__,n=typeof t=="string"?t.trim():"";if(n){let[i,r]=n.split(":"),o=(i??"").trim()||"127.0.0.1",a=Number(r??8082);try{connectFirestoreEmulator(this.firestore,o,a);}catch{}}else {let i=import.meta?.env;if(!!i?.DEV&&String(i?.VITE_USE_EMULATORS)==="true"){let o=String(i?.VITE_OPENRTC_EMULATOR_HOST??"127.0.0.1").trim()||"127.0.0.1",a=Number(i?.VITE_OPENRTC_FIRESTORE_EMULATOR_PORT??8082);try{connectFirestoreEmulator(this.firestore,o,a);}catch{}}}}catch{}this.discovery=new G({options:this.options,firestore:this.firestore,getDevicesCollectionRef:()=>this.getDevicesCollectionRef(),resolveDeviceRef:t=>this.resolveDeviceRef(t)}),this.friendDiscovery=new z({app:e.app,appTag:e.appTag,discoveryMode:e.discoveryMode,apiKey:e.apiKey,spaceKey:e.spaceKey,matchesTag:e.matchesTag,normalizeDevice:e.normalizeDevice,resolveOrCreateLocalDeviceRef:()=>this.resolveOrCreateLocalDeviceRef(),usesPersonalSpaceMode:()=>this.usesPersonalSpaceMode()}),this.sessionSignaling=new V({app:e.app,appTag:e.appTag,discoveryMode:e.discoveryMode,getCurrentUserId:()=>e.getCurrentUserId(),getLocalDeviceId:()=>e.getLocalDeviceId(),getSessionsCollectionRef:()=>this.getSessionsCollectionRef(),getMessagesCollectionRef:()=>this.getMessagesCollectionRef(),parseScopedId:t=>this.parseScopedId(t),toMillis:t=>this.toMillis(t)});}setRtdbPresence(e,t){this.discovery.setRtdbPresence(e,t);}stopRtdbPresence(){this.discovery.stopRtdbPresence();}searchDevices(e){return this.discovery.searchDevices(e)}listDevices(e){return this.discovery.listDevices(e)}subscribeDevices(){return this.discovery.subscribeDevices()}onDevicesChange(e,t){return this.discovery.onDevicesChange(e,t)}async handleScopeChange(){await this.discovery.handleScopeChange();}stopAuthScopedActivity(){this.discovery.stopAuthScopedActivity();}async updatePresence(e,t,n,i,r,o){let a=await this.resolveOrCreateLocalDeviceRef();if(!a)return;let d=this.options.getLocalDeviceId(),c=Date.now(),l=o?.trim()||this.options.getDefaultDeviceName(),u=this.options.getCurrentUserId(),h=n?c+Math.max(0,Math.trunc(i)):c+2592e6,g=await getDoc(a).catch(()=>null),f={appTag:this.options.appTag,tag:this.options.appTag,kind:"device",deviceId:d,deviceName:l,nodeId:e,platformType:"web",online:n,ticket:t,metadata:r??null,capabilities:{canHost:false,canSync:false,readOnly:false},lastSeenAt:serverTimestamp(),updatedAt:serverTimestamp(),expiresAt:h,excludedPeers:[]};u&&(f.userId=u),g?.exists()||(f.createdAt=serverTimestamp()),await setDoc(a,f,{merge:true});}async setOffline(e){let t=await this.resolveOrCreateLocalDeviceRef();if(!t)return;let n={appTag:this.options.appTag,tag:this.options.appTag,kind:"device",deviceId:this.options.getLocalDeviceId(),deviceName:this.options.getDefaultDeviceName(),nodeId:e,platformType:"web",online:false,updatedAt:serverTimestamp(),lastSeenAt:serverTimestamp(),expiresAt:Date.now()+2592e6,excludedPeers:[]},i=this.options.getCurrentUserId();i&&(n.userId=i);try{await updateDoc(t,n);}catch(r){if(!pt(r))throw r}}async cleanupStaleDevices(){await this.discovery.cleanupStaleDevices();}async updateDevice(e,t){let n=await this.resolveDeviceRef(e);if(!n)throw new Error("updateDevice requires a known device record");let i={updatedAt:serverTimestamp()};typeof t.deviceName=="string"&&(i.deviceName=t.deviceName),t.capabilities&&(i.capabilities={canHost:t.capabilities.canHost??t.capabilities.can_host??false,canSync:t.capabilities.canSync??t.capabilities.can_sync??false,readOnly:t.capabilities.readOnly??t.capabilities.read_only??false}),typeof t.metadata=="string"&&(i.metadata=t.metadata),await updateDoc(n,i);}async deleteDevice(e){let t=await this.resolveDeviceRef(e);t&&await deleteDoc(t);}async createSession(e){await this.sessionSignaling.createSession(e);}async updateSession(e,t){await this.sessionSignaling.updateSession(e,t);}async sendMessage(e,t,n,i){return this.sessionSignaling.sendMessage(e,t,n,i)}async pollMessages(e){return this.sessionSignaling.pollMessages(e)}async subscribeSessions(e){return this.sessionSignaling.subscribeSessions(e)}refreshDeviceForAutoConnect(e){return this.discovery.refreshDeviceForAutoConnect(e)}toMillis(e){if(typeof e=="number"&&Number.isFinite(e))return e;if(typeof e=="string"){let t=Date.parse(e);return Number.isNaN(t)?void 0:t}if(e instanceof Date)return e.getTime();if(e&&typeof e=="object"&&typeof e.toMillis=="function")return e.toMillis()}async getDevicesCollectionRef(){let e=await this.getDevicesCollectionPath();return e?collection(this.firestore,e):null}async getSessionsCollectionRef(){let e=await this.getNamespaceRoot();return e?collection(this.firestore,`${e}/sessions`):null}async getMessagesCollectionRef(){let e=await this.getNamespaceRoot();return e?collection(this.firestore,`${e}/messages`):null}async getDevicesCollectionPath(){let e=await this.getNamespaceRoot();if(!e)return null;if(this.usesPersonalSpaceMode())return `${e}/devices`;let t=this.options.getDiscoveryScopeId();return t?`${e}/users/${t}/devices`:null}async getNamespaceRoot(){if(this.usesPersonalSpaceMode()){if(!this.namespaceRootPromise){let e=this.options.apiKey?.trim()??"",t=this.options.spaceKey?.trim()??"";this.namespaceRootPromise=ge(e,t).then(n=>`spaces/${n}`);}return this.namespaceRootPromise}return `apps/${this.options.appTag}`}usesPersonalSpaceMode(){return (this.options.discoveryMode??"personal")==="personal"&&typeof this.options.apiKey=="string"&&this.options.apiKey.trim().length>0&&typeof this.options.spaceKey=="string"&&this.options.spaceKey.trim().length>0}parseScopedId(e){let t=e.split("::");return t.length===2?t[1]:e}async resolveOrCreateLocalDeviceRef(){let e=await this.getDevicesCollectionRef();return e?doc(e,this.options.getLocalDeviceId()):null}async resolveDeviceRef(e){let t=await this.getDevicesCollectionRef();if(!t)return null;let n=doc(t,e);if((await getDoc(n)).exists())return n;let i=await getDocs(query(t,where("deviceId","==",e),limit(1)));if(!i.empty)return i.docs[0].ref;let r=await getDocs(query(t,where("nodeId","==",e),limit(1)));return r.empty?null:r.docs[0].ref}watchFriendDevices(e,t){return this.friendDiscovery.watchFriendDevices(e,t)}updateFriendTicket(e){return this.friendDiscovery.updateFriendTicket(e)}};function J(s,e){switch(s.kind){case "user-scoped":return `presence/${s.appTag}/users/${s.userId}/devices/${e}`;case "personal":return `presence/spaces/${s.namespaceId}/devices/${e}`}}function ft(s){switch(s.kind){case "user-scoped":return `presence/${s.appTag}/users/${s.userId}/devices`;case "personal":return `presence/spaces/${s.namespaceId}/devices`}}function Oe(s,e,t){return `presence/${s}/rooms/${e}/members/${t}`}function ht(s,e){return `presence/${s}/rooms/${e}/members`}var q=class{constructor(e){this.db=getDatabase(e);try{let t=globalThis?.__OPENRTC_RTDB_EMULATOR_HOST__,n=typeof t=="string"?t.trim():"";if(n){let[i,r]=n.split(":"),o=(i??"").trim()||"127.0.0.1",a=Number(r??9001);try{connectDatabaseEmulator(this.db,o,a);}catch{}}else {let i=import.meta?.env;if(!!i?.DEV&&String(i?.VITE_USE_EMULATORS)==="true"){let o=String(i?.VITE_OPENRTC_EMULATOR_HOST??"127.0.0.1").trim()||"127.0.0.1",a=Number(i?.VITE_OPENRTC_RTDB_EMULATOR_PORT??9001);try{connectDatabaseEmulator(this.db,o,a);}catch{}}}}catch{}}async registerDevice(e,t,n=0){let i=ref(this.db,J(e,t));await onDisconnect(i).set({online:false,lastSeenAt:serverTimestamp$1(),ticketVersion:n}),await set(i,{online:true,lastSeenAt:serverTimestamp$1(),ticketVersion:n});}async bumpTicketVersion(e,t,n){let i=ref(this.db,J(e,t));await onDisconnect(i).set({online:false,lastSeenAt:serverTimestamp$1(),ticketVersion:n});let r=ref(this.db,`${J(e,t)}/ticketVersion`);await set(r,n);}async markOffline(e,t,n=0){let i=ref(this.db,J(e,t));await onDisconnect(i).cancel(),await set(i,{online:false,lastSeenAt:serverTimestamp$1(),ticketVersion:n});}async registerRoomMember(e,t,n){let i=ref(this.db,Oe(e,t,n));await onDisconnect(i).set({online:false,lastSeenAt:serverTimestamp$1()}),await set(i,{online:true,lastSeenAt:serverTimestamp$1()});}async markRoomMemberOffline(e,t,n){let i=ref(this.db,Oe(e,t,n));await onDisconnect(i).cancel(),await set(i,{online:false,lastSeenAt:serverTimestamp$1()});}onRoomPresenceChange(e,t,n){let i=ref(this.db,ht(e,t));return onValue(i,o=>{let a=o.val()??{},d={};for(let[c,l]of Object.entries(a))l&&typeof l=="object"&&(d[c]={online:l.online===true});n(d);},o=>{console.warn("[RtdbPresence] room presence subscription error:",o);})}onPresenceChange(e,t){let n=ref(this.db,ft(e));return onValue(n,r=>{let o=r.val()??{},a={};for(let[d,c]of Object.entries(o))if(c&&typeof c=="object"){let l=c;a[d]={online:l.online===true,ticketVersion:typeof l.ticketVersion=="number"?l.ticketVersion:0};}t(a);},r=>{console.warn("[RtdbPresence] presence subscription error:",r);})}};var Y=class{constructor(e,t,n){this.updatePresenceFn=e;this.withWebPresenceMetadataFn=t;this.resolveWebLogicalDeviceIdFn=n;this.interval=null;this.state=null;}getState(){return this.state}setState(e){this.state=e;}stop(){this.stopLegacyTimer(),this.state=null;}stopLegacyTimer(){this.interval&&(clearInterval(this.interval),this.interval=null);}startLegacy(){if(this.stopLegacyTimer(),!this.state)return;let e=()=>{let t=this.state;if(!t)return;let n=this.resolveWebLogicalDeviceIdFn(),i=this.withWebPresenceMetadataFn(t.metadata,n);this.updatePresenceFn(t.localNodeId,t.ticket,true,3e5,i,t.deviceName).catch(r=>{console.warn("[WasmBridge] browser presence tick failed:",r);});};e(),this.interval=setInterval(e,6e4);}};function vt(s){try{let e=s.replace(/-/g,"+").replace(/_/g,"/"),t=(4-e.length%4)%4,n=e+"=".repeat(t);if(typeof atob=="function")return JSON.parse(atob(n));let i=globalThis.Buffer;if(i)return JSON.parse(i.from(n,"base64").toString("utf8"))}catch{return null}return null}function se(s){let e=typeof s=="string"?s.trim():"";if(!e)return null;let t=0;for(let n=0;n<e.length;n+=1)t=t*31+e.charCodeAt(n)>>>0;return t.toString(16).padStart(8,"0").slice(0,8)}function _(s){let e=typeof s=="string"?s.trim():"";if(!e)return {present:false};let t=e.lastIndexOf("."),n=t>=0?e.slice(0,t):e,i=t>=0?e.slice(t+1):null,r=i?vt(i):null,o=r&&typeof r.t=="string"&&r.t.trim().length>0?r.t.trim():null,a=r&&typeof r.s=="string"&&r.s.trim().length>0?r.s.trim():null,d=r&&typeof r.m=="number"&&Number.isFinite(r.m)?r.m:null;return {present:true,irohFingerprint:se(n),tokenFingerprint:se(o),tokenSuffixFingerprint:se(i),scope:a,maxConnections:d}}var b=class b{constructor(e){this.deps=e;this.startedAutoConnectKey=null;this.autoConnectStartsInFlight=new Set;this.browserAutoConnectUnsubscribe=null;this.browserAutoConnectLastAttemptAt=new Map;this.browserAutoConnectInFlight=new Set;this.browserAutoConnectWaitStartedAt=new Map;this.browserAutoConnectEscalationCount=new Map;this.browserAutoConnectFailureCount=new Map;this.browserAutoConnectBackoffUntilMs=new Map;this.browserAutoConnectObservedSignatures=new Map;this.browserAutoConnectRecoveryTimers=new Map;this.browserAutoConnectPendingDevices=new Map;this.browserAutoConnectScanTimer=null;this.presenceStartGeneration=0;this.browserPresenceLoop=new Y((t,n,i,r,o,a)=>this.deps.updatePresence(t,n,i,r,o,a),(t,n)=>this.deps.withWebPresenceMetadata(t,n),()=>this.deps.resolveWebLogicalDeviceId());}stop(){this.stopAutoConnect(),this.stopPresenceLoop();}get pendingDevices(){return this.browserAutoConnectPendingDevices}set pendingDevices(e){this.browserAutoConnectPendingDevices=e;}get autoConnectKey(){return this.startedAutoConnectKey}set autoConnectKey(e){this.startedAutoConnectKey=e;}get presenceLoopState(){return this.browserPresenceLoop.getState()}set presenceLoopState(e){this.browserPresenceLoop.setState(e);}stopPresence(){this.stopPresenceLoop();}updatePresenceLoopState(e){this.browserPresenceLoop.setState(e);}startAutoConnect(e,t){this.deps.isTicketOnlyMode()||(async()=>{let n=this.deps.resolveWebLogicalDeviceId(),i=this.browserPresenceLoop.getState(),r=typeof i?.localNodeId=="string"&&i.localNodeId.trim()||null,o=`${e}::${n}`;if(!(this.startedAutoConnectKey===o||this.autoConnectStartsInFlight.has(o))){this.autoConnectStartsInFlight.add(o);try{this.stopAutoConnect(),this.startedAutoConnectKey=o,this.browserAutoConnectUnsubscribe=this.deps.getBrowserFirestoreSignaling().onDevicesChange(a=>{this.scheduleBrowserAutoConnectScan(a,r,n);});}finally{this.autoConnectStartsInFlight.delete(o);}}})();}notifyDisconnectRequested(e){if(!this.startedAutoConnectKey||this.browserAutoConnectPendingDevices.size===0)return;let t=e.trim();if(!t)return;let n=[...this.browserAutoConnectPendingDevices.values()].find(i=>(typeof i.nodeId=="string"?i.nodeId.trim():"")===t);n?.deviceId&&this.queueBrowserAutoConnectRecoveryForDevice(n,{resetWaitStartedAt:true});}triggerBrowserAutoConnectRecovery(e){if(!this.startedAutoConnectKey||this.browserAutoConnectPendingDevices.size===0)return;let t=[...this.browserAutoConnectPendingDevices.values()].find(n=>{let i=typeof n.deviceId=="string"?n.deviceId.trim():"",r=typeof n.nodeId=="string"?n.nodeId.trim():"";return !!e.deviceId&&i===e.deviceId||!!e.deviceIdHint&&i===e.deviceIdHint||!!e.remoteNodeId&&r===e.remoteNodeId});t?.deviceId&&this.queueBrowserAutoConnectRecoveryForDevice(t);}async setAutoConnectExcluded(e,t){let n=await this.deps.waitForWasmClient();n&&typeof n.set_auto_connect_excluded=="function"&&await n.set_auto_connect_excluded(e,t);}startPresenceLoop(e,t,n,i,r){if(this.deps.isTicketOnlyMode())return;this.stopPresenceLoop();let o=++this.presenceStartGeneration;this.browserPresenceLoop.setState({localNodeId:t,ticket:i,metadata:r,deviceName:n});let a=this.deps.resolveWebLogicalDeviceId(),d=this.deps.buildRtdbScope(e);if(!this.deps.isRtdbPresenceDisabledForSession()&&d&&a){let c=this.deps.withWebPresenceMetadata(r,a),l=false,u=false,h=false,g=null,f=null,v=()=>o===this.presenceStartGeneration&&this.browserPresenceLoop.getState()!==null,m=(w,Z)=>{!v()||l||(l=true,console.warn(`[WasmBridge] ${w}; using Firestore presence heartbeat fallback`,Z),this.startLegacyBrowserPresenceLoop());},I=()=>{!v()||!l||!u||!h||(l=false,this.browserPresenceLoop.stopLegacyTimer());};g=setTimeout(()=>{u||m("initial presence write timed out");},b.INITIAL_PRESENCE_WRITE_TIMEOUT_MS),f=setTimeout(()=>{h||m("RTDB presence register timed out");},b.RTDB_PRESENCE_REGISTER_TIMEOUT_MS),this.deps.updatePresence(t,i,true,10080*60*1e3,c,n).then(()=>{u=true,g&&(clearTimeout(g),g=null),I();}).catch(w=>{g&&(clearTimeout(g),g=null),console.warn("[WasmBridge] initial presence write failed:",w),m("initial presence write failed",w);}),this.deps.registerRtdbPresence(d,a,this.deps.getRtdbTicketVersion()).then(()=>{h=true,f&&(clearTimeout(f),f=null),I();}).catch(w=>{f&&(clearTimeout(f),f=null),console.warn("[WasmBridge] RTDB presence register failed:",w),m("RTDB presence register failed",w);});return}this.startLegacyBrowserPresenceLoop();}stopAutoConnect(){this.deps.waitForWasmClient(250).then(e=>{e&&typeof e.stop_auto_connect=="function"&&e.stop_auto_connect();}),this.browserAutoConnectUnsubscribe?.(),this.browserAutoConnectUnsubscribe=null,this.browserAutoConnectScanTimer&&(clearTimeout(this.browserAutoConnectScanTimer),this.browserAutoConnectScanTimer=null),this.browserAutoConnectPendingDevices.clear(),this.startedAutoConnectKey=null,this.autoConnectStartsInFlight.clear(),this.browserAutoConnectInFlight.clear(),this.browserAutoConnectLastAttemptAt.clear(),this.browserAutoConnectWaitStartedAt.clear(),this.browserAutoConnectEscalationCount.clear(),this.browserAutoConnectFailureCount.clear(),this.browserAutoConnectBackoffUntilMs.clear(),this.browserAutoConnectObservedSignatures.clear();for(let e of this.browserAutoConnectRecoveryTimers.values())clearTimeout(e);this.browserAutoConnectRecoveryTimers.clear();}clearBrowserAutoConnectDeviceState(e){this.browserAutoConnectWaitStartedAt.delete(e),this.browserAutoConnectEscalationCount.delete(e),this.browserAutoConnectFailureCount.delete(e),this.browserAutoConnectBackoffUntilMs.delete(e),this.browserAutoConnectLastAttemptAt.delete(e);let t=this.browserAutoConnectRecoveryTimers.get(e);t&&(clearTimeout(t),this.browserAutoConnectRecoveryTimers.delete(e));}queueBrowserAutoConnectRecoveryForDevice(e,t){if(!e?.deviceId)return;let n=e.deviceId;this.browserAutoConnectInFlight.delete(n),this.browserAutoConnectObservedSignatures.delete(n),this.browserAutoConnectLastAttemptAt.delete(n),this.browserAutoConnectBackoffUntilMs.delete(n),this.browserAutoConnectFailureCount.delete(n),t?.resetWaitStartedAt&&this.browserAutoConnectWaitStartedAt.delete(n);let i=this.browserPresenceLoop.getState(),r=typeof i?.localNodeId=="string"&&i.localNodeId.trim()||null,o=this.deps.resolveWebLogicalDeviceId();this.scheduleBrowserAutoConnectScan([...this.browserAutoConnectPendingDevices.values()],r,o);let a=this.browserAutoConnectRecoveryTimers.get(n);a&&clearTimeout(a);let d=setTimeout(()=>{if(this.browserAutoConnectRecoveryTimers.delete(n),!this.browserAutoConnectPendingDevices.has(n))return;this.browserAutoConnectInFlight.delete(n),this.browserAutoConnectObservedSignatures.delete(n),this.browserAutoConnectLastAttemptAt.delete(n);let c=this.browserPresenceLoop.getState(),l=typeof c?.localNodeId=="string"&&c.localNodeId.trim()||null;this.scheduleBrowserAutoConnectScan([...this.browserAutoConnectPendingDevices.values()],l,this.deps.resolveWebLogicalDeviceId());},b.BROWSER_AUTO_CONNECT_SETTLE_GUARD_MS+100);this.browserAutoConnectRecoveryTimers.set(n,d);}browserAutoConnectLifecycleFresh(e){return typeof e=="number"&&e>0&&Date.now()-e<b.BROWSER_AUTO_CONNECT_SETTLE_GUARD_MS}getRustOwnedAutoConnectGate(e){let t=typeof e.deviceId=="string"?e.deviceId.trim():"",n=typeof e.nodeId=="string"?e.nodeId.trim():"";if(!t&&!n)return "none";let i=false;for(let r of this.deps.getLastDeliveredConnectionStates()){let o=t.length>0&&(r.deviceId===t||r.deviceIdHint===t),a=n.length>0&&r.remoteNodeId===n;if(!(!o&&!a)){if(r.replacementInProgress){this.browserAutoConnectLifecycleFresh(r.lastLifecycleTransitionAtMs)&&(i=true);continue}if(r.state==="connecting"){if(r.routable===true)return "healthy";this.browserAutoConnectLifecycleFresh(r.lastLifecycleTransitionAtMs)&&(i=true);continue}if(r.state==="connected"){if(r.routable===true)return "healthy";this.browserAutoConnectLifecycleFresh(r.lastLifecycleTransitionAtMs)&&(i=true);continue}r.state==="pending"&&(i=true);}}return i?"transitional":"none"}browserAutoConnectNonInitiatorGraceMs(e){let t=Math.max(0,Math.min(3,Math.trunc(e))),n=C.browserAutoConnect.nonInitiatorBaseGraceMs,i=Math.min(n*(1<<t),C.browserAutoConnect.nonInitiatorMaxGraceMs),r=(t*37+7)%41-20;return Math.max(1e3,i+Math.trunc(i*r/100))}queueBrowserAutoConnectGraceExpiryRecheck(e,t){if(!e)return;let n=this.browserAutoConnectRecoveryTimers.get(e);n&&clearTimeout(n);let i=setTimeout(()=>{if(this.browserAutoConnectRecoveryTimers.delete(e),!this.browserAutoConnectPendingDevices.has(e))return;this.browserAutoConnectObservedSignatures.delete(e);let r=this.browserPresenceLoop.getState(),o=typeof r?.localNodeId=="string"&&r.localNodeId.trim()||null;this.scheduleBrowserAutoConnectScan([...this.browserAutoConnectPendingDevices.values()],o,this.deps.resolveWebLogicalDeviceId());},Math.max(50,Math.trunc(t)));this.browserAutoConnectRecoveryTimers.set(e,i);}applyBrowserAutoConnectFailureBackoff(e){let t=(this.browserAutoConnectFailureCount.get(e)??0)+1;this.browserAutoConnectFailureCount.set(e,t);let n=b.BROWSER_AUTO_CONNECT_RETRY_COOLDOWN_MS*Math.max(1,2**Math.min(4,t-1)),i=Math.min(b.BROWSER_AUTO_CONNECT_RETRY_MAX_MS,n),r=Math.trunc(i*(t*31%21-10)/100),o=Math.max(b.BROWSER_AUTO_CONNECT_RETRY_COOLDOWN_MS,i+r),a=Date.now()+o;this.browserAutoConnectBackoffUntilMs.set(e,a),this.queueBrowserAutoConnectGraceExpiryRecheck(e,o+25);}async shouldAttemptBrowserAutoConnectDial(e,t,n){if(!e.online||!e.ticket||!e.deviceId||e.deviceId===n)return false;let i=e.deviceId;if(Array.isArray(e.excludedPeers)&&e.excludedPeers.some(Z=>String(Z??"").trim().toLowerCase()===n.trim().toLowerCase()))return console.log(`[WasmPresenceManager][auto-connect-dial] BAIL \u2014 peer excluded this device for this session deviceKey=${i}`),this.clearBrowserAutoConnectDeviceState(i),false;let r=typeof e.nodeId=="string"?e.nodeId.trim():"",o=r.length>0&&await this.deps.isConnected(r).catch(()=>false),a=await this.deps.waitForWasmClient(0).catch(()=>null);if(a&&typeof a.is_auto_connect_excluded=="function"&&a.is_auto_connect_excluded(i)===true)return console.log(`[WasmPresenceManager][auto-connect-dial] BAIL \u2014 peer auto-connect suppressed for this session deviceKey=${i}`),this.clearBrowserAutoConnectDeviceState(i),false;let d=this.getRustOwnedAutoConnectGate(e);if(d!=="none")if(d==="healthy"&&!o)console.log(`[WasmPresenceManager][auto-connect-dial] rust-owned healthy gate ignored; transport disconnected deviceKey=${i}`);else return d==="healthy"&&r.length>0&&this.clearBrowserAutoConnectDeviceState(i),false;let c=e.deviceId||r,l=c?await this.deps.getPeerSession(c).catch(()=>null):null;if(l?.settledReady)return this.clearBrowserAutoConnectDeviceState(i),false;let u=typeof l?.lastLifecycleTransitionAtMs=="number"?l.lastLifecycleTransitionAtMs:0,h=this.browserAutoConnectLifecycleFresh(u),g=l?.activeTransportStableId!=null;if(console.log(`[WasmPresenceManager][auto-connect-dial] evaluating deviceKey=${i} remoteNodeId=${r.slice(0,8)} localNodeId=${(t??"").slice(0,8)} transportConnected=${o} sessionStatus=${l?.status??"none"} withinSettleGuard=${h} sessionHasActiveTransport=${g}`),o)return console.log(`[WasmPresenceManager][auto-connect-dial] BAIL \u2014 transport already connected deviceKey=${i}`),this.browserAutoConnectWaitStartedAt.delete(i),this.browserAutoConnectEscalationCount.delete(i),false;if(l?.replacementPending&&h||l?.status==="connecting"&&(h||g)||l?.status==="connected"&&h)return l?.settledReady&&this.clearBrowserAutoConnectDeviceState(i),false;if(!t||!r)return console.log(`[WasmPresenceManager][auto-connect-dial] PROCEED \u2014 no tiebreak info deviceKey=${i}`),true;if(t>r)return console.log(`[WasmPresenceManager][auto-connect-dial] PROCEED \u2014 tiebreak WIN (localNodeId > remoteNodeId) deviceKey=${i}`),this.browserAutoConnectWaitStartedAt.delete(i),true;let f=Date.now(),v=this.browserAutoConnectEscalationCount.get(i)??0,m=this.browserAutoConnectWaitStartedAt.get(i)??f;this.browserAutoConnectWaitStartedAt.has(i)||this.browserAutoConnectWaitStartedAt.set(i,m);let I=f-m,w=this.browserAutoConnectNonInitiatorGraceMs(v);return I<w?(console.log(`[WasmPresenceManager][auto-connect-dial] WAIT \u2014 non-initiator grace not elapsed deviceKey=${i} waitedMs=${I} graceMs=${w} escalation=${v}`),this.queueBrowserAutoConnectGraceExpiryRecheck(i,w-I+25),false):(console.log(`[WasmPresenceManager][auto-connect-dial] PROCEED \u2014 grace expired, escalating deviceKey=${i} escalation=${v+1}`),this.browserAutoConnectWaitStartedAt.delete(i),this.browserAutoConnectEscalationCount.set(i,v+1),true)}async hasHealthyBrowserAutoConnectSession(e){let t=typeof e.nodeId=="string"?e.nodeId.trim():"",n=t.length>0&&await this.deps.isConnected(t).catch(()=>false),i=this.getRustOwnedAutoConnectGate(e);if(i!=="none")return !(i==="healthy"&&!n);let r=e.deviceId||t;if(!r)return false;let o=await this.deps.getPeerSession(r).catch(()=>null);return !!(o?.settledReady||this.browserAutoConnectLifecycleFresh(o?.lastLifecycleTransitionAtMs)&&((o?.status==="connecting"||o?.status==="connected")&&o.activeTransportStableId!=null||n))}browserAutoConnectSignature(e){let t=typeof e.updatedAt=="number"?e.updatedAt:typeof e.updatedAt?.toMillis=="function"?e.updatedAt.toMillis():typeof e.lastSeenAt=="number"?e.lastSeenAt:typeof e.lastSeenAt?.toMillis=="function"?e.lastSeenAt.toMillis():0;return JSON.stringify({deviceId:e.deviceId,nodeId:e.nodeId??null,online:!!e.online,ticket:e.ticket??null,updatedAt:t})}async refreshBrowserAutoConnectDeviceForDial(e){let t=typeof e.deviceId=="string"?e.deviceId.trim():"";if(!t)return e;let i=await this.deps.getBrowserFirestoreSignaling().refreshDeviceForAutoConnect(t).catch(a=>(console.warn("[WasmSignaling][auto-connect][dial-refresh] failed to refresh device ticket before dial",{deviceId:t,error:a,cachedTicket:_(e.ticket)}),null))??e,r=(i.ticket??null)!==(e.ticket??null),o=(i.nodeId??null)!==(e.nodeId??null);return console.info("[WasmSignaling][auto-connect][dial-ticket]",{deviceId:t,ticketChanged:r,nodeChanged:o,cachedTicket:_(e.ticket),effectiveTicket:_(i.ticket),cachedNodeId:e.nodeId??null,effectiveNodeId:i.nodeId??null}),i}scheduleBrowserAutoConnectScan(e,t,n){this.browserAutoConnectPendingDevices=new Map(e.filter(i=>!!i.deviceId).map(i=>[i.deviceId,i])),!this.browserAutoConnectScanTimer&&(this.browserAutoConnectScanTimer=setTimeout(()=>{this.browserAutoConnectScanTimer=null,this.processBrowserAutoConnectSnapshot(t,n);},b.BROWSER_AUTO_CONNECT_SCAN_DEBOUNCE_MS));}async processBrowserAutoConnectSnapshot(e,t){let n=new Map(this.browserAutoConnectPendingDevices),i=new Set(n.keys());for(let r of Array.from(this.browserAutoConnectObservedSignatures.keys()))i.has(r)||(this.browserAutoConnectObservedSignatures.delete(r),this.clearBrowserAutoConnectDeviceState(r));for(let r of n.values()){if(!r.deviceId)continue;let o=r.deviceId,a=this.browserAutoConnectSignature(r),d=this.browserAutoConnectObservedSignatures.get(o)??null,c=this.browserAutoConnectLastAttemptAt.get(o)??0,l=this.browserAutoConnectBackoffUntilMs.get(o)??0,u=Math.max(l,c+b.BROWSER_AUTO_CONNECT_RETRY_COOLDOWN_MS),h=u>0&&Date.now()>=u;if(d===a&&!h){u>Date.now()&&this.queueBrowserAutoConnectGraceExpiryRecheck(o,u-Date.now()+25);continue}this.browserAutoConnectObservedSignatures.set(o,a),!this.browserAutoConnectInFlight.has(o)&&(this.browserAutoConnectInFlight.add(o),(async()=>{try{if(!await this.shouldAttemptBrowserAutoConnectDial(r,e,t))return;let f=Date.now(),v=this.browserAutoConnectLastAttemptAt.get(o)??0;if(f-v<b.BROWSER_AUTO_CONNECT_RETRY_COOLDOWN_MS)return;if(await this.hasHealthyBrowserAutoConnectSession(r)){this.clearBrowserAutoConnectDeviceState(o);return}let m=await this.refreshBrowserAutoConnectDeviceForDial(r);if(!m?.ticket){console.warn("[WasmSignaling][auto-connect][dial] skipped because the refreshed device has no ticket",{deviceId:r.deviceId,cachedTicket:_(r.ticket)});return}let I=this.browserAutoConnectSignature(m);if(this.browserAutoConnectPendingDevices.set(o,m),this.browserAutoConnectObservedSignatures.set(o,I),await this.hasHealthyBrowserAutoConnectSession(m)){this.clearBrowserAutoConnectDeviceState(o);return}this.browserAutoConnectLastAttemptAt.set(o,f),await this.deps.connectToDevice({deviceId:m.deviceId,endpointTicket:m.ticket}),this.browserAutoConnectFailureCount.delete(o),this.browserAutoConnectBackoffUntilMs.delete(o);}catch(g){if(await this.hasHealthyBrowserAutoConnectSession(r).catch(()=>false)){this.clearBrowserAutoConnectDeviceState(o);return}this.applyBrowserAutoConnectFailureBackoff(o),console.warn("[WasmSignaling] browser auto-connect attempt failed:",{deviceId:r.deviceId,ticket:_(r.ticket),failureCount:this.browserAutoConnectFailureCount.get(o)??0,backoffUntilMs:this.browserAutoConnectBackoffUntilMs.get(o)??null,error:g});}finally{this.browserAutoConnectInFlight.delete(o);}})());}}stopPresenceLoop(){this.presenceStartGeneration+=1,this.browserPresenceLoop.stop();}startLegacyBrowserPresenceLoop(){this.browserPresenceLoop.startLegacy();}};b.RTDB_PRESENCE_REGISTER_TIMEOUT_MS=5e3,b.INITIAL_PRESENCE_WRITE_TIMEOUT_MS=5e3,b.BROWSER_AUTO_CONNECT_SCAN_DEBOUNCE_MS=C.browserAutoConnect.scanDebounceMs,b.BROWSER_AUTO_CONNECT_RETRY_COOLDOWN_MS=C.browserAutoConnect.retryCooldownMs,b.BROWSER_AUTO_CONNECT_SETTLE_GUARD_MS=C.browserAutoConnect.settleGuardMs,b.BROWSER_AUTO_CONNECT_RETRY_MAX_MS=C.browserAutoConnect.retryMaxMs;var Q=b;function mt(){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 oe(s,e,t){if(mt()){if(typeof t>"u"){console[s](e);return}console[s](e,t);}}function X(s,e){oe("debug",s,e);}function E(s,e){oe("info",s,e);}function rn(s,e){oe("log",s,e);}function B(s){return !s||typeof s!="object"?{}:s instanceof Map?Object.fromEntries(s):s}function x(s){let e=B(s),t=B(e.device);if(!Object.keys(t).length)return e;let n={...t,...e};return delete n.device,n}function p(s,...e){for(let t of e){let n=s[t];if(typeof n=="string"&&n.trim().length>0)return n}}function O(s,...e){for(let t of e){let n=s[t];if(typeof n=="boolean")return n}}function y(s,...e){for(let t of e){let n=s[t];if(typeof n=="number"&&Number.isFinite(n))return n}}function A(s,...e){let t=p(s,...e);return t==="iroh"||t==="iroh-quic"||t==="iroh-relay"||t==="webrtc"||t==="moq"?t:void 0}function xe(s){return (s.discoveryMode??"personal")==="personal"&&typeof s.apiKey=="string"&&s.apiKey.trim().length>0&&typeof s.spaceKey=="string"&&s.spaceKey.trim().length>0}function Fe(s,e,t){return t?true:(typeof s.appTag=="string"?s.appTag:typeof s.tag=="string"?s.tag:void 0)===e}function ae(s,e){let t=x(s),n=p(t,"deviceId","device_id")||e||"",i=p(t,"nodeId","node_id")||"",r=p(t,"ticket")||"";return {deviceId:n,deviceName:p(t,"deviceName","device_name")||"Unknown Device",online:!!t.online,ticket:r,kind:p(t,"kind"),nodeId:i||void 0,platformType:p(t,"platformType","platform_type"),capabilities:t.capabilities||void 0,sessionId:p(t,"sessionId","session_id"),userId:p(t,"userId","user_id"),lastSeenAt:t.lastSeenAt??t.last_seen_at,expiresAt:t.expiresAt??t.expires_at,createdAt:t.createdAt??t.created_at,updatedAt:t.updatedAt??t.updated_at,metadata:p(t,"metadata"),excludedPeers:ce(t.excludedPeers??t.excluded_peers)}}function ce(s){return Array.isArray(s)?s.filter(e=>typeof e=="string"):[]}function yt(s){return {...s,connectionStatus:"connectionStatus"in s&&typeof s.connectionStatus=="string"?s.connectionStatus:s.online?"online":"disconnected",settledReady:"settledReady"in s&&typeof s.settledReady=="boolean"?s.settledReady:false,readinessState:"readinessState"in s&&typeof s.readinessState=="string"?s.readinessState:void 0,readinessReason:"readinessReason"in s&&typeof s.readinessReason=="string"?s.readinessReason:void 0,peerHealth:"peerHealth"in s&&typeof s.peerHealth=="string"?s.peerHealth:"unknown",peerId:"peerId"in s&&typeof s.peerId=="string"?s.peerId:void 0,promotionEligible:"promotionEligible"in s&&typeof s.promotionEligible=="boolean"?s.promotionEligible:true,scopes:"scopes"in s?ce(s.scopes):[],connectionId:"connectionId"in s&&typeof s.connectionId=="string"?s.connectionId:void 0,deviceIdHint:"deviceIdHint"in s&&typeof s.deviceIdHint=="string"?s.deviceIdHint:void 0,activeTransportStableId:"activeTransportStableId"in s&&typeof s.activeTransportStableId=="number"?s.activeTransportStableId:"activeTransportStableId"in s?s.activeTransportStableId??null:void 0,transportGeneration:"transportGeneration"in s&&typeof s.transportGeneration=="number"?s.transportGeneration:void 0,activeTransport:"activeTransport"in s?s.activeTransport:void 0,parallelTransport:"parallelTransport"in s?s.parallelTransport:void 0}}function bt(s,e,t){let n=t?t({connectionId:e.activeConnectionId??void 0,deviceId:e.deviceId??void 0,deviceIdHint:e.deviceIdHint??void 0,nodeId:e.nodeId??void 0}):s.promotionEligible??true;if(!n)return {...s,peerHealth:e.health??s.peerHealth,peerId:e.peerId??s.peerId,promotionEligible:n,scopes:e.scopes?.length?[...e.scopes]:s.scopes,connectionId:e.activeConnectionId??s.connectionId,deviceIdHint:e.deviceIdHint??s.deviceIdHint,activeTransportStableId:e.activeTransportStableId??s.activeTransportStableId,transportGeneration:e.transportGeneration??s.transportGeneration,activeTransport:e.activeTransport??s.activeTransport,parallelTransport:e.parallelTransport===void 0?s.parallelTransport:e.parallelTransport,readinessReason:e.readinessReason??s.readinessReason};let i=e.status??s.connectionStatus,r=typeof i=="string"?i.trim().toLowerCase():"",o=r==="failed"||r==="closed"||r==="disconnected",a=e.readinessState==="routable";if(!o&&s.readinessState==="routable"&&(s.connectionStatus==="connected"||s.settledReady)&&!a)return {...s,peerHealth:e.health??s.peerHealth,peerId:e.peerId??s.peerId,promotionEligible:n,scopes:e.scopes?.length?[...e.scopes]:s.scopes,connectionId:e.activeConnectionId??s.connectionId,deviceIdHint:e.deviceIdHint??s.deviceIdHint,activeTransportStableId:e.activeTransportStableId??s.activeTransportStableId,transportGeneration:e.transportGeneration??s.transportGeneration,activeTransport:e.activeTransport??s.activeTransport,parallelTransport:e.parallelTransport===void 0?s.parallelTransport:e.parallelTransport,readinessReason:e.readinessReason??s.readinessReason};let d=o?false:a||s.readinessState==="routable",c=a&&!o&&(r==="connecting"||r==="connected")?"connected":i,l=a?"routable":e.readinessState??s.readinessState,u=d?e.readinessReason??s.readinessReason??"peer-session-settled":e.readinessReason??s.readinessReason;return {...s,connectionStatus:c,settledReady:d,readinessState:l,readinessReason:u,peerHealth:e.health??s.peerHealth,peerId:e.peerId??s.peerId,promotionEligible:n,scopes:e.scopes?.length?[...e.scopes]:s.scopes,connectionId:e.activeConnectionId??s.connectionId,deviceIdHint:e.deviceIdHint??s.deviceIdHint,activeTransportStableId:e.activeTransportStableId??s.activeTransportStableId,transportGeneration:e.transportGeneration??s.transportGeneration,activeTransport:e.activeTransport??s.activeTransport,parallelTransport:e.parallelTransport===void 0?s.parallelTransport:e.parallelTransport}}function St(s,e){if(e.promotionEligible===false)return {...s,peerHealth:e.health??s.peerHealth,peerId:e.peerId??s.peerId,promotionEligible:false,connectionId:e.connectionId??s.connectionId,deviceIdHint:e.deviceIdHint??s.deviceIdHint,activeTransportStableId:e.activeTransportStableId??s.activeTransportStableId,transportGeneration:e.transportGeneration??s.transportGeneration,activeTransport:e.activeTransport??s.activeTransport,parallelTransport:e.parallelTransport===void 0?s.parallelTransport:e.parallelTransport,scopes:e.scopes?.length?[...e.scopes]:s.scopes};let t=e.status??s.connectionStatus,n=typeof t=="string"?t.trim().toLowerCase():"",i=n==="failed"||n==="closed"||n==="disconnected",r=e.routable===true||e.protocolState==="routable"||s.readinessState==="routable",o=e.transportState==="connected"&&e.health==="healthy",a=i?false:r,d=!i&&(r||o)&&(n==="connecting"||n==="connected"||e.transportState==="connected")?"connected":t,c=a?"routable":(e.routable===false&&e.protocolState?e.protocolState:void 0)??s.readinessState??(e.status==="connecting"?e.transportState==="connected"?"transport-only":"connecting":void 0),l=a?s.readinessReason??(e.routable===true?"peer-projection-routable":void 0):(e.routable===false&&e.error?e.error:void 0)??s.readinessReason??(e.status==="connecting"?e.transportState==="connected"?"peer-projection-transport-ready":"peer-projection-connecting":void 0);return {...s,connectionStatus:d,settledReady:a,readinessState:c,readinessReason:l,peerHealth:e.health??s.peerHealth,peerId:e.peerId??s.peerId,promotionEligible:e.promotionEligible??s.promotionEligible??true,connectionId:e.connectionId??s.connectionId,deviceIdHint:e.deviceIdHint??s.deviceIdHint,activeTransportStableId:e.activeTransportStableId??s.activeTransportStableId,transportGeneration:e.transportGeneration??s.transportGeneration,activeTransport:e.activeTransport??s.activeTransport,parallelTransport:e.parallelTransport===void 0?s.parallelTransport:e.parallelTransport,scopes:e.scopes?.length?[...e.scopes]:s.scopes}}function wt(s){let{device:e,session:t=null,peer:n=null,isPromotionEligible:i}=s,r=yt(e);return t&&(r=bt(r,t,i)),n&&(r=St(r,n)),r}function Ne(s){let e=x(s),t={...ae(e),connectionStatus:p(e,"connectionStatus","connection_status")||"disconnected",settledReady:O(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:ce(e.scopes),connectionId:p(e,"connectionId","connection_id"),deviceIdHint:p(e,"deviceIdHint","device_id_hint"),activeTransportStableId:y(e,"activeTransportStableId","active_transport_stable_id")??void 0,transportGeneration:y(e,"transportGeneration","transport_generation")??void 0,activeTransport:A(e,"activeTransport","active_transport"),parallelTransport:A(e,"parallelTransport","parallel_transport")??null};return wt({device:t})}function We(s){let e=x(s);return {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"),candidateConnectionIds:Array.isArray(e.candidateConnectionIds)?e.candidateConnectionIds.filter(t=>typeof t=="string"):Array.isArray(e.candidate_connection_ids)?e.candidate_connection_ids.filter(t=>typeof t=="string"):[],status:p(e,"status")||"disconnected",health:p(e,"health")||"unknown",settledReady:O(e,"settledReady","settled_ready")??false,readinessState:p(e,"readinessState","readiness_state")??void 0,activeTransportStableId:y(e,"activeTransportStableId","active_transport_stable_id")??void 0,transportGeneration:y(e,"transportGeneration","transport_generation")??void 0,activeTransport:A(e,"activeTransport","active_transport"),parallelTransport:A(e,"parallelTransport","parallel_transport")??null,replacementPending:O(e,"replacementPending","replacement_pending")??void 0,lastLifecycleTransitionAtMs:y(e,"lastLifecycleTransitionAtMs","last_lifecycle_transition_at_ms")??void 0,readinessReason:p(e,"readinessReason","readiness_reason")??void 0,transitionCount:y(e,"transitionCount","transition_count")??void 0,connectingTransitionCount:y(e,"connectingTransitionCount","connecting_transition_count")??void 0,replacementCount:y(e,"replacementCount","replacement_count")??void 0,retireCount:y(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(t=>typeof t=="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")}}function on(s){let e=B(s);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,transportStableId:typeof e.transportStableId=="number"?e.transportStableId:null,transportSource:typeof e.transportSource=="string"?e.transportSource:null,lastTransportChangeAtMs:typeof e.lastTransportChangeAtMs=="number"?e.lastTransportChangeAtMs: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,connectingTransitionCount:typeof e.connectingTransitionCount=="number"?e.connectingTransitionCount: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 an(s){let e=B(s);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 It(s){switch(s){case "connected":return "connected";case "connecting":return "connecting";case "failed":return "failed";default:return "closed"}}function Le(s){let e=s.activeConnectionId||s.candidateConnectionIds[0]||null;if(!e)return null;let t=It(s.status),n=t==="connected"?"connected":t==="connecting"?"connecting":"closed",i=t==="connected"?s.settledReady?"routable":"transport-only":t==="connecting"?"connecting":"closed";return {connectionId:e,deviceId:s.deviceId??null,deviceIdHint:s.deviceIdHint??null,remoteNodeId:s.nodeId??null,state:t,transportState:n,protocolState:i,routable:!!s.settledReady,readinessState:s.readinessState,readinessReason:s.readinessReason,transportGeneration:s.transportGeneration,activeTransportStableId:s.activeTransportStableId,activeTransport:s.activeTransport,parallelTransport:s.parallelTransport??null,replacementInProgress:s.replacementPending,lastLifecycleTransitionAtMs:s.lastLifecycleTransitionAtMs,transitionCount:s.transitionCount,connectingTransitionCount:s.connectingTransitionCount,replacementCount:s.replacementCount,retireCount:s.retireCount,lastDisconnectReason:s.lastDisconnectReason??void 0,lastReconnectReason:s.lastReconnectReason??void 0,updatedAt:s.lastSeenAtMs,error:s.error??void 0}}function Ue(s){let e=B(s),t=p(e,"connectionId","connection_id");if(!t)return null;let n=p(e,"state")||"connecting",i=y(e,"createdAt","created_at")??y(e,"updatedAt","updated_at")??Date.now(),r=y(e,"updatedAt","updated_at")??i;return {connectionId:t,deviceId:p(e,"deviceId","device_id"),deviceIdHint:p(e,"deviceIdHint","device_id_hint"),remoteNodeId:p(e,"remoteNodeId","remote_node_id"),state:n,transportState:p(e,"transportState","transport_state")??(n==="connected"?"connected":n==="connecting"?"connecting":"closed"),protocolState:p(e,"protocolState","protocol_state")??(n==="connected"?"routable":n==="connecting"?"connecting":"closed"),routable:O(e,"routable")??false,readinessState:p(e,"readinessState","readiness_state")??void 0,readinessReason:p(e,"readinessReason","readiness_reason")??void 0,transportGeneration:y(e,"transportGeneration","transport_generation")??void 0,activeTransportStableId:y(e,"activeTransportStableId","active_transport_stable_id")??void 0,activeTransport:A(e,"activeTransport","active_transport"),parallelTransport:A(e,"parallelTransport","parallel_transport")??null,replacementInProgress:O(e,"replacementInProgress","replacement_in_progress")??void 0,lastLifecycleTransitionAtMs:y(e,"lastLifecycleTransitionAtMs","last_lifecycle_transition_at_ms")??void 0,transitionCount:y(e,"transitionCount","transition_count")??void 0,connectingTransitionCount:y(e,"connectingTransitionCount","connecting_transition_count")??void 0,replacementCount:y(e,"replacementCount","replacement_count")??void 0,retireCount:y(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:i,updatedAt:r}}function He(s,e){return s?s.connectionId===e.connectionId&&(s.deviceId??null)===(e.deviceId??null)&&(s.deviceIdHint??null)===(e.deviceIdHint??null)&&(s.remoteNodeId??null)===(e.remoteNodeId??null)&&s.state===e.state&&(s.transportState??null)===(e.transportState??null)&&(s.protocolState??null)===(e.protocolState??null)&&!!s.routable==!!e.routable&&(s.activeTransport??null)===(e.activeTransport??null)&&(s.parallelTransport??null)===(e.parallelTransport??null)&&(s.transportGeneration??null)===(e.transportGeneration??null)&&!!s.replacementInProgress==!!e.replacementInProgress&&(s.transitionCount??null)===(e.transitionCount??null)&&(s.connectingTransitionCount??null)===(e.connectingTransitionCount??null)&&(s.replacementCount??null)===(e.replacementCount??null)&&(s.retireCount??null)===(e.retireCount??null)&&(s.lastDisconnectReason??null)===(e.lastDisconnectReason??null)&&(s.lastReconnectReason??null)===(e.lastReconnectReason??null)&&(s.error??null)===(e.error??null):false}var S=class S{constructor(e$1){this.authListeners=[];this.wasmClient=null;this.createdAtMs=Date.now();this.missingWasmWarnings=new Set;this.wasmReadyWarningDelayMs=15e3;this.browserFirestoreSignaling=null;this.lastObservedFirebaseUserId=null;this.sessionReaders=new Set;this.authContext=null;this.injectedBrowserAuthSessionActive=false;this._rtdbPresence=null;this.rtdbPresenceScope=null;this.rtdbTicketVersion=0;this.rtdbPresenceDisabledForSession=false;this.hasSyncedAuthToWasmClient=false;this.lastWasmAuthUserId=null;this.lastWasmAuthToken=null;this.lastDeliveredConnectionStates=new Map;this.autoConnectRecoveryUnsubscribe=null;this.coreClient=null;try{let n=typeof import.meta<"u"?import.meta.env:null;if(!!n&&String(n.VITE_USE_EMULATORS)==="true"&&(n.DEV||String(n.VITE_E2E)==="true")){let r=String(n.VITE_OPENRTC_FIRESTORE_EMULATOR_HOST||"").trim()||"127.0.0.1:8082";globalThis.__OPENRTC_FIRESTORE_EMULATOR_HOST__=r;}}catch{}if(this.appTag=ee(e$1),this.options={...e$1,appTag:this.appTag,authMode:fe(e$1),projectId:he(e$1)},this.presenceManager=new Q({isTicketOnlyMode:()=>this.isTicketOnlyMode(),waitForWasmClient:(n,i)=>this.waitForWasmClient(n,i),warnMissingWasmOnce:n=>this.warnMissingWasmOnce(n),resolveWebLogicalDeviceId:()=>this.resolveWebLogicalDeviceId(),withWebPresenceMetadata:(n,i)=>this.withWebPresenceMetadata(n,i),updatePresence:(n,i,r,o,a,d)=>this.updatePresence(n,i,r,o,a,d),buildRtdbScope:n=>this.buildRtdbScope(n),registerRtdbPresence:(n,i,r)=>this.registerRtdbPresence(n,i,r),isRtdbPresenceDisabledForSession:()=>this.rtdbPresenceDisabledForSession,getRtdbTicketVersion:()=>this.rtdbTicketVersion,getPeerSession:n=>this.getPeerSession(n),isConnected:n=>this.isConnected(n),connectToDevice:n=>this.connectToDevice(n),getBrowserFirestoreSignaling:()=>this.getBrowserFirestoreSignaling(),getLastDeliveredConnectionStates:()=>this.lastDeliveredConnectionStates.values(),forceReconnectSnapshot:()=>this.forceReconnectSnapshot()}),this.persistenceReady=Promise.resolve(),this.isTicketOnlyMode()){this.app=null,this.auth=null;return}let t=e();this.app=t.getApp(),this.auth=t.getAuth(),t.onAuthStateChanged(n=>{if(this.authContext)return;if(this.isPersonalSpaceMode()){this.authListeners.forEach(o=>o(this.toRuntimeIdentity(n)));return}let i=n?.uid??null,r=this.lastObservedFirebaseUserId;this.lastObservedFirebaseUserId=i,r&&r!==i&&this.stopAuthScopedActivity({userId:r}),this.browserFirestoreSignaling?.handleScopeChange(),this.authListeners.forEach(o=>o(this.toRuntimeIdentity(n)));});}get rtdbPresence(){return this._rtdbPresence}get tag(){return this.appTag}getRuntimeCapabilities(){return N(F)}getDeviceIdentityStorageKey(){let e=ve(this.options);return `${S.WEB_DEVICE_ID_STORAGE_PREFIX}_${e}`}getNodeIdPersistenceMode(){return this.options.nodeIdPersistence??"persistent"}isTicketOnlyMode(){return this.options.signalingMode==="ticket-only"}createRandomDeviceId(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`web-${Date.now()}-${Math.random().toString(36).slice(2,10)}`}resolveWebLogicalDeviceId(){let e=this.getNodeIdPersistenceMode();if(typeof localStorage>"u")return this.createRandomDeviceId();let t=this.getDeviceIdentityStorageKey(),n=Date.now(),i=null;try{let c=localStorage.getItem(t);i=c?JSON.parse(c):null;}catch{i=null;}let r=typeof i?.deviceId=="string"?i.deviceId.trim():"",o=typeof i?.expiresAt=="number"?i.expiresAt:void 0;if(e==="persistent"){let c=r||this.createRandomDeviceId();return localStorage.setItem(t,JSON.stringify({deviceId:c})),c}if(r&&typeof o=="number"&&o>n){let c=n+S.EPHEMERAL_DEVICE_ID_TTL_MS;return localStorage.setItem(t,JSON.stringify({deviceId:r,expiresAt:c})),r}let a=this.createRandomDeviceId(),d=n+S.EPHEMERAL_DEVICE_ID_TTL_MS;return localStorage.setItem(t,JSON.stringify({deviceId:a,expiresAt:d})),a}getDefaultBrowserDeviceName(){return this.options.deviceName?.trim()||(this.options.storagePrefix?`Web (${this.options.storagePrefix.replace(/_$/,"")})`:"Web Browser")}getBrowserFirestoreSignaling(){if(this.isTicketOnlyMode())throw new Error('[openrtc] Browser signaling is disabled when signalingMode="ticket-only".');return this.browserFirestoreSignaling||(this.browserFirestoreSignaling=new j({app:this.app,auth:this.auth,appTag:this.appTag,apiKey:this.options.apiKey,spaceKey:this.options.spaceKey,discoveryMode:this.options.discoveryMode,getCurrentUserId:()=>this.getCurrentUserId(),getDiscoveryScopeId:()=>this.getDiscoveryScopeId(),getLocalDeviceId:()=>this.resolveWebLogicalDeviceId(),getDefaultDeviceName:()=>this.getDefaultBrowserDeviceName(),matchesTag:e=>this.matchesTag(e),normalizeDevice:(e,t)=>this.normalizeDevice(e,t)})),this.browserFirestoreSignaling}withWebPresenceMetadata(e,t){if(!e||!e.trim())return JSON.stringify({deviceId:t});try{let n=JSON.parse(e);if(n&&typeof n=="object"&&!Array.isArray(n))return JSON.stringify({...n,deviceId:t})}catch{}return JSON.stringify({deviceId:t,metadata:e})}async setAuthContext(e){let t=this.injectedBrowserAuthSessionActive;if(this.authContext=e,!this.isTicketOnlyMode()&&e?.customToken?.trim())try{await this.ensureBrowserFirestoreAuth(e.userId,e.customToken.trim());}catch(n){console.warn("[WasmBridge] ensureBrowserFirestoreAuth failed (non-fatal):",n);}else if(!this.isTicketOnlyMode()&&!e&&t)try{await this.auth?.signOut();}catch(n){console.warn("[WasmBridge] Failed to clear injected browser auth session:",n);}finally{this.injectedBrowserAuthSessionActive=false;}this.syncWasmAuthToken(),this.isTicketOnlyMode()||await this.browserFirestoreSignaling?.handleScopeChange(),this.authListeners.forEach(n=>n(this.currentUser));}async ensureBrowserFirestoreAuth(e$1,t){if((this.auth?.currentUser?.uid??null)===e$1){this.injectedBrowserAuthSessionActive=true;return}await e().signInWithCustomTokenValue(t),this.injectedBrowserAuthSessionActive=true;}syncWasmAuthToken(){if(!this.wasmClient||typeof this.wasmClient.set_auth_token!="function")return;let e=this.authContext?.userId??null,t=this.authContext?.token??null;this.hasSyncedAuthToWasmClient&&this.lastWasmAuthUserId===e&&this.lastWasmAuthToken===t||(this.lastWasmAuthUserId=e,this.lastWasmAuthToken=t,this.hasSyncedAuthToWasmClient=true,this.wasmClient.set_auth_token(t));}toRuntimeIdentity(e){return e?{id:e.uid,email:e.email,displayName:e.displayName,isAnonymous:e.isAnonymous,getToken:async(t=false)=>{try{return await e.getIdToken(t)}catch{return null}}}:null}getCurrentUserId(){return this.authContext?.userId?this.authContext.userId:this.isTicketOnlyMode()?null:this.auth?.currentUser?.uid??null}getCurrentUserIdForScope(){return this.getCurrentUserId()}getAuthContext(){return this.authContext}isPersonalSpaceMode(){return xe(this.options)}getResolvedOptions(){return this.options}getDiscoveryScopeId(){if(this.isTicketOnlyMode())return null;let e=this.getCurrentUserId();return e||(this.isPersonalSpaceMode()?this.resolveWebLogicalDeviceId():null)}matchesTag(e){return Fe(e,this.appTag,this.isPersonalSpaceMode())}matchesLegacyOrCurrentTag(e){return this.matchesTag(e)}async stopSessionSubscriptions(){let e=Array.from(this.sessionReaders);this.sessionReaders.clear(),await Promise.allSettled(e.map(async t=>{try{await t.cancel();}catch{}}));}async stopRuntimeAuthScopedLoops(){let e=await this.waitForWasmClient(250);if(e)try{typeof e.stop_auth_scoped_activity=="function"?e.stop_auth_scoped_activity():(typeof e.stop_presence_loop=="function"&&e.stop_presence_loop(),typeof e.stop_auto_connect=="function"&&e.stop_auto_connect());}catch(t){console.warn("[WasmSignaling] Failed to stop auth-scoped runtime loops:",t);}}stopBrowserAutoConnect(){this.stopAutoConnectRecoverySubscription(),this.presenceManager.stop();}disableRtdbPresenceForSession(e,t){this.rtdbPresenceDisabledForSession||console.warn(`[WasmBridge] Disabling RTDB presence for this browser session (${e})`,t),this.rtdbPresenceDisabledForSession=true,this.rtdbPresenceScope=null,this.browserFirestoreSignaling?.stopRtdbPresence();}async registerRtdbPresence(e,t,n){if(this.isTicketOnlyMode())return;if(!this._rtdbPresence)try{this._rtdbPresence=new q(this.app);}catch(o){throw this.disableRtdbPresenceForSession("RTDB service unavailable",o),o}this.rtdbPresenceScope=e;let i=n??this.rtdbTicketVersion;this.getBrowserFirestoreSignaling().setRtdbPresence(this._rtdbPresence,e);try{await this._rtdbPresence.registerDevice(e,t,i);}catch(o){throw this.disableRtdbPresenceForSession("registerDevice failed",o),o}}async stopAuthScopedActivity(e){le("WasmBridge.stopAuthScopedActivity",{userId:e?.userId??null});let t=await this.waitForWasmClient(500);if(t&&typeof t.revoke_tokens_by_scope=="function")try{await t.revoke_tokens_by_scope("user-device");}catch(n){console.warn("[WasmBridge] user-device revoke during auth-scoped shutdown failed:",n);}this.stopAutoConnectRecoverySubscription(),this.presenceManager.stop(),this.rtdbPresenceDisabledForSession=false,this.rtdbPresenceScope=null,this.rtdbTicketVersion=0,this.browserFirestoreSignaling?.stopAuthScopedActivity(),await this.stopSessionSubscriptions(),this.lastDeliveredConnectionStates.clear(),await this.stopRuntimeAuthScopedLoops();}setWasmClient(e){this.wasmClient=e,this.hasSyncedAuthToWasmClient=false,this.lastDeliveredConnectionStates.clear(),this.syncWasmAuthToken();}warnMissingWasmOnce(e){!this.wasmClient&&Date.now()-this.createdAtMs<this.wasmReadyWarningDelayMs||this.missingWasmWarnings.has(e)||(this.missingWasmWarnings.add(e),console.warn(`[WasmSignaling] ${e} skipped: wasm client is not ready.`));}async waitForWasmClient(e=4e3,t=50){if(this.wasmClient)return this.wasmClient;let n=Date.now();for(;!this.wasmClient&&Date.now()-n<e;)await new Promise(i=>setTimeout(i,t));return this.wasmClient??null}normalizeDevice(e,t){return ae(e,t)}normalizeDeviceRecord(e,t){return this.normalizeDevice(e,t)}getResolvedWebLogicalDeviceId(){return this.resolveWebLogicalDeviceId()}normalizeDeviceStatusSnapshot(e){return Ne(e)}normalizePeerSessionSnapshot(e){return We(e)}toBackendConnectionStateFromPeerSession(e){return Le(e)}normalizeConnectionStateSnapshot(e){return Ue(e)}normalizeWindowConnectionStateDetail(e){return this.normalizeConnectionStateSnapshot(e)}stabilizeConnectionState(e){let t=this.lastDeliveredConnectionStates.get(e.connectionId);return {...e,deviceId:e.deviceId??t?.deviceId??null,deviceIdHint:e.deviceIdHint??t?.deviceIdHint??null,remoteNodeId:e.remoteNodeId??t?.remoteNodeId??null,createdAt:e.createdAt??t?.createdAt,updatedAt:e.updatedAt??t?.updatedAt}}sameConnectionState(e,t){return He(e,t)}deliverConnectionState(e,t,n,i){let r=this.stabilizeConnectionState(e);this.lastDeliveredConnectionStates.set(r.connectionId,r);let a=(i??this.lastDeliveredConnectionStates).get(r.connectionId);this.sameConnectionState(a,r)||(i&&i.set(r.connectionId,r),n==="event"&&X("[WasmBridge] connection-state-changed event",{connectionId:r.connectionId,deviceId:r.deviceId??null,deviceIdHint:r.deviceIdHint??null,remoteNodeId:r.remoteNodeId??null,state:r.state,transportState:r.transportState??null,protocolState:r.protocolState??null,routable:r.routable??null,error:r.error??null}),t(r));}async enrichBackendConnectionState(e){let t=await this.getPeerSession(e.connectionId).catch(()=>null),n=t?this.toBackendConnectionStateFromPeerSession(t):null;if(n){let r=Math.max(e.updatedAt??0,n.updatedAt??0)||void 0,o=!!e.routable&&!n.routable;return {...n,...e,deviceId:n.deviceId??e.deviceId??null,deviceIdHint:n.deviceIdHint??e.deviceIdHint??null,remoteNodeId:n.remoteNodeId??e.remoteNodeId??null,state:o?e.state:n.state,transportState:o?e.transportState??n.transportState:n.transportState,protocolState:o?e.protocolState??n.protocolState:n.protocolState,routable:o?e.routable:n.routable,transportGeneration:e.transportGeneration??n.transportGeneration,replacementInProgress:e.replacementInProgress??n.replacementInProgress,transitionCount:e.transitionCount??n.transitionCount,connectingTransitionCount:e.connectingTransitionCount??n.connectingTransitionCount,replacementCount:e.replacementCount??n.replacementCount,retireCount:e.retireCount??n.retireCount,lastDisconnectReason:e.lastDisconnectReason??n.lastDisconnectReason,lastReconnectReason:e.lastReconnectReason??n.lastReconnectReason,createdAt:e.createdAt??n.updatedAt,updatedAt:r}}let i=await this.resolvePeerIdentity(e.connectionId).catch(()=>null);return {...e,deviceId:e.deviceId??i?.deviceId??null,deviceIdHint:e.deviceIdHint??i?.deviceIdHint??null,remoteNodeId:e.remoteNodeId??i?.nodeId??null}}get browserAutoConnectPendingDevices(){return this.presenceManager.pendingDevices}set browserAutoConnectPendingDevices(e){this.presenceManager.pendingDevices=e;}async processBrowserAutoConnectSnapshot(e,t){await this.presenceManager.processBrowserAutoConnectSnapshot(e,t);}async hasHealthyBrowserAutoConnectSession(e){return this.presenceManager.hasHealthyBrowserAutoConnectSession(e)}get startedAutoConnectKey(){return this.presenceManager.autoConnectKey}set startedAutoConnectKey(e){this.presenceManager.autoConnectKey=e;}get browserPresenceLoopState(){return this.presenceManager.presenceLoopState}set browserPresenceLoopState(e){this.presenceManager.presenceLoopState=e;}triggerBrowserAutoConnectRecovery(e){this.presenceManager.triggerBrowserAutoConnectRecovery(e);}get currentUser(){if(this.authContext?.userId){let e=this.authContext.token??null,t=this.authContext.tokenProvider;return {id:this.authContext.userId,getToken:async(n=false)=>{if(e&&(!n||!t))return e;if(t)try{let r=await t(n);if(r)return r}catch{}let i=this.isTicketOnlyMode()?null:this.auth?.currentUser??null;if(i&&i.uid===this.authContext?.userId)try{return await i.getIdToken(n)}catch{return null}return null}}}return this.isTicketOnlyMode()?null:this.toRuntimeIdentity(this.auth?.currentUser??null)}onAuthChange(e){return this.authListeners.push(e),e(this.currentUser),()=>{this.authListeners=this.authListeners.filter(t=>t!==e);}}async checkForSSOToken(){this.isTicketOnlyMode()||await e().checkForSSOToken();}async waitForAuth(){this.isTicketOnlyMode()||this.isPersonalSpaceMode()||this.authContext?.userId||this.auth?.currentUser||await e().waitForAuth();}async signInAnonymously(){if(!this.isTicketOnlyMode()){if(this.options.authMode!=="anonymous")throw new Error(`[pluto-rtc] Anonymous sign-in is disabled when authMode=${this.options.authMode}.`);await e().signInAnonymously();}}async signInWithPluto(){if(this.isTicketOnlyMode())throw new Error('[openrtc] Pluto sign-in is unavailable when signalingMode="ticket-only".');await e().signInWithPluto();}async signOut(){let e=this.getCurrentUserId();await this.stopAuthScopedActivity({userId:e}),this.authContext=null,this.hasSyncedAuthToWasmClient=false,this.syncWasmAuthToken(),this.isTicketOnlyMode()||await this.auth?.signOut(),this.authListeners.forEach(t=>t(this.currentUser));}async getTurnCredentials(){return this.isTicketOnlyMode()||!this.auth?.currentUser?null:typeof this.options.turnCredentialsProvider=="function"?await this.options.turnCredentialsProvider()??null:null}async updatePresence(e,t,n=true,i=3e5,r,o){if(this.isTicketOnlyMode())return;let a=this.resolveWebLogicalDeviceId(),d=this.getNodeIdPersistenceMode()==="ephemeral"?S.EPHEMERAL_DEVICE_ID_TTL_MS:i,c=this.withWebPresenceMetadata(r,a);if(this.presenceManager.updatePresenceLoopState({localNodeId:e,ticket:t,metadata:c,deviceName:o?.trim()||this.getDefaultBrowserDeviceName()}),await this.getBrowserFirestoreSignaling().updatePresence(e,t,n,d,c,o),this._rtdbPresence&&this.rtdbPresenceScope){let l=this.resolveWebLogicalDeviceId();l&&(this.rtdbTicketVersion+=1,this._rtdbPresence.bumpTicketVersion(this.rtdbPresenceScope,l,this.rtdbTicketVersion).catch(u=>console.warn("[WasmBridge] RTDB ticketVersion bump failed:",u)));}}async setOffline(e){if(this.presenceManager.stopPresence(),!this.isTicketOnlyMode()){if(this._rtdbPresence&&this.rtdbPresenceScope){let t=this.resolveWebLogicalDeviceId();t&&this._rtdbPresence.markOffline(this.rtdbPresenceScope,t,this.rtdbTicketVersion).catch(n=>console.warn("[WasmBridge] RTDB markOffline failed:",n));}await this.getBrowserFirestoreSignaling().setOffline(e);}}async updateDevice(e,t){if(!e?.trim())throw new Error("updateDevice requires a deviceId");this.isTicketOnlyMode()||await this.getBrowserFirestoreSignaling().updateDevice(e,t);}async deleteDevice(e){if(!e?.trim())throw new Error("deleteDevice requires a deviceId");this.isTicketOnlyMode()||await this.getBrowserFirestoreSignaling().deleteDevice(e);}async cleanupStaleDevices(){this.isTicketOnlyMode()||await this.getBrowserFirestoreSignaling().cleanupStaleDevices();}async sendMessage(e,t,n,i){if(this.isTicketOnlyMode())throw new Error('[openrtc] sendMessage() is unavailable when signalingMode="ticket-only".');return this.getBrowserFirestoreSignaling().sendMessage(e,t,n,i)}async pollMessages(e){return this.isTicketOnlyMode()?[]:this.getBrowserFirestoreSignaling().pollMessages(e)}async searchDevices(e){return this.isTicketOnlyMode()?[]:this.getBrowserFirestoreSignaling().searchDevices(e)}async listDevicesWithStatus(){if(this.isTicketOnlyMode())return [];let e=this.getDiscoveryScopeId();if(!e)return [];let t=await this.waitForWasmClient(500);if(t&&typeof t.devices_with_status=="function"){let i=await t.devices_with_status(e);return (Array.isArray(i)?i:[]).filter(a=>this.matchesTag(x(a))).map(a=>this.normalizeDeviceStatusSnapshot(a))}return (await this.getBrowserFirestoreSignaling().listDevices()).map(i=>this.normalizeDeviceStatusSnapshot({...i,connectionStatus:i.online?"online":"disconnected"}))}async getPeerSession(e){let t=await this.waitForWasmClient(500);if(t&&typeof t.peer_session=="function"){let n=await t.peer_session(e);return !n||typeof n!="object"?null:this.normalizePeerSessionSnapshot(n)}return this.warnMissingWasmOnce("getPeerSession"),null}async listPeerSessions(){let e=await this.waitForWasmClient(500);if(e&&typeof e.peer_sessions=="function"){let t=await e.peer_sessions();return (Array.isArray(t)?t:[]).map(n=>this.normalizePeerSessionSnapshot(n)).filter(n=>!!(n.peerId||n.deviceId||n.deviceIdHint||n.nodeId||n.activeConnectionId))}return this.warnMissingWasmOnce("listPeerSessions"),[]}async waitForSettledPeer(e,t){let n=await this.waitForWasmClient(500);if(n&&typeof n.wait_for_settled_peer=="function"){let i=await n.wait_for_settled_peer(e,t);return !i||typeof i!="object"?null:this.normalizePeerSessionSnapshot(i)}return this.warnMissingWasmOnce("waitForSettledPeer"),null}async openPeerBi(e,t){let n=await this.waitForWasmClient(500);if(n&&typeof n.open_peer_bi=="function"){let i=await n.open_peer_bi(e,t);if(!i?.recv||!i?.send)throw new Error("WASM open_peer_bi returned an invalid bidirectional stream");return {readable:i.recv,writable:i.send}}throw this.warnMissingWasmOnce("openPeerBi"),new Error("WASM runtime does not support open_peer_bi()")}async openPeerBiTransportOnly(e,t){let n=await this.waitForWasmClient(500),i=n&&typeof n.open_peer_bi_transport_only=="function";if(console.debug("[WasmBridge] openPeerBiTransportOnly",{peerId:e,hasWasmClient:!!n,hasTransportOnly:i,timeoutMs:t}),i){let r=await n.open_peer_bi_transport_only(e,t);if(!r?.recv||!r?.send)throw new Error("WASM open_peer_bi_transport_only returned an invalid bidirectional stream");return {readable:r.recv,writable:r.send}}return console.debug("[WasmBridge] openPeerBiTransportOnly falling back to openPeerBi",{peerId:e}),this.openPeerBi(e,t)}async openPeerUni(e,t){let n=await this.waitForWasmClient(500);if(n&&typeof n.open_peer_uni=="function"){let i=await n.open_peer_uni(e,t);if(!i)throw new Error("WASM open_peer_uni returned an invalid writable stream");return {writable:i}}throw this.warnMissingWasmOnce("openPeerUni"),new Error("WASM runtime does not support open_peer_uni()")}async resolvePeerConnectionRecords(e){let t=await this.waitForWasmClient(500);if(t&&typeof t.resolve_peer_connection_records=="function"){let n=await t.resolve_peer_connection_records(e);return (Array.isArray(n)?n:[]).map(i=>({connectionId:typeof i.connectionId=="string"?i.connectionId:"",nodeId:typeof i.nodeId=="string"?i.nodeId:null,deviceId:typeof i.deviceId=="string"?i.deviceId:null,deviceIdHint:typeof i.deviceIdHint=="string"?i.deviceIdHint:null,endpointId:typeof i.endpointId=="string"?i.endpointId:null,transportGeneration:typeof i.transportGeneration=="number"?i.transportGeneration:0,transportStableId:typeof i.transportStableId=="number"?i.transportStableId:null,transportSource:typeof i.transportSource=="string"?i.transportSource:null,lastTransportChangeAtMs:typeof i.lastTransportChangeAtMs=="number"?i.lastTransportChangeAtMs:0,state:typeof i.state=="string"?i.state:"pending",statusReason:typeof i.statusReason=="string"?i.statusReason:null,createdAtMs:typeof i.createdAtMs=="number"?i.createdAtMs:0,updatedAtMs:typeof i.updatedAtMs=="number"?i.updatedAtMs:0}))}return this.warnMissingWasmOnce("resolvePeerConnectionRecords"),[]}async resolvePeerIdentity(e){let t=await this.waitForWasmClient(500);if(t){let n=i=>{if(!i||typeof i!="object")return {peerId:null,deviceId:null,deviceIdHint:null,nodeId:null};let r=i;return {peerId:typeof r.peerId=="string"?r.peerId:null,deviceId:typeof r.deviceId=="string"?r.deviceId:null,deviceIdHint:typeof r.deviceIdHint=="string"?r.deviceIdHint:null,nodeId:typeof r.nodeId=="string"?r.nodeId:null}};if(typeof t.peer_session=="function")try{let i=await t.peer_session(e),r=n(i);if(r.peerId||r.deviceId||r.deviceIdHint||r.nodeId)return r}catch{}if(typeof t.peer_snapshot=="function")try{return n(await t.peer_snapshot(e))}catch{}}return this.warnMissingWasmOnce("resolvePeerIdentity"),{peerId:null,deviceId:null,deviceIdHint:null,nodeId:null}}onDevicesChange(e,t){return this.isTicketOnlyMode()?(e([]),()=>{}):this.getBrowserFirestoreSignaling().onDevicesChange(e,t)}async subscribeDevices(e){return this.isTicketOnlyMode()?new ReadableStream({start(t){t.close();}}):this.getBrowserFirestoreSignaling().subscribeDevices()}startAutoConnect(e,t){this.presenceManager.startAutoConnect(e,t),this.startAutoConnectRecoverySubscription(),(async()=>{let n=await this.waitForWasmClient();if(!(!n||typeof n.start_auto_connect!="function"))try{n.start_auto_connect(e,t);}catch(i){console.warn("[WasmBridge] failed to record auto-connect context on wasm client",{userId:e,localDeviceId:t,error:i});}})();}startAutoConnectRecoverySubscription(){if(this.autoConnectRecoveryUnsubscribe)return;let e=this.onConnectionStateChange(t=>{let n=typeof t.state=="string"?t.state:"";(n==="closed"||n==="failed")&&this.presenceManager.triggerBrowserAutoConnectRecovery(t);});typeof e=="function"?this.autoConnectRecoveryUnsubscribe=e:e.then(t=>{typeof t=="function"&&(this.autoConnectRecoveryUnsubscribe=t);});}stopAutoConnectRecoverySubscription(){if(this.autoConnectRecoveryUnsubscribe){try{this.autoConnectRecoveryUnsubscribe();}catch(e){console.warn("[WasmBridge] auto-connect recovery unsubscribe failed",e);}this.autoConnectRecoveryUnsubscribe=null;}}notifyDisconnectRequested(e){this.presenceManager.notifyDisconnectRequested(e);}async setAutoConnectExcluded(e,t){await this.presenceManager.setAutoConnectExcluded(e,t);}async disconnectDevice(e){let t=await this.waitForWasmClient();if(!t||typeof t.disconnect_device!="function"){this.warnMissingWasmOnce("disconnectDevice"),await this.presenceManager.setAutoConnectExcluded(e,true).catch(()=>{});return}let n=this.browserAutoConnectPendingDevices.get(e),i=typeof n?.nodeId=="string"&&n.nodeId.trim().length>0?n.nodeId.trim():null;try{await t.disconnect_device(e,i);}catch(r){throw console.warn("[WasmBridge] disconnect_device failed",{deviceId:e,nodeIdHint:i,error:r?.message??String(r)}),r}}setCoreClient(e){e&&typeof e.connect=="function"?this.coreClient=e:this.coreClient=null;}async connectToDevice(e){let t=await this.waitForWasmClient();if(!t||typeof t.connect_device!="function")throw this.warnMissingWasmOnce("connectToDevice"),new Error("WASM runtime does not support connect_device()");let n=await t.connect_device(e.deviceId??null,e.endpointTicket),i=e.endpointTicket;return i&&this.coreClient&&this.coreClient.connect(i,2e4,e.deviceId??null).catch(o=>{console.warn("[WasmBridge] Failed to establish TS Connection after connect_device; WebRTC upgrade may be unavailable for this peer",{deviceId:e.deviceId??null,remoteNodeId:n?.remoteNodeId??null,connectionId:n?.connectionId??null,error:o?.message??String(o)});}),n}forceReconnectSnapshot(){(async()=>{let e=await this.waitForWasmClient();e&&typeof e.force_reconnect_snapshot=="function"?e.force_reconnect_snapshot():this.warnMissingWasmOnce("forceReconnectSnapshot");})();}startPresenceLoop(e,t,n,i,r){this.presenceManager.startPresenceLoop(e,t,n,i,r);}buildRtdbScope(e){if(this.isTicketOnlyMode())return null;let t=this.options.discoveryMode??"personal",n=this.appTag;if(t==="personal")return null;let i=e||this.getDiscoveryScopeId()||this.getCurrentUserId();return i?{kind:"user-scoped",appTag:n,userId:i}:null}async createSession(e){if(this.isTicketOnlyMode())throw new Error('[openrtc] createSession() is unavailable when signalingMode="ticket-only".');let t=this.getCurrentUserId();if(!t&&!e.initiator&&!e.target&&!this.isPersonalSpaceMode())throw new Error("createSession requires user scope");let n={...e,appTag:e.appTag??this.appTag,initiator:e.initiator??t??void 0,target:e.target??t??void 0};await this.getBrowserFirestoreSignaling().createSession(n);}async updateSession(e,t){if(this.isTicketOnlyMode())throw new Error('[openrtc] updateSession() is unavailable when signalingMode="ticket-only".');await this.getBrowserFirestoreSignaling().updateSession(e,t);}async subscribeSessions(e){return this.isTicketOnlyMode()?new ReadableStream({start(t){t.close();}}):this.getBrowserFirestoreSignaling().subscribeSessions(e)}async getLocalDeviceId(){return this.resolveWebLogicalDeviceId()}async isConnected(e){let t=await this.waitForWasmClient();return t&&typeof t.is_connected=="function"?await t.is_connected(e):false}async getConnectionStates(){let e=await this.waitForWasmClient(500);if(e&&typeof e.connection_states=="function"){let i=await e.connection_states(),r=(Array.isArray(i)?i:[]).map(o=>this.normalizeConnectionStateSnapshot(o)).filter(o=>!!o);return r.length>0&&X("[WasmBridge] replaying current wasm connection states",r.map(o=>({connectionId:o.connectionId,deviceId:o.deviceId??null,deviceIdHint:o.deviceIdHint??null,remoteNodeId:o.remoteNodeId??null,state:o.state,transportState:o.transportState??null,protocolState:o.protocolState??null,routable:o.routable??null}))),r}let n=(await this.listPeerSessions().catch(()=>[])).map(i=>this.toBackendConnectionStateFromPeerSession(i)).filter(i=>!!i);return n.length>0&&X("[WasmBridge] replaying current wasm connection states",n.map(i=>({connectionId:i.connectionId,deviceId:i.deviceId??null,deviceIdHint:i.deviceIdHint??null,remoteNodeId:i.remoteNodeId??null,state:i.state,transportState:i.transportState??null,protocolState:i.protocolState??null,routable:i.routable??null}))),n}onConnectionStateChange(e){if(typeof window>"u")return ()=>{};let t=new Map,n=new Map,i=null,r=false,o=()=>{if(i!==null||r)return;let d=()=>{if(i=null,r)return;let c=[...n.values()];n.clear();for(let l of c)this.enrichBackendConnectionState(l).then(u=>{r||this.deliverConnectionState(u,e,"event",t);}).catch(u=>{r||(console.warn("[WasmBridge] Failed to enrich connection-state-changed event:",u),this.deliverConnectionState(l,e,"event",t));});};typeof requestAnimationFrame=="function"?i=requestAnimationFrame(d):(i=0,queueMicrotask(d));},a=d=>{let c=d,l=c?.detail&&typeof c.detail=="object"?c.detail:null;if(!l)return;let u=this.normalizeWindowConnectionStateDetail(l);u&&(n.set(u.connectionId,u),o());};return window.addEventListener("connection-state-changed",a),this.getConnectionStates().then(d=>{d.forEach(c=>this.deliverConnectionState(c,e,"replay",t));}).catch(d=>{console.warn("[WasmBridge] Failed to replay wasm connection states after subscription:",d);}),()=>{r=true,i!==null&&typeof cancelAnimationFrame=="function"&&cancelAnimationFrame(i),i=null,n.clear(),window.removeEventListener("connection-state-changed",a);}}async sendExplicitFilePath(e,t,n=""){throw new Error("sendExplicitFilePath is native-only. Use sendExplicitFileData in web/wasm runtime.")}encodeTransferIdBytes(e){let t=e.replace(/-/g,"").toLowerCase();if(/^[0-9a-f]{32}$/.test(t)){let i=new Uint8Array(16);for(let r=0;r<16;r+=1)i[r]=Number.parseInt(t.slice(r*2,r*2+2),16);return i}let n=new Uint8Array(16);if(typeof crypto<"u"&&typeof crypto.getRandomValues=="function")return crypto.getRandomValues(n),n;for(let i=0;i<n.length;i+=1)n[i]=Math.floor(Math.random()*256);return n}buildWebRTCExplicitMessage(e,t,n,i,r){let o=r?4:0,a=new Uint8Array(25+o+i.byteLength),d=new DataView(a.buffer);a[0]=S.EXPLICIT_FILE_PROTOCOL_TYPE,a.set(e,1),d.setUint32(17,t>>>0,false),d.setUint32(21,n>>>0,false);let c=25;return r&&(d.setUint32(c,i.byteLength,false),c+=4),a.set(i,c),a}async sendExplicitFileOverWebRTC(e,t,n){if(typeof e.sendOnWebRTC!="function")throw new Error("WebRTC send is unavailable for explicit transfer");let i=60*1024,r=512*1024,o=r/2,a=8,d=this.encodeTransferIdBytes(n),c=new Uint8Array(await t.arrayBuffer()),l=c.byteLength===0?0:Math.ceil(c.byteLength/i),u=new TextEncoder().encode(JSON.stringify({transfer_id:n,filename:t.name,size:t.size,mime_type:t.type||"application/octet-stream"})),h=this.buildWebRTCExplicitMessage(d,4294967295,0,u,true);await e.sendOnWebRTC(h);let g=e.getWebRTCTransport?.();for(let f=0;f<l;f+=1){let v=c.slice(f*i,Math.min((f+1)*i,c.byteLength)),m=this.buildWebRTCExplicitMessage(d,f,l,v,false);await e.sendOnWebRTC(m),(f+1)%a===0&&g&&typeof g.getBufferedAmount=="function"&&typeof g.waitForDrain=="function"&&g.getBufferedAmount()>r&&await g.waitForDrain(o);}}async sendExplicitFileData(e){let t=e.connection,n=e.file,i=e.transferId&&e.transferId.trim().length>0?e.transferId:`transfer-${Date.now()}`,r=e.remoteNodeId?.trim()||t?.remoteNodeId?.trim()||t?.deviceId?.trim(),o=t;if(E("[WasmBridge] sendExplicitFileData start",{connectionId:e.connectionId??null,connectionRemoteNodeId:t?.remoteNodeId??null,remoteNodeId:r??null,fileName:n.name,fileSize:n.size,transferId:i}),o&&o.getUpgradeState?.()==="upgraded"&&typeof o.sendOnWebRTC=="function")try{await this.sendExplicitFileOverWebRTC(o,n,i),E("[WasmBridge] sendExplicitFileData completed via WebRTC",{remoteNodeId:r??null,transferId:i,fileName:n.name,fileSize:n.size});return}catch(u){console.warn("[WasmBridge] WebRTC explicit transfer failed; falling back to iroh",u);}if(!r)throw new Error("Web explicit transfer requires an active connection with a resolved remote node ID");let a=await this.waitForWasmClient();if(!a||typeof a.open_bi!="function")throw new Error("WASM explicit transfer requires open_bi support");let d=await a.open_bi(r);E("[WasmBridge] sendExplicitFileData open_bi resolved",{remoteNodeId:r,transferId:e.transferId??null});let c=d.send.getWriter(),l=new TextEncoder;try{let u={transfer_id:i,filename:n.name,size:n.size,mime_type:n.type||"application/octet-stream"},h=l.encode(JSON.stringify(u)),g=new Uint8Array(4);new DataView(g.buffer).setUint32(0,h.byteLength,!1),await c.write(new Uint8Array([S.EXPLICIT_FILE_PROTOCOL_TYPE])),await c.write(g),await c.write(h);let f=new Uint8Array(await n.arrayBuffer());for(let v=0;v<f.byteLength;v+=S.EXPLICIT_FILE_CHUNK_SIZE_BYTES){let m=f.slice(v,Math.min(v+S.EXPLICIT_FILE_CHUNK_SIZE_BYTES,f.byteLength));await c.write(m);}}finally{await c.close().catch(()=>{}),c.releaseLock(),E("[WasmBridge] sendExplicitFileData completed",{remoteNodeId:r,transferId:i,fileName:n.name,fileSize:n.size});}}async getTransferHistory(e=50){return []}async deleteTransferJob(e){}watchFriendDevices(e,t){return this.isTicketOnlyMode()?()=>{}:this.getBrowserFirestoreSignaling().watchFriendDevices(e,t)}async updateFriendTicket(e){this.isTicketOnlyMode()||await this.getBrowserFirestoreSignaling().updateFriendTicket(e);}};S.EXPLICIT_FILE_PROTOCOL_TYPE=2,S.EXPLICIT_FILE_CHUNK_SIZE_BYTES=64*1024,S.WEB_DEVICE_ID_STORAGE_PREFIX="pluto_rtc_web_device_identity",S.EPHEMERAL_DEVICE_ID_TTL_MS=C.browserIdentity.ephemeralDeviceIdTtlMs;var Ge=S;var Ke=class{constructor(e){this.backend=e;}get currentUser(){return this.backend.currentUser}setAuthContext(e){return this.backend.setAuthContext?.(e)}async signInAnonymously(){return this.backend.signInAnonymously()}async signInWithPluto(){if(typeof this.backend.signInWithPluto!="function")throw new Error("Selected runtime adapter does not support Pluto SSO.");return this.backend.signInWithPluto()}async signOut(){return this.backend.signOut()}async stopAuthScopedActivity(){typeof this.backend.stopAuthScopedActivity=="function"&&await this.backend.stopAuthScopedActivity();}async getTurnCredentials(){return this.backend.getTurnCredentials()}async updatePresence(e,t,n,i,r){return this.backend.updatePresence(e,t,n,i,r)}async setOffline(e){return this.backend.setOffline(e)}async cleanupStaleDevices(){return this.backend.cleanupStaleDevices()}async searchDevices(e){return this.backend.searchDevices(e)}async listDevicesWithStatus(){if(typeof this.backend.listDevicesWithStatus!="function")throw new Error("Selected runtime adapter does not support listDevicesWithStatus().");return this.backend.listDevicesWithStatus()}async getPeerSession(e){return typeof this.backend.getPeerSession!="function"?null:this.backend.getPeerSession(e)}async listPeerSessions(){return typeof this.backend.listPeerSessions!="function"?[]:this.backend.listPeerSessions()}async waitForSettledPeer(e,t){return typeof this.backend.waitForSettledPeer!="function"?null:this.backend.waitForSettledPeer(e,t)}async resolvePeerIdentity(e){return typeof this.backend.resolvePeerIdentity!="function"?{peerId:null,deviceId:null,deviceIdHint:null,nodeId:null}:this.backend.resolvePeerIdentity(e)}async resolvePeerConnectionRecords(e){return typeof this.backend.resolvePeerConnectionRecords!="function"?[]:this.backend.resolvePeerConnectionRecords(e)}async updateDevice(e,t){return this.backend.updateDevice(e,t)}async deleteDevice(e){return this.backend.deleteDevice(e)}onDevicesChange(e,t){return this.backend.onDevicesChange(e,t)}onAuthChange(e){return this.backend.onAuthChange(e)}async checkForSSOToken(){return this.backend.checkForSSOToken()}async waitForAuth(){return this.backend.waitForAuth()}async sendMessage(e,t,n,i){return this.backend.sendMessage(e,t,n,i)}async pollMessages(e){return this.backend.pollMessages(e)}async subscribeDevices(e){return this.backend.subscribeDevices(e)}startAutoConnect(e,t){this.backend.startAutoConnect(e,t);}startPresenceLoop(e,t,n,i,r){this.backend.startPresenceLoop(e,t,n,i,r);}async createSession(e){return this.backend.createSession(e)}async updateSession(e,t){return this.backend.updateSession(e,t)}async subscribeSessions(e){return this.backend.subscribeSessions(e)}forceReconnectSnapshot(){this.backend.forceReconnectSnapshot();}async getLocalDeviceId(){return typeof this.backend.getLocalDeviceId!="function"?null:this.backend.getLocalDeviceId()}async getLocalDeviceInfo(){return typeof this.backend.getLocalDeviceInfo!="function"?null:this.backend.getLocalDeviceInfo()}async updateLocalDeviceName(e){return typeof this.backend.updateLocalDeviceName!="function"?null:this.backend.updateLocalDeviceName(e)}async startManagedSessionNative(e){let t=this.backend;if(typeof t.startManagedSessionNative!="function")throw new Error("Selected runtime adapter does not support startManagedSessionNative().");return t.startManagedSessionNative(e)}async getManagedNodeId(e){if(console.info("[DelegatingRuntimeAdapter][getManagedNodeId] enter",{hasMethod:typeof this.backend.getManagedNodeId=="function",backendCtor:this.backend.constructor?.name??null}),typeof this.backend.getManagedNodeId!="function")return null;let t=await this.backend.getManagedNodeId(e);return console.info("[DelegatingRuntimeAdapter][getManagedNodeId] resolved",{result:t}),t}async startPresenceLoopOnce(e,t,n,i,r){let o=this.backend;if(typeof o.startPresenceLoopOnce!="function")throw new Error("Selected runtime adapter does not support startPresenceLoopOnce().");return o.startPresenceLoopOnce(e,t,n,i,r)}async startAutoConnectOnce(e,t){let n=this.backend;if(typeof n.startAutoConnectOnce!="function")throw new Error("Selected runtime adapter does not support startAutoConnectOnce().");return n.startAutoConnectOnce(e,t)}async getEndpointTicket(){if(typeof this.backend.getEndpointTicket!="function")throw new Error("Selected runtime adapter does not support getEndpointTicket().");return this.backend.getEndpointTicket()}async getEndpointTicketWithToken(e,t){let n=this.backend;return typeof n.getEndpointTicketWithToken!="function"?null:n.getEndpointTicketWithToken(e,t)}async registerSessionToken(e,t,n){let i=this.backend;typeof i.registerSessionToken=="function"&&await i.registerSessionToken(e,t,n);}async revokeSessionTokensByScope(e){let t=this.backend;return typeof t.revokeSessionTokensByScope!="function"?[]:t.revokeSessionTokensByScope(e)}async openPeerBi(e,t){if(typeof this.backend.openPeerBi!="function")throw new Error("Selected runtime adapter does not support openPeerBi().");return this.backend.openPeerBi(e,t)}async openPeerBiTransportOnly(e,t){let n=this.backend;return typeof n.openPeerBiTransportOnly=="function"?n.openPeerBiTransportOnly(e,t):this.openPeerBi(e,t)}async openPeerUni(e,t){if(typeof this.backend.openPeerUni!="function")throw new Error("Selected runtime adapter does not support openPeerUni().");return this.backend.openPeerUni(e,t)}async connectToDevice(e){if(typeof this.backend.connectToDevice!="function")throw new Error("Selected runtime adapter does not support connectToDevice().");return this.backend.connectToDevice(e)}async disconnectDevice(e){if(typeof this.backend.disconnectDevice!="function")throw new Error("Selected runtime adapter does not support disconnectDevice().");return this.backend.disconnectDevice(e)}async isConnected(e){return this.backend.isConnected(e)}async getConnectionStates(){return typeof this.backend.getConnectionStates!="function"?[]:this.backend.getConnectionStates()}onConnectionStateChange(e){return typeof this.backend.onConnectionStateChange!="function"?()=>{}:this.backend.onConnectionStateChange(e)}async sendExplicitFilePath(e,t,n){if(typeof this.backend.sendExplicitFilePath!="function")throw new Error("Selected runtime adapter does not support sendExplicitFilePath().");return this.backend.sendExplicitFilePath(e,t,n)}async sendExplicitFileData(e){if(typeof this.backend.sendExplicitFileData!="function")throw new Error("Selected runtime adapter does not support sendExplicitFileData().");return this.backend.sendExplicitFileData(e)}async getTransferHistory(e){return typeof this.backend.getTransferHistory!="function"?[]:this.backend.getTransferHistory(e)}async deleteTransferJob(e){if(typeof this.backend.deleteTransferJob=="function")return this.backend.deleteTransferJob(e)}getRuntimeCapabilities(){let e=this.backend;return typeof e.getRuntimeCapabilities=="function"?e.getRuntimeCapabilities():N(F)}async onIncomingNativeMessage(e){let t=this.backend;return typeof t.onIncomingNativeMessage!="function"?()=>{}:t.onIncomingNativeMessage(e)}unwrap(){return this.backend}setCoreClient(e){let t=this.backend;typeof t.setCoreClient=="function"&&t.setCoreClient(e);}};
2
- export{X as a,E as b,rn as c,ge as d,ee as e,fe as f,he as g,ve as h,le as i,wt as j,Ne as k,We as l,on as m,an as n,Ue as o,C as p,Dt as q,F as r,Rt as s,N as t,L as u,Ge as v,Ke as w};
@@ -1 +0,0 @@
1
- import {a,b}from'./chunk-DIQYFAGL.js';function c(){return a()}var t=class extends b{constructor(e){super({...e,bridge:a(),allowWasmFallback:e.allowWasmFallback??false});}};export{c as a,t as b};
package/wasm/README.md DELETED
@@ -1,64 +0,0 @@
1
- # Pluto RTC Rust Core
2
-
3
- The Rust crate is the realtime engine behind Pluto RTC.
4
-
5
- It powers:
6
- - the native runtime used by Tauri and other native hosts
7
- - the WASM runtime loaded by the npm package in browsers
8
-
9
- ## Core Responsibilities
10
- - app-scoped device discovery
11
- - presence publishing and cleanup
12
- - signaling messages and sessions
13
- - room membership
14
- - peer identity resolution
15
- - iroh endpoint lifecycle and connection management
16
- - shared runtime records used by both native and WASM hosts
17
-
18
- ## Native vs WASM
19
-
20
- ### Native
21
- Used for:
22
- - Tauri desktop/mobile-style hosts
23
- - headless or CLI-style runners
24
- - advanced endpoint and router integration
25
-
26
- Native-only features include:
27
- - endpoint adoption/export
28
- - custom router / no-internal-router mode
29
- - native auth relay helpers
30
- - protocol registry and plugin registration
31
-
32
- ### WASM
33
- The same runtime logic compiles to WebAssembly for browser hosts.
34
-
35
- The npm package loads that WASM build and forwards auth/runtime configuration into it. The browser path should behave like the native path at the runtime-contract level.
36
-
37
- ## Recommended Native Shape
38
- - use `ClientBuilder` / injected runtime construction
39
- - keep host-specific behavior outside the core where possible
40
- - use the runtime manager and protocol registry for advanced native composition
41
-
42
- ## Peer Sessions and Custom Protocols
43
-
44
- The Rust core owns one peer-session view per `deviceId`. Host layers should
45
- consume connected peer-session snapshots rather than reason about transport
46
- records directly.
47
-
48
- Protocol authors have two supported extension paths:
49
-
50
- 1. **Session-adjacent stream composition**
51
- - wait for a connected peer session
52
- - open `open_bi` / `open_uni` streams
53
- - define framing and message semantics externally
54
-
55
- 2. **ALPN protocol plugins**
56
- - register protocol plugins through `RuntimeManager` / `ProtocolRegistry`
57
- - use `SessionAdjacent` plugins for runtime-ready hooks without ALPN routing
58
- - use `Alpn` plugins when the native runtime should register a dedicated ALPN
59
-
60
- WASM/browser consumers should prefer the first model. The second is a
61
- Rust-first advanced capability.
62
-
63
- ## Important Rule
64
- Rust owns discovery, signaling, presence, lifecycle, and peer identity. TypeScript should wrap those contracts, not duplicate them.