openrtc 0.1.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 (122) hide show
  1. package/README.md +106 -0
  2. package/dist/OpenRTC.d.ts +71 -0
  3. package/dist/OpenRTC.js +130 -0
  4. package/dist/api/MediaTransport.d.ts +7 -0
  5. package/dist/api/MediaTransport.js +262 -0
  6. package/dist/api/PlutoPeerConnection.d.ts +50 -0
  7. package/dist/api/PlutoPeerConnection.js +434 -0
  8. package/dist/api/PlutoWebSocket.d.ts +24 -0
  9. package/dist/api/PlutoWebSocket.js +113 -0
  10. package/dist/api/PlutoWebTransport.d.ts +29 -0
  11. package/dist/api/PlutoWebTransport.js +105 -0
  12. package/dist/auth/host.d.ts +73 -0
  13. package/dist/auth/host.js +513 -0
  14. package/dist/auth/index.d.ts +1 -0
  15. package/dist/auth/index.js +1 -0
  16. package/dist/auth/internal.d.ts +1 -0
  17. package/dist/auth/internal.js +1 -0
  18. package/dist/compat/index.d.ts +20 -0
  19. package/dist/compat/index.js +20 -0
  20. package/dist/core/Client.d.ts +352 -0
  21. package/dist/core/Client.js +3689 -0
  22. package/dist/core/Connection.d.ts +67 -0
  23. package/dist/core/Connection.js +404 -0
  24. package/dist/core/IEngineBridge.d.ts +18 -0
  25. package/dist/core/IEngineBridge.js +1 -0
  26. package/dist/core/ISignalingTransport.d.ts +13 -0
  27. package/dist/core/ISignalingTransport.js +1 -0
  28. package/dist/core/PeerLifecycleManager.d.ts +43 -0
  29. package/dist/core/PeerLifecycleManager.js +330 -0
  30. package/dist/core/PeerProjectionStore.d.ts +43 -0
  31. package/dist/core/PeerProjectionStore.js +327 -0
  32. package/dist/core/PlutoRTC.d.ts +13 -0
  33. package/dist/core/PlutoRTC.js +26 -0
  34. package/dist/core/Room.d.ts +47 -0
  35. package/dist/core/Room.js +376 -0
  36. package/dist/core/Signaling.d.ts +39 -0
  37. package/dist/core/Signaling.js +147 -0
  38. package/dist/core/bridges/BridgeCodecs.d.ts +19 -0
  39. package/dist/core/bridges/BridgeCodecs.js +317 -0
  40. package/dist/core/bridges/BrowserFirestoreRooms.d.ts +36 -0
  41. package/dist/core/bridges/BrowserFirestoreRooms.js +169 -0
  42. package/dist/core/bridges/BrowserFirestoreSignaling.d.ts +111 -0
  43. package/dist/core/bridges/BrowserFirestoreSignaling.js +1010 -0
  44. package/dist/core/bridges/NativeIpcBridge.d.ts +156 -0
  45. package/dist/core/bridges/NativeIpcBridge.js +1472 -0
  46. package/dist/core/bridges/RtdbPresence.d.ts +122 -0
  47. package/dist/core/bridges/RtdbPresence.js +201 -0
  48. package/dist/core/bridges/TauriBridge.d.ts +8 -0
  49. package/dist/core/bridges/TauriBridge.js +7 -0
  50. package/dist/core/bridges/WasmBridge.d.ts +233 -0
  51. package/dist/core/bridges/WasmBridge.js +1811 -0
  52. package/dist/core/config.d.ts +31 -0
  53. package/dist/core/config.js +138 -0
  54. package/dist/core/transports/ITransport.d.ts +12 -0
  55. package/dist/core/transports/ITransport.js +1 -0
  56. package/dist/core/transports/LocalDaemonBridge.d.ts +41 -0
  57. package/dist/core/transports/LocalDaemonBridge.js +227 -0
  58. package/dist/core/transports/TauriSignaling.d.ts +28 -0
  59. package/dist/core/transports/TauriSignaling.js +373 -0
  60. package/dist/core/transports/TransportFactory.d.ts +9 -0
  61. package/dist/core/transports/TransportFactory.js +59 -0
  62. package/dist/core/transports/WasmSignaling.d.ts +78 -0
  63. package/dist/core/transports/WasmSignaling.js +522 -0
  64. package/dist/core/transports/WebRTCTransport.d.ts +23 -0
  65. package/dist/core/transports/WebRTCTransport.js +132 -0
  66. package/dist/core/trust.d.ts +23 -0
  67. package/dist/core/trust.js +99 -0
  68. package/dist/core/types.d.ts +559 -0
  69. package/dist/core/types.js +19 -0
  70. package/dist/index.d.ts +3 -0
  71. package/dist/index.js +3 -0
  72. package/dist/moq/MoQMediaTransport.d.ts +6 -0
  73. package/dist/moq/MoQMediaTransport.js +106 -0
  74. package/dist/moq/MoQPublisher.d.ts +22 -0
  75. package/dist/moq/MoQPublisher.js +179 -0
  76. package/dist/moq/MoQSession.d.ts +35 -0
  77. package/dist/moq/MoQSession.js +166 -0
  78. package/dist/moq/MoQSubscriber.d.ts +19 -0
  79. package/dist/moq/MoQSubscriber.js +235 -0
  80. package/dist/moq/common.d.ts +47 -0
  81. package/dist/moq/common.js +304 -0
  82. package/dist/moq/messages.d.ts +105 -0
  83. package/dist/moq/messages.js +367 -0
  84. package/dist/presets/plutoHosted.d.ts +13 -0
  85. package/dist/presets/plutoHosted.js +18 -0
  86. package/dist/runtime/DelegatingRuntimeAdapter.d.ts +68 -0
  87. package/dist/runtime/DelegatingRuntimeAdapter.js +250 -0
  88. package/dist/runtime/IpcRuntimeAdapter.d.ts +9 -0
  89. package/dist/runtime/IpcRuntimeAdapter.js +13 -0
  90. package/dist/runtime/RuntimeClient.d.ts +257 -0
  91. package/dist/runtime/RuntimeClient.js +1484 -0
  92. package/dist/runtime/TauriRuntimeAdapter.d.ts +1 -0
  93. package/dist/runtime/TauriRuntimeAdapter.js +1 -0
  94. package/dist/runtime/WasmRuntimeAdapter.d.ts +6 -0
  95. package/dist/runtime/WasmRuntimeAdapter.js +11 -0
  96. package/dist/runtime/factories.d.ts +24 -0
  97. package/dist/runtime/factories.js +66 -0
  98. package/dist/runtime/index.d.ts +6 -0
  99. package/dist/runtime/index.js +5 -0
  100. package/dist/runtime/ipc.d.ts +8 -0
  101. package/dist/runtime/ipc.js +65 -0
  102. package/dist/runtime/ipcContract.d.ts +46 -0
  103. package/dist/runtime/ipcContract.js +1 -0
  104. package/dist/runtime/tauri.d.ts +16 -0
  105. package/dist/runtime/tauri.js +22 -0
  106. package/dist/runtime/types.d.ts +110 -0
  107. package/dist/runtime/types.js +1 -0
  108. package/dist/transports/TauriTransport.d.ts +17 -0
  109. package/dist/transports/TauriTransport.js +49 -0
  110. package/dist/transports/WebTransport.d.ts +23 -0
  111. package/dist/transports/WebTransport.js +71 -0
  112. package/dist/utils/debug.d.ts +4 -0
  113. package/dist/utils/debug.js +33 -0
  114. package/dist/utils/runtime.d.ts +1 -0
  115. package/dist/utils/runtime.js +10 -0
  116. package/package.json +97 -0
  117. package/wasm/README.md +64 -0
  118. package/wasm/openrtc.d.ts +284 -0
  119. package/wasm/openrtc.js +2132 -0
  120. package/wasm/openrtc_bg.wasm +0 -0
  121. package/wasm/openrtc_bg.wasm.d.ts +110 -0
  122. package/wasm/package.json +16 -0
