openrtc 0.1.3 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/LICENSE +92 -0
  2. package/README.md +73 -9
  3. package/dist/DelegatingRuntimeAdapter-BxOcVIx_.d.ts +201 -0
  4. package/dist/{IpcRuntimeAdapter-CT-W0Mtp.d.ts → IpcRuntimeAdapter-U5AEH0jn.d.ts} +6 -2
  5. package/dist/auth/index.js +1 -1
  6. package/dist/auth/internal.js +1 -1
  7. package/dist/chunk-7DN33VUQ.js +1 -0
  8. package/dist/chunk-BLOEZIFJ.js +1 -0
  9. package/dist/chunk-FQETZQPW.js +2 -0
  10. package/dist/chunk-IUHUYHNZ.js +1 -0
  11. package/dist/chunk-UBEE42VU.js +2 -0
  12. package/dist/chunk-UPO23UMZ.js +3 -0
  13. package/dist/chunk-WNJE3MJF.js +1 -0
  14. package/dist/{factories-0TxDPMeu.d.ts → framing-lxzHEuSr.d.ts} +479 -226
  15. package/dist/index.d.ts +201 -7
  16. package/dist/index.js +2 -1
  17. package/dist/openrtc_bg.wasm +0 -0
  18. package/dist/runtime/WasmRuntimeAdapter.d.ts +2 -1
  19. package/dist/runtime/WasmRuntimeAdapter.js +1 -1
  20. package/dist/runtime/index.d.ts +213 -392
  21. package/dist/runtime/index.js +1 -1
  22. package/dist/runtime/tauri.d.ts +5 -6
  23. package/dist/runtime/tauri.js +1 -1
  24. package/dist/transport/index.d.ts +11 -0
  25. package/dist/transport/index.js +1 -0
  26. package/dist/{DelegatingRuntimeAdapter-CW8d78dZ.d.ts → types-D0fRvUbN.d.ts} +222 -171
  27. package/env/index.d.ts +64 -0
  28. package/env/index.mjs +230 -0
  29. package/package.json +29 -18
  30. package/dist/chunk-26POO5PL.js +0 -4
  31. package/dist/chunk-4MH42GUI.js +0 -2
  32. package/dist/chunk-D54VGRRH.js +0 -1
  33. package/dist/chunk-DIQYFAGL.js +0 -2
  34. package/dist/chunk-PZ25OCVG.js +0 -2
  35. package/dist/chunk-UVASANPG.js +0 -1
  36. package/wasm/README.md +0 -64
  37. package/wasm/openrtc.d.ts +0 -320
  38. package/wasm/openrtc.js +0 -2290
  39. package/wasm/openrtc_bg.wasm +0 -0
  40. package/wasm/openrtc_bg.wasm.d.ts +0 -113
  41. package/wasm/package.json +0 -16