@@ -0,0 +1,23 @@
1
+ export declare const TRANSPORT_TRUST_VERSION = 1;
2
+ export interface TrustedDeviceMetadataRecord {
3
+ version: number;
4
+ identityPublicKey: string;
5
+ identityFingerprint: string;
6
+ }
7
+ export interface LocalTrustedIdentityRecord {
8
+ publicKey: Uint8Array;
9
+ secretKey: Uint8Array;
10
+ fingerprint: string;
11
+ }
12
+ export interface TransportTrustPayload {
13
+ version: number;
14
+ deviceId: string;
15
+ identityFingerprint: string;
16
+ challenge?: string;
17
+ signedChallenge?: string;
18
+ }
19
+ export declare function createTransportTrustChallenge(byteLength?: number): string;
20
+ export declare function signTransportTrustChallenge(challenge: string, identitySecretKey: Uint8Array): string;
21
+ export declare function verifyTransportTrustChallenge(challenge: string, signedChallenge: string, identityPublicKey: string): boolean;
22
+ export declare function parseTrustedDeviceMetadata(metadata?: string | null): TrustedDeviceMetadataRecord | null;
23
+ export declare function getLocalTrustedIdentity(): Promise<LocalTrustedIdentityRecord | null>;
@@ -0,0 +1,99 @@
1
+ import * as nacl from 'tweetnacl';
2
+ const TRUSTED_DEVICE_METADATA_KEY = 'trustedDevice';
3
+ const TRUSTED_IDENTITY_STORAGE_KEY = 'plutonium:e2ee:identity:v1';
4
+ export const TRANSPORT_TRUST_VERSION = 1;
5
+ function decodeBase64(value) {
6
+ const binary = atob(value);
7
+ const bytes = new Uint8Array(binary.length);
8
+ for (let index = 0; index < binary.length; index += 1) {
9
+ bytes[index] = binary.charCodeAt(index);
10
+ }
11
+ return bytes;
12
+ }
13
+ function encodeBase64(value) {
14
+ let binary = '';
15
+ for (let index = 0; index < value.length; index += 1) {
16
+ binary += String.fromCharCode(value[index]);
17
+ }
18
+ return btoa(binary);
19
+ }
20
+ async function computeFingerprint(publicKey) {
21
+ const hashBuffer = await crypto.subtle.digest('SHA-256', publicKey);
22
+ const hashBytes = new Uint8Array(hashBuffer);
23
+ return Array.from(hashBytes)
24
+ .map((byte) => byte.toString(16).padStart(2, '0'))
25
+ .join('');
26
+ }
27
+ export function createTransportTrustChallenge(byteLength = 32) {
28
+ const challenge = crypto.getRandomValues(new Uint8Array(byteLength));
29
+ return encodeBase64(challenge);
30
+ }
31
+ export function signTransportTrustChallenge(challenge, identitySecretKey) {
32
+ const signature = nacl.sign.detached(decodeBase64(challenge), identitySecretKey);
33
+ return encodeBase64(signature);
34
+ }
35
+ export function verifyTransportTrustChallenge(challenge, signedChallenge, identityPublicKey) {
36
+ try {
37
+ return nacl.sign.detached.verify(decodeBase64(challenge), decodeBase64(signedChallenge), decodeBase64(identityPublicKey));
38
+ }
39
+ catch {
40
+ return false;
41
+ }
42
+ }
43
+ export function parseTrustedDeviceMetadata(metadata) {
44
+ if (!metadata || !metadata.trim()) {
45
+ return null;
46
+ }
47
+ try {
48
+ const parsed = JSON.parse(metadata);
49
+ const record = parsed && typeof parsed === 'object' && !Array.isArray(parsed)
50
+ ? parsed[TRUSTED_DEVICE_METADATA_KEY]
51
+ : null;
52
+ if (!record || typeof record !== 'object' || Array.isArray(record)) {
53
+ return null;
54
+ }
55
+ const normalized = record;
56
+ const version = typeof normalized.version === 'number' ? normalized.version : null;
57
+ const identityPublicKey = typeof normalized.identityPublicKey === 'string' ? normalized.identityPublicKey : null;
58
+ const identityFingerprint = typeof normalized.identityFingerprint === 'string'
59
+ ? normalized.identityFingerprint
60
+ : null;
61
+ if (!version || !identityPublicKey || !identityFingerprint) {
62
+ return null;
63
+ }
64
+ return {
65
+ version,
66
+ identityPublicKey,
67
+ identityFingerprint,
68
+ };
69
+ }
70
+ catch {
71
+ return null;
72
+ }
73
+ }
74
+ export async function getLocalTrustedIdentity() {
75
+ if (typeof localStorage === 'undefined') {
76
+ return null;
77
+ }
78
+ const raw = localStorage.getItem(TRUSTED_IDENTITY_STORAGE_KEY);
79
+ if (!raw) {
80
+ return null;
81
+ }
82
+ try {
83
+ const parsed = JSON.parse(raw);
84
+ if (typeof parsed.publicKey !== 'string' || typeof parsed.secretKey !== 'string') {
85
+ return null;
86
+ }
87
+ const publicKey = decodeBase64(parsed.publicKey);
88
+ const secretKey = decodeBase64(parsed.secretKey);
89
+ const fingerprint = await computeFingerprint(publicKey);
90
+ return {
91
+ publicKey,
92
+ secretKey,
93
+ fingerprint,
94
+ };
95
+ }
96
+ catch {
97
+ return null;
98
+ }
99
+ }
@@ -0,0 +1,559 @@
1
+ export type PlanTier = 'free' | 'starter' | 'pro' | 'internal';
2
+ export interface AppLimits {
3
+ /** Max devices per authenticated user. -1 = unlimited. */
4
+ devicesPerUser: number;
5
+ /** Max total rooms the developer app can have open at once. -1 = unlimited. */
6
+ maxRooms: number;
7
+ /** Max members per room. -1 = unlimited. */
8
+ maxMembersPerRoom: number;
9
+ /** Max active devices across all provisioned personal spaces for this app. -1 = unlimited. */
10
+ maxPersonalDevices: number;
11
+ }
12
+ export declare const DEFAULT_FREE_LIMITS: AppLimits;
13
+ export declare const DEFAULT_MOQ_RELAY_URL = "https://relay.cloudflare.mediaoverquic.com";
14
+ export declare const DEFAULT_ICE_SERVERS: {
15
+ urls: string;
16
+ }[];
17
+ export interface PlutoRTCConfiguration extends RTCConfiguration {
18
+ iceServers?: RTCIceServer[];
19
+ privacyMode?: boolean;
20
+ useTurn?: boolean;
21
+ }
22
+ export declare const DEFAULT_WEBRTC_CONFIG: PlutoRTCConfiguration;
23
+ export interface PlutoMoQConfiguration {
24
+ relayUrl?: string;
25
+ }
26
+ export declare const DEFAULT_MOQ_CONFIG: PlutoMoQConfiguration;
27
+ export interface PlutoIrohConfiguration {
28
+ relayOnly?: boolean;
29
+ persistenceMode?: 'persistent' | 'ephemeral';
30
+ }
31
+ export type DiscoveryMode = 'personal' | 'user-scoped';
32
+ export type AuthMode = 'external' | 'anonymous' | 'required';
33
+ export type SignalingMode = 'hosted' | 'ticket-only';
34
+ export type RoomCreationMode = 'client-open' | 'client-auth' | 'server-only';
35
+ export type EndpointKind = 'device' | 'ephemeral';
36
+ export type PeerLifecycleStatus = 'disconnected' | 'connecting' | 'connected' | 'failed' | 'closed';
37
+ export type PeerHealth = 'unknown' | 'healthy' | 'suspect' | 'stale';
38
+ export type PeerScope = 'persistent' | 'session' | string;
39
+ export type ChannelOwnership = 'shared' | 'exclusive';
40
+ export type ChannelPeerModel = 'device-first' | 'node-first' | 'anonymous-ticket';
41
+ export type ChannelRoutingMode = 'stream-envelope' | 'session-default';
42
+ export type ChannelReadinessMode = 'settled-peer' | 'transport-only';
43
+ export type ChannelPromotionPolicy = 'eligible' | 'never';
44
+ export type ChannelSignalingPolicy = 'hosted' | 'ticket-only';
45
+ export interface ChannelDescriptor {
46
+ id: string;
47
+ kind: 'system' | 'auth' | 'share' | 'transfer' | 'sync' | string;
48
+ ownership: ChannelOwnership;
49
+ peerModel: ChannelPeerModel;
50
+ routing: ChannelRoutingMode;
51
+ readiness: ChannelReadinessMode;
52
+ promotionPolicy?: ChannelPromotionPolicy;
53
+ signalingPolicy?: ChannelSignalingPolicy;
54
+ description?: string;
55
+ }
56
+ export type ProtocolName = 'iroh' | 'webrtc' | 'websocket' | 'webtransport' | 'moq';
57
+ export type ProtocolMaturity = 'stable' | 'experimental' | 'unsupported';
58
+ export interface ProtocolCapability {
59
+ protocol: ProtocolName;
60
+ maturity: ProtocolMaturity;
61
+ available: boolean;
62
+ reason?: string;
63
+ }
64
+ export type ProtocolCapabilityMap = Record<ProtocolName, ProtocolCapability>;
65
+ export interface ClientOptions {
66
+ /**
67
+ * API key issued from the Pluto developer dashboard (https://api.openrtc.app/developer).
68
+ * The runtime derives its app namespace from this key.
69
+ */
70
+ apiKey?: string;
71
+ /**
72
+ * Explicitly opt in to the legacy shared hosted fallback when no apiKey is provided.
73
+ *
74
+ * This should only be used for controlled demos/tests. Production integrations
75
+ * should always provide an API key.
76
+ */
77
+ allowAnonymousHostedDefaults?: boolean;
78
+ /**
79
+ * Discovery mode for this app. Defaults to 'personal'.
80
+ * - 'personal': No user accounts. Devices share a spaceKey to discover each other.
81
+ * - 'user-scoped': Developer mints tokens for their users. Devices scoped per user.
82
+ *
83
+ * Set in the developer dashboard. The server validates this against the app's plan.
84
+ */
85
+ discoveryMode?: DiscoveryMode;
86
+ /**
87
+ * Space key for 'personal' discovery mode. Acts as a shared secret that scopes
88
+ * device discovery without requiring user authentication. Devices with the same
89
+ * spaceKey + apiKey will see each other.
90
+ *
91
+ * Only used when discoveryMode is 'personal'. Ignored for managed modes.
92
+ */
93
+ spaceKey?: string;
94
+ /**
95
+ * Pre-minted session token from your backend (for managed modes).
96
+ * Your backend calls PlutoRTC's /v1/tokens endpoint and passes the token here.
97
+ */
98
+ sessionToken?: string;
99
+ authMode?: AuthMode;
100
+ signalingMode?: SignalingMode;
101
+ projectId?: string;
102
+ storagePrefix?: string;
103
+ deviceTTL?: number;
104
+ deviceName?: string;
105
+ nodeIdPersistence?: 'persistent' | 'ephemeral';
106
+ secretKey?: string;
107
+ strictMode?: boolean;
108
+ localDeviceId?: string;
109
+ onDevices?: (devices: Device[]) => void;
110
+ onAutoConnect?: (devices: Device[]) => void;
111
+ onIncomingSession?: (session: SignalingSession) => Promise<void>;
112
+ transports?: {
113
+ iroh?: boolean | PlutoIrohConfiguration;
114
+ webrtc?: boolean | PlutoRTCConfiguration;
115
+ moq?: boolean | PlutoMoQConfiguration;
116
+ };
117
+ transportPriority?: ProtocolName[];
118
+ disableIrohFallback?: boolean;
119
+ }
120
+ export interface Device {
121
+ /**
122
+ * @deprecated Internal namespace metadata. Public integrations should not depend on `appTag`.
123
+ */
124
+ appTag?: string;
125
+ deviceId: string;
126
+ deviceName: string;
127
+ online: boolean;
128
+ ticket: string;
129
+ /**
130
+ * @deprecated Legacy/internal namespace metadata. Public integrations should not depend on `tag`.
131
+ */
132
+ tag?: string;
133
+ kind?: EndpointKind | string;
134
+ nodeId?: string;
135
+ platformType?: string;
136
+ capabilities?: {
137
+ canHost?: boolean;
138
+ canSync?: boolean;
139
+ readOnly?: boolean;
140
+ can_host?: boolean;
141
+ can_sync?: boolean;
142
+ read_only?: boolean;
143
+ };
144
+ sessionId?: string;
145
+ userId?: string;
146
+ lastSeenAt?: any;
147
+ expiresAt?: any;
148
+ createdAt?: any;
149
+ updatedAt?: any;
150
+ metadata?: string;
151
+ }
152
+ export interface PeerState {
153
+ peerId: string;
154
+ deviceId?: string;
155
+ deviceIdHint?: string;
156
+ nodeId?: string;
157
+ connectionId?: string;
158
+ connectionIds: string[];
159
+ ticket?: string;
160
+ online?: boolean;
161
+ deviceName?: string;
162
+ platformType?: string;
163
+ status: PeerLifecycleStatus;
164
+ health: PeerHealth;
165
+ transportState?: string;
166
+ protocolState?: string;
167
+ routable?: boolean;
168
+ promotionEligible?: boolean;
169
+ scopes: PeerScope[];
170
+ lastSeenAt?: number;
171
+ error?: string;
172
+ }
173
+ export interface BackendConnectionState {
174
+ connectionId: string;
175
+ deviceId?: string | null;
176
+ deviceIdHint?: string | null;
177
+ remoteNodeId?: string | null;
178
+ state: string;
179
+ transportState?: string;
180
+ protocolState?: string;
181
+ routable?: boolean;
182
+ readinessState?: string;
183
+ readinessReason?: string;
184
+ transportGeneration?: number;
185
+ activeTransportStableId?: number | null;
186
+ replacementInProgress?: boolean;
187
+ lastLifecycleTransitionAtMs?: number;
188
+ transitionCount?: number;
189
+ connectingTransitionCount?: number;
190
+ replacementCount?: number;
191
+ retireCount?: number;
192
+ lastDisconnectReason?: string | null;
193
+ lastReconnectReason?: string | null;
194
+ error?: string;
195
+ createdAt?: number;
196
+ updatedAt?: number;
197
+ }
198
+ export interface NativeConnectResult {
199
+ connectionId: string;
200
+ deviceId?: string | null;
201
+ deviceIdHint?: string | null;
202
+ remoteNodeId?: string | null;
203
+ state: string;
204
+ }
205
+ export interface BackendPeerBiStream {
206
+ readable: ReadableStream<Uint8Array>;
207
+ writable: WritableStream<Uint8Array>;
208
+ }
209
+ export interface BackendPeerUniStream {
210
+ writable: WritableStream<Uint8Array>;
211
+ }
212
+ export interface IncomingStreamChannelMetadata {
213
+ channelId: string;
214
+ metadata?: Record<string, unknown> | null;
215
+ }
216
+ export interface LocalDeviceInfo {
217
+ deviceId: string;
218
+ deviceName: string;
219
+ platformType?: string;
220
+ capabilities?: Device['capabilities'];
221
+ lastSeenAt?: string;
222
+ }
223
+ export interface RoomMember {
224
+ nodeId: string;
225
+ userId: string;
226
+ ticket: string;
227
+ joinedAt: number;
228
+ lastSeenAt: number;
229
+ expiresAt?: number;
230
+ }
231
+ export interface JoinRoomOptions {
232
+ bootstrapPeers?: boolean;
233
+ }
234
+ export interface SignalingEnvelope {
235
+ name?: string;
236
+ senderId: string;
237
+ targetId: string;
238
+ state?: string;
239
+ payload: string;
240
+ replyPayload?: string;
241
+ timestamp?: number;
242
+ }
243
+ export interface SignalingSession {
244
+ connectionId: string;
245
+ initiator?: string;
246
+ target?: string;
247
+ initiatorDeviceId: string;
248
+ targetDeviceId: string;
249
+ connectionType?: string;
250
+ offer?: any;
251
+ offerE2ee?: any;
252
+ answer?: any;
253
+ answerE2ee?: any;
254
+ iceCandidates: any[];
255
+ initiatorNodeId?: string;
256
+ targetNodeId?: string;
257
+ initiatorEndpointAddr?: string;
258
+ targetEndpointAddr?: string;
259
+ intent?: string;
260
+ /**
261
+ * @deprecated Internal namespace metadata. Public integrations should not depend on `appTag`.
262
+ */
263
+ appTag?: string;
264
+ createdAt?: number;
265
+ expiresAt?: number;
266
+ state: string;
267
+ }
268
+ export interface ScanningLoopOptions {
269
+ localDeviceId: string;
270
+ autoConnect?: boolean;
271
+ autoConnectDebounceMs?: number;
272
+ retryThrottleMs?: number;
273
+ tieBreaker?: (localDeviceId: string, remoteDeviceId: string) => boolean;
274
+ shouldSkipDevice?: (device: Device) => boolean;
275
+ isConnected?: (deviceId: string) => boolean;
276
+ isConnecting?: (deviceId: string) => boolean;
277
+ onDevices?: (devices: Device[]) => void;
278
+ onAutoConnect?: (device: Device) => Promise<void> | void;
279
+ onIncomingSession?: (session: SignalingSession) => Promise<void> | void;
280
+ hasProtectedConnectionIntent?: (deviceId: string) => boolean;
281
+ cleanupStaleConnection?: (deviceId: string) => Promise<void>;
282
+ allowIncomingNodeId?: (nodeId: string) => Promise<void>;
283
+ acceptIncomingSession?: (sessionId: string, initiatorDeviceId: string) => Promise<{
284
+ success: boolean;
285
+ error?: string;
286
+ }>;
287
+ onIncomingSessionAccepted?: (session: SignalingSession) => Promise<void> | void;
288
+ }
289
+ export interface ScanningLoopHandle {
290
+ stop: () => void;
291
+ }
292
+ export interface ConnectDeviceHooks {
293
+ getConnectionState?: (deviceId: string) => Promise<string | undefined> | string | undefined;
294
+ forceDisconnect?: (deviceId: string) => Promise<void>;
295
+ refreshState?: () => Promise<void>;
296
+ directConnect: (device: Device) => Promise<void>;
297
+ signalConnect: (params: {
298
+ localDeviceId: string;
299
+ targetDeviceId: string;
300
+ targetUserId?: string;
301
+ device: Device;
302
+ }) => Promise<{
303
+ success: boolean;
304
+ error?: string;
305
+ }>;
306
+ onConnected?: (device: Device) => Promise<void> | void;
307
+ onRetry?: (device: Device, attempt: number, delayMs: number) => void;
308
+ }
309
+ export interface ConnectDeviceOptions {
310
+ localDeviceId: string;
311
+ targetUserId?: string;
312
+ maxRetries?: number;
313
+ initialBackoffMs?: number;
314
+ }
315
+ export interface ConnectDeviceResult {
316
+ success: boolean;
317
+ skipped?: 'already-connecting' | 'missing-local-device-id';
318
+ error?: string;
319
+ attempts: number;
320
+ }
321
+ export interface ManagedDeviceConnectOptions {
322
+ localDeviceId: string;
323
+ targetUserId?: string;
324
+ maxRetries?: number;
325
+ initialBackoffMs?: number;
326
+ onRetry?: (device: Device, attempt: number, delayMs: number) => void;
327
+ onConnected?: (device: Device) => void | Promise<void>;
328
+ }
329
+ export interface DeviceStatusSnapshot extends Device {
330
+ connectionStatus: PeerLifecycleStatus | 'online';
331
+ settledReady?: boolean;
332
+ readinessState?: string;
333
+ readinessReason?: string;
334
+ peerHealth: PeerHealth;
335
+ peerId?: string;
336
+ promotionEligible?: boolean;
337
+ scopes: PeerScope[];
338
+ connectionId?: string;
339
+ deviceIdHint?: string;
340
+ activeTransportStableId?: number | null;
341
+ transportGeneration?: number;
342
+ }
343
+ export interface ManagedConnectionRecord {
344
+ connectionId: string;
345
+ nodeId?: string | null;
346
+ deviceId?: string | null;
347
+ deviceIdHint?: string | null;
348
+ endpointId?: string | null;
349
+ transportGeneration: number;
350
+ transportStableId?: number | null;
351
+ transportSource?: string | null;
352
+ lastTransportChangeAtMs: number;
353
+ state: string;
354
+ statusReason?: string | null;
355
+ transitionCount?: number;
356
+ connectingTransitionCount?: number;
357
+ replacementCount?: number;
358
+ retireCount?: number;
359
+ lastDisconnectReason?: string | null;
360
+ lastReconnectReason?: string | null;
361
+ createdAtMs: number;
362
+ updatedAtMs: number;
363
+ }
364
+ export type ManagedConnectionHealthStatus = 'healthy' | 'awaitingReplacement' | 'dead';
365
+ export interface ManagedConnectionHealthSnapshot {
366
+ connectionId: string;
367
+ deviceId?: string | null;
368
+ deviceIdHint?: string | null;
369
+ nodeId?: string | null;
370
+ activeTransportStableId?: number | null;
371
+ transportGeneration: number;
372
+ status: ManagedConnectionHealthStatus;
373
+ settledReady?: boolean;
374
+ readinessState?: string;
375
+ replacementPending?: boolean;
376
+ lastLifecycleTransitionAtMs?: number;
377
+ readinessReason?: string;
378
+ transitionCount?: number;
379
+ connectingTransitionCount?: number;
380
+ replacementCount?: number;
381
+ retireCount?: number;
382
+ lastDisconnectReason?: string | null;
383
+ lastReconnectReason?: string | null;
384
+ }
385
+ export interface ResolvedPeerIdentity {
386
+ peerId?: string | null;
387
+ deviceId?: string | null;
388
+ deviceIdHint?: string | null;
389
+ nodeId?: string | null;
390
+ }
391
+ export interface PeerSessionSnapshot {
392
+ peerId: string;
393
+ deviceId?: string | null;
394
+ deviceIdHint?: string | null;
395
+ nodeId?: string | null;
396
+ activeConnectionId?: string | null;
397
+ candidateConnectionIds: string[];
398
+ status: PeerLifecycleStatus;
399
+ health: PeerHealth;
400
+ settledReady?: boolean;
401
+ readinessState?: string;
402
+ activeTransportStableId?: number | null;
403
+ transportGeneration?: number;
404
+ replacementPending?: boolean;
405
+ lastLifecycleTransitionAtMs?: number;
406
+ readinessReason?: string;
407
+ transitionCount?: number;
408
+ connectingTransitionCount?: number;
409
+ replacementCount?: number;
410
+ retireCount?: number;
411
+ lastDisconnectReason?: string | null;
412
+ lastReconnectReason?: string | null;
413
+ scopes: PeerScope[];
414
+ lastSeenAtMs: number;
415
+ error?: string | null;
416
+ }
417
+ export interface RuntimeBootstrapOptions {
418
+ platform: 'native' | 'web';
419
+ initializeWeb?: () => Promise<void>;
420
+ isNativeReady?: () => Promise<boolean>;
421
+ retryNativeInit?: () => Promise<void>;
422
+ waitForNativeInitEvent?: (timeoutMs: number) => Promise<boolean>;
423
+ quickPollAttempts?: number;
424
+ quickPollIntervalMs?: number;
425
+ retryPollAttempts?: number;
426
+ retryPollIntervalMs?: number;
427
+ nativeInitEventTimeoutMs?: number;
428
+ initializeClient?: boolean;
429
+ }
430
+ export interface RuntimeBootstrapResult {
431
+ ready: boolean;
432
+ mode: 'native' | 'web';
433
+ }
434
+ export interface RuntimeIdentity {
435
+ id: string;
436
+ email?: string | null;
437
+ displayName?: string | null;
438
+ isAnonymous?: boolean;
439
+ getToken?: (forceRefresh?: boolean) => Promise<string | null>;
440
+ }
441
+ export type DeviceEvent = {
442
+ type: 'added';
443
+ device: Device;
444
+ } | {
445
+ type: 'modified';
446
+ device: Device;
447
+ } | {
448
+ type: 'removed';
449
+ deviceId: string;
450
+ };
451
+ export type SessionEvent = {
452
+ type: 'added';
453
+ session: SignalingSession;
454
+ } | {
455
+ type: 'modified';
456
+ session: SignalingSession;
457
+ } | {
458
+ type: 'removed';
459
+ sessionId: string;
460
+ };
461
+ export interface ExplicitFileDataSendParams {
462
+ connectionId?: string;
463
+ connection?: {
464
+ send: (message: unknown) => Promise<void>;
465
+ deviceId?: string;
466
+ remoteNodeId?: string;
467
+ };
468
+ remoteNodeId?: string;
469
+ file: File;
470
+ transferId: string;
471
+ channelId?: string;
472
+ }
473
+ export interface ISignalingBackend {
474
+ currentUser: RuntimeIdentity | null;
475
+ signInAnonymously(): Promise<void>;
476
+ signInWithPluto?(): Promise<void>;
477
+ signOut(): Promise<void>;
478
+ stopAuthScopedActivity?(): Promise<void>;
479
+ getTurnCredentials(): Promise<any>;
480
+ updatePresence(localNodeId: string, ticketStr: string, isOnline: boolean, ttlMs: number, metadata?: string): Promise<void>;
481
+ setOffline(localNodeId: string): Promise<void>;
482
+ cleanupStaleDevices(): Promise<void>;
483
+ searchDevices(excludeNodeId?: string): Promise<Device[]>;
484
+ listDevicesWithStatus?(): Promise<DeviceStatusSnapshot[]>;
485
+ getPeerSession?(id: string): Promise<PeerSessionSnapshot | null>;
486
+ listPeerSessions?(): Promise<PeerSessionSnapshot[]>;
487
+ waitForSettledPeer?(id: string, timeoutMs?: number): Promise<PeerSessionSnapshot | null>;
488
+ resolvePeerIdentity?(id: string): Promise<ResolvedPeerIdentity>;
489
+ resolvePeerConnectionRecords?(id: string): Promise<ManagedConnectionRecord[]>;
490
+ updateDevice(deviceId: string, updates: {
491
+ deviceName?: string;
492
+ capabilities?: Device['capabilities'];
493
+ metadata?: string;
494
+ }): Promise<void>;
495
+ deleteDevice(deviceId: string): Promise<void>;
496
+ onDevicesChange(callback: (devices: Device[]) => void, excludeNodeId?: string): () => void;
497
+ onAuthChange(callback: (user: RuntimeIdentity | null) => void): () => void;
498
+ checkForSSOToken(): Promise<void>;
499
+ waitForAuth(): Promise<void>;
500
+ sendMessage(targetId: string, payload: string, state?: string, replyPayload?: string): Promise<string>;
501
+ pollMessages(targetId: string): Promise<SignalingEnvelope[]>;
502
+ subscribeDevices(userId: string): Promise<ReadableStream<DeviceEvent[]>>;
503
+ startAutoConnectOnce?(userId: string, localDeviceId: string): Promise<void>;
504
+ startAutoConnect(userId: string, localDeviceId: string): void;
505
+ notifyDisconnectRequested?(remoteNodeId: string): void;
506
+ startPresenceLoopOnce?(userId: string, localNodeId: string, deviceName: string, ticket: string, metadata?: string): Promise<void>;
507
+ startPresenceLoop(userId: string, localNodeId: string, deviceName: string, ticket: string, metadata?: string): void;
508
+ createSession(session: SignalingSession): Promise<void>;
509
+ updateSession(sessionId: string, updateData: any): Promise<void>;
510
+ subscribeSessions(localDeviceId: string): Promise<ReadableStream<SessionEvent[]>>;
511
+ forceReconnectSnapshot(): void;
512
+ getLocalDeviceId?(): Promise<string | null>;
513
+ getLocalDeviceInfo?(): Promise<LocalDeviceInfo | null>;
514
+ updateLocalDeviceName?(deviceName: string): Promise<LocalDeviceInfo | null>;
515
+ getManagedNodeId?(options?: {
516
+ initializeIfMissing?: boolean;
517
+ }): Promise<string | null>;
518
+ getEndpointTicket?(): Promise<string>;
519
+ openPeerBi?(id: string, timeoutMs?: number): Promise<BackendPeerBiStream>;
520
+ openPeerUni?(id: string, timeoutMs?: number): Promise<BackendPeerUniStream>;
521
+ connectToDevice?(params: {
522
+ deviceId?: string | null;
523
+ endpointTicket: string;
524
+ }): Promise<NativeConnectResult>;
525
+ disconnectDevice?(deviceId: string): Promise<void>;
526
+ setAutoConnectExcluded?(deviceId: string, excluded: boolean): Promise<void>;
527
+ isConnected(nodeId: string): Promise<boolean>;
528
+ getConnectionStates?(): Promise<BackendConnectionState[]>;
529
+ onConnectionStateChange?(callback: (state: BackendConnectionState) => void): Promise<() => void> | (() => void);
530
+ sendExplicitFilePath?(connectionId: string, filePath: string, transferId?: string): Promise<string>;
531
+ sendExplicitFileData?(params: ExplicitFileDataSendParams): Promise<void>;
532
+ getTransferHistory?(limit?: number): Promise<Array<[string, unknown]>>;
533
+ deleteTransferJob?(jobId: string): Promise<void>;
534
+ }
535
+ export interface SignalingOptions {
536
+ apiKey?: string;
537
+ allowAnonymousHostedDefaults?: boolean;
538
+ authMode?: AuthMode;
539
+ projectId?: string;
540
+ storagePrefix?: string;
541
+ nodeIdPersistence?: 'persistent' | 'ephemeral';
542
+ }
543
+ export interface TransportContext {
544
+ sendMoQ: (data: Uint8Array) => Promise<void>;
545
+ priorities: ProtocolName[];
546
+ disableIrohFallback: boolean;
547
+ isMoQReady: () => boolean;
548
+ }
549
+ export interface ConnectionOptions {
550
+ reliable?: boolean;
551
+ rtcConfig?: RTCConfiguration;
552
+ transportContext?: TransportContext;
553
+ }
554
+ export interface JoinRequest {
555
+ id: string;
556
+ userId: string;
557
+ ticket: string;
558
+ state: 'pending' | 'accepted' | 'rejected';
559
+ }
@@ -0,0 +1,19 @@
1
+ // --- Billing / Plan Types ---
2
+ export const DEFAULT_FREE_LIMITS = {
3
+ devicesPerUser: 2,
4
+ maxRooms: 10,
5
+ maxMembersPerRoom: 5,
6
+ maxPersonalDevices: 50, // free: 10 rooms * 5 members = 50
7
+ };
8
+ // --- Constants ---
9
+ export const DEFAULT_MOQ_RELAY_URL = 'https://relay.cloudflare.mediaoverquic.com';
10
+ export const DEFAULT_ICE_SERVERS = [
11
+ { urls: 'stun:stun.l.google.com:19302' },
12
+ { urls: 'stun:stun.cloudflare.com:3478' }
13
+ ];
14
+ export const DEFAULT_WEBRTC_CONFIG = {
15
+ iceServers: DEFAULT_ICE_SERVERS
16
+ };
17
+ export const DEFAULT_MOQ_CONFIG = {
18
+ relayUrl: DEFAULT_MOQ_RELAY_URL
19
+ };