package/LICENSE ADDED
@@ -0,0 +1,92 @@
1
+ Required Notice: Copyright (c) 2026 Bryant Hargreaves and OpenRTC contributors.
2
+ Licensor Line of Business: OpenRTC realtime collaboration runtime, SDKs, developer services, and related tools (https://openrtc.app)
3
+
4
+ # PolyForm Shield License 1.0.0
5
+
6
+ <https://polyformproject.org/licenses/shield/1.0.0>
7
+
8
+ ## Acceptance
9
+
10
+ In order to get any license under these terms, you must agree to them as both strict obligations and conditions to all your licenses.
11
+
12
+ ## Copyright License
13
+
14
+ The licensor grants you a copyright license for the software to do everything you might do with the software that would otherwise infringe the licensor's copyright in it for any permitted purpose. However, you may only distribute the software according to [Distribution License](#distribution-license) and make changes or new works based on the software according to [Changes and New Works License](#changes-and-new-works-license).
15
+
16
+ ## Distribution License
17
+
18
+ The licensor grants you an additional copyright license to distribute copies of the software. Your license to distribute covers distributing the software with changes and new works permitted by [Changes and New Works License](#changes-and-new-works-license).
19
+
20
+ ## Notices
21
+
22
+ You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms or the URL for them above, as well as copies of any plain-text lines beginning with `Required Notice:` that the licensor provided with the software. For example:
23
+
24
+ > Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
25
+
26
+ ## Changes and New Works License
27
+
28
+ The licensor grants you an additional copyright license to make changes and new works based on the software for any permitted purpose.
29
+
30
+ ## Patent License
31
+
32
+ The licensor grants you a patent license for the software that covers patent claims the licensor can license, or becomes able to license, that you would infringe by using the software.
33
+
34
+ ## Noncompete
35
+
36
+ Any purpose is a permitted purpose, except for providing any product that competes with the software or any product the licensor or any of its affiliates provides using the software.
37
+
38
+ ## Competition
39
+
40
+ Goods and services compete even when they provide functionality through different kinds of interfaces or for different technical platforms. Applications can compete with services, libraries with plugins, frameworks with development tools, and so on, even if they're written in different programming languages or for different computer architectures. Goods and services compete even when provided free of charge. If you market a product as a practical substitute for the software or another product, it definitely competes.
41
+
42
+ ## New Products
43
+
44
+ If you are using the software to provide a product that does not compete, but the licensor or any of its affiliates brings your product into competition by providing a new version of the software or another product using the software, you may continue using versions of the software available under these terms beforehand to provide your competing product, but not any later versions.
45
+
46
+ ## Discontinued Products
47
+
48
+ You may begin using the software to compete with a product or service that the licensor or any of its affiliates has stopped providing, unless the licensor includes a plain-text line beginning with `Licensor Line of Business:` with the software that mentions that line of business. For example:
49
+
50
+ > Licensor Line of Business: YoyodyneCMS Content Management System (http://example.com/cms)
51
+
52
+ ## Sales of Business
53
+
54
+ If the licensor or any of its affiliates sells a line of business developing the software or using the software to provide a product, the buyer can also enforce [Noncompete](#noncompete) for that product.
55
+
56
+ ## Fair Use
57
+
58
+ You may have "fair use" rights for the software under the law. These terms do not limit them.
59
+
60
+ ## No Other Rights
61
+
62
+ These terms do not allow you to sublicense or transfer any of your licenses to anyone else, or prevent the licensor from granting licenses to anyone else. These terms do not imply any other licenses.
63
+
64
+ ## Patent Defense
65
+
66
+ If you make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
67
+
68
+ ## Violations
69
+
70
+ The first time you are notified in writing that you have violated any of these terms, or done anything with the software not covered by your licenses, your licenses can nonetheless continue if you come into full compliance with these terms, and take practical steps to correct past violations, within 32 days of receiving notice. Otherwise, all your licenses end immediately.
71
+
72
+ ## No Liability
73
+
74
+ ***As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.***
75
+
76
+ ## Definitions
77
+
78
+ The **licensor** is the individual or entity offering these terms, and the **software** is the software the licensor makes available under these terms.
79
+
80
+ A **product** can be a good or service, or a combination of them.
81
+
82
+ **You** refers to the individual or entity agreeing to these terms.
83
+
84
+ **Your company** is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all its affiliates.
85
+
86
+ **Affiliates** means the other organizations than an organization has control over, is under the control of, or is under common control with.
87
+
88
+ **Control** means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
89
+
90
+ **Your licenses** are all the licenses granted to you for the software under these terms.
91
+
92
+ **Use** means anything you do with the software requiring one of your licenses.
package/README.md CHANGED
@@ -8,27 +8,81 @@ It does not implement a second realtime engine. It exposes the Rust runtime to:
8
8
 
9
9
  ## Recommended Usage
10
10
 
11
- Use the OpenRTC client entry points for new integrations:
11
+ Use the OpenRTC client entry points for new integrations, and choose the
12
+ avenue that matches your product:
13
+
14
+ - `user-scoped` for a signed-in user's durable device mesh
15
+ - `space` for a small live shared namespace
16
+ - rooms for intentional group membership
17
+ - tickets/share grants for explicit one-off pairing without a roster
12
18
 
13
19
  ```ts
14
20
  import { OpenRTC } from 'openrtc';
15
21
 
16
22
  const client = OpenRTC({
17
23
  apiKey: 'pk_live_...',
24
+ discoveryMode: 'user-scoped',
18
25
  authMode: 'external',
19
26
  });
20
27
 
21
28
  await client.connect();
29
+ await client.devices.startSession({
30
+ deviceName: 'Work Laptop',
31
+ });
22
32
  ```
23
33
 
24
34
  For normal app code, the default flow is:
25
35
 
26
- 1. discover or select a `deviceId`
27
- 2. call `connectPeer(...)` or `connectToDevice(...)`
28
- 3. wait for `waitForConnectedPeer(deviceId)`
29
- 4. open peer-targeted streams with `openPeerBi(...)` / `openPeerUni(...)`
36
+ 1. discover or select a device
37
+ 2. open a named logical app channel with `client.channels.connect({ device, channelId })`
38
+ 3. send and receive app payloads on that channel
39
+
40
+ `channels.connect(...)` owns the peer dial, readiness wait, channel selection,
41
+ roster-ticket reuse, and default `session` lifecycle scope. Use `client.peers.connect(...)`,
42
+ `client.channels.openBi(...)`, `connectScoped(...)`, `openPeerBi(...)`, or
43
+ `openPeerUni(...)` only when you need explicit lifecycle, stream, or transport
44
+ control.
30
45
 
31
- Low-level peer handles returned by runtime methods, along with `openPeerBi(deviceId)` and `openPeerUni(deviceId)`, remain available for advanced runtime flows, but they are not the default integration model.
46
+ ## Naming Guide
47
+
48
+ Prefer the short app-facing names in new code:
49
+
50
+ ```ts
51
+ import { OpenRTC, spaceToken } from 'openrtc';
52
+
53
+ const client = OpenRTC({
54
+ apiKey: 'pk_live_...',
55
+ discoveryMode: 'space',
56
+ authMode: 'anonymous',
57
+ space: 'team-canvas',
58
+ spaceTokenProvider: spaceToken({
59
+ apiKey: 'pk_live_...',
60
+ space: 'team-canvas',
61
+ }),
62
+ });
63
+ ```
64
+
65
+ - Use `space` instead of `spaceKey` in app code.
66
+ - Use `spaceTokenProvider` and `spaceToken(...)` for scoped shared-space auth.
67
+ - Use `client.devices.*`, `client.rooms.*`, `client.tickets.*`,
68
+ `client.channels.*`, and `client.peers.*` before reaching for lower-level
69
+ runtime names.
70
+
71
+ ## Discovery Avenues
72
+
73
+ OpenRTC discovery is not one generic live device list:
74
+
75
+ - User-scope/user-device is the persistent owned-device avenue. Devices remain
76
+ visible while `presenceStatus` degrades `online` -> `idle` -> `offline`, and
77
+ are removed only by explicit deletion or offline retention expiry.
78
+ - Spaces and rooms are ephemeral collaboration avenues. Active rosters may
79
+ filter or clean up stale entries.
80
+ - Ticket-only/share flows do not use a hosted discovery roster; the ticket or
81
+ grant is the bootstrap avenue.
82
+
83
+ Status-aware device APIs should preserve presence-only changes and merge
84
+ authoritative roster refreshes with live watch state so no avenue-specific
85
+ device disappears just because one read model missed it.
32
86
 
33
87
  ## What This Package Owns
34
88
  - runtime factories and adapters
@@ -54,8 +108,8 @@ Those responsibilities belong to the Rust runtime and the host platform adapter.
54
108
 
55
109
  The recommended TypeScript extension path is:
56
110
 
57
- 1. wait for a Rust-backed connected peer session
58
- 2. open a bidirectional or unidirectional stream
111
+ 1. choose the public avenue (`user-scoped`, `space`, room, or ticket/share)
112
+ 2. open a named logical channel with `client.channels.connect(...)`
59
113
  3. implement your own framing and message semantics in app code
60
114
 
61
115
  This keeps the runtime responsible for peer/session establishment while leaving
@@ -83,15 +137,25 @@ full ALPN plugin layer.
83
137
  - `openrtc-tauri`
84
138
  - `createTauriIpcBridge()`
85
139
  - `TauriRuntimeAdapter`
140
+ - Rust plugin crate: `openrtc-tauri-plugin`
86
141
  - `openrtc/runtime/tauri` remains as a deprecated compatibility shim for one release cycle
87
142
 
143
+ For Tauri desktop/mobile apps, use `OpenRTC.native(options)` with the
144
+ `openrtc-tauri` bridge and register `openrtc-tauri-plugin` in the Rust Tauri
145
+ builder. Do not copy product-owned RTC command files into new apps. The plugin
146
+ owns the native IPC command set and delegates lifecycle, discovery, presence,
147
+ auto-connect, and connection state to one `openrtc::client::Client`. Do not use
148
+ `OpenRTC(options)` inside a Tauri shell unless you intentionally want the
149
+ browser/WASM runtime for a prototype; that path bypasses the native Rust runtime
150
+ and can hide native lifecycle/presence issues from tests.
151
+
88
152
  ## Auth Model
89
153
  - `anonymous`: no Pluto auth required
90
154
  - `required`: Pluto auth required; the SDK may initiate Pluto SSO
91
155
  - `external`: Pluto auth still required, but the host app acquires it and injects it into the runtime
92
156
 
93
157
  ## Design Rule
94
- If a feature requires discovery, signaling, presence, or lifecycle state, the TypeScript package should delegate to Rust rather than reimplement it locally, except for the scoped browser Firebase host layer where the official browser SDK is the source of truth.
158
+ If a feature requires discovery, signaling, presence, or lifecycle state, the TypeScript package should delegate to Rust rather than reimplement it locally, except for the scoped browser Firebase host layer where the official browser SDK is the source of truth. In both cases, keep the avenue semantics intact: persistent user-device rosters are not space/room live rosters.
95
159
 
96
160
  ## Allowed vs. Not Allowed
97
161
 
@@ -0,0 +1,201 @@
1
+ import { D as DiscoveryMode, A as AuthMode, S as SignalingMode, E as ExplicitFileDataSendParams, I as ISignalingBackend, R as RuntimeIdentity, a as Device, b as DeviceStatusSnapshot, P as PeerSessionSnapshot, c as ResolvedPeerIdentity, M as ManagedConnectionRecord, d as SignalingEnvelope, e as DeviceEvent, f as SignalingSession, g as SessionEvent, L as LocalDeviceInfo, N as NativeManagedSessionStartResult, G as GrantScope, B as BackendPeerBiStream, h as BackendPeerUniStream, i as NativeConnectResult, j as BackendConnectionState } from './types-D0fRvUbN.js';
2
+
3
+ type RuntimeAdapterKind = 'browser-wasm' | 'native-ipc' | 'tauri-ipc' | 'unknown';
4
+ interface RuntimeCapabilities {
5
+ adapter: RuntimeAdapterKind;
6
+ signaling: {
7
+ firestore: boolean;
8
+ nativeIpc: boolean;
9
+ rtdbPresence: boolean;
10
+ };
11
+ transport: {
12
+ irohQuic: boolean;
13
+ irohLan: boolean;
14
+ webRtcUpgrade: boolean;
15
+ webRtcLan: boolean;
16
+ nativeWebRtc: boolean;
17
+ moq: boolean;
18
+ ble: boolean;
19
+ wasm: boolean;
20
+ };
21
+ nativeProtocols: {
22
+ productAlpn: boolean;
23
+ irohDocs: boolean;
24
+ irohBlobs: boolean;
25
+ irohGossip: boolean;
26
+ };
27
+ lifecycle: {
28
+ managedSession: boolean;
29
+ autoConnect: boolean;
30
+ manualDisconnect: boolean;
31
+ connectionStateEvents: boolean;
32
+ peerSessions: boolean;
33
+ };
34
+ transfers: {
35
+ explicitFilePath: boolean;
36
+ explicitFileData: boolean;
37
+ history: boolean;
38
+ };
39
+ fallback: {
40
+ wasm: boolean;
41
+ };
42
+ }
43
+ interface RuntimeCapabilityProfile {
44
+ environment: 'web' | 'native' | 'unknown';
45
+ transports: {
46
+ quic: boolean;
47
+ irohRelay: boolean;
48
+ irohLan: boolean;
49
+ webRtc: boolean;
50
+ webRtcLan: boolean;
51
+ moq: boolean;
52
+ ble: boolean;
53
+ };
54
+ lifecycle: RuntimeCapabilities['lifecycle'];
55
+ storage: {
56
+ localFileSystem: boolean;
57
+ transferHistory: boolean;
58
+ };
59
+ nativeProtocols: RuntimeCapabilities['nativeProtocols'];
60
+ }
61
+ interface NativeRuntimeTransportFeatureStatus {
62
+ compiled?: boolean;
63
+ enabled?: boolean;
64
+ }
65
+ interface NativeRuntimeStatusSnapshot {
66
+ ready?: boolean;
67
+ nodeId?: string | null;
68
+ node_id?: string | null;
69
+ transport?: {
70
+ irohQuic?: NativeRuntimeTransportFeatureStatus;
71
+ irohLan?: NativeRuntimeTransportFeatureStatus;
72
+ webRtc?: NativeRuntimeTransportFeatureStatus;
73
+ webRtcLan?: NativeRuntimeTransportFeatureStatus;
74
+ moq?: NativeRuntimeTransportFeatureStatus;
75
+ ble?: NativeRuntimeTransportFeatureStatus;
76
+ irohRelayOnly?: boolean;
77
+ irohRelayTransportPolicy?: string | null;
78
+ };
79
+ }
80
+ declare const BROWSER_WASM_RUNTIME_CAPABILITIES: RuntimeCapabilities;
81
+ declare const NATIVE_IPC_RUNTIME_CAPABILITIES: RuntimeCapabilities;
82
+ declare function cloneRuntimeCapabilities(capabilities: RuntimeCapabilities): RuntimeCapabilities;
83
+ declare function runtimeCapabilitiesFromNativeStatus(status: NativeRuntimeStatusSnapshot | null | undefined, allowWasmFallback?: boolean): RuntimeCapabilities;
84
+ declare function runtimeCapabilityProfile(capabilities: RuntimeCapabilities): RuntimeCapabilityProfile;
85
+
86
+ type AuthContext = {
87
+ userId: string;
88
+ token?: string | null;
89
+ refreshToken?: string | null;
90
+ customToken?: string | null;
91
+ tokenProvider?: (forceRefresh?: boolean) => Promise<string | null>;
92
+ expiresAtMs?: number | null;
93
+ };
94
+
95
+ interface WasmBridgeOptions {
96
+ apiKey?: string;
97
+ discoveryMode?: DiscoveryMode;
98
+ spaceKey?: string;
99
+ authMode?: AuthMode;
100
+ signalingMode?: SignalingMode;
101
+ projectId?: string;
102
+ storagePrefix?: string;
103
+ nodeIdPersistence?: 'persistent' | 'ephemeral';
104
+ localDeviceId?: string;
105
+ deviceName?: string;
106
+ turnCredentialsProvider?: () => Promise<{
107
+ iceServers?: RTCIceServer[];
108
+ } | null | undefined>;
109
+ applicationCrypto?: ExplicitFileDataSendParams['applicationCrypto'];
110
+ spaceAuth?: 'scoped-token';
111
+ }
112
+
113
+ declare abstract class DelegatingRuntimeAdapter implements ISignalingBackend {
114
+ protected readonly backend: ISignalingBackend;
115
+ protected constructor(backend: ISignalingBackend);
116
+ get currentUser(): RuntimeIdentity | null;
117
+ setAuthContext(context: AuthContext | null): Promise<void> | void;
118
+ signInAnonymously(): Promise<void>;
119
+ signInWithPluto(): Promise<void>;
120
+ signOut(): Promise<void>;
121
+ stopAuthScopedActivity(): Promise<void>;
122
+ getTurnCredentials(): Promise<any>;
123
+ updatePresence(localNodeId: string, ticketStr: string, isOnline: boolean, ttlMs: number, metadata?: string): Promise<void>;
124
+ setOffline(localNodeId: string): Promise<void>;
125
+ cleanupStaleDevices(): Promise<void>;
126
+ searchDevices(excludeNodeId?: string): Promise<Device[]>;
127
+ listDevicesWithStatus(): Promise<DeviceStatusSnapshot[]>;
128
+ getPeerSession(id: string): Promise<PeerSessionSnapshot | null>;
129
+ listPeerSessions(): Promise<PeerSessionSnapshot[]>;
130
+ waitForSettledPeer(id: string, timeoutMs?: number): Promise<PeerSessionSnapshot | null>;
131
+ resolvePeerIdentity(id: string): Promise<ResolvedPeerIdentity>;
132
+ resolvePeerConnectionRecords(id: string): Promise<ManagedConnectionRecord[]>;
133
+ updateDevice(deviceId: string, updates: {
134
+ deviceName?: string;
135
+ capabilities?: Device['capabilities'];
136
+ metadata?: string;
137
+ }): Promise<void>;
138
+ deleteDevice(deviceId: string): Promise<void>;
139
+ onDevicesChange(callback: (devices: Device[]) => void, excludeNodeId?: string): () => void;
140
+ onAuthChange(callback: (user: RuntimeIdentity | null) => void): () => void;
141
+ checkForSSOToken(): Promise<void>;
142
+ waitForAuth(): Promise<void>;
143
+ sendMessage(targetId: string, payload: string, state?: string, replyPayload?: string): Promise<string>;
144
+ pollMessages(targetId: string): Promise<SignalingEnvelope[]>;
145
+ subscribeDevices(userId: string): Promise<ReadableStream<DeviceEvent[]>>;
146
+ startAutoConnect(userId: string, localDeviceId: string): void;
147
+ startPresenceLoop(userId: string, localNodeId: string, deviceName: string, ticket: string, metadata?: string): void;
148
+ createSession(session: SignalingSession): Promise<void>;
149
+ updateSession(sessionId: string, updateData: any): Promise<void>;
150
+ subscribeSessions(localDeviceId: string): Promise<ReadableStream<SessionEvent[]>>;
151
+ forceReconnectSnapshot(): void;
152
+ getLocalDeviceId(): Promise<string | null>;
153
+ getLocalDeviceInfo(): Promise<LocalDeviceInfo | null>;
154
+ updateLocalDeviceName(deviceName: string): Promise<LocalDeviceInfo | null>;
155
+ startManagedSessionNative(options: {
156
+ userId: string;
157
+ deviceName?: string;
158
+ localDeviceId?: string | null;
159
+ metadata?: string;
160
+ autoConnect?: boolean;
161
+ presence?: boolean;
162
+ }): Promise<NativeManagedSessionStartResult>;
163
+ getManagedNodeId(options?: {
164
+ initializeIfMissing?: boolean;
165
+ }): Promise<string | null>;
166
+ startPresenceLoopOnce(userId: string, localNodeId: string, deviceName: string, ticket: string, metadata?: string): Promise<void>;
167
+ startAutoConnectOnce(userId: string, localDeviceId: string): Promise<void>;
168
+ getEndpointTicket(): Promise<string>;
169
+ getEndpointTicketWithToken(scope: GrantScope, maxConnections: number): Promise<string | null>;
170
+ registerSessionToken(token: string, scope: GrantScope, maxConnections: number): Promise<void>;
171
+ revokeSessionTokensByScope(scope: GrantScope): Promise<string[]>;
172
+ openPeerBi(id: string, timeoutMs?: number): Promise<BackendPeerBiStream>;
173
+ incoming_streams(): Promise<ReadableStream<unknown>>;
174
+ openPeerNativeBi(id: string, label: string, timeoutMs?: number): Promise<BackendPeerBiStream>;
175
+ openPeerBiTransportOnly(id: string, timeoutMs?: number): Promise<BackendPeerBiStream>;
176
+ openPeerUni(id: string, timeoutMs?: number): Promise<BackendPeerUniStream>;
177
+ connectToDevice(params: {
178
+ deviceId?: string | null;
179
+ endpointTicket: string;
180
+ }): Promise<NativeConnectResult>;
181
+ disconnectDevice(deviceId: string): Promise<void>;
182
+ isConnected(nodeId: string): Promise<boolean>;
183
+ getConnectionStates(): Promise<BackendConnectionState[]>;
184
+ onConnectionStateChange(callback: (state: BackendConnectionState) => void): Promise<() => void> | (() => void);
185
+ sendExplicitFilePath(connectionId: string, filePath: string, transferId?: string): Promise<string>;
186
+ sendExplicitFileData(params: ExplicitFileDataSendParams): Promise<void>;
187
+ getTransferHistory(limit?: number): Promise<Array<[string, unknown]>>;
188
+ deleteTransferJob(jobId: string): Promise<void>;
189
+ getRuntimeCapabilities(): RuntimeCapabilities;
190
+ onIncomingNativeMessage(callback: (connectionId: string, remoteNodeId: string | null, message: any) => void): Promise<() => void>;
191
+ unwrap(): ISignalingBackend;
192
+ /**
193
+ * Forward setCoreClient() to the inner backend if it implements it. This
194
+ * lets the core Client inject a reference into backends (e.g. WasmBridge)
195
+ * that need to escalate transport-level dials into full Client.connect()
196
+ * handshakes.
197
+ */
198
+ setCoreClient(client: unknown): void;
199
+ }
200
+
201
+ export { type AuthContext as A, BROWSER_WASM_RUNTIME_CAPABILITIES as B, DelegatingRuntimeAdapter as D, NATIVE_IPC_RUNTIME_CAPABILITIES as N, type RuntimeCapabilities as R, type WasmBridgeOptions as W, type RuntimeCapabilityProfile as a, type RuntimeAdapterKind as b, type NativeRuntimeStatusSnapshot as c, type NativeRuntimeTransportFeatureStatus as d, cloneRuntimeCapabilities as e, runtimeCapabilityProfile as f, runtimeCapabilitiesFromNativeStatus as r };
@@ -1,4 +1,5 @@
1
- import { W as WasmBridgeOptions, k as ClientOptions, D as DelegatingRuntimeAdapter } from './DelegatingRuntimeAdapter-CW8d78dZ.js';
1
+ import { C as ClientOptions } from './types-D0fRvUbN.js';
2
+ import { W as WasmBridgeOptions, D as DelegatingRuntimeAdapter } from './DelegatingRuntimeAdapter-BxOcVIx_.js';
2
3
 
3
4
  type PlutoIpcUnlisten = () => void | Promise<void>;
4
5
  interface PlutoIpcBridge {
@@ -6,6 +7,9 @@ interface PlutoIpcBridge {
6
7
  listen<T = unknown>(event: string, handler: (payload: T) => void): Promise<PlutoIpcUnlisten>;
7
8
  isAvailable?(): boolean | Promise<boolean>;
8
9
  }
10
+ type NativeIpcFailureKind = 'command-unavailable' | 'runtime-unavailable' | 'timeout' | 'unknown';
11
+ declare function classifyNativeIpcFailure(error: unknown): NativeIpcFailureKind;
12
+ declare function isNativeIpcCommandUnavailable(error: unknown): boolean;
9
13
 
10
14
  interface NativeIpcBridgeOptions extends WasmBridgeOptions {
11
15
  allowWasmFallback?: boolean;
@@ -21,4 +25,4 @@ declare class IpcRuntimeAdapter extends DelegatingRuntimeAdapter {
21
25
  constructor(options: IpcRuntimeAdapterOptions);
22
26
  }
23
27
 
24
- export { IpcRuntimeAdapter as I, type NativeIpcBridgeOptions as N, type PlutoIpcBridge as P, type IpcRuntimeAdapterOptions as a, type PlutoIpcUnlisten as b };
28
+ export { IpcRuntimeAdapter as I, type NativeIpcBridgeOptions as N, type PlutoIpcBridge as P, type IpcRuntimeAdapterOptions as a, type NativeIpcFailureKind as b, type PlutoIpcUnlisten as c, classifyNativeIpcFailure as d, isNativeIpcCommandUnavailable as i };
@@ -1 +1 @@
1
- export{f as authHost,e as getAuthHost,d as registerDesktopAuthRelay}from'../chunk-4MH42GUI.js';
1
+ export{E as authHost,D as getAuthHost,C as registerDesktopAuthRelay}from'../chunk-FQETZQPW.js';
@@ -1 +1 @@
1
- export{d as registerDesktopAuthRelay}from'../chunk-4MH42GUI.js';
1
+ export{C as registerDesktopAuthRelay}from'../chunk-FQETZQPW.js';
@@ -0,0 +1 @@
1
+ import {g,h}from'./chunk-UBEE42VU.js';function c(){return g()}var i=class extends h{constructor(r){super({...r,bridge:g(),allowWasmFallback:r.allowWasmFallback??false});}};export{c as a,i as b};
@@ -0,0 +1 @@
1
+ var e=["iroh","iroh-quic","iroh-relay","iroh-lan","ble","webrtc","webrtc-lan","moq"],t=new Set(e);function r(o){if(typeof o!="string")return;let n=o.trim().toLowerCase();return t.has(n)?n:void 0}function i(o){let n=r(o);return n==="iroh"||n==="iroh-quic"||n==="iroh-relay"||n==="iroh-lan"||n==="ble"}function a(o){let n=r(o);return n==="iroh-quic"||n==="iroh-lan"||n==="ble"}function l(o){let n=r(o);return n==="webrtc"||n==="webrtc-lan"||n==="moq"}function s(o){let n=r(o);return n==="webrtc"||n==="webrtc-lan"}function c(o){let n=r(o);return n==="webrtc"||n==="moq"}export{e as a,r as b,i as c,a as d,l as e,s as f,c as g};
@@ -0,0 +1,2 @@
1
+ import {getApps,initializeApp}from'firebase/app';import {getFunctions,connectFunctionsEmulator,httpsCallable}from'firebase/functions';import {browserLocalPersistence,inMemoryPersistence,browserPopupRedirectResolver,initializeAuth,getAuth,connectAuthEmulator,setPersistence,onIdTokenChanged,getIdToken,signInWithCustomToken,onAuthStateChanged,signInAnonymously,signInWithEmailAndPassword,createUserWithEmailAndPassword,signOut,deleteUser,updateProfile,GoogleAuthProvider,OAuthProvider,signInWithCredential,signInWithPopup,signInWithRedirect,getRedirectResult}from'firebase/auth';function _(){return typeof window>"u"?false:!!(window.__TAURI_IPC__||window.__TAURI_INTERNALS__||window.__TAURI__||window.location.protocol==="tauri:"||window.location.hostname==="tauri.localhost")}var E=new Set;function S(e,t){E.has(e)||(E.add(e),console.warn(t));}function ie(e){return /^pk_(live|test)_[0-9a-f]{40}$/.test(e)}async function Ee(e,t){let n=`${e}:${t}`,r=new TextEncoder().encode(n),i=await crypto.subtle.digest("SHA-256",r);return Array.from(new Uint8Array(i)).map(d=>d.toString(16).padStart(2,"0")).join("")}function I(e){let t=typeof e.apiKey=="string"?e.apiKey.trim():"";if(t)return ie(t)||S(`invalid-api-key:${t.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_${t.slice(-16)}`;throw new Error("[openrtc] `apiKey` is required. Create an app at https://api.openrtc.app/developer.")}function P(e){return e.authMode?e.authMode:("apiKey"in e&&typeof e.apiKey=="string"&&e.apiKey.trim().length>0&&typeof(e.spaceKey??e.space)=="string"&&(e.spaceKey??e.space).trim().length>0||S("default-auth-mode","[pluto-rtc] `authMode` is not set; defaulting to `anonymous` for compatibility."),"anonymous")}function He(e){let t=typeof e.projectId=="string"?e.projectId.trim():"";return t||(S("default-project-id","[pluto-rtc] `projectId` is not set; defaulting to the built-in PlutoRTC Firebase project."),b)}function H(e){return e.trim().replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")}function Le(e){let t="storagePrefix"in e&&typeof e.storagePrefix=="string"?H(e.storagePrefix):"";return t||H(I(e))||"default"}var Fe={devicesPerUser:2,maxRooms:10,maxMembersPerRoom:5,maxPersonalDevices:25},R="https://relay.cloudflare.mediaoverquic.com:443/moq",se=[{urls:"stun:stun.l.google.com:19302"},{urls:"stun:stun.cloudflare.com:3478"}],L={iceServers:se},B={relayUrl:R};var F=["iroh-relay","iroh","moq"];function ae(e){return (Array.isArray(e.urls)?e.urls:[e.urls]).some(n=>typeof n=="string"&&(n.startsWith("turn:")||n.startsWith("turns:")))}function ce(e){let n=(Array.isArray(e.urls)?e.urls:[e.urls]).filter(o=>typeof o=="string"&&!o.startsWith("stun:"));return n.length===0?null:{...e,urls:Array.isArray(e.urls)?n:n[0]}}function C(e){if(e)return e.map(t=>ce(t)).filter(t=>t!==null)}function A(e){return (e??"").trim().replace(/\/+$/,"").toLowerCase()}function W(e,t){let n=new Set(["iroh-relay","iroh","moq"]);t&&n.add("webrtc");let o=(e??F).filter(r=>n.has(r));return o.length>0?o:[...F]}function qe(e){return !!e?.transports?.webrtc}function Ke(e,t){let n=e?.transports?.webrtc||void 0;if(n)return e?.strictMode||n.privacyMode?{...n,iceServers:C(n.iceServers),iceTransportPolicy:"relay"}:n.iceTransportPolicy==="relay"&&!(Array.isArray(n.iceServers)&&n.iceServers.some(r=>ae(r)))?(t?.("[Client] Overriding relay-only ICE policy to all because no TURN servers are configured"),{...n,iceTransportPolicy:"all"}):n}var le=["iroh-lan","webrtc-lan","ble","webrtc","moq","iroh"];function k(e){let t=e.spaceKey??e.space;return {...e,...t!==void 0?{spaceKey:t}:{}}}function q(e){return {...e,iceServers:e.iceServers?e.iceServers.map(t=>({...t})):e.iceServers}}function K(e){return {...e}}function de(e){return {...e}}function ue(e){if(e)return {iroh:typeof e.iroh=="object"?de(e.iroh):e.iroh,webrtc:typeof e.webrtc=="object"?q(e.webrtc):e.webrtc,ble:typeof e.ble=="object"?{...e.ble}:e.ble,moq:typeof e.moq=="object"?K(e.moq):e.moq}}function pe(e){e.strictMode&&!e.transports&&(e.transports={iroh:{relayOnly:true}}),e.transports&&(e.transports.webrtc===true?e.transports.webrtc=q(L):e.transports.webrtc===false&&(e.transports.webrtc=void 0),e.transports.moq===true?e.transports.moq=K(B):e.transports.moq===false&&(e.transports.moq=void 0),e.transports.iroh===true?e.transports.iroh={}:e.transports.iroh===false&&(e.transports.iroh=void 0));}function ge(e){if(!e.strictMode||!e.transports)return;let t=e.transports.iroh&&typeof e.transports.iroh=="object"?e.transports.iroh:{};e.transports.iroh={...t,relayOnly:true,relayTransportPolicy:t.relayTransportPolicy??"auto",localDiscovery:false,localDiscoveryMode:void 0},e.transports.ble=void 0;let n=e.transports.webrtc;n&&typeof n=="object"&&(e.transports.webrtc={...n,privacyMode:true,lanMode:false,iceServers:C(n.iceServers)??[],iceTransportPolicy:"relay"});let o=e.transports.moq;if(o&&typeof o=="object"){let r=o.relayUrl?.trim();if(!r||A(r)===A(R))throw new Error("[OpenRTC] strictMode requires transports.moq.relayUrl to point at a self-hosted MoQ relay; the default public relay is not allowed.");e.transports.moq={...o,relayUrl:r};}}function Qe(e){let t=k(e),n=I(t),o=P(t),r={strictMode:false,disableIrohFallback:false,transportPriority:[...le],...t,authMode:o,transports:ue(t.transports)};pe(r),ge(r),r.strictMode&&(r.transportPriority=W(t.transportPriority,!!r.transports?.webrtc));let i=j(r),s=(r.discoveryMode??"space")==="space"?"client-open":"client-auth";return {appTag:n,authMode:o,configuredPersistenceMode:i,options:r,roomCreationMode:s}}function j(e){let t=e.transports?.iroh;return e.nodeIdPersistence??(typeof t=="object"?t.persistenceMode:void 0)??"persistent"}function Ve(e){return "options"in e&&"configuredPersistenceMode"in e?{apiKey:e.options.apiKey,authMode:P(e.options),projectId:e.options.projectId,storagePrefix:e.options.storagePrefix,nodeIdPersistence:e.configuredPersistenceMode}:{apiKey:e.apiKey,authMode:P(e),projectId:e.projectId,storagePrefix:e.storagePrefix,nodeIdPersistence:j(e)}}function Je(e,t){t&&(e.transports={...e.transports||{},...t});}var b="pluto-rtc-prod",z={apiKey:"AIzaSyA62Krj-7ZYFT5xjrTUq7mXana41Ahj_mM",authDomain:"api.openrtc.app",projectId:b,storageBucket:"pluto-rtc-prod.firebasestorage.app",messagingSenderId:"607066575224",appId:"1:607066575224:web:ed3f51825ba228db92b88d"};function Xe(e){let t=k(e),n=typeof t.projectId=="string"&&t.projectId.trim()?t.projectId.trim():b;return {...t,projectId:n}}function $(e){return new Promise(t=>setTimeout(t,e))}function tt(e){let t=new Uint8Array(e.byteLength);return t.set(e),t}function nt(e){let t=e.reduce((r,i)=>r+i.byteLength,0),n=new Uint8Array(t),o=0;for(let r of e)n.set(r,o),o+=r.byteLength;return n}function rt(e,t,n){let o=t*Math.pow(2,Math.max(0,e-1));return Math.min(n,o)}function ot(e){try{let t=e;return !!t&&!!t.send&&typeof t.send.getWriter=="function"&&!!t.recv&&typeof t.recv.getReader=="function"}catch{return false}}function it(e,t){let n=e;if(!n)return null;try{let o=n.send,r=n.recv;if(!o||typeof o.getWriter!="function"||!r||typeof r.getReader!="function")return null;let i=typeof n.endpoint_id=="string"&&n.endpoint_id.trim().length>0?n.endpoint_id:t;return {send:o,recv:r,endpoint_id:i}}catch{return null}}function st(e,t){let n={send:e.send,recv:t,endpoint_id:typeof e.endpoint_id=="string"?e.endpoint_id:""};return e?.applicationCryptoWrapped===true&&(n.applicationCryptoWrapped=true),n}async function at(e,t){if(!e)return false;try{let n=e.send?.getWriter?.();if(n)try{await n.close();}catch{}finally{try{n.releaseLock();}catch{}}}catch{}try{let n=e.recv?.getReader?.();if(n)try{await n.cancel(t);}catch{}finally{try{n.releaseLock();}catch{}}}catch{}return true}function ct(e,t,n={}){let o=n.context??"prependBytesToReader",r=n.traceId,i=t.byteLength===0,s=n.pendingRead??null,l=a=>n.release?.(a),d=(a,p)=>n.log?.(a,p);return new ReadableStream({async pull(a){if(!i){i=true,a.enqueue(t);return}if(s){let u=s;s=null;let g;try{g=await u;}catch(y){a.error(y),l("pending-read-error"),d("prepend-bytes:pending-read-error",{context:o,traceId:r||null,error:y?.message||String(y)});return}if(g.done){a.close(),l("pending-done");return}g.value&&a.enqueue(g.value);return}let p;try{p=await e.read();}catch(u){a.error(u),l("read-error"),d("prepend-bytes:read-error",{context:o,traceId:r||null,error:u?.message||String(u)});return}let{done:T,value:v}=p;if(T){a.close(),l("done");return}v&&a.enqueue(v);},async cancel(a){l("cancel");}})}async function lt(e,t){let n=e.read(),o=t-Date.now();if(o<=0)return {status:"timeout",pendingRead:n};let r=Symbol("probe-timeout"),i,s=new Promise(l=>{i=setTimeout(()=>l(r),o);});try{let l=await Promise.race([n,s]);if(l===r)return {status:"timeout",pendingRead:n};let{done:d,value:a}=l;return d?{status:"done"}:{status:"data",value:a&&a.byteLength>0?new Uint8Array(a):new Uint8Array(0)}}finally{i&&clearTimeout(i);}}function G(e,t,n){let o;return new Promise((r,i)=>{o=setTimeout(()=>{if(o=void 0,typeof n=="function"){i(n());return}let s=n?`${n} timed out`:"timeout";i(new Error(`${s} after ${t}ms`));},t),e.then(s=>{o!==void 0&&clearTimeout(o),r(s);},s=>{o!==void 0&&clearTimeout(o),i(s);});})}var X="pluto-rtc-auth",D=null;function Oe(){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 c(e,t){if(Oe()){if(typeof t>"u"){console.log(e);return}console.log(e,t);}}function Ct(e){D=e;}function Me(){return _()}function re(){return typeof navigator>"u"?false:/iPhone|iPad|iPod|Android/i.test(navigator.userAgent||"")}function ee(){return Me()&&re()}function m(e,t,n){return G(e,t,()=>new Error(`${n} timeout after ${t}ms`))}function te(e){let t="0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._",n=new Uint8Array(e);window.crypto.getRandomValues(n);let o="";for(let r=0;r<e;r+=1)o+=t[n[r]%t.length];return o}async function ne(e){let n=new TextEncoder().encode(e),o=await crypto.subtle.digest("SHA-256",n);return Array.from(new Uint8Array(o)).map(i=>i.toString(16).padStart(2,"0")).join("")}var N=class{constructor(){this.redirectResultPromise=null;this.redirectResultConsumed=false;this.lastRelayedToken=null;this.lastRelayedRefreshToken=null;this.desktopTokenRefreshIntervalId=null;let t=getApps().find(r=>r.name===X);this.app=t||initializeApp(z,X);let n=re(),o=ee();if(n)try{let r=o?{persistence:[browserLocalPersistence,inMemoryPersistence]}:{persistence:[browserLocalPersistence,inMemoryPersistence],popupRedirectResolver:browserPopupRedirectResolver};this.auth=initializeAuth(this.app,r),c("[PLUTO-RTC][AUTH-HOST] Using mobile-safe Firebase auth initialization",{appName:this.app.name,persistence:"browserLocalPersistence->inMemoryPersistence",redirectResolver:o?"disabled-for-tauri-mobile":"browserPopupRedirectResolver",tauriMobile:o});}catch{this.auth=getAuth(this.app),console.warn("[PLUTO-RTC][AUTH-HOST] Mobile-safe auth initialization unavailable; falling back to default getAuth");}else this.auth=getAuth(this.app);this.functions=getFunctions(this.app);try{let r=typeof globalThis<"u"?String(globalThis.__OPENRTC_AUTH_EMULATOR_HOST__??"").trim():"",i=typeof globalThis<"u"?String(globalThis.__OPENRTC_FUNCTIONS_EMULATOR_HOST__??"").trim():"",s=typeof import.meta<"u"?import.meta.env:null;if(!!r||!!i||!!s&&String(s.VITE_USE_EMULATORS)==="true"&&(s.DEV||String(s.VITE_E2E)==="true")){let d=String(s?.VITE_OPENRTC_EMULATOR_HOST??"127.0.0.1").trim()||"127.0.0.1",[a,p]=r.split(":"),[T,v]=i.split(":"),u=(a??"").trim()||d,g=(T??"").trim()||d,y=Number(p??s?.VITE_OPENRTC_AUTH_EMULATOR_PORT??9100),oe=Number(v??s?.VITE_OPENRTC_FUNCTIONS_EMULATOR_PORT??5002);try{connectAuthEmulator(this.auth,`http://${u}:${y}`,{disableWarnings:!0});}catch{}try{connectFunctionsEmulator(this.functions,g,oe);}catch{}}}catch{}n?this.persistenceReady=Promise.resolve():this.persistenceReady=setPersistence(this.auth,browserLocalPersistence).catch(r=>{console.warn("[PLUTO-RTC][AUTH-HOST] Failed to set auth persistence",{message:r?.message});}),c("[PLUTO-RTC][AUTH-HOST] Initialized auth host",{appName:this.app.name,mobileSafeAuth:n}),onIdTokenChanged(this.auth,r=>{c("[PLUTO-RTC][AUTH-HOST] Firebase ID token changed",{hasUser:!!r,uid:r?.uid,providerDataCount:r?.providerData?.length||0}),this.syncDesktopAuthToken(r);}),this.desktopTokenRefreshIntervalId||(this.desktopTokenRefreshIntervalId=setInterval(()=>{this.syncDesktopAuthToken(this.auth.currentUser,true);},600*1e3));}async syncDesktopAuthToken(t,n=false){if(!D)return;let o=t?await getIdToken(t,n).catch(()=>null):null,r=t?t.refreshToken??null:null;if(o===this.lastRelayedToken&&r===this.lastRelayedRefreshToken)return;this.lastRelayedToken=o,this.lastRelayedRefreshToken=r;let i=await Promise.allSettled([Promise.resolve(D({authToken:o,refreshToken:r}))]);i[0]?.status==="rejected"&&console.warn("[PLUTO-RTC][AUTH-HOST] Failed to relay auth token to desktop backend",{message:i[0].reason?.message});}getApp(){return this.app}getCurrentUser(){return this.auth.currentUser}getAuth(){return this.auth}onAuthStateChanged(t){return c("[PLUTO-RTC][AUTH-HOST] onAuthStateChanged listener registered (via onIdTokenChanged)"),onIdTokenChanged(this.auth,t)}onIdTokenChanged(t){return c("[PLUTO-RTC][AUTH-HOST] onIdTokenChanged listener registered"),onIdTokenChanged(this.auth,t)}async getIdToken(t){return this.auth.currentUser?getIdToken(this.auth.currentUser,t?.forceRefresh??true):null}async checkForSSOToken(){if(typeof window>"u")return;let t=new URLSearchParams(window.location.search),n=new URLSearchParams(window.location.hash.startsWith("#")?window.location.hash.slice(1):window.location.hash),o=t.get("token")||n.get("token")||(t.get("custom_token")==="true"||n.get("custom_token")==="true"?t.get("id_token")||n.get("id_token"):null);if(o)try{await this.persistenceReady,await signInWithCustomToken(this.auth,o),window.history.replaceState({},document.title,window.location.pathname);}catch(r){console.error("[PLUTO-RTC][AUTH-HOST] SSO sign-in failed:",r);}}async signInWithCustomTokenValue(t){return await this.persistenceReady,(await signInWithCustomToken(this.auth,t)).user}async signInWithPluto(t){if(typeof window>"u")throw new Error("Pluto SSO requires a browser environment.");let n=t?.redirectUri||window.location.href,o=t?.authorizeBaseUrl||"https://pluto.openrtc.app/sso/authorize",r=new URL(o);r.searchParams.set("redirect_uri",n),window.location.assign(r.toString());}async waitForAuth(){if(await this.persistenceReady,!this.auth.currentUser)return new Promise(t=>{let n=onAuthStateChanged(this.auth,o=>{o&&(n(),t());});})}async signInAnonymously(){await signInAnonymously(this.auth);}async signIn(t,n){return (await signInWithEmailAndPassword(this.auth,t,n)).user}async signUp(t,n){return (await createUserWithEmailAndPassword(this.auth,t,n)).user}async signOut(){await signOut(this.auth);}async deleteAccount(){if(!this.auth.currentUser)throw new Error("No user signed in");await deleteUser(this.auth.currentUser);}async signInWithCredential(t){let n=Date.now();if(c("[PLUTO-RTC][AUTH-HOST] signInWithCredential start",{callbackId:t.callbackId,provider:t.provider,hasIdToken:!!t.idToken,hasAccessToken:!!t.accessToken,hasNonce:!!t.nonce}),t.isCustomToken){c("[PLUTO-RTC][AUTH-HOST] signInWithCredential: custom token detected, using signInWithCustomToken");try{if(ee())c("[PLUTO-RTC][AUTH-HOST] Skipping authStateReady before custom token sign-in on Tauri mobile",{callbackId:t.callbackId});else {c("[PLUTO-RTC][AUTH-HOST] Awaiting authStateReady...");try{await m(this.auth.authStateReady(),5e3,"authStateReady"),c("[PLUTO-RTC][AUTH-HOST] Auth state ready, signing in with custom token...");}catch(s){console.warn("[PLUTO-RTC][AUTH-HOST] authStateReady did not resolve in time; continuing custom token sign-in",{callbackId:t.callbackId,message:s?.message});}}let i;try{i=await m(signInWithCustomToken(this.auth,t.idToken),25e3,"signInWithCustomToken (custom token path)");}catch(s){console.warn("[PLUTO-RTC][AUTH-HOST] First custom token sign-in attempt failed; retrying once",{callbackId:t.callbackId,message:s?.message,code:s?.code}),await $(250),i=await m(signInWithCustomToken(this.auth,t.idToken),25e3,"signInWithCustomToken (custom token path retry)");}if(c("[PLUTO-RTC][AUTH-HOST] signInWithCustomToken success",{callbackId:t.callbackId,provider:t.provider,uid:i.user?.uid,elapsedMs:Date.now()-n}),i.user&&(t.displayName||t.photoURL))try{await updateProfile(i.user,{displayName:t.displayName||i.user.displayName||void 0,photoURL:t.photoURL||i.user.photoURL||void 0});}catch(s){console.warn("[PLUTO-RTC][AUTH-HOST] Failed to update custom-token user profile",{callbackId:t.callbackId,message:s?.message});}return i.user}catch(r){throw console.error("[PLUTO-RTC][AUTH-HOST] signInWithCustomToken failed",{callbackId:t.callbackId,error:r?.message,code:r?.code,stack:r?.stack,elapsedMs:Date.now()-n}),r}}let o;t.provider==="google"?o=GoogleAuthProvider.credential(t.idToken,t.accessToken):o=new OAuthProvider("apple.com").credential({idToken:t.idToken,rawNonce:t.nonce,accessToken:t.accessToken});try{let r=await m(signInWithCredential(this.auth,o),1e4,"firebase signInWithCredential");return c("[PLUTO-RTC][AUTH-HOST] signInWithCredential success",{callbackId:t.callbackId,provider:t.provider,uid:r.user?.uid,elapsedMs:Date.now()-n}),r.user}catch(r){console.warn("[PLUTO-RTC][AUTH-HOST] signInWithCredential primary path failed; trying custom token fallback",{callbackId:t.callbackId,provider:t.provider,elapsedMs:Date.now()-n,code:r?.code,message:r?.message});let i=await m(this.mintSessionTokenFromProviderToken(t),15e3,"mintSessionTokenFromProviderToken"),s=await m(signInWithCustomToken(this.auth,i),15e3,"signInWithCustomToken");return c("[PLUTO-RTC][AUTH-HOST] signInWithCustomToken fallback success",{callbackId:t.callbackId,provider:t.provider,uid:s.user?.uid,elapsedMs:Date.now()-n}),s.user}}async mintSessionTokenFromProviderToken(t){let n=httpsCallable(this.functions,"mintSessionToken");c("[PLUTO-RTC][AUTH-HOST] mintSessionToken fallback request start",{provider:t.provider,hasIdToken:!!t.idToken,hasNonce:!!t.nonce});let r=(await n({provider:t.provider,idToken:t.idToken,nonce:t.nonce})).data?.token;if(!r)throw new Error("mintSessionToken did not return a token for provider exchange");return c("[PLUTO-RTC][AUTH-HOST] mintSessionToken fallback request success",{provider:t.provider}),r}async signInWithPopup(t){if(t==="google"){let i=new GoogleAuthProvider;i.addScope("email"),i.addScope("profile"),i.setCustomParameters({prompt:"select_account"});let s=await signInWithPopup(this.auth,i);return {idToken:await getIdToken(s.user,true),refreshToken:s.user.refreshToken}}let n=new OAuthProvider("apple.com");n.addScope("email"),n.addScope("name");let o=te(32);typeof sessionStorage<"u"&&sessionStorage.setItem("apple_auth_nonce",o),n.setCustomParameters({nonce:await ne(o)});let r=await signInWithPopup(this.auth,n);return {idToken:await getIdToken(r.user,true),refreshToken:r.user.refreshToken}}async signInWithRedirect(t,n){if(t==="google"){let i=new GoogleAuthProvider;i.addScope("email"),i.addScope("profile"),i.setCustomParameters({prompt:"select_account"}),await signInWithRedirect(this.auth,i);return}let o=new OAuthProvider("apple.com");o.addScope("email"),o.addScope("name");let r=n?.nonce||te(32);typeof sessionStorage<"u"&&sessionStorage.setItem("apple_auth_nonce",r),o.setCustomParameters({nonce:await ne(r)}),await signInWithRedirect(this.auth,o);}async consumeRedirectResult(){return this.redirectResultConsumed?(c("[PLUTO-RTC][AUTH-HOST] consumeRedirectResult skipped (already consumed)"),null):this.redirectResultPromise?this.redirectResultPromise:(this.redirectResultPromise=(async()=>{try{c("[PLUTO-RTC][AUTH-HOST] consumeRedirectResult start");let t=await getRedirectResult(this.auth);if(!t)return c("[PLUTO-RTC][AUTH-HOST] consumeRedirectResult: no redirect result"),{fromRedirect:!1,user:null};this.redirectResultConsumed=!0;let n=await getIdToken(t.user,!0).catch(()=>null),o=t.providerId||t.user.providerData?.[0]?.providerId||null;return c("[PLUTO-RTC][AUTH-HOST] consumeRedirectResult success",{uid:t.user.uid,providerId:o,hasIdToken:!!n}),{fromRedirect:!0,user:t.user,providerId:o,idToken:n}}finally{this.redirectResultPromise=null;}})(),this.redirectResultPromise)}async startGoogleSignIn(){await this.signInWithRedirect("google");}async startAppleSignIn(){await this.signInWithRedirect("apple");}async mintSessionToken(){let o=(await httpsCallable(this.functions,"mintSessionToken")()).data;if(!o?.token)throw new Error("mintSessionToken did not return a token");return o.token}},M=null;function De(){return M||(M=new N),M}var At=new Proxy({},{get(e,t,n){let o=De(),r=o[t];return typeof r=="function"?r.bind(o):r}});
2
+ export{lt as A,G as B,Ct as C,De as D,At as E,_ as a,Ee as b,I as c,P as d,He as e,Le as f,Fe as g,se as h,L as i,B as j,qe as k,Ke as l,k as m,Qe as n,Ve as o,Je as p,Xe as q,$ as r,tt as s,nt as t,rt as u,ot as v,it as w,st as x,at as y,ct as z};
@@ -0,0 +1 @@
1
+ import {z,y}from'./chunk-WNJE3MJF.js';var n=class extends z{constructor(e){super(new y(e));}setWasmClient(e){this.unwrap().setWasmClient(e);}};export{n as a};