@strevokit/meeting-sdk 0.0.0-stage → 0.6.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.
- package/CHANGELOG.md +68 -0
- package/LICENSE +215 -0
- package/README.md +141 -2
- package/dist/index.d.ts +231 -0
- package/dist/index.js +2817 -0
- package/dist/index.js.map +7 -0
- package/docs/api-reference.md +343 -0
- package/docs/examples/react.tsx +144 -0
- package/docs/examples/vanilla.html +101 -0
- package/package.json +62 -4
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/internal/env.ts", "../../signaling-protocol/dist/version.js", "../../signaling-protocol/dist/limits.js", "../../signaling-protocol/dist/rejection.js", "../../signaling-protocol/dist/primitives.js", "../../signaling-protocol/dist/catalog.js", "../../signaling-protocol/dist/rolePolicy.js", "../../signaling-protocol/dist/payloads.js", "../../signaling-protocol/dist/parse.js", "../../signaling-protocol/dist/build.js", "../src/public/errors.ts", "../src/internal/emitter.ts", "../src/internal/errorMapping.ts", "../src/internal/localMedia.ts", "../src/internal/log.ts", "../src/internal/mediaDelivery.ts", "../src/internal/roster.ts", "../src/internal/signalingSession.ts", "../src/internal/engine.ts", "../src/internal/selectedPair.ts", "../src/internal/peerLink.ts", "../src/internal/remoteMedia.ts", "../src/internal/peerMediaDelivery.ts", "../src/internal/token.ts", "../src/createMeetingEngine.ts"],
|
|
4
|
+
"sourcesContent": ["/** The subset of the browser `WebSocket` the engine uses. */\nexport interface SocketLike {\n readonly protocol: string;\n readonly readyState: number;\n onopen: ((event: unknown) => void) | null;\n onmessage: ((event: { readonly data: unknown }) => void) | null;\n onclose: ((event: { readonly code: number; readonly reason: string }) => void) | null;\n onerror: ((event: unknown) => void) | null;\n send(data: string): void;\n close(code?: number, reason?: string): void;\n}\n\nexport type SocketConstructor = new (url: string, protocols: string[]) => SocketLike;\n\n/** The subset of `navigator.mediaDevices` the engine uses. */\nexport interface MediaDevicesLike {\n getUserMedia?(constraints: MediaStreamConstraints): Promise<MediaStream>;\n getDisplayMedia?(options?: DisplayMediaStreamOptions): Promise<MediaStream>;\n}\n\nexport type TimerHandle = unknown;\n\n/** The subset of `RTCRtpTransceiver` the engine uses. */\nexport interface TransceiverLike {\n direction: string;\n readonly sender: { readonly track: MediaStreamTrack | null; replaceTrack(track: MediaStreamTrack | null): Promise<void> };\n readonly receiver: { readonly track: MediaStreamTrack };\n}\n\nexport type SessionDescriptionLike = { readonly type: string; readonly sdp?: string };\n\nexport type IceCandidateLike = {\n readonly candidate: string;\n readonly sdpMid?: string | null;\n readonly sdpMLineIndex?: number | null;\n readonly usernameFragment?: string | null;\n};\n\n/** The fields of an `RTCStats` entry the engine reads; every other field is ignored. */\nexport type StatsReportLike = {\n readonly type: string;\n readonly id: string;\n readonly selectedCandidatePairId?: string;\n readonly localCandidateId?: string;\n readonly remoteCandidateId?: string;\n readonly candidateType?: string;\n readonly state?: string;\n readonly nominated?: boolean;\n};\n\n/** The subset of `RTCStatsReport` the engine uses. */\nexport interface StatsCollectionLike {\n forEach(callback: (report: StatsReportLike) => void): void;\n}\n\nexport type IceServerLike = { urls: string | string[]; username?: string; credential?: string };\n\n/** The subset of `RTCConfiguration` the engine reads and writes; other fields pass through untouched. */\nexport type PeerConfigurationLike = { iceServers?: IceServerLike[] };\n\n/** The subset of `RTCPeerConnection` the engine uses. */\nexport interface PeerConnectionLike {\n readonly signalingState: string;\n readonly connectionState?: string;\n readonly iceConnectionState?: string;\n readonly localDescription: SessionDescriptionLike | null;\n onicecandidate: ((event: { readonly candidate: IceCandidateLike | null }) => void) | null;\n onconnectionstatechange: ((event: unknown) => void) | null;\n oniceconnectionstatechange: ((event: unknown) => void) | null;\n addTransceiver(kind: \"audio\" | \"video\", init: { direction: \"sendrecv\" }): TransceiverLike;\n getTransceivers(): TransceiverLike[];\n createOffer(options?: { iceRestart?: boolean }): Promise<SessionDescriptionLike>;\n createAnswer(): Promise<SessionDescriptionLike>;\n getStats(): Promise<StatsCollectionLike>;\n getConfiguration(): PeerConfigurationLike;\n setConfiguration(configuration: PeerConfigurationLike): void;\n setLocalDescription(description: SessionDescriptionLike): Promise<void>;\n setRemoteDescription(description: { type: \"offer\" | \"answer\"; sdp: string }): Promise<void>;\n addIceCandidate(candidate: IceCandidateLike): Promise<void>;\n close(): void;\n}\n\nexport type PeerConnectionConstructor = new (configuration: {\n iceServers: { urls: string[]; username?: string; credential?: string }[];\n}) => PeerConnectionLike;\n\nexport type MediaStreamConstructor = new (tracks: MediaStreamTrack[]) => MediaStream;\n\n/** Browser capabilities the engine depends on, resolved once per engine. */\nexport interface EngineEnvironment {\n readonly WebSocket: SocketConstructor | undefined;\n readonly mediaDevices: MediaDevicesLike | undefined;\n readonly RTCPeerConnection?: PeerConnectionConstructor | undefined;\n readonly MediaStream?: MediaStreamConstructor | undefined;\n setTimeout(callback: () => void, ms: number): TimerHandle;\n clearTimeout(handle: TimerHandle): void;\n now(): number;\n}\n\nlet override: EngineEnvironment | undefined;\n\nexport function defaultEnvironment(): EngineEnvironment {\n const scope = globalThis as {\n WebSocket?: unknown;\n RTCPeerConnection?: unknown;\n MediaStream?: unknown;\n navigator?: { mediaDevices?: MediaDevicesLike };\n };\n return {\n WebSocket: typeof scope.WebSocket === \"function\" ? (scope.WebSocket as SocketConstructor) : undefined,\n mediaDevices: scope.navigator?.mediaDevices,\n RTCPeerConnection:\n typeof scope.RTCPeerConnection === \"function\" ? (scope.RTCPeerConnection as PeerConnectionConstructor) : undefined,\n MediaStream: typeof scope.MediaStream === \"function\" ? (scope.MediaStream as MediaStreamConstructor) : undefined,\n setTimeout: (callback, ms) => globalThis.setTimeout(callback, ms),\n clearTimeout: (handle) => globalThis.clearTimeout(handle as ReturnType<typeof globalThis.setTimeout>),\n now: () => Date.now(),\n };\n}\n\nexport function currentEnvironment(): EngineEnvironment {\n return override ?? defaultEnvironment();\n}\n\n/** Replaces the environment for engines created afterwards; `undefined` restores the default. */\nexport function __setTestEnvironment(environment: EngineEnvironment | undefined): void {\n override = environment;\n}\n", "/** Protocol version stamped on every outbound message. */\nexport const PROTOCOL_VERSION = 1;\n/** Protocol versions a receiver accepts. */\nexport const SUPPORTED_PROTOCOL_VERSIONS = Object.freeze([1]);\n/** Strict check: a JSON number that is an integer in SUPPORTED_PROTOCOL_VERSIONS (no coercion). */\nexport function isSupportedVersion(value) {\n return (typeof value === \"number\" &&\n Number.isInteger(value) &&\n SUPPORTED_PROTOCOL_VERSIONS.includes(value));\n}\n", "/** Maximum UTF-8 byte length of one serialized frame. The realtime service's WebSocket max payload must be at least this. */\nexport const MAX_MESSAGE_BYTES = 65536;\n/** Maximum UTF-8 byte length of `payload.sdp` on `webrtc.offer` / `webrtc.answer`. */\nexport const MAX_SDP_BYTES = 49152;\n/** Maximum length (UTF-16 code units) of `payload.candidate.candidate`. */\nexport const MAX_ICE_CANDIDATE_LENGTH = 1024;\n/** Maximum Unicode code points of `payload.displayName` (matches the API's display_name default). */\nexport const MAX_DISPLAY_NAME_CODE_POINTS = 255;\n/** Maximum length of a reason code. */\nexport const MAX_REASON_LENGTH = 64;\nexport const MAX_SDP_MID_LENGTH = 64;\nexport const MAX_USERNAME_FRAGMENT_LENGTH = 256;\nexport const MAX_SDP_MLINE_INDEX = 1023;\n/** Maximum entries in `session.welcome.iceServers`. */\nexport const MAX_ICE_SERVERS = 4;\n/** Maximum `urls` per `iceServers` entry. */\nexport const MAX_ICE_SERVER_URLS = 4;\n/** Maximum length of one `iceServers[].urls` element. */\nexport const MAX_ICE_SERVER_URL_LENGTH = 256;\nexport const MAX_ICE_SERVER_USERNAME_LENGTH = 256;\nexport const MAX_ICE_SERVER_CREDENTIAL_LENGTH = 256;\n", "/** Stable rejection reason codes (part of the public contract). */\nexport const REJECTION_CODES = Object.freeze([\n \"invalid_envelope\",\n \"unsupported_version\",\n \"unknown_type\",\n \"direction_not_allowed\",\n \"invalid_payload\",\n]);\n/** Stable sub-reasons carried in `SignalingRejection.detail`. */\nexport const REJECTION_DETAILS = Object.freeze([\n \"message_too_large\",\n \"not_text\",\n \"invalid_json\",\n \"not_an_object\",\n \"invalid_ulid\",\n \"payload_not_object\",\n \"missing_field\",\n \"wrong_type\",\n \"too_long\",\n \"out_of_range\",\n \"invalid_format\",\n]);\nconst CODE_MESSAGES = {\n invalid_envelope: \"Message envelope is invalid.\",\n unsupported_version: \"Protocol version is missing or not supported.\",\n unknown_type: \"Message type is not part of the protocol.\",\n direction_not_allowed: \"Message type is not allowed in this direction.\",\n invalid_payload: \"Message payload is invalid.\",\n};\nconst DETAIL_MESSAGES = {\n message_too_large: \"Message exceeds the maximum size.\",\n not_text: \"Message frame must be UTF-8 text.\",\n invalid_json: \"Message frame is not valid JSON.\",\n not_an_object: \"Message must be a JSON object.\",\n invalid_ulid: \"Identifier must be a canonical ULID.\",\n payload_not_object: \"Payload must be a JSON object.\",\n missing_field: \"A required field is missing.\",\n wrong_type: \"A field has the wrong type.\",\n too_long: \"A field is too long.\",\n out_of_range: \"A field is out of range.\",\n invalid_format: \"A field has an invalid format.\",\n};\n/** Build a rejection. Messages come only from fixed templates. */\nexport function reject(code, detail, field) {\n const rejection = {\n code,\n message: detail ? DETAIL_MESSAGES[detail] : CODE_MESSAGES[code],\n };\n if (field !== undefined)\n rejection.field = field;\n if (detail !== undefined)\n rejection.detail = detail;\n return rejection;\n}\n/** Thrown only by outbound helpers (createSignalingMessage / encodeSignalingMessage). */\nexport class SignalingProtocolError extends Error {\n rejection;\n constructor(rejection) {\n super(`${rejection.code}: ${rejection.message}`);\n this.name = \"SignalingProtocolError\";\n this.rejection = rejection;\n }\n}\n", "const ULID_PATTERN = /^[0-9A-HJKMNP-TV-Z]{26}$/;\nconst REASON_CODE_PATTERN = /^[a-z][a-z0-9_]{0,63}$/;\nconst TIMESTAMP_PATTERN = /^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(?:\\.\\d{1,9})?Z$/;\n/** Canonical ULID: 26 chars, uppercase Crockford base32 (the API's public_id format). */\nexport function isCanonicalUlid(value) {\n return typeof value === \"string\" && ULID_PATTERN.test(value);\n}\n/** UTF-8 byte length without TextEncoder, so it runs in browsers and Node alike. */\nexport function utf8ByteLength(value) {\n let bytes = 0;\n for (let i = 0; i < value.length; i++) {\n const unit = value.charCodeAt(i);\n if (unit < 0x80) {\n bytes += 1;\n }\n else if (unit < 0x800) {\n bytes += 2;\n }\n else if (unit >= 0xd800 && unit <= 0xdbff && i + 1 < value.length) {\n const next = value.charCodeAt(i + 1);\n if (next >= 0xdc00 && next <= 0xdfff) {\n bytes += 4;\n i++;\n }\n else {\n bytes += 3;\n }\n }\n else {\n bytes += 3;\n }\n }\n return bytes;\n}\n/** Number of Unicode code points (surrogate pairs count once). */\nexport function codePointLength(value) {\n let count = 0;\n for (let i = 0; i < value.length; i++) {\n const unit = value.charCodeAt(i);\n if (unit >= 0xd800 && unit <= 0xdbff && i + 1 < value.length) {\n const next = value.charCodeAt(i + 1);\n if (next >= 0xdc00 && next <= 0xdfff)\n i++;\n }\n count++;\n }\n return count;\n}\nexport function isReasonCode(value) {\n return typeof value === \"string\" && REASON_CODE_PATTERN.test(value);\n}\n/** RFC 3339 UTC timestamp with `Z` suffix and a real calendar date. */\nexport function isRfc3339UtcTimestamp(value) {\n if (typeof value !== \"string\")\n return false;\n const match = TIMESTAMP_PATTERN.exec(value);\n if (!match)\n return false;\n const [year, month, day, hour, minute, second] = match\n .slice(1, 7)\n .map((part) => Number(part));\n if (month < 1 || month > 12 || day < 1)\n return false;\n if (hour > 23 || minute > 59 || second > 59)\n return false;\n const daysInMonth = new Date(Date.UTC(year, month, 0)).getUTCDate();\n return day <= daysInMonth;\n}\n/** Non-null, non-array object whose prototype is Object.prototype or null. */\nexport function isPlainObject(value) {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return false;\n }\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n/** Read an own property only; inherited properties are treated as absent. */\nexport function readOwn(obj, key) {\n return Object.hasOwn(obj, key) ? obj[key] : undefined;\n}\nexport function hasOwn(obj, key) {\n return Object.hasOwn(obj, key);\n}\n", "const CATALOG = {\n \"participant.join\": { family: \"participant\", direction: \"client_to_server\" },\n \"participant.joined\": { family: \"participant\", direction: \"server_to_client\" },\n \"participant.leave\": { family: \"participant\", direction: \"client_to_server\" },\n \"participant.left\": { family: \"participant\", direction: \"server_to_client\" },\n \"participant.reconnected\": { family: \"participant\", direction: \"server_to_client\" },\n \"webrtc.offer\": { family: \"webrtc\", direction: \"both\" },\n \"webrtc.answer\": { family: \"webrtc\", direction: \"both\" },\n \"webrtc.ice_candidate\": { family: \"webrtc\", direction: \"both\" },\n \"webrtc.connected\": { family: \"webrtc\", direction: \"client_to_server\" },\n \"webrtc.disconnected\": { family: \"webrtc\", direction: \"client_to_server\" },\n \"webrtc.failed\": { family: \"webrtc\", direction: \"client_to_server\" },\n \"webrtc.ice_restart\": { family: \"webrtc\", direction: \"both\" },\n \"webrtc.ice_restart_result\": { family: \"webrtc\", direction: \"client_to_server\" },\n \"media.camera.started\": { family: \"media\", direction: \"both\" },\n \"media.camera.stopped\": { family: \"media\", direction: \"both\" },\n \"media.microphone.started\": { family: \"media\", direction: \"both\" },\n \"media.microphone.stopped\": { family: \"media\", direction: \"both\" },\n \"media.screen.started\": { family: \"media\", direction: \"both\" },\n \"media.screen.stopped\": { family: \"media\", direction: \"both\" },\n \"meeting.started\": { family: \"meeting\", direction: \"server_to_client\" },\n \"meeting.ended\": { family: \"meeting\", direction: \"server_to_client\" },\n \"meeting.terminated\": { family: \"meeting\", direction: \"server_to_client\" },\n \"meeting.end\": { family: \"meeting\", direction: \"client_to_server\" },\n \"session.authenticated\": { family: \"session\", direction: \"server_to_client\" },\n \"session.welcome\": { family: \"session\", direction: \"server_to_client\" },\n \"session.rejected\": { family: \"session\", direction: \"server_to_client\" },\n \"session.ice_servers\": { family: \"session\", direction: \"server_to_client\" },\n};\nfor (const entry of Object.values(CATALOG))\n Object.freeze(entry);\n/** Family and allowed direction for every v1 message type. */\nexport const MESSAGE_CATALOG = Object.freeze(CATALOG);\n/** All v1 message types, in catalog order. */\nexport const MESSAGE_TYPES = Object.freeze(Object.keys(CATALOG));\nexport function isMessageType(value) {\n return typeof value === \"string\" && Object.hasOwn(CATALOG, value);\n}\nexport function isDirectionAllowed(type, direction) {\n const allowed = MESSAGE_CATALOG[type].direction;\n return allowed === \"both\" || allowed === direction;\n}\n", "const ALL_ROLES = Object.freeze([\"host\", \"participant\"]);\n/** Types restricted to specific roles; every other type is allowed for all roles. */\nexport const ROLE_POLICY = Object.freeze({\n \"media.screen.started\": Object.freeze([\"host\"]),\n \"media.screen.stopped\": Object.freeze([\"host\"]),\n \"meeting.end\": Object.freeze([\"host\"]),\n});\nexport function allowedRoles(type) {\n return ROLE_POLICY[type] ?? ALL_ROLES;\n}\nexport function isRoleAllowed(type, role) {\n return allowedRoles(type).includes(role);\n}\n", "import { MAX_DISPLAY_NAME_CODE_POINTS, MAX_ICE_CANDIDATE_LENGTH, MAX_ICE_SERVER_CREDENTIAL_LENGTH, MAX_ICE_SERVER_URL_LENGTH, MAX_ICE_SERVER_URLS, MAX_ICE_SERVER_USERNAME_LENGTH, MAX_ICE_SERVERS, MAX_REASON_LENGTH, MAX_SDP_BYTES, MAX_SDP_MID_LENGTH, MAX_SDP_MLINE_INDEX, MAX_USERNAME_FRAGMENT_LENGTH, } from \"./limits.js\";\nimport { codePointLength, hasOwn, isCanonicalUlid, isPlainObject, isReasonCode, isRfc3339UtcTimestamp, utf8ByteLength, } from \"./primitives.js\";\nimport { reject } from \"./rejection.js\";\nclass PayloadFailure {\n rejection;\n constructor(rejection) {\n this.rejection = rejection;\n }\n}\nfunction fail(detail, path) {\n throw new PayloadFailure(reject(\"invalid_payload\", detail, path));\n}\nfunction required(obj, key, path) {\n if (!hasOwn(obj, key))\n fail(\"missing_field\", path);\n return obj[key];\n}\nfunction requiredString(obj, key, path) {\n const value = required(obj, key, path);\n if (typeof value !== \"string\")\n fail(\"wrong_type\", path);\n return value;\n}\nfunction participantRef(obj, key, path, ctx, allowSelf) {\n const value = requiredString(obj, key, path);\n if (!isCanonicalUlid(value))\n fail(\"invalid_ulid\", path);\n if (!allowSelf && value === ctx.participantId)\n fail(\"invalid_format\", path);\n return value;\n}\nfunction reasonCode(obj, key, path) {\n const value = requiredString(obj, key, path);\n if (value.length > MAX_REASON_LENGTH)\n fail(\"too_long\", path);\n if (!isReasonCode(value))\n fail(\"invalid_format\", path);\n return value;\n}\nfunction timestamp(obj, key, path) {\n const value = requiredString(obj, key, path);\n if (!isRfc3339UtcTimestamp(value))\n fail(\"invalid_format\", path);\n return value;\n}\nfunction sdp(obj) {\n const path = \"payload.sdp\";\n const value = requiredString(obj, \"sdp\", path);\n if (value.length === 0)\n fail(\"invalid_format\", path);\n if (value.length > MAX_SDP_BYTES)\n fail(\"too_long\", path);\n if (value.length * 3 > MAX_SDP_BYTES && utf8ByteLength(value) > MAX_SDP_BYTES) {\n fail(\"too_long\", path);\n }\n return value;\n}\nfunction nullableString(obj, key, path, maxLength) {\n const value = obj[key];\n if (value === null)\n return null;\n if (typeof value !== \"string\")\n fail(\"wrong_type\", path);\n if (value.length > maxLength)\n fail(\"too_long\", path);\n return value;\n}\nfunction iceCandidate(obj) {\n const base = \"payload.candidate\";\n const raw = required(obj, \"candidate\", base);\n if (!isPlainObject(raw))\n fail(\"wrong_type\", base);\n const candidate = requiredString(raw, \"candidate\", `${base}.candidate`);\n if (candidate.length > MAX_ICE_CANDIDATE_LENGTH)\n fail(\"too_long\", `${base}.candidate`);\n required(raw, \"sdpMid\", `${base}.sdpMid`);\n const sdpMid = nullableString(raw, \"sdpMid\", `${base}.sdpMid`, MAX_SDP_MID_LENGTH);\n const indexPath = `${base}.sdpMLineIndex`;\n const index = required(raw, \"sdpMLineIndex\", indexPath);\n let sdpMLineIndex = null;\n if (index !== null) {\n if (typeof index !== \"number\")\n fail(\"wrong_type\", indexPath);\n if (!Number.isInteger(index) || index < 0 || index > MAX_SDP_MLINE_INDEX) {\n fail(\"out_of_range\", indexPath);\n }\n sdpMLineIndex = index;\n }\n if (candidate.length > 0 && sdpMid === null && sdpMLineIndex === null) {\n fail(\"invalid_format\", base);\n }\n const value = { candidate, sdpMid, sdpMLineIndex };\n if (hasOwn(raw, \"usernameFragment\")) {\n value.usernameFragment = nullableString(raw, \"usernameFragment\", `${base}.usernameFragment`, MAX_USERNAME_FRAGMENT_LENGTH);\n }\n return value;\n}\nconst empty = () => ({});\nconst sessionDescription = (p, ctx) => ({\n targetParticipantId: participantRef(p, \"targetParticipantId\", \"payload.targetParticipantId\", ctx, false),\n sdp: sdp(p),\n});\nconst peer = (p, ctx) => ({\n peerParticipantId: participantRef(p, \"peerParticipantId\", \"payload.peerParticipantId\", ctx, false),\n});\nfunction role(obj) {\n const value = requiredString(obj, \"role\", \"payload.role\");\n if (value !== \"host\" && value !== \"participant\")\n fail(\"invalid_format\", \"payload.role\");\n return value;\n}\nfunction optionalDisplayName(p, value) {\n if (hasOwn(p, \"displayName\")) {\n const path = \"payload.displayName\";\n const displayName = p.displayName;\n if (typeof displayName !== \"string\")\n fail(\"wrong_type\", path);\n if (displayName.length === 0)\n fail(\"invalid_format\", path);\n if (codePointLength(displayName) > MAX_DISPLAY_NAME_CODE_POINTS)\n fail(\"too_long\", path);\n value.displayName = displayName;\n }\n return value;\n}\nconst ICE_SERVER_URL_SCHEMES = [\"stun:\", \"stuns:\", \"turn:\", \"turns:\"];\nfunction optionalBoundedString(obj, key, path, maxLength, value) {\n if (!hasOwn(obj, key))\n return;\n const raw = obj[key];\n if (typeof raw !== \"string\")\n fail(\"wrong_type\", path);\n if (raw.length > maxLength)\n fail(\"too_long\", path);\n value[key] = raw;\n}\nfunction iceServer(raw, path) {\n if (!isPlainObject(raw))\n fail(\"wrong_type\", path);\n const urlsPath = `${path}.urls`;\n const urls = required(raw, \"urls\", urlsPath);\n if (!Array.isArray(urls))\n fail(\"wrong_type\", urlsPath);\n if (urls.length === 0 || urls.length > MAX_ICE_SERVER_URLS)\n fail(\"out_of_range\", urlsPath);\n const checked = urls.map((url, index) => {\n const urlPath = `${urlsPath}.${index}`;\n if (typeof url !== \"string\")\n fail(\"wrong_type\", urlPath);\n if (url.length > MAX_ICE_SERVER_URL_LENGTH)\n fail(\"too_long\", urlPath);\n if (!ICE_SERVER_URL_SCHEMES.some((scheme) => url.startsWith(scheme) && url.length > scheme.length)) {\n fail(\"invalid_format\", urlPath);\n }\n return url;\n });\n const value = { urls: checked };\n optionalBoundedString(raw, \"username\", `${path}.username`, MAX_ICE_SERVER_USERNAME_LENGTH, value);\n optionalBoundedString(raw, \"credential\", `${path}.credential`, MAX_ICE_SERVER_CREDENTIAL_LENGTH, value);\n return value;\n}\nfunction iceServers(obj) {\n const path = \"payload.iceServers\";\n const servers = required(obj, \"iceServers\", path);\n if (!Array.isArray(servers))\n fail(\"wrong_type\", path);\n if (servers.length > MAX_ICE_SERVERS)\n fail(\"too_long\", path);\n return servers.map((server, index) => iceServer(server, `${path}.${index}`));\n}\nfunction sessionWelcome(p) {\n const value = optionalDisplayName(p, {\n role: role(p),\n joinedAt: timestamp(p, \"joinedAt\", \"payload.joinedAt\"),\n });\n if (hasOwn(p, \"mediaMode\")) {\n const path = \"payload.mediaMode\";\n const mediaMode = p.mediaMode;\n if (typeof mediaMode !== \"string\")\n fail(\"wrong_type\", path);\n if (mediaMode !== \"p2p\" && mediaMode !== \"sfu\")\n fail(\"invalid_format\", path);\n value.mediaMode = mediaMode;\n }\n if (hasOwn(p, \"iceServers\"))\n value.iceServers = iceServers(p);\n if (hasOwn(p, \"iceServersExpireAt\")) {\n value.iceServersExpireAt = timestamp(p, \"iceServersExpireAt\", \"payload.iceServersExpireAt\");\n }\n return value;\n}\nconst VALIDATORS = {\n \"participant.join\": empty,\n \"participant.joined\": (p) => optionalDisplayName(p, { role: role(p) }),\n \"participant.leave\": empty,\n \"participant.left\": (p) => ({ reason: reasonCode(p, \"reason\", \"payload.reason\") }),\n \"participant.reconnected\": empty,\n \"webrtc.offer\": sessionDescription,\n \"webrtc.answer\": sessionDescription,\n \"webrtc.ice_candidate\": (p, ctx) => ({\n targetParticipantId: participantRef(p, \"targetParticipantId\", \"payload.targetParticipantId\", ctx, false),\n candidate: iceCandidate(p),\n }),\n \"webrtc.connected\": (p, ctx) => {\n const value = peer(p, ctx);\n for (const key of [\"path\", \"localPath\", \"remotePath\"]) {\n if (hasOwn(p, key))\n value[key] = reasonCode(p, key, `payload.${key}`);\n }\n return value;\n },\n \"webrtc.disconnected\": peer,\n \"webrtc.failed\": (p, ctx) => ({\n ...peer(p, ctx),\n reason: reasonCode(p, \"reason\", \"payload.reason\"),\n }),\n \"webrtc.ice_restart\": (p, ctx) => ({\n targetParticipantId: participantRef(p, \"targetParticipantId\", \"payload.targetParticipantId\", ctx, false),\n }),\n \"webrtc.ice_restart_result\": (p, ctx) => ({\n ...peer(p, ctx),\n outcome: reasonCode(p, \"outcome\", \"payload.outcome\"),\n }),\n \"media.camera.started\": empty,\n \"media.camera.stopped\": empty,\n \"media.microphone.started\": empty,\n \"media.microphone.stopped\": empty,\n \"media.screen.started\": empty,\n \"media.screen.stopped\": empty,\n \"meeting.started\": (p) => ({ startedAt: timestamp(p, \"startedAt\", \"payload.startedAt\") }),\n \"meeting.ended\": (p, ctx) => {\n const value = { endedAt: timestamp(p, \"endedAt\", \"payload.endedAt\") };\n if (hasOwn(p, \"endedByParticipantId\")) {\n value.endedByParticipantId = participantRef(p, \"endedByParticipantId\", \"payload.endedByParticipantId\", ctx, true);\n }\n return value;\n },\n \"meeting.terminated\": (p) => ({\n terminatedAt: timestamp(p, \"terminatedAt\", \"payload.terminatedAt\"),\n reason: reasonCode(p, \"reason\", \"payload.reason\"),\n }),\n \"meeting.end\": empty,\n \"session.authenticated\": (p) => ({ role: role(p) }),\n \"session.welcome\": sessionWelcome,\n \"session.rejected\": (p) => {\n const value = { code: reasonCode(p, \"code\", \"payload.code\") };\n if (hasOwn(p, \"detail\"))\n value.detail = reasonCode(p, \"detail\", \"payload.detail\");\n return value;\n },\n \"session.ice_servers\": (p) => ({\n iceServers: iceServers(p),\n expiresAt: timestamp(p, \"expiresAt\", \"payload.expiresAt\"),\n }),\n};\n/**\n * Validate a payload for `type`. Builds a fresh object with documented fields only,\n * so unknown fields and hostile keys are never copied.\n */\nexport function validatePayload(type, payload, ctx) {\n try {\n return { ok: true, value: VALIDATORS[type](payload, ctx) };\n }\n catch (error) {\n if (error instanceof PayloadFailure)\n return { ok: false, rejection: error.rejection };\n throw error;\n }\n}\n", "import { isDirectionAllowed, isMessageType } from \"./catalog.js\";\nimport { MAX_MESSAGE_BYTES } from \"./limits.js\";\nimport { validatePayload } from \"./payloads.js\";\nimport { isCanonicalUlid, isPlainObject, readOwn, utf8ByteLength } from \"./primitives.js\";\nimport { reject } from \"./rejection.js\";\nimport { PROTOCOL_VERSION, isSupportedVersion } from \"./version.js\";\nfunction failure(error) {\n return { ok: false, error };\n}\nfunction resolveDirection(options) {\n const direction = options?.direction;\n return direction === \"client_to_server\" || direction === \"server_to_client\"\n ? direction\n : undefined;\n}\n/** Ordered checks (contract steps 3-8): object, version, type, direction, envelope fields, payload. */\nfunction parseValue(input, direction) {\n if (!isPlainObject(input))\n return failure(reject(\"invalid_envelope\", \"not_an_object\"));\n if (!isSupportedVersion(readOwn(input, \"version\"))) {\n return failure(reject(\"unsupported_version\", undefined, \"version\"));\n }\n const type = readOwn(input, \"type\");\n if (!isMessageType(type))\n return failure(reject(\"unknown_type\", undefined, \"type\"));\n if (direction !== undefined && !isDirectionAllowed(type, direction)) {\n return failure(reject(\"direction_not_allowed\", undefined, \"type\"));\n }\n const meetingId = readOwn(input, \"meetingId\");\n if (!isCanonicalUlid(meetingId)) {\n return failure(reject(\"invalid_envelope\", \"invalid_ulid\", \"meetingId\"));\n }\n const participantId = readOwn(input, \"participantId\");\n if (!isCanonicalUlid(participantId)) {\n return failure(reject(\"invalid_envelope\", \"invalid_ulid\", \"participantId\"));\n }\n const payload = readOwn(input, \"payload\");\n if (!isPlainObject(payload)) {\n return failure(reject(\"invalid_envelope\", \"payload_not_object\", \"payload\"));\n }\n const result = validatePayload(type, payload, { participantId });\n if (!result.ok)\n return failure(result.rejection);\n const message = {\n version: PROTOCOL_VERSION,\n type,\n meetingId,\n participantId,\n payload: result.value,\n };\n return { ok: true, message };\n}\n/** Validate an already-parsed value. Never throws. */\nexport function parseSignalingMessage(input, options) {\n try {\n return parseValue(input, resolveDirection(options));\n }\n catch {\n return failure(reject(\"invalid_envelope\"));\n }\n}\nfunction exceedsMaxMessageBytes(frame) {\n if (frame.length > MAX_MESSAGE_BYTES)\n return true;\n if (frame.length * 3 <= MAX_MESSAGE_BYTES)\n return false;\n return utf8ByteLength(frame) > MAX_MESSAGE_BYTES;\n}\n/** Validate a raw text frame: size, then JSON, then full validation. Never throws. */\nexport function decodeSignalingFrame(frame, options) {\n try {\n if (typeof frame !== \"string\")\n return failure(reject(\"invalid_envelope\", \"not_text\"));\n if (exceedsMaxMessageBytes(frame)) {\n return failure(reject(\"invalid_envelope\", \"message_too_large\"));\n }\n let value;\n try {\n value = JSON.parse(frame);\n }\n catch {\n return failure(reject(\"invalid_envelope\", \"invalid_json\"));\n }\n return parseValue(value, resolveDirection(options));\n }\n catch {\n return failure(reject(\"invalid_envelope\"));\n }\n}\n", "import { MAX_MESSAGE_BYTES } from \"./limits.js\";\nimport { parseSignalingMessage } from \"./parse.js\";\nimport { utf8ByteLength } from \"./primitives.js\";\nimport { SignalingProtocolError, reject } from \"./rejection.js\";\nimport { PROTOCOL_VERSION } from \"./version.js\";\n/**\n * Build an outbound message stamped with PROTOCOL_VERSION.\n * Throws SignalingProtocolError if it would not pass validation (outbound data is our own code).\n */\nexport function createSignalingMessage(type, fields) {\n const result = parseSignalingMessage({\n version: PROTOCOL_VERSION,\n type,\n meetingId: fields.meetingId,\n participantId: fields.participantId,\n payload: fields.payload,\n });\n if (!result.ok)\n throw new SignalingProtocolError(result.error);\n return result.message;\n}\n/**\n * Serialize a message to a text frame. The message is re-validated (so only documented\n * fields are sent) and the frame must fit in MAX_MESSAGE_BYTES; otherwise this throws.\n */\nexport function encodeSignalingMessage(message) {\n const result = parseSignalingMessage(message);\n if (!result.ok)\n throw new SignalingProtocolError(result.error);\n const frame = JSON.stringify(result.message);\n if (utf8ByteLength(frame) > MAX_MESSAGE_BYTES) {\n throw new SignalingProtocolError(reject(\"invalid_envelope\", \"message_too_large\"));\n }\n return frame;\n}\n", "/**\n * Every code a {@link MeetingError} can carry. Codes are stable strings; new codes may be added in minor\n * versions, so handle unknown codes generically.\n */\nexport type MeetingErrorCode =\n | \"join_token_invalid\"\n | \"join_token_expired\"\n | \"origin_not_allowed\"\n | \"connection_failed\"\n | \"join_timeout\"\n | \"join_cancelled\"\n | \"connection_lost\"\n | \"session_replaced\"\n | \"service_unavailable\"\n | \"rate_limited\"\n | \"meeting_ended\"\n | \"protocol_error\"\n | \"already_joined\"\n | \"engine_closed\"\n | \"not_joined\"\n | \"not_permitted\"\n | \"permission_denied\"\n | \"device_not_found\"\n | \"device_unavailable\"\n | \"screen_share_cancelled\"\n | \"unsupported_environment\"\n | \"media_connection_failed\"\n | \"media_participant_limit\";\n\ntype ErrorInfo = { readonly message: string; readonly retryable: boolean };\n\nexport const ERROR_INFO: Readonly<Record<MeetingErrorCode, ErrorInfo>> = Object.freeze({\n join_token_invalid: { message: \"This meeting link is not valid. Ask for a new one.\", retryable: false },\n join_token_expired: { message: \"This meeting link has expired. Ask for a new one.\", retryable: true },\n origin_not_allowed: { message: \"This site is not allowed to join this meeting.\", retryable: false },\n connection_failed: {\n message: \"Could not connect to the meeting. Check your connection and try again.\",\n retryable: true,\n },\n join_timeout: { message: \"Joining the meeting took too long. Please try again.\", retryable: true },\n join_cancelled: { message: \"Joining was cancelled.\", retryable: false },\n connection_lost: { message: \"The connection to the meeting was lost.\", retryable: true },\n session_replaced: { message: \"You joined this meeting from another tab or device.\", retryable: false },\n service_unavailable: {\n message: \"The meeting service is temporarily unavailable. Please try again shortly.\",\n retryable: true,\n },\n rate_limited: { message: \"Too many attempts. Please wait a moment and try again.\", retryable: true },\n meeting_ended: { message: \"This meeting has ended.\", retryable: false },\n protocol_error: { message: \"Something went wrong in the meeting connection.\", retryable: false },\n already_joined: { message: \"This meeting is already joined or joining.\", retryable: false },\n engine_closed: {\n message: \"This meeting session has ended. Create a new one to join again.\",\n retryable: false,\n },\n not_joined: { message: \"Join the meeting first.\", retryable: false },\n not_permitted: { message: \"You don't have permission to do that in this meeting.\", retryable: false },\n permission_denied: {\n message: \"Camera or microphone access was blocked. Allow access in your browser settings.\",\n retryable: false,\n },\n device_not_found: { message: \"No camera or microphone was found.\", retryable: false },\n device_unavailable: {\n message: \"Your camera or microphone is being used by another application.\",\n retryable: true,\n },\n screen_share_cancelled: { message: \"Screen sharing was cancelled.\", retryable: false },\n unsupported_environment: {\n message:\n \"This browser does not support meetings. Try a current version of Chrome, Edge, Firefox, or Safari.\",\n retryable: false,\n },\n media_connection_failed: {\n message: \"Audio and video couldn't connect to the other participant. Check your network and try rejoining.\",\n retryable: true,\n },\n media_participant_limit: {\n message: \"Audio and video are available with one other participant in this meeting.\",\n retryable: false,\n },\n});\n\n/**\n * The single error type raised by the SDK. `message` is a short English sentence that is safe to show to users;\n * branch on `code` rather than on `message`.\n */\nexport class MeetingError extends Error {\n override readonly name = \"MeetingError\" as const;\n /** Stable machine-readable code. */\n readonly code: MeetingErrorCode;\n /** True when retrying the same action later (with a fresh token for join errors) may succeed. */\n readonly retryable: boolean;\n\n constructor(code: MeetingErrorCode) {\n const info = ERROR_INFO[code];\n super(info.message);\n this.code = code;\n this.retryable = info.retryable;\n }\n}\n", "import type { Log } from \"./log.js\";\n\ntype Listener<T> = (event: T) => void;\n\n/** Synchronous typed emitter. A throwing listener never affects other listeners or the caller. */\nexport class Emitter<Events extends object> {\n readonly #listeners = new Map<keyof Events, Set<Listener<never>>>();\n readonly #log: Log;\n\n constructor(log: Log) {\n this.#log = log;\n }\n\n on<K extends keyof Events>(type: K, listener: Listener<Events[K]>): () => void {\n let set = this.#listeners.get(type);\n if (!set) {\n set = new Set();\n this.#listeners.set(type, set);\n }\n const entry = listener as Listener<never>;\n set.add(entry);\n return () => {\n this.#listeners.get(type)?.delete(entry);\n };\n }\n\n emit<K extends keyof Events>(type: K, event: Events[K]): void {\n const set = this.#listeners.get(type);\n if (!set || set.size === 0) return;\n for (const listener of [...set]) {\n try {\n (listener as Listener<Events[K]>)(event);\n } catch {\n this.#log.warn(\"event listener threw\", { messageType: String(type) });\n }\n }\n }\n\n clear(): void {\n this.#listeners.clear();\n }\n}\n", "import { MeetingError, type MeetingErrorCode } from \"../public/errors.js\";\nimport type { CloseReason, MediaKind, ParticipantLeftReason } from \"../public/types.js\";\n\nexport type ClosePhase = \"before_joined\" | \"after_joined\";\nexport type MappedClose = { reason: CloseReason; error?: MeetingError };\n\nconst BEFORE_JOINED: Readonly<Record<number, MeetingErrorCode>> = {\n 1001: \"service_unavailable\",\n 4001: \"join_token_invalid\",\n 4002: \"join_token_expired\",\n 4003: \"origin_not_allowed\",\n 4004: \"meeting_ended\",\n 4008: \"join_timeout\",\n 4009: \"session_replaced\",\n 4011: \"protocol_error\",\n 4029: \"rate_limited\",\n 4503: \"service_unavailable\",\n};\n\nconst AFTER_JOINED: Readonly<Record<number, readonly [CloseReason, MeetingErrorCode | undefined]>> = {\n 1000: [\"left\", undefined],\n 1001: [\"error\", \"service_unavailable\"],\n 4001: [\"error\", \"join_token_invalid\"],\n 4002: [\"error\", \"join_token_expired\"],\n 4003: [\"error\", \"origin_not_allowed\"],\n 4004: [\"meeting_ended\", undefined],\n 4009: [\"session_replaced\", \"session_replaced\"],\n 4011: [\"error\", \"protocol_error\"],\n 4029: [\"error\", \"rate_limited\"],\n 4503: [\"error\", \"service_unavailable\"],\n};\n\n/** Maps a connection close to the public close reason and error. */\nexport function mapClose(code: number, phase: ClosePhase): MappedClose {\n if (phase === \"before_joined\") {\n return { reason: \"join_failed\", error: new MeetingError(BEFORE_JOINED[code] ?? \"connection_failed\") };\n }\n const [reason, errorCode] = AFTER_JOINED[code] ?? [\"connection_lost\", \"connection_lost\"];\n return errorCode ? { reason, error: new MeetingError(errorCode) } : { reason };\n}\n\nconst REJECTIONS: Readonly<Record<string, MeetingErrorCode>> = {\n rate_limited: \"rate_limited\",\n service_unavailable: \"service_unavailable\",\n role_not_allowed: \"not_permitted\",\n};\n\nexport function mapRejection(code: string): MeetingError {\n return new MeetingError(Object.hasOwn(REJECTIONS, code) ? (REJECTIONS[code] as MeetingErrorCode) : \"protocol_error\");\n}\n\nconst LEFT_REASONS = new Set<ParticipantLeftReason>([\"left\", \"disconnected\", \"removed\", \"meeting_ended\"]);\n\nexport function mapLeftReason(reason: string): ParticipantLeftReason {\n return LEFT_REASONS.has(reason as ParticipantLeftReason) ? (reason as ParticipantLeftReason) : \"other\";\n}\n\nconst DEVICE_ERRORS: Readonly<Record<string, MeetingErrorCode>> = {\n NotAllowedError: \"permission_denied\",\n SecurityError: \"permission_denied\",\n NotFoundError: \"device_not_found\",\n OverconstrainedError: \"device_not_found\",\n NotReadableError: \"device_unavailable\",\n AbortError: \"device_unavailable\",\n TypeError: \"unsupported_environment\",\n};\n\nconst SCREEN_ERRORS: Readonly<Record<string, MeetingErrorCode>> = {\n NotAllowedError: \"screen_share_cancelled\",\n AbortError: \"screen_share_cancelled\",\n SecurityError: \"permission_denied\",\n TypeError: \"unsupported_environment\",\n};\n\nfunction errorName(error: unknown): string | undefined {\n if (typeof error !== \"object\" || error === null) return undefined;\n const name = (error as { name?: unknown }).name;\n return typeof name === \"string\" ? name : undefined;\n}\n\n/** Maps a browser capture failure to a MeetingError. The original error is dropped, never attached. */\nexport function mapMediaError(kind: MediaKind, error: unknown): MeetingError {\n if (error instanceof MeetingError) return error;\n const name = errorName(error);\n const table = kind === \"screen\" ? SCREEN_ERRORS : DEVICE_ERRORS;\n const code = name !== undefined && Object.hasOwn(table, name) ? table[name] : undefined;\n return new MeetingError(code ?? \"device_unavailable\");\n}\n", "import { MeetingError } from \"../public/errors.js\";\nimport type { LocalMedia, MediaKind, MediaState } from \"../public/types.js\";\nimport type { EngineEnvironment } from \"./env.js\";\nimport { mapMediaError } from \"./errorMapping.js\";\nimport type { Log } from \"./log.js\";\n\nexport interface LocalMediaHooks {\n /** Tells the meeting about a local change. Returns false when the connection is gone. */\n announce(kind: MediaKind, enabled: boolean): boolean;\n /** A local change took effect. */\n changed(kind: MediaKind, enabled: boolean, stream: MediaStream | null): void;\n}\n\ntype Operation = { readonly target: boolean; readonly deviceId: string | undefined; readonly promise: Promise<void> };\ntype PerKind<T> = Record<MediaKind, T>;\n\nconst KINDS: readonly MediaKind[] = [\"camera\", \"microphone\", \"screen\"];\n\nfunction stopTracks(stream: MediaStream): void {\n for (const track of stream.getTracks()) {\n try {\n track.stop();\n } catch {\n // Stopping an already-ended track is harmless.\n }\n }\n}\n\nfunction setTracksEnabled(stream: MediaStream, enabled: boolean): void {\n for (const track of stream.getTracks()) track.enabled = enabled;\n}\n\nfunction hasLiveTrack(stream: MediaStream): boolean {\n return stream.getTracks().some((track) => track.readyState === \"live\");\n}\n\n/** The device a capture came from: what the browser reports, else the device that was asked for. */\nfunction deviceOf(stream: MediaStream, requested: string | undefined): string | null {\n const track = stream.getTracks()[0];\n const reported = typeof track?.getSettings === \"function\" ? track.getSettings().deviceId : undefined;\n return reported || requested || null;\n}\n\n/**\n * Local camera, microphone, and screen captures. Changes to one kind run one at a time in call order; a call\n * for the state and device a queued change will reach shares that change's promise.\n */\nexport class LocalMediaController {\n readonly #env: EngineEnvironment;\n readonly #hooks: LocalMediaHooks;\n readonly #log: Log;\n readonly #state: PerKind<boolean> = { camera: false, microphone: false, screen: false };\n readonly #streams: PerKind<MediaStream | null> = { camera: null, microphone: null, screen: null };\n readonly #devices: PerKind<string | null> = { camera: null, microphone: null, screen: null };\n readonly #tails: PerKind<Promise<void>> = {\n camera: Promise.resolve(),\n microphone: Promise.resolve(),\n screen: Promise.resolve(),\n };\n readonly #queued: PerKind<Operation[]> = { camera: [], microphone: [], screen: [] };\n #released = false;\n #generation = 0;\n\n constructor(env: EngineEnvironment, hooks: LocalMediaHooks, log: Log) {\n this.#env = env;\n this.#hooks = hooks;\n this.#log = log;\n }\n\n get state(): MediaState {\n return Object.freeze({ ...this.#state });\n }\n\n get streams(): LocalMedia {\n return Object.freeze({\n camera: this.#state.camera ? this.#streams.camera : null,\n microphone: this.#state.microphone ? this.#streams.microphone : null,\n screen: this.#state.screen ? this.#streams.screen : null,\n });\n }\n\n /**\n * Turns `kind` on or off. `deviceId` applies to turning the camera or microphone on: it captures that device, or\n * switches to it in place when `kind` is already on with another device.\n */\n set(kind: MediaKind, enabled: boolean, deviceId?: string): Promise<void> {\n const wanted = enabled && kind !== \"screen\" ? deviceId : undefined;\n const queue = this.#queued[kind];\n const last = queue[queue.length - 1];\n if (last) {\n if (last.target === enabled && last.deviceId === wanted) return last.promise;\n } else if (this.#state[kind] === enabled && !this.#released && !this.#needsSwitch(kind, wanted)) {\n return Promise.resolve();\n }\n const promise = this.#tails[kind].then(() => this.#run(kind, enabled, wanted));\n const operation: Operation = { target: enabled, deviceId: wanted, promise };\n queue.push(operation);\n const settle = (): void => {\n const index = queue.indexOf(operation);\n if (index >= 0) queue.splice(index, 1);\n };\n this.#tails[kind] = promise.then(settle, settle);\n return promise;\n }\n\n /** Turns `kind` off locally without announcing it, because the meeting refused the change. */\n rollback(kind: MediaKind): void {\n if (!this.#state[kind]) return;\n this.#turnOff(kind, false);\n }\n\n /** Stops every capture. Pending and later changes reject with `not_joined`. Emits nothing. */\n releaseAll(): void {\n this.#released = true;\n this.#generation += 1;\n for (const kind of KINDS) {\n const stream = this.#streams[kind];\n if (stream) stopTracks(stream);\n this.#streams[kind] = null;\n this.#devices[kind] = null;\n this.#state[kind] = false;\n }\n }\n\n /** True when `kind` is on and a specific device other than the one in use was asked for. */\n #needsSwitch(kind: MediaKind, deviceId: string | undefined): boolean {\n return this.#state[kind] && deviceId !== undefined && deviceId !== this.#devices[kind];\n }\n\n async #run(kind: MediaKind, enabled: boolean, deviceId: string | undefined): Promise<void> {\n if (this.#released) throw new MeetingError(\"not_joined\");\n if (enabled && this.#needsSwitch(kind, deviceId)) return this.#switchDevice(kind, deviceId as string);\n if (this.#state[kind] === enabled) return;\n if (enabled) await this.#turnOn(kind, deviceId);\n else this.#turnOff(kind, true);\n }\n\n /**\n * Replaces a running capture with one from another device. The new capture is handed on before the old one stops,\n * so the meeting keeps receiving media; nothing is announced because the on/off state does not change. When the\n * new device cannot be captured, the old capture keeps running.\n */\n async #switchDevice(kind: MediaKind, deviceId: string): Promise<void> {\n const generation = this.#generation;\n const stream = await this.#capture(kind, deviceId);\n if (generation !== this.#generation || this.#released || !this.#state[kind]) {\n stopTracks(stream);\n throw new MeetingError(\"not_joined\");\n }\n const previous = this.#streams[kind];\n this.#streams[kind] = stream;\n this.#devices[kind] = deviceOf(stream, deviceId);\n this.#watchEnded(kind, stream);\n this.#hooks.changed(kind, true, stream);\n if (previous) stopTracks(previous);\n }\n\n async #turnOn(kind: MediaKind, deviceId: string | undefined): Promise<void> {\n if (kind === \"microphone\") {\n const kept = this.#streams.microphone;\n const sameDevice = deviceId === undefined || deviceId === this.#devices.microphone;\n if (kept && hasLiveTrack(kept) && sameDevice) {\n setTracksEnabled(kept, true);\n if (!this.#hooks.announce(kind, true)) {\n setTracksEnabled(kept, false);\n throw new MeetingError(\"not_joined\");\n }\n this.#state.microphone = true;\n this.#hooks.changed(kind, true, kept);\n return;\n }\n if (kept && !hasLiveTrack(kept)) {\n stopTracks(kept);\n this.#streams.microphone = null;\n this.#devices.microphone = null;\n }\n }\n\n const generation = this.#generation;\n const stream = await this.#capture(kind, deviceId);\n if (generation !== this.#generation || this.#released || !this.#hooks.announce(kind, true)) {\n stopTracks(stream);\n throw new MeetingError(\"not_joined\");\n }\n // A kept microphone from another device is replaced only once the chosen one is captured.\n const replaced = this.#streams[kind];\n this.#streams[kind] = stream;\n this.#devices[kind] = kind === \"screen\" ? null : deviceOf(stream, deviceId);\n this.#state[kind] = true;\n this.#watchEnded(kind, stream);\n this.#hooks.changed(kind, true, stream);\n if (replaced) stopTracks(replaced);\n }\n\n #turnOff(kind: MediaKind, announce: boolean): void {\n const stream = this.#streams[kind];\n if (kind === \"microphone\") {\n if (stream) setTracksEnabled(stream, false);\n } else {\n if (stream) stopTracks(stream);\n this.#streams[kind] = null;\n this.#devices[kind] = null;\n }\n this.#state[kind] = false;\n const sent = !announce || this.#hooks.announce(kind, false);\n this.#hooks.changed(kind, false, null);\n if (!sent) throw new MeetingError(\"not_joined\");\n }\n\n async #capture(kind: MediaKind, deviceId?: string): Promise<MediaStream> {\n const devices = this.#env.mediaDevices;\n try {\n if (kind === \"screen\") {\n if (typeof devices?.getDisplayMedia !== \"function\") throw new MeetingError(\"unsupported_environment\");\n return await devices.getDisplayMedia({ video: true, audio: false });\n }\n if (typeof devices?.getUserMedia !== \"function\") throw new MeetingError(\"unsupported_environment\");\n const track: boolean | MediaTrackConstraints = deviceId === undefined ? true : { deviceId: { exact: deviceId } };\n return await devices.getUserMedia(kind === \"camera\" ? { video: track, audio: false } : { audio: track, video: false });\n } catch (error) {\n const mapped = mapMediaError(kind, error);\n this.#log.warn(\"capture failed\", { kind, code: mapped.code });\n throw mapped;\n }\n }\n\n /** A capture the browser or device ended (unplugged, revoked, \"Stop sharing\") turns that kind off and is announced. */\n #watchEnded(kind: MediaKind, stream: MediaStream): void {\n const onEnded = (): void => {\n if (this.#streams[kind] !== stream) return;\n if (!this.#state[kind]) {\n // A muted microphone that ended is dropped, so the next unmute captures again.\n if (kind === \"microphone\") {\n this.#streams.microphone = null;\n this.#devices.microphone = null;\n }\n return;\n }\n this.#log.info(kind === \"screen\" ? \"screen share ended by the browser\" : \"capture ended\", { kind });\n this.set(kind, false).catch(() => undefined);\n };\n for (const track of stream.getTracks()) track.addEventListener(\"ended\", onEnded, { once: true });\n }\n}\n", "import type { MeetingLogger } from \"../public/types.js\";\n\ntype Level = \"debug\" | \"info\" | \"warn\" | \"error\";\nexport type LogFields = Readonly<Record<string, string | number | boolean | undefined>>;\n\nconst ALLOWED_KEYS = new Set([\n \"state\",\n \"code\",\n \"reason\",\n \"kind\",\n \"participantId\",\n \"meetingId\",\n \"closeCode\",\n \"messageType\",\n \"durationMs\",\n \"attempt\",\n \"path\",\n \"localPath\",\n \"remotePath\",\n]);\n\nconst JWT_SHAPE = /[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]*/;\nconst NEGOTIATION_CONTENT = /sdp|candidate/i;\n\nfunction isSafeString(value: string): boolean {\n return !JWT_SHAPE.test(value) && !NEGOTIATION_CONTENT.test(value);\n}\n\nfunction sanitize(fields: LogFields | undefined): Record<string, string | number | boolean> | undefined {\n if (!fields) return undefined;\n const out: Record<string, string | number | boolean> = {};\n for (const [key, value] of Object.entries(fields)) {\n if (!ALLOWED_KEYS.has(key) || value === undefined) continue;\n if (typeof value === \"string\" && !isSafeString(value)) continue;\n out[key] = value;\n }\n return out;\n}\n\n/** Wraps the consumer's logger: allow-listed fields only, and a throwing logger never affects the engine. */\nexport class Log {\n readonly #logger: MeetingLogger | undefined;\n\n constructor(logger: MeetingLogger | undefined) {\n this.#logger = logger;\n }\n\n debug(message: string, fields?: LogFields): void {\n this.#write(\"debug\", message, fields);\n }\n\n info(message: string, fields?: LogFields): void {\n this.#write(\"info\", message, fields);\n }\n\n warn(message: string, fields?: LogFields): void {\n this.#write(\"warn\", message, fields);\n }\n\n error(message: string, fields?: LogFields): void {\n this.#write(\"error\", message, fields);\n }\n\n #write(level: Level, message: string, fields: LogFields | undefined): void {\n const logger = this.#logger;\n if (!logger) return;\n try {\n const method = logger[level];\n if (typeof method !== \"function\") return;\n const safe = sanitize(fields);\n if (safe) method.call(logger, message, safe);\n else method.call(logger, message);\n } catch {\n // A failing logger must never break the meeting.\n }\n }\n}\n", "import type { IceServerConfig, PayloadMap, SignalingMessage } from \"@strevokit/signaling-protocol\";\nimport type {\n MediaConnectionStatus,\n MediaKind,\n MediaState,\n MeetingEventMap,\n RemoteMedia,\n} from \"../public/types.js\";\nimport type { PeerOutboundType } from \"./signalingSession.js\";\n\nexport type DeliveryEventType = \"remote_media_changed\" | \"media_connection_changed\" | \"error\";\n\nexport interface PresentPeer {\n readonly id: string;\n readonly media: MediaState;\n}\n\n/** What a media delivery strategy may use from the engine. */\nexport interface MediaDeliveryContext {\n /** Self. */\n readonly participantId: string;\n /** From `session.welcome`; may be empty. */\n readonly iceServers: readonly IceServerConfig[];\n /** Epoch ms when the credentials in `iceServers` expire; null when none were given. */\n readonly iceServersExpireAt: number | null;\n /** Sends a media frame through the signaling session. False when it could not be sent. */\n send<T extends PeerOutboundType>(type: T, payload: PayloadMap[T]): boolean;\n /** Emits a public engine event (suppressed after dispose). */\n emit<K extends DeliveryEventType>(type: K, event: MeetingEventMap[K]): void;\n}\n\n/**\n * Carries audio and video between participants. The engine reports roster facts, local capture changes and\n * media-negotiation frames here; strategies never change the public API.\n */\nexport interface MediaDelivery {\n attach(context: MediaDeliveryContext): void;\n /** Every other participant in the committed joined snapshot, reported together. */\n peersPresent(entries: readonly PresentPeer[]): void;\n /** A participant who joined after the joined snapshot was committed. */\n peerPresent(participantId: string, media: MediaState): void;\n peerMediaChanged(participantId: string, kind: MediaKind, enabled: boolean): void;\n peerLeft(participantId: string): void;\n peerReconnected(participantId: string): void;\n onPeerFrame(message: SignalingMessage): void;\n /** Fresh connectivity servers from the platform; `expiresAt` is epoch ms. */\n iceServersUpdated(iceServers: readonly IceServerConfig[], expiresAt: number): void;\n localMediaChanged(kind: MediaKind, stream: MediaStream | null): void;\n /**\n * Whether this delivery can carry screen-share media bits to peers. The engine refuses\n * `startScreenShare` when false, before opening the display-capture prompt.\n */\n supportsScreenShare(): boolean;\n remoteMedia(participantId: string): RemoteMedia;\n connectionStatus(participantId: string): MediaConnectionStatus | null;\n /** Closes everything and emits nothing. Idempotent. */\n close(): void;\n}\n\nexport const NO_REMOTE_MEDIA: RemoteMedia = Object.freeze({ camera: null, microphone: null, screen: null });\n\n/** Announces local media state only; no remote media is delivered. */\nexport class SignalingOnlyMediaDelivery implements MediaDelivery {\n attach(): void {}\n\n peersPresent(): void {}\n\n peerPresent(): void {}\n\n peerMediaChanged(): void {}\n\n peerLeft(): void {}\n\n peerReconnected(): void {}\n\n onPeerFrame(): void {}\n\n iceServersUpdated(): void {}\n\n localMediaChanged(): void {}\n\n supportsScreenShare(): boolean {\n return false;\n }\n\n remoteMedia(): RemoteMedia {\n return NO_REMOTE_MEDIA;\n }\n\n connectionStatus(): MediaConnectionStatus | null {\n return null;\n }\n\n close(): void {}\n}\n", "import type { MediaKind, MediaState, Participant, ParticipantRole } from \"../public/types.js\";\n\ntype Entry = {\n id: string;\n role: ParticipantRole;\n displayName?: string;\n media: { camera: boolean; microphone: boolean; screen: boolean };\n};\n\nexport type UpsertResult = \"buffered\" | \"added\" | \"updated\";\n\nfunction snapshot(entry: Entry): Participant {\n const media: MediaState = Object.freeze({ ...entry.media });\n const participant: { id: string; role: ParticipantRole; displayName?: string; media: MediaState } = {\n id: entry.id,\n role: entry.role,\n media,\n };\n if (entry.displayName !== undefined) participant.displayName = entry.displayName;\n return Object.freeze(participant);\n}\n\n/**\n * Other participants and their media state. Frames received while joining are buffered until `commit()`, which\n * marks the initial snapshot as complete.\n */\nexport class Roster {\n readonly #entries = new Map<string, Entry>();\n #committed = false;\n #cache: readonly Participant[] | undefined;\n\n get committed(): boolean {\n return this.#committed;\n }\n\n upsertJoined(id: string, role: ParticipantRole, displayName?: string): UpsertResult {\n const existing = this.#entries.get(id);\n this.#cache = undefined;\n if (existing) {\n existing.role = role;\n if (displayName !== undefined) existing.displayName = displayName;\n else delete existing.displayName;\n return this.#committed ? \"updated\" : \"buffered\";\n }\n const entry: Entry = { id, role, media: { camera: false, microphone: false, screen: false } };\n if (displayName !== undefined) entry.displayName = displayName;\n this.#entries.set(id, entry);\n return this.#committed ? \"added\" : \"buffered\";\n }\n\n /** Returns true when the participant's state changed. Unknown participants are ignored after commit. */\n setMedia(id: string, kind: MediaKind, enabled: boolean): boolean {\n let entry = this.#entries.get(id);\n if (!entry) {\n if (this.#committed) return false;\n this.upsertJoined(id, \"participant\");\n entry = this.#entries.get(id);\n if (!entry) return false;\n }\n if (entry.media[kind] === enabled) return false;\n entry.media[kind] = enabled;\n this.#cache = undefined;\n return true;\n }\n\n remove(id: string): boolean {\n const removed = this.#entries.delete(id);\n if (removed) this.#cache = undefined;\n return removed;\n }\n\n commit(): void {\n this.#committed = true;\n this.#cache = undefined;\n }\n\n get(id: string): Participant | undefined {\n const entry = this.#entries.get(id);\n return entry ? snapshot(entry) : undefined;\n }\n\n /** Committed participants in arrival order; empty before commit. */\n list(): readonly Participant[] {\n if (!this.#committed) return Object.freeze([]);\n this.#cache ??= Object.freeze([...this.#entries.values()].map(snapshot));\n return this.#cache;\n }\n\n clear(): void {\n this.#entries.clear();\n this.#cache = undefined;\n }\n}\n", "import {\n type MessageType,\n type PayloadMap,\n type SignalingMessage,\n createSignalingMessage,\n decodeSignalingFrame,\n encodeSignalingMessage,\n} from \"@strevokit/signaling-protocol\";\nimport type { EngineEnvironment, SocketLike } from \"./env.js\";\nimport type { Log } from \"./log.js\";\nimport type { Addressing } from \"./token.js\";\n\nexport const SIGNALING_SUBPROTOCOL = \"strevokit.signaling.v1\";\nconst TOKEN_SUBPROTOCOL_PREFIX = \"strevokit.join-token.\";\n/** Close code reported when the connection could not be established or was lost without a close frame. */\nexport const ABNORMAL_CLOSE = 1006;\n\n/** Every frame type the engine sends; all have an empty payload. */\nexport const OUTBOUND_TYPES = Object.freeze([\n \"participant.join\",\n \"participant.leave\",\n \"meeting.end\",\n \"media.camera.started\",\n \"media.camera.stopped\",\n \"media.microphone.started\",\n \"media.microphone.stopped\",\n \"media.screen.started\",\n \"media.screen.stopped\",\n] as const satisfies readonly MessageType[]);\n\nexport type OutboundType = (typeof OUTBOUND_TYPES)[number];\n\n/** Media-negotiation and connection-report frames, sent on behalf of the media delivery. */\nexport const PEER_OUTBOUND_TYPES = Object.freeze([\n \"webrtc.offer\",\n \"webrtc.answer\",\n \"webrtc.ice_candidate\",\n \"webrtc.connected\",\n \"webrtc.disconnected\",\n \"webrtc.failed\",\n \"webrtc.ice_restart\",\n \"webrtc.ice_restart_result\",\n] as const satisfies readonly MessageType[]);\n\nexport type PeerOutboundType = (typeof PEER_OUTBOUND_TYPES)[number];\n\nexport interface SessionCallbacks {\n onMessage(message: SignalingMessage): void;\n onProtocolError(): void;\n /** `opened` is false when the connection never reached the open state. Called at most once. */\n onClose(code: number, reason: string, opened: boolean): void;\n}\n\nexport interface SessionOptions {\n env: EngineEnvironment;\n realtimeUrl: string;\n token: string;\n addressing: Addressing;\n log: Log;\n callbacks: SessionCallbacks;\n}\n\n/** One signaling connection: handshake, frame encoding and decoding, and close reporting. */\nexport class SignalingSession {\n readonly #env: EngineEnvironment;\n readonly #url: string;\n readonly #addressing: Addressing;\n readonly #log: Log;\n #token: string | undefined;\n #callbacks: SessionCallbacks | undefined;\n #socket: SocketLike | undefined;\n #opened = false;\n\n constructor(options: SessionOptions) {\n this.#env = options.env;\n this.#url = `${options.realtimeUrl}/v1/meetings/${options.addressing.meetingId}/signaling`;\n this.#addressing = options.addressing;\n this.#log = options.log;\n this.#token = options.token;\n this.#callbacks = options.callbacks;\n }\n\n open(): void {\n const token = this.#token;\n this.#token = undefined;\n const Socket = this.#env.WebSocket;\n if (!Socket || token === undefined) {\n this.#fail();\n return;\n }\n let socket: SocketLike;\n try {\n socket = new Socket(this.#url, [SIGNALING_SUBPROTOCOL, `${TOKEN_SUBPROTOCOL_PREFIX}${token}`]);\n } catch {\n this.#log.warn(\"connection could not be created\");\n this.#fail();\n return;\n }\n this.#socket = socket;\n socket.onopen = () => this.#handleOpen();\n socket.onmessage = (event) => this.#handleFrame(event.data);\n socket.onclose = (event) => this.#handleClose(event.code, event.reason);\n socket.onerror = () => undefined;\n }\n\n /** Sends an empty-payload frame. Returns false when the connection is not open or the frame cannot be built. */\n send(type: OutboundType): boolean {\n const socket = this.#socket;\n if (!socket || !this.#opened || !this.#callbacks) return false;\n try {\n const message = createSignalingMessage(type, {\n meetingId: this.#addressing.meetingId,\n participantId: this.#addressing.participantId,\n payload: {},\n });\n socket.send(encodeSignalingMessage(message));\n return true;\n } catch {\n this.#log.warn(\"frame could not be sent\", { messageType: type });\n return false;\n }\n }\n\n /**\n * Sends a media frame. Returns false when the connection is not open or the frame fails validation. The payload\n * is never logged.\n */\n sendPeer<T extends PeerOutboundType>(type: T, payload: PayloadMap[T]): boolean {\n const socket = this.#socket;\n if (!socket || !this.#opened || !this.#callbacks) return false;\n try {\n const message = createSignalingMessage(type, {\n meetingId: this.#addressing.meetingId,\n participantId: this.#addressing.participantId,\n payload,\n });\n socket.send(encodeSignalingMessage(message as SignalingMessage));\n return true;\n } catch {\n this.#log.debug(\"frame could not be sent\", { messageType: type });\n return false;\n }\n }\n\n /** Closes the connection. No further callbacks are made. */\n close(code = 1000): void {\n this.#callbacks = undefined;\n const socket = this.#socket;\n if (!socket) return;\n try {\n socket.close(code);\n } catch {\n // Already closing or closed.\n }\n }\n\n #handleOpen(): void {\n if (!this.#callbacks) return;\n if (this.#socket?.protocol !== SIGNALING_SUBPROTOCOL) {\n this.#log.warn(\"unexpected subprotocol negotiated\");\n const socket = this.#socket;\n this.#fail();\n try {\n socket?.close(1000);\n } catch {\n // Ignore: the connection is being abandoned.\n }\n return;\n }\n this.#opened = true;\n }\n\n #handleFrame(data: unknown): void {\n const callbacks = this.#callbacks;\n if (!callbacks) return;\n const result = decodeSignalingFrame(data, { direction: \"server_to_client\" });\n try {\n if (result.ok) callbacks.onMessage(result.message);\n else {\n this.#log.debug(\"invalid frame received\", { code: result.error.code });\n callbacks.onProtocolError();\n }\n } catch {\n this.#log.error(\"frame handling failed\");\n }\n }\n\n #handleClose(code: number, reason: string): void {\n const callbacks = this.#callbacks;\n this.#callbacks = undefined;\n if (!callbacks) return;\n try {\n callbacks.onClose(typeof code === \"number\" ? code : ABNORMAL_CLOSE, typeof reason === \"string\" ? reason : \"\", this.#opened);\n } catch {\n this.#log.error(\"close handling failed\");\n }\n }\n\n #fail(): void {\n const callbacks = this.#callbacks;\n this.#callbacks = undefined;\n if (!callbacks) return;\n try {\n callbacks.onClose(ABNORMAL_CLOSE, \"\", false);\n } catch {\n this.#log.error(\"close handling failed\");\n }\n }\n}\n", "import {\n type IceServerConfig,\n type MediaMode,\n ROLE_POLICY,\n type SignalingMessage,\n isRoleAllowed,\n} from \"@strevokit/signaling-protocol\";\nimport { MeetingError, type MeetingErrorCode } from \"../public/errors.js\";\nimport type {\n CloseReason,\n ConnectionState,\n LocalMedia,\n MediaConnectionStatus,\n MediaDeviceOptions,\n MediaKind,\n MediaState,\n MeetingEngine,\n MeetingEventListener,\n MeetingEventMap,\n MeetingEventType,\n MeetingLogger,\n Participant,\n ParticipantRole,\n RemoteMedia,\n SelfParticipant,\n} from \"../public/types.js\";\nimport { Emitter } from \"./emitter.js\";\nimport type { EngineEnvironment, TimerHandle } from \"./env.js\";\nimport { mapClose, mapLeftReason, mapRejection } from \"./errorMapping.js\";\nimport { LocalMediaController } from \"./localMedia.js\";\nimport { Log } from \"./log.js\";\nimport { type MediaDelivery, SignalingOnlyMediaDelivery } from \"./mediaDelivery.js\";\nimport { Roster } from \"./roster.js\";\nimport { type OutboundType, SignalingSession } from \"./signalingSession.js\";\nimport type { Addressing } from \"./token.js\";\n\nconst LEAVE_FALLBACK_MS = 5000;\nconst RESTRICTED_PENDING_MS = 2000;\nconst END_MEETING_TIMEOUT_MS = 10_000;\n\nexport interface EngineConfig {\n token: string;\n realtimeUrl: string;\n joinTimeoutMs: number;\n logger: MeetingLogger | undefined;\n addressing: Addressing;\n env: EngineEnvironment;\n /** Chooses how media is carried once the welcome says how the platform routes this meeting. */\n createMediaDelivery: MediaDeliveryFactory;\n}\n\nexport type MediaDeliveryFactory = (\n mediaMode: MediaMode | undefined,\n deps: { env: EngineEnvironment; log: Log },\n) => MediaDelivery;\n\nconst MEDIA_KINDS: readonly MediaKind[] = [\"camera\", \"microphone\", \"screen\"];\n\ntype Deferred = { promise: Promise<void>; resolve: () => void; reject: (error: MeetingError) => void };\n\nfunction deferred(): Deferred {\n let resolve!: () => void;\n let reject!: (error: MeetingError) => void;\n const promise = new Promise<void>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n return { promise, resolve, reject };\n}\n\nfunction mediaFrame(type: string): { kind: MediaKind; enabled: boolean } | undefined {\n const match = /^media\\.(camera|microphone|screen)\\.(started|stopped)$/.exec(type);\n if (!match) return undefined;\n return { kind: match[1] as MediaKind, enabled: match[2] === \"started\" };\n}\n\nexport class MeetingEngineImpl implements MeetingEngine {\n readonly #realtimeUrl: string;\n readonly #joinTimeoutMs: number;\n readonly #addressing: Addressing;\n readonly #env: EngineEnvironment;\n readonly #createDelivery: MediaDeliveryFactory;\n #delivery: MediaDelivery = new SignalingOnlyMediaDelivery();\n readonly #log: Log;\n readonly #emitter: Emitter<MeetingEventMap>;\n readonly #roster = new Roster();\n readonly #media: LocalMediaController;\n\n #token: string | undefined;\n #state: ConnectionState = \"idle\";\n #disposed = false;\n #session: SignalingSession | undefined;\n #self: SelfParticipant | null = null;\n #role: ParticipantRole | undefined;\n #join: Deferred | undefined;\n #leave: Deferred | undefined;\n #joinTimer: TimerHandle | undefined;\n #leaveTimer: TimerHandle | undefined;\n #endMeeting: Deferred | undefined;\n #endMeetingTimer: TimerHandle | undefined;\n #pendingRestricted: { kind: MediaKind; timer: TimerHandle } | undefined;\n\n constructor(config: EngineConfig) {\n this.#token = config.token;\n this.#realtimeUrl = config.realtimeUrl;\n this.#joinTimeoutMs = config.joinTimeoutMs;\n this.#addressing = config.addressing;\n this.#env = config.env;\n this.#createDelivery = config.createMediaDelivery;\n this.#log = new Log(config.logger);\n this.#emitter = new Emitter(this.#log);\n this.#media = new LocalMediaController(\n config.env,\n {\n announce: (kind, enabled) => this.#announce(kind, enabled),\n changed: (kind, enabled, stream) => {\n this.#emit(\"local_media_changed\", { kind, enabled, stream });\n this.#delivery.localMediaChanged(kind, stream);\n },\n },\n this.#log,\n );\n }\n\n get state(): ConnectionState {\n return this.#state;\n }\n\n get self(): SelfParticipant | null {\n return this.#self;\n }\n\n get participants(): readonly Participant[] {\n return this.#roster.list();\n }\n\n get localMediaState(): MediaState {\n return this.#media.state;\n }\n\n get localMedia(): LocalMedia {\n return this.#media.streams;\n }\n\n remoteMedia(participantId: string): RemoteMedia {\n return this.#delivery.remoteMedia(participantId);\n }\n\n mediaConnectionStatus(participantId: string): MediaConnectionStatus | null {\n return this.#delivery.connectionStatus(participantId);\n }\n\n join(): Promise<void> {\n if (this.#state === \"closed\") return Promise.reject(new MeetingError(\"engine_closed\"));\n if (this.#state !== \"idle\") return Promise.reject(new MeetingError(\"already_joined\"));\n const token = this.#token;\n this.#token = undefined;\n if (!this.#env.WebSocket || token === undefined) return Promise.reject(new MeetingError(\"unsupported_environment\"));\n\n const join = deferred();\n this.#join = join;\n this.#setState(\"connecting\");\n if (!this.#is(\"connecting\")) return join.promise;\n\n this.#joinTimer = this.#env.setTimeout(() => this.#failJoin(new MeetingError(\"join_timeout\")), this.#joinTimeoutMs);\n const session = new SignalingSession({\n env: this.#env,\n realtimeUrl: this.#realtimeUrl,\n token,\n addressing: this.#addressing,\n log: this.#log,\n callbacks: {\n onMessage: (message) => this.#onMessage(message),\n onProtocolError: () => this.#onProtocolError(),\n onClose: (code) => this.#onClose(session, code),\n },\n });\n this.#session = session;\n session.open();\n return join.promise;\n }\n\n leave(): Promise<void> {\n switch (this.#state) {\n case \"idle\":\n case \"closed\":\n return Promise.resolve();\n case \"leaving\":\n return this.#leave?.promise ?? Promise.resolve();\n case \"connecting\":\n case \"joining\":\n this.#failJoin(new MeetingError(\"join_cancelled\"));\n return Promise.resolve();\n case \"joined\":\n break;\n }\n const leave = deferred();\n this.#leave = leave;\n this.#media.releaseAll();\n this.#releaseRemoteMedia();\n this.#setState(\"leaving\");\n if (!this.#is(\"leaving\")) return leave.promise;\n if (!this.#session?.send(\"participant.leave\")) {\n this.#finish(\"left\");\n return leave.promise;\n }\n this.#leaveTimer = this.#env.setTimeout(() => this.#finish(\"left\"), LEAVE_FALLBACK_MS);\n return leave.promise;\n }\n\n endMeeting(): Promise<void> {\n if (this.#state !== \"joined\") return Promise.reject(new MeetingError(\"not_joined\"));\n if (this.#role !== \"host\") return Promise.reject(new MeetingError(\"not_permitted\"));\n if (this.#endMeeting) return this.#endMeeting.promise;\n\n const pending = deferred();\n this.#endMeeting = pending;\n if (!this.#session?.send(\"meeting.end\")) {\n this.#endMeeting = undefined;\n return Promise.reject(new MeetingError(\"service_unavailable\"));\n }\n this.#endMeetingTimer = this.#env.setTimeout(() => {\n const p = this.#endMeeting;\n this.#endMeeting = undefined;\n this.#endMeetingTimer = undefined;\n p?.reject(new MeetingError(\"service_unavailable\"));\n }, END_MEETING_TIMEOUT_MS);\n return pending.promise;\n }\n\n enableCamera(options?: MediaDeviceOptions): Promise<void> {\n return this.#mediaCall(\"camera\", true, options?.deviceId);\n }\n\n disableCamera(): Promise<void> {\n return this.#mediaCall(\"camera\", false);\n }\n\n mute(): Promise<void> {\n return this.#mediaCall(\"microphone\", false);\n }\n\n unmute(options?: MediaDeviceOptions): Promise<void> {\n return this.#mediaCall(\"microphone\", true, options?.deviceId);\n }\n\n startScreenShare(): Promise<void> {\n return this.#mediaCall(\"screen\", true);\n }\n\n stopScreenShare(): Promise<void> {\n return this.#mediaCall(\"screen\", false);\n }\n\n on<K extends MeetingEventType>(type: K, listener: MeetingEventListener<K>): () => void {\n if (this.#disposed) return () => undefined;\n return this.#emitter.on(type, listener);\n }\n\n dispose(): void {\n if (this.#disposed) return;\n this.#disposed = true;\n this.#emitter.clear();\n const end = this.#endMeeting;\n this.#endMeeting = undefined;\n this.#teardown();\n this.#state = \"closed\";\n const join = this.#join;\n this.#join = undefined;\n if (join) {\n join.promise.catch(() => undefined);\n join.reject(new MeetingError(\"join_cancelled\"));\n }\n this.#leave?.resolve();\n end?.reject(new MeetingError(\"engine_closed\"));\n }\n\n #mediaCall(kind: MediaKind, enabled: boolean, deviceId?: string): Promise<void> {\n if (this.#state !== \"joined\") return Promise.reject(new MeetingError(\"not_joined\"));\n if (kind === \"screen\") {\n const type = enabled ? \"media.screen.started\" : \"media.screen.stopped\";\n if (this.#role === undefined || !isRoleAllowed(type, this.#role)) {\n return Promise.reject(new MeetingError(\"not_permitted\"));\n }\n // Refuse before getDisplayMedia when this meeting cannot deliver screen bits to peers.\n if (enabled && !this.#delivery.supportsScreenShare()) {\n return Promise.reject(new MeetingError(\"unsupported_environment\"));\n }\n }\n return this.#media.set(kind, enabled, typeof deviceId === \"string\" && deviceId !== \"\" ? deviceId : undefined);\n }\n\n #announce(kind: MediaKind, enabled: boolean): boolean {\n if (this.#state !== \"joined\") return false;\n const type = `media.${kind}.${enabled ? \"started\" : \"stopped\"}` as OutboundType;\n if (!this.#session?.send(type)) return false;\n if (this.#pendingRestricted?.kind === kind) this.#clearPendingRestricted();\n if (ROLE_POLICY[type]) {\n this.#pendingRestricted = {\n kind,\n timer: this.#env.setTimeout(() => {\n this.#pendingRestricted = undefined;\n }, RESTRICTED_PENDING_MS),\n };\n }\n return true;\n }\n\n #clearPendingRestricted(): void {\n if (this.#pendingRestricted) this.#env.clearTimeout(this.#pendingRestricted.timer);\n this.#pendingRestricted = undefined;\n }\n\n #onMessage(message: SignalingMessage): void {\n const state = this.#state;\n if (state === \"closed\" || state === \"idle\") return;\n const from = message.participantId;\n const isSelf = from === this.#addressing.participantId;\n\n switch (message.type) {\n case \"session.authenticated\": {\n if (state !== \"connecting\") return;\n this.#role = message.payload.role;\n this.#setState(\"joining\");\n if (!this.#is(\"joining\")) return;\n if (!this.#session?.send(\"participant.join\")) this.#failJoin(new MeetingError(\"connection_failed\"));\n return;\n }\n case \"session.welcome\": {\n if (state !== \"joining\") return;\n this.#clearTimer(\"join\");\n this.#roster.commit();\n const payload = message.payload;\n const self: { id: string; role: ParticipantRole; joinedAt: string; displayName?: string } = {\n id: this.#addressing.participantId,\n role: payload.role,\n joinedAt: payload.joinedAt,\n };\n if (payload.displayName !== undefined) self.displayName = payload.displayName;\n this.#self = Object.freeze(self);\n this.#role = payload.role;\n const join = this.#join;\n this.#join = undefined;\n this.#setState(\"joined\");\n this.#emit(\"joined\", { self: this.#self, participants: this.#roster.list() });\n join?.resolve();\n if (this.#is(\"joined\")) {\n const expiresAt = payload.iceServersExpireAt !== undefined ? Date.parse(payload.iceServersExpireAt) : NaN;\n this.#startDelivery(payload.mediaMode, payload.iceServers ?? [], Number.isFinite(expiresAt) ? expiresAt : null);\n }\n return;\n }\n case \"session.ice_servers\": {\n if (!this.#is(\"joined\")) {\n this.#log.debug(\"frame ignored\", { messageType: message.type, state });\n return;\n }\n const expiresAt = Date.parse(message.payload.expiresAt);\n if (Number.isFinite(expiresAt)) this.#delivery.iceServersUpdated(message.payload.iceServers, expiresAt);\n return;\n }\n case \"participant.joined\": {\n if (isSelf || state === \"connecting\") return;\n const result = this.#roster.upsertJoined(from, message.payload.role, message.payload.displayName);\n const participant = this.#roster.get(from);\n if (result === \"added\" && participant) {\n this.#emit(\"participant_joined\", { participant });\n const present = this.#roster.committed && this.#is(\"joined\") ? this.#roster.get(from) : undefined;\n if (present) this.#delivery.peerPresent(from, present.media);\n }\n return;\n }\n case \"participant.left\": {\n if (isSelf || state === \"connecting\") return;\n if (this.#roster.remove(from) && this.#roster.committed) {\n this.#delivery.peerLeft(from);\n this.#emit(\"participant_left\", { participantId: from, reason: mapLeftReason(message.payload.reason) });\n }\n return;\n }\n case \"participant.reconnected\": {\n if (isSelf || !this.#roster.committed) return;\n this.#delivery.peerReconnected(from);\n this.#emit(\"participant_reconnected\", { participantId: from });\n return;\n }\n case \"media.camera.started\":\n case \"media.camera.stopped\":\n case \"media.microphone.started\":\n case \"media.microphone.stopped\":\n case \"media.screen.started\":\n case \"media.screen.stopped\": {\n const change = mediaFrame(message.type);\n if (isSelf || state === \"connecting\" || !change) return;\n if (this.#roster.setMedia(from, change.kind, change.enabled) && this.#roster.committed) {\n this.#emit(\"participant_media_changed\", { participantId: from, kind: change.kind, enabled: change.enabled });\n this.#delivery.peerMediaChanged(from, change.kind, change.enabled);\n }\n return;\n }\n case \"meeting.ended\":\n case \"meeting.terminated\": {\n this.#log.info(\"meeting ended\", { messageType: message.type });\n if (state === \"connecting\" || state === \"joining\") this.#failJoin(new MeetingError(\"meeting_ended\"));\n else this.#finish(\"meeting_ended\");\n return;\n }\n case \"session.rejected\": {\n const payload = message.payload as { code: string; detail?: string; ref_type?: string; refType?: string };\n const isEndMeetingRejection =\n payload.ref_type === \"meeting.end\" || payload.refType === \"meeting.end\" || this.#endMeeting !== undefined;\n if (this.#endMeeting && isEndMeetingRejection) {\n const deferred = this.#endMeeting;\n this.#clearEndMeetingTimer();\n this.#endMeeting = undefined;\n let mappedCode: MeetingErrorCode = \"service_unavailable\";\n if (payload.code === \"role_not_allowed\") mappedCode = \"not_permitted\";\n else if (payload.code === \"rate_limited\") mappedCode = \"rate_limited\";\n deferred.reject(new MeetingError(mappedCode));\n return;\n }\n this.#onRejected(payload.code);\n return;\n }\n case \"webrtc.offer\":\n case \"webrtc.answer\":\n case \"webrtc.ice_candidate\":\n case \"webrtc.ice_restart\":\n this.#delivery.onPeerFrame(message);\n return;\n default:\n this.#log.debug(\"frame ignored\", { messageType: message.type });\n }\n }\n\n #startDelivery(\n mediaMode: MediaMode | undefined,\n iceServers: readonly IceServerConfig[],\n iceServersExpireAt: number | null,\n ): void {\n const delivery = this.#createDelivery(mediaMode, { env: this.#env, log: this.#log });\n this.#delivery = delivery;\n delivery.attach({\n participantId: this.#addressing.participantId,\n iceServers,\n iceServersExpireAt,\n send: (type, payload) => this.#delivery === delivery && (this.#session?.sendPeer(type, payload) ?? false),\n emit: (type, event) => {\n if (this.#delivery === delivery) this.#emit(type, event);\n },\n });\n const local = this.#media.streams;\n for (const kind of MEDIA_KINDS) {\n const stream = local[kind];\n if (stream) delivery.localMediaChanged(kind, stream);\n }\n if (this.#delivery !== delivery || !this.#is(\"joined\")) return;\n delivery.peersPresent(this.#roster.list().map((participant) => ({ id: participant.id, media: participant.media })));\n }\n\n /** Reports every remote media and connection status as gone, then closes the delivery. */\n #releaseRemoteMedia(): void {\n const delivery = this.#delivery;\n for (const participant of this.#roster.list()) {\n const media = delivery.remoteMedia(participant.id);\n for (const kind of MEDIA_KINDS) {\n if (media[kind]) this.#emit(\"remote_media_changed\", { participantId: participant.id, kind, stream: null });\n }\n if (delivery.connectionStatus(participant.id) !== null) {\n this.#emit(\"media_connection_changed\", { participantId: participant.id, status: null });\n }\n }\n delivery.close();\n }\n\n #onRejected(code: string): void {\n const error = mapRejection(code);\n if (this.#state === \"connecting\" || this.#state === \"joining\") {\n this.#failJoin(error);\n return;\n }\n if (code === \"role_not_allowed\") {\n const pending = this.#pendingRestricted;\n this.#clearPendingRestricted();\n if (pending) this.#media.rollback(pending.kind);\n }\n this.#log.warn(\"request rejected\", { code: error.code });\n this.#emit(\"error\", { error });\n }\n\n #onProtocolError(): void {\n if (this.#state === \"closed\") return;\n this.#emit(\"error\", { error: new MeetingError(\"protocol_error\") });\n }\n\n #onClose(session: SignalingSession, code: number): void {\n if (this.#session !== session) return;\n this.#session = undefined;\n this.#log.info(\"connection closed\", { closeCode: code });\n switch (this.#state) {\n case \"connecting\":\n case \"joining\": {\n const { error } = mapClose(code, \"before_joined\");\n this.#failJoin(error ?? new MeetingError(\"connection_failed\"));\n return;\n }\n case \"joined\": {\n const { reason, error } = mapClose(code, \"after_joined\");\n this.#finish(reason, error);\n return;\n }\n case \"leaving\":\n this.#finish(\"left\");\n return;\n default:\n return;\n }\n }\n\n #failJoin(error: MeetingError): void {\n if (this.#state !== \"connecting\" && this.#state !== \"joining\") return;\n const join = this.#join;\n this.#join = undefined;\n this.#teardown();\n this.#log.warn(\"join failed\", { code: error.code });\n this.#setState(\"closed\");\n this.#emit(\"closed\", { reason: \"join_failed\", error });\n join?.reject(error);\n }\n\n #finish(reason: CloseReason, error?: MeetingError): void {\n if (this.#state === \"closed\") return;\n const end = this.#endMeeting;\n this.#endMeeting = undefined;\n this.#teardown();\n this.#setState(\"closed\");\n this.#emit(\"closed\", error ? { reason, error } : { reason });\n this.#leave?.resolve();\n if (end) {\n if (reason === \"meeting_ended\") end.resolve();\n else end.reject(error ?? new MeetingError(\"engine_closed\"));\n }\n }\n\n #teardown(): void {\n this.#clearTimer(\"join\");\n this.#clearTimer(\"leave\");\n this.#clearEndMeetingTimer();\n this.#clearPendingRestricted();\n this.#media.releaseAll();\n this.#delivery.close();\n const session = this.#session;\n this.#session = undefined;\n session?.close();\n this.#roster.clear();\n }\n\n #clearEndMeetingTimer(): void {\n if (this.#endMeetingTimer !== undefined) this.#env.clearTimeout(this.#endMeetingTimer);\n this.#endMeetingTimer = undefined;\n }\n\n #clearTimer(which: \"join\" | \"leave\"): void {\n const handle = which === \"join\" ? this.#joinTimer : this.#leaveTimer;\n if (handle !== undefined) this.#env.clearTimeout(handle);\n if (which === \"join\") this.#joinTimer = undefined;\n else this.#leaveTimer = undefined;\n }\n\n /** Re-reads the state after emitting, since listeners may have changed it. */\n #is(state: ConnectionState): boolean {\n return this.#state === state;\n }\n\n #setState(next: ConnectionState): void {\n const previous = this.#state;\n if (previous === next) return;\n this.#state = next;\n this.#log.info(\"state changed\", { state: next });\n this.#emit(\"state_changed\", { state: next, previous });\n }\n\n #emit<K extends MeetingEventType>(type: K, event: MeetingEventMap[K]): void {\n if (!this.#disposed) this.#emitter.emit(type, event);\n }\n}\n", "import type { PeerConnectionLike, StatsReportLike } from \"./env.js\";\n\nexport type SelectedPair = { readonly localId: string; readonly localType: string; readonly remoteType: string };\n\n/**\n * The candidate pair the browser is sending media over, from its stats: the transport's selected pair first, then\n * the succeeded and nominated pair for browsers without that field. Null when stats are unavailable or incomplete.\n */\nexport async function selectedPair(pc: PeerConnectionLike): Promise<SelectedPair | null> {\n const reports = await statsOf(pc);\n if (!reports) return null;\n const byId = new Map(reports.map((report) => [report.id, report]));\n const selectedId = reports.find((r) => r.type === \"transport\" && r.selectedCandidatePairId)?.selectedCandidatePairId;\n const pair =\n (selectedId ? byId.get(selectedId) : undefined) ??\n reports.find((r) => r.type === \"candidate-pair\" && r.state === \"succeeded\" && r.nominated === true);\n if (!pair?.localCandidateId || !pair.remoteCandidateId) return null;\n const localType = byId.get(pair.localCandidateId)?.candidateType;\n const remoteType = byId.get(pair.remoteCandidateId)?.candidateType;\n if (!localType || !remoteType) return null;\n return { localId: pair.localCandidateId, localType, remoteType };\n}\n\n/** IDs of every local candidate the browser has reported so far. Null when stats are unavailable. */\nexport async function localCandidateIds(pc: PeerConnectionLike): Promise<Set<string> | null> {\n const reports = await statsOf(pc);\n if (!reports) return null;\n return new Set(reports.filter((r) => r.type === \"local-candidate\").map((r) => r.id));\n}\n\nasync function statsOf(pc: PeerConnectionLike): Promise<StatsReportLike[] | null> {\n try {\n const collection = await pc.getStats();\n const reports: StatsReportLike[] = [];\n collection.forEach((report) => reports.push(report));\n return reports;\n } catch {\n return null;\n }\n}\n\nexport type PathKind = \"direct\" | \"relayed\";\n\n/**\n * How media is carried: `localPath` for this side of the selected pair, `remotePath` for the other side, and `path`\n * relayed when either side is. `remotePath` is this browser's view of the other side and may miss a remote relay.\n */\nexport type PathReport = { readonly path: PathKind; readonly localPath: PathKind; readonly remotePath: PathKind };\n\nexport function pathReport(pair: SelectedPair): PathReport {\n const localPath = kindOf(pair.localType);\n const remotePath = kindOf(pair.remoteType);\n return { path: localPath === \"relayed\" || remotePath === \"relayed\" ? \"relayed\" : \"direct\", localPath, remotePath };\n}\n\nexport function samePath(a: PathReport, b: PathReport): boolean {\n return a.path === b.path && a.localPath === b.localPath && a.remotePath === b.remotePath;\n}\n\nfunction kindOf(candidateType: string): PathKind {\n return candidateType === \"relay\" ? \"relayed\" : \"direct\";\n}\n", "import type { IceCandidate, IceServerConfig, PayloadMap } from \"@strevokit/signaling-protocol\";\nimport type { EngineEnvironment, IceCandidateLike, PeerConnectionLike, TimerHandle, TransceiverLike } from \"./env.js\";\nimport type { Log } from \"./log.js\";\nimport { localCandidateIds, type PathReport, pathReport, samePath, selectedPair } from \"./selectedPair.js\";\n\n/** Remote candidates kept until the remote description is set. */\nexport const MAX_QUEUED_CANDIDATES = 64;\n/** Time allowed from link creation to the first `connected`. */\nexport const CONNECTION_TIMEOUT_MS = 30_000;\n/** Time allowed for one switch attempt to select a fresh local candidate. */\nexport const SWITCH_ATTEMPT_TIMEOUT_MS = 15_000;\n/** Delays before retrying a failed switch attempt; the last one repeats. */\nexport const SWITCH_RETRY_DELAYS_MS: readonly number[] = [5_000, 10_000, 20_000];\n/** No switch attempt starts closer than this to the expiry of the credentials in use. */\nexport const SWITCH_DEADLINE_MARGIN_MS = 5_000;\n/** How often a switch attempt checks the selected candidate pair. */\nexport const SWITCH_POLL_MS = 1_000;\n/** How long a drop during a switch is held back before it is reported as an interruption. */\nexport const SWITCH_INTERRUPTION_HOLD_MS = 5_000;\n/** Times after each path report at which the path is read again; after the last, every `PATH_RECHECK_INTERVAL_MS`. */\nexport const PATH_RECHECK_DELAYS_MS: readonly number[] = [2_000, 10_000];\nexport const PATH_RECHECK_INTERVAL_MS = 30_000;\n\nexport type LinkRole = \"offerer\" | \"answerer\";\nexport type LinkStatus = \"connecting\" | \"connected\" | \"interrupted\" | \"failed\";\nexport type LinkFailure = \"connection_failed\" | \"connection_timeout\" | \"negotiation_failed\";\nexport type LocalKind = \"camera\" | \"microphone\" | \"screen\";\nexport type SwitchOutcome = \"completed\" | \"failed\";\nexport type RestartReason = \"refresh\" | \"peer_request\";\nexport interface PeerLinkCallbacks {\n sendOffer(payload: PayloadMap[\"webrtc.offer\"]): void;\n sendAnswer(payload: PayloadMap[\"webrtc.answer\"]): void;\n sendCandidate(payload: PayloadMap[\"webrtc.ice_candidate\"]): void;\n /** Called on every status transition after `connecting`. `reason` is set for `failed`. */\n statusChanged(status: LinkStatus, reason?: LinkFailure): void;\n /**\n * How media is carried on each side, after each move to `connected` and after each completed switch. Null when the\n * browser reports no stats.\n */\n connected(report: PathReport | null): void;\n /** Answerer: asks the other side to restart. False when it cannot be asked, which ends the switch. */\n requestRestart(): boolean;\n /** The outcome of one switch attempt. */\n switchResult(outcome: SwitchOutcome): void;\n}\n\n/** A planned move to fresh candidates before the credentials in use expire. */\ntype SwitchState = {\n deadline: number;\n attempt: number;\n /** Local candidate IDs known before the current attempt; the attempt completes on a pair outside this set. */\n known: ReadonlySet<string>;\n attemptTimer: TimerHandle | undefined;\n pollTimer: TimerHandle | undefined;\n retryTimer: TimerHandle | undefined;\n};\n\nfunction copyServers(iceServers: readonly IceServerConfig[]): { urls: string[]; username?: string; credential?: string }[] {\n return iceServers.map((server) => {\n const copy: { urls: string[]; username?: string; credential?: string } = { urls: [...server.urls] };\n if (server.username !== undefined) copy.username = server.username;\n if (server.credential !== undefined) copy.credential = server.credential;\n return copy;\n });\n}\n\nexport interface PeerLinkOptions {\n env: EngineEnvironment;\n log: Log;\n selfId: string;\n peerId: string;\n iceServers: readonly IceServerConfig[];\n timeoutMs: number;\n local: Readonly<Record<LocalKind, MediaStreamTrack | null>>;\n callbacks: PeerLinkCallbacks;\n}\n\nexport function roleFor(selfId: string, peerId: string): LinkRole {\n return selfId < peerId ? \"offerer\" : \"answerer\";\n}\n\n/** Maps `connectionState`, or `iceConnectionState` where the former is unavailable, to a coarse state. */\nfunction coarseState(pc: PeerConnectionLike): \"connecting\" | \"connected\" | \"disconnected\" | \"failed\" | \"closed\" {\n const state = typeof pc.connectionState === \"string\" ? pc.connectionState : pc.iceConnectionState;\n switch (state) {\n case \"connected\":\n case \"completed\":\n return \"connected\";\n case \"disconnected\":\n return \"disconnected\";\n case \"failed\":\n return \"failed\";\n case \"closed\":\n return \"closed\";\n default:\n return \"connecting\";\n }\n}\n\n/** One media connection to one other participant, with fixed audio, camera, and screen transceivers. */\nexport class PeerLink {\n readonly peerId: string;\n readonly role: LinkRole;\n #status: LinkStatus = \"connecting\";\n #everConnected = false;\n #closed = false;\n readonly #pc: PeerConnectionLike;\n readonly #env: EngineEnvironment;\n readonly #log: Log;\n readonly #callbacks: PeerLinkCallbacks;\n readonly #local: Record<LocalKind, MediaStreamTrack | null>;\n readonly #queued: IceCandidateLike[] = [];\n #remoteDescriptionSet = false;\n #offerHandled = false;\n #audio: TransceiverLike | undefined;\n #video: TransceiverLike | undefined;\n #screen: TransceiverLike | undefined;\n #streams: Record<LocalKind, MediaStream | null> = { camera: null, microphone: null, screen: null };\n #timer: TimerHandle | undefined;\n #chain: Promise<void> = Promise.resolve();\n #switch: SwitchState | null = null;\n #restarting = false;\n #interruptionHold: TimerHandle | undefined;\n #lastReport: PathReport | null = null;\n #recheckTimer: TimerHandle | undefined;\n\n /** Throws when the connection cannot be created; the owner treats that as a negotiation failure. */\n constructor(options: PeerLinkOptions) {\n this.peerId = options.peerId;\n this.role = roleFor(options.selfId, options.peerId);\n this.#env = options.env;\n this.#log = options.log;\n this.#callbacks = options.callbacks;\n const { local } = options;\n this.#local = { ...local };\n const PeerConnection = options.env.RTCPeerConnection;\n if (!PeerConnection) throw new Error(\"peer connections unavailable\");\n this.#pc = new PeerConnection({ iceServers: copyServers(options.iceServers) });\n this.#pc.onicecandidate = (event) => this.#onLocalCandidate(event.candidate);\n this.#pc.onconnectionstatechange = () => this.#onStateChange();\n this.#pc.oniceconnectionstatechange = () => {\n if (typeof this.#pc.connectionState !== \"string\") this.#onStateChange();\n };\n this.#timer = this.#env.setTimeout(() => {\n this.#timer = undefined;\n if (!this.#everConnected) this.#fail(\"connection_timeout\");\n }, options.timeoutMs);\n this.#log.debug(\"media connection created\", { participantId: this.peerId });\n }\n\n get status(): LinkStatus {\n return this.#status;\n }\n\n get everConnected(): boolean {\n return this.#everConnected;\n }\n\n /** Usable for rendering: connected at least once, and neither failed nor closed. */\n get usable(): boolean {\n return this.#everConnected && !this.#closed && this.#status !== \"failed\";\n }\n\n /** The stable stream holding the received track of `kind`, once the transceivers exist. */\n remoteStream(kind: LocalKind): MediaStream | null {\n return this.#streams[kind];\n }\n\n /** Offerer: adds the transceivers (audio \u2192 camera \u2192 screen) and sends the offer. */\n start(): void {\n if (this.role !== \"offerer\" || this.#audio) return;\n this.#run(async () => {\n this.#audio = this.#pc.addTransceiver(\"audio\", { direction: \"sendrecv\" });\n this.#video = this.#pc.addTransceiver(\"video\", { direction: \"sendrecv\" });\n this.#screen = this.#pc.addTransceiver(\"video\", { direction: \"sendrecv\" });\n this.#bindStreams();\n await this.#attachAll();\n const offer = await this.#pc.createOffer();\n await this.#pc.setLocalDescription(offer);\n if (this.#closed) return;\n const sdp = this.#pc.localDescription?.sdp ?? offer.sdp ?? \"\";\n this.#callbacks.sendOffer({ targetParticipantId: this.peerId, sdp });\n });\n }\n\n /**\n * Answerer: applies the offer and sends the answer. A later offer (a restart) is answered when no other\n * negotiation is in progress, keeping the transceivers and received streams; otherwise it is ignored.\n */\n acceptOffer(sdp: string): void {\n if (this.role !== \"answerer\") {\n this.#log.debug(\"frame ignored\", { messageType: \"webrtc.offer\", reason: \"offerer\" });\n return;\n }\n if (this.#offerHandled) {\n this.#acceptReoffer(sdp);\n return;\n }\n this.#offerHandled = true;\n this.#run(async () => {\n await this.#pc.setRemoteDescription({ type: \"offer\", sdp });\n this.#remoteDescriptionSet = true;\n // Bind by index: two video m-lines cannot be told apart by track.kind alone.\n const transceivers = this.#pc.getTransceivers();\n this.#audio = transceivers[0];\n this.#video = transceivers[1];\n this.#screen = transceivers[2];\n for (const transceiver of [this.#audio, this.#video, this.#screen]) {\n if (transceiver) transceiver.direction = \"sendrecv\";\n }\n this.#bindStreams();\n await this.#attachAll();\n const answer = await this.#pc.createAnswer();\n await this.#pc.setLocalDescription(answer);\n if (this.#closed) return;\n const answerSdp = this.#pc.localDescription?.sdp ?? answer.sdp ?? \"\";\n this.#callbacks.sendAnswer({ targetParticipantId: this.peerId, sdp: answerSdp });\n await this.#flushCandidates();\n });\n }\n\n /** Offerer: applies the answer while an offer is outstanding; otherwise ignored. */\n acceptAnswer(sdp: string): void {\n if (this.role !== \"offerer\") {\n this.#log.debug(\"frame ignored\", { messageType: \"webrtc.answer\", reason: \"answerer\" });\n return;\n }\n this.#run(async () => {\n if (this.#pc.signalingState !== \"have-local-offer\") {\n this.#log.debug(\"frame ignored\", { messageType: \"webrtc.answer\", state: this.#pc.signalingState });\n return;\n }\n if (!this.#restarting) {\n await this.#pc.setRemoteDescription({ type: \"answer\", sdp });\n this.#remoteDescriptionSet = true;\n await this.#flushCandidates();\n return;\n }\n this.#restarting = false;\n try {\n await this.#pc.setRemoteDescription({ type: \"answer\", sdp });\n } catch {\n this.#restartFailed();\n return;\n }\n await this.#flushCandidates();\n });\n }\n\n /** Replaces the server list for future candidate gathering. The current connection is untouched. */\n updateIceServers(iceServers: readonly IceServerConfig[]): void {\n if (this.#closed) return;\n try {\n this.#pc.setConfiguration({ ...this.#pc.getConfiguration(), iceServers: copyServers(iceServers) });\n } catch {\n this.#log.debug(\"negotiation step failed\", { participantId: this.peerId, reason: \"configuration\" });\n }\n }\n\n /**\n * Moves to fresh candidates before `deadlineMs` when this side sends through a relay, whose allocation is tied to\n * the credentials about to expire. Direct paths and links that are not connected are left alone.\n */\n planSwitch(deadlineMs: number): void {\n if (this.#closed || this.#status !== \"connected\") return;\n const active = this.#switch;\n if (active) {\n active.deadline = deadlineMs;\n return;\n }\n void selectedPair(this.#pc).then((pair) => {\n if (this.#closed || this.#switch || this.#status !== \"connected\" || pair?.localType !== \"relay\") return;\n const started: SwitchState = {\n deadline: deadlineMs,\n attempt: 0,\n known: new Set(),\n attemptTimer: undefined,\n pollTimer: undefined,\n retryTimer: undefined,\n };\n this.#switch = started;\n this.#log.debug(\"media path switch started\", { participantId: this.peerId });\n void this.#beginAttempt(started);\n });\n }\n\n /**\n * Offerer: renegotiates with fresh candidates. Joins a restart whose answer is still outstanding instead of starting\n * another; a restart that already finished may predate the other side's fresh servers, so it does not count.\n */\n restart(reason: RestartReason): void {\n if (this.role !== \"offerer\" || this.#closed || this.#restarting) return;\n this.#restarting = true;\n this.#log.debug(\"media connection restart\", { participantId: this.peerId, reason });\n this.#chain = this.#chain.then(async () => {\n if (this.#closed) return;\n try {\n const offer = await this.#pc.createOffer({ iceRestart: true });\n await this.#pc.setLocalDescription(offer);\n if (this.#closed) return;\n const sdp = this.#pc.localDescription?.sdp ?? offer.sdp ?? \"\";\n this.#callbacks.sendOffer({ targetParticipantId: this.peerId, sdp });\n } catch {\n this.#restarting = false;\n this.#restartFailed();\n }\n });\n }\n\n addRemoteCandidate(candidate: IceCandidate): void {\n if (this.#closed) return;\n const copy: IceCandidateLike = {\n candidate: candidate.candidate,\n sdpMid: candidate.sdpMid,\n sdpMLineIndex: candidate.sdpMLineIndex,\n ...(candidate.usernameFragment !== undefined ? { usernameFragment: candidate.usernameFragment } : {}),\n };\n if (!this.#remoteDescriptionSet) {\n if (this.#queued.length >= MAX_QUEUED_CANDIDATES) {\n this.#log.debug(\"late candidate dropped\", { participantId: this.peerId, reason: \"queue_full\" });\n return;\n }\n this.#queued.push(copy);\n return;\n }\n void this.#applyCandidate(copy);\n }\n\n /** Sends `track` for `kind` (or nothing for `null`). Skipped when that track is already being sent. */\n attachLocal(kind: LocalKind, track: MediaStreamTrack | null): void {\n this.#local[kind] = track;\n if (this.#closed) return;\n const sender =\n (kind === \"camera\" ? this.#video : kind === \"screen\" ? this.#screen : this.#audio)?.sender;\n if (!sender || sender.track === track) return;\n sender.replaceTrack(track).catch(() => {\n this.#log.debug(\"negotiation step failed\", { participantId: this.peerId, kind, reason: \"replace_track\" });\n });\n }\n\n /** Closes the connection and stops received tracks. Reports nothing. Idempotent. */\n close(): void {\n if (this.#closed) return;\n this.#closed = true;\n this.#clearTimer();\n this.#endSwitch();\n this.#clearInterruptionHold();\n this.#clearRecheck();\n this.#pc.onicecandidate = null;\n this.#pc.onconnectionstatechange = null;\n this.#pc.oniceconnectionstatechange = null;\n for (const stream of Object.values(this.#streams)) {\n for (const track of stream?.getTracks() ?? []) {\n try {\n track.stop();\n } catch {\n // Already stopped.\n }\n }\n }\n try {\n this.#pc.close();\n } catch {\n // Already closed.\n }\n }\n\n #run(step: () => Promise<void>): void {\n this.#chain = this.#chain.then(async () => {\n if (this.#closed) return;\n try {\n await step();\n } catch {\n if (this.#closed) return;\n this.#log.debug(\"negotiation step failed\", { participantId: this.peerId });\n this.#fail(\"negotiation_failed\");\n }\n });\n }\n\n #acceptReoffer(sdp: string): void {\n this.#run(async () => {\n if (this.#pc.signalingState !== \"stable\") {\n this.#log.debug(\"frame ignored\", { messageType: \"webrtc.offer\", reason: \"busy\" });\n return;\n }\n try {\n await this.#pc.setRemoteDescription({ type: \"offer\", sdp });\n const answer = await this.#pc.createAnswer();\n await this.#pc.setLocalDescription(answer);\n if (this.#closed) return;\n const answerSdp = this.#pc.localDescription?.sdp ?? answer.sdp ?? \"\";\n this.#callbacks.sendAnswer({ targetParticipantId: this.peerId, sdp: answerSdp });\n } catch {\n this.#restartFailed();\n return;\n }\n await this.#flushCandidates();\n });\n }\n\n /** A restart negotiation step failed: the connection stays as it is and the current attempt, if any, fails. */\n #restartFailed(): void {\n if (this.#closed) return;\n this.#log.debug(\"negotiation step failed\", { participantId: this.peerId, reason: \"restart\" });\n const current = this.#switch;\n if (current?.attemptTimer !== undefined) this.#attemptFailed(current);\n }\n\n async #beginAttempt(current: SwitchState): Promise<void> {\n current.attempt += 1;\n const known = await localCandidateIds(this.#pc);\n if (this.#switch !== current || this.#closed) return;\n current.known = known ?? new Set();\n current.attemptTimer = this.#env.setTimeout(() => this.#attemptFailed(current), SWITCH_ATTEMPT_TIMEOUT_MS);\n if (this.role === \"offerer\") {\n this.restart(\"refresh\");\n } else if (!this.#callbacks.requestRestart()) {\n this.#endSwitch();\n return;\n }\n this.#schedulePoll(current);\n }\n\n #schedulePoll(current: SwitchState): void {\n current.pollTimer = this.#env.setTimeout(() => {\n current.pollTimer = undefined;\n void this.#checkSwitch(current);\n }, SWITCH_POLL_MS);\n }\n\n async #checkSwitch(current: SwitchState): Promise<void> {\n if (this.#switch !== current || current.attemptTimer === undefined) return;\n const pair = coarseState(this.#pc) === \"connected\" ? await selectedPair(this.#pc) : null;\n if (this.#switch !== current || current.attemptTimer === undefined) return;\n if (!pair || current.known.has(pair.localId)) {\n this.#schedulePoll(current);\n return;\n }\n this.#endSwitch();\n const report = pathReport(pair);\n this.#log.debug(\"media path switch completed\", { participantId: this.peerId, attempt: current.attempt, ...report });\n this.#sendPath(report);\n this.#callbacks.switchResult(\"completed\");\n }\n\n #attemptFailed(current: SwitchState): void {\n if (this.#switch !== current || this.#closed) return;\n this.#clearSwitchTimers(current);\n this.#restarting = false;\n this.#log.debug(\"media path switch attempt failed\", { participantId: this.peerId, attempt: current.attempt });\n this.#callbacks.switchResult(\"failed\");\n if (this.#switch !== current || this.#closed) return;\n const delay = SWITCH_RETRY_DELAYS_MS[Math.min(current.attempt, SWITCH_RETRY_DELAYS_MS.length) - 1] ?? 0;\n if (this.#env.now() + delay >= current.deadline - SWITCH_DEADLINE_MARGIN_MS) {\n this.#endSwitch();\n this.#log.debug(\"media path switch stopped\", { participantId: this.peerId, attempt: current.attempt });\n return;\n }\n current.retryTimer = this.#env.setTimeout(() => {\n current.retryTimer = undefined;\n if (this.#switch === current && !this.#closed) void this.#beginAttempt(current);\n }, delay);\n }\n\n #endSwitch(): void {\n const current = this.#switch;\n if (!current) return;\n this.#switch = null;\n this.#clearSwitchTimers(current);\n }\n\n #clearSwitchTimers(current: SwitchState): void {\n for (const timer of [current.attemptTimer, current.pollTimer, current.retryTimer]) {\n if (timer !== undefined) this.#env.clearTimeout(timer);\n }\n current.attemptTimer = undefined;\n current.pollTimer = undefined;\n current.retryTimer = undefined;\n }\n\n #clearInterruptionHold(): void {\n if (this.#interruptionHold !== undefined) this.#env.clearTimeout(this.#interruptionHold);\n this.#interruptionHold = undefined;\n }\n\n #bindStreams(): void {\n const Stream = this.#env.MediaStream;\n if (!Stream) return;\n if (this.#audio && !this.#streams.microphone) this.#streams.microphone = new Stream([this.#audio.receiver.track]);\n if (this.#video && !this.#streams.camera) this.#streams.camera = new Stream([this.#video.receiver.track]);\n if (this.#screen && !this.#streams.screen) this.#streams.screen = new Stream([this.#screen.receiver.track]);\n }\n\n async #attachAll(): Promise<void> {\n const pairs: [TransceiverLike | undefined, MediaStreamTrack | null][] = [\n [this.#audio, this.#local.microphone],\n [this.#video, this.#local.camera],\n [this.#screen, this.#local.screen],\n ];\n for (const [transceiver, track] of pairs) {\n if (transceiver && track && transceiver.sender.track !== track) await transceiver.sender.replaceTrack(track);\n }\n }\n\n async #flushCandidates(): Promise<void> {\n for (const candidate of this.#queued.splice(0)) await this.#applyCandidate(candidate);\n }\n\n async #applyCandidate(candidate: IceCandidateLike): Promise<void> {\n if (this.#closed) return;\n try {\n await this.#pc.addIceCandidate(candidate);\n } catch {\n this.#log.debug(\"late candidate dropped\", { participantId: this.peerId, reason: \"rejected\" });\n }\n }\n\n #onLocalCandidate(candidate: IceCandidateLike | null): void {\n if (this.#closed || !candidate || candidate.candidate === \"\") return;\n const payload: IceCandidate = {\n candidate: candidate.candidate,\n sdpMid: candidate.sdpMid ?? null,\n sdpMLineIndex: candidate.sdpMLineIndex ?? null,\n };\n if (typeof candidate.usernameFragment === \"string\") payload.usernameFragment = candidate.usernameFragment;\n this.#callbacks.sendCandidate({ targetParticipantId: this.peerId, candidate: payload });\n }\n\n #onStateChange(): void {\n if (this.#closed || this.#status === \"failed\") return;\n const state = coarseState(this.#pc);\n this.#log.debug(\"media connection state\", { participantId: this.peerId, state });\n switch (state) {\n case \"connected\":\n this.#everConnected = true;\n this.#clearTimer();\n this.#clearInterruptionHold();\n if (this.#setStatus(\"connected\")) void this.#reportPath();\n return;\n case \"disconnected\":\n if (!this.#everConnected) return;\n if (this.#switch && this.#status === \"connected\") {\n // Moving to fresh candidates can drop the connection briefly; report it only if it lasts.\n this.#interruptionHold ??= this.#env.setTimeout(() => {\n this.#interruptionHold = undefined;\n if (!this.#closed && coarseState(this.#pc) !== \"connected\") this.#setStatus(\"interrupted\");\n }, SWITCH_INTERRUPTION_HOLD_MS);\n return;\n }\n this.#setStatus(\"interrupted\");\n return;\n case \"failed\":\n this.#fail(\"connection_failed\");\n return;\n default:\n return;\n }\n }\n\n /** True when the status changed. */\n #setStatus(status: LinkStatus, reason?: LinkFailure): boolean {\n if (this.#status === status) return false;\n this.#status = status;\n this.#callbacks.statusChanged(status, reason);\n return true;\n }\n\n async #reportPath(): Promise<void> {\n const pair = await selectedPair(this.#pc);\n if (this.#closed || this.#status !== \"connected\") return;\n this.#sendPath(pair ? pathReport(pair) : null);\n }\n\n /** Reports the path and reads it again on the recheck schedule, starting over from the first delay. */\n #sendPath(report: PathReport | null): void {\n this.#lastReport = report;\n this.#callbacks.connected(report);\n this.#scheduleRecheck(0);\n }\n\n #scheduleRecheck(step: number): void {\n this.#clearRecheck();\n const at = PATH_RECHECK_DELAYS_MS[step];\n const delay = at === undefined ? PATH_RECHECK_INTERVAL_MS : at - (PATH_RECHECK_DELAYS_MS[step - 1] ?? 0);\n this.#recheckTimer = this.#env.setTimeout(() => {\n this.#recheckTimer = undefined;\n void this.#recheckPath(step);\n }, delay);\n }\n\n /**\n * The browser can settle on the path after the first report, for example when the other side's relay address was\n * first seen as peer-reflexive. A changed path is reported again; an unchanged one sends nothing.\n */\n async #recheckPath(step: number): Promise<void> {\n if (this.#closed) return;\n const idle = () => this.#status !== \"connected\" || this.#switch !== null;\n const pair = idle() ? null : await selectedPair(this.#pc);\n if (this.#closed || this.#recheckTimer !== undefined) return;\n const report = pair && !idle() ? pathReport(pair) : null;\n if (report && !(this.#lastReport && samePath(report, this.#lastReport))) {\n this.#log.debug(\"media path updated\", { participantId: this.peerId, ...report });\n this.#sendPath(report);\n return;\n }\n this.#scheduleRecheck(step + 1);\n }\n\n #clearRecheck(): void {\n if (this.#recheckTimer !== undefined) this.#env.clearTimeout(this.#recheckTimer);\n this.#recheckTimer = undefined;\n }\n\n #fail(reason: LinkFailure): void {\n if (this.#closed || this.#status === \"failed\") return;\n this.#clearTimer();\n this.#setStatus(\"failed\", reason);\n this.close();\n }\n\n #clearTimer(): void {\n if (this.#timer !== undefined) this.#env.clearTimeout(this.#timer);\n this.#timer = undefined;\n }\n}\n", "import type { MediaKind, MediaState, MeetingEventMap, RemoteMedia } from \"../public/types.js\";\nimport { NO_REMOTE_MEDIA } from \"./mediaDelivery.js\";\n\nconst KINDS: readonly MediaKind[] = [\"camera\", \"microphone\", \"screen\"];\n\nexport type RemoteMediaInputs = {\n /** The participant is the one this side carries media with. */\n readonly active: boolean;\n /** The link connected at least once and is neither failed nor closed. */\n readonly usable: boolean;\n /** What the participant announced through signaling. */\n readonly announced: MediaState;\n readonly streams: {\n readonly camera: MediaStream | null;\n readonly microphone: MediaStream | null;\n readonly screen: MediaStream | null;\n };\n};\n\n/** A kind is available when the link to an active participant is usable and the participant announced it on. */\nexport function computeRemoteMedia(inputs: RemoteMediaInputs): RemoteMedia {\n if (!inputs.active || !inputs.usable) return NO_REMOTE_MEDIA;\n const camera = inputs.announced.camera ? inputs.streams.camera : null;\n const microphone = inputs.announced.microphone ? inputs.streams.microphone : null;\n const screen = inputs.announced.screen ? inputs.streams.screen : null;\n if (camera === null && microphone === null && screen === null) return NO_REMOTE_MEDIA;\n return Object.freeze({ camera, microphone, screen });\n}\n\ntype Emit = (event: MeetingEventMap[\"remote_media_changed\"]) => void;\n\n/** The last reported remote media per participant; reports each change of a kind exactly once. */\nexport class RemoteMediaTracker {\n readonly #current = new Map<string, RemoteMedia>();\n\n get(participantId: string): RemoteMedia {\n return this.#current.get(participantId) ?? NO_REMOTE_MEDIA;\n }\n\n update(participantId: string, next: RemoteMedia, emit: Emit): void {\n const previous = this.get(participantId);\n if (next === NO_REMOTE_MEDIA) this.#current.delete(participantId);\n else this.#current.set(participantId, next);\n for (const kind of KINDS) {\n if (previous[kind] !== next[kind]) emit({ participantId, kind, stream: next[kind] });\n }\n }\n\n /** Forgets everything without reporting. */\n clear(): void {\n this.#current.clear();\n }\n}\n", "import type { IceCandidate, IceServerConfig, SignalingMessage } from \"@strevokit/signaling-protocol\";\nimport { MeetingError } from \"../public/errors.js\";\nimport type { MediaConnectionStatus, MediaKind, MediaState, MeetingEventMap, RemoteMedia } from \"../public/types.js\";\nimport type { EngineEnvironment, TimerHandle } from \"./env.js\";\nimport type { Log } from \"./log.js\";\nimport type { DeliveryEventType, MediaDelivery, MediaDeliveryContext, PresentPeer } from \"./mediaDelivery.js\";\nimport { CONNECTION_TIMEOUT_MS, type LinkFailure, type LinkStatus, type LocalKind, PeerLink, roleFor } from \"./peerLink.js\";\nimport { RemoteMediaTracker, computeRemoteMedia } from \"./remoteMedia.js\";\n\n/** How long frames from a participant not yet usable are kept. */\nexport const EARLY_FRAME_HOLD_MS = 5000;\n/** Early candidates kept per participant. */\nexport const MAX_EARLY_CANDIDATES = 64;\n\nconst NOTHING_ANNOUNCED: MediaState = Object.freeze({ camera: false, microphone: false, screen: false });\n\nexport interface PeerMediaDeliveryOptions {\n env: EngineEnvironment;\n log: Log;\n /** Not public: tests shorten the time allowed for a first connection. */\n connectionTimeoutMs?: number;\n}\n\ntype EarlyCandidates = { candidates: IceCandidate[]; timer: TimerHandle };\ntype HeldOffer = { from: string; sdp: string; timer: TimerHandle };\n\n/**\n * Carries camera, microphone, and screen directly to and from exactly one other participant. Every participant\n * applies the same rule: pair only while exactly one other participant is present, keep a pair once it has\n * connected, and report the participants it does not carry with a non-fatal error.\n */\nexport class PeerMediaDelivery implements MediaDelivery {\n readonly #env: EngineEnvironment;\n readonly #log: Log;\n readonly #timeoutMs: number;\n #context: MediaDeliveryContext | undefined;\n /** The latest server list; links created later use it. */\n #iceServers: readonly IceServerConfig[] = [];\n /** Whether the platform relays restart requests and results (it announces credential expiry). */\n #serverSupportsRestart = false;\n #inert = false;\n #closed = false;\n readonly #present = new Map<string, MediaState>();\n #activeId: string | null = null;\n #link: PeerLink | null = null;\n readonly #status = new Map<string, MediaConnectionStatus>();\n readonly #remote = new RemoteMediaTracker();\n readonly #limitReported = new Set<string>();\n readonly #early = new Map<string, EarlyCandidates>();\n #heldOffer: HeldOffer | undefined;\n readonly #local: Record<LocalKind, MediaStreamTrack | null> = { camera: null, microphone: null, screen: null };\n\n constructor(options: PeerMediaDeliveryOptions) {\n this.#env = options.env;\n this.#log = options.log;\n this.#timeoutMs = options.connectionTimeoutMs ?? CONNECTION_TIMEOUT_MS;\n }\n\n attach(context: MediaDeliveryContext): void {\n if (this.#closed || this.#context) return;\n this.#context = context;\n this.#iceServers = context.iceServers;\n this.#serverSupportsRestart = context.iceServersExpireAt !== null;\n if (!this.#env.RTCPeerConnection || !this.#env.MediaStream) {\n this.#inert = true;\n this.#log.warn(\"media connections unsupported\");\n this.#emit(\"error\", { error: new MeetingError(\"unsupported_environment\") });\n }\n }\n\n peersPresent(entries: readonly PresentPeer[]): void {\n if (!this.#active()) return;\n for (const { id, media } of entries) {\n this.#present.set(id, { ...media });\n this.#limitReported.delete(id);\n }\n this.#evaluate();\n const held = this.#heldOffer;\n if (held && entries.some((entry) => entry.id === held.from)) {\n this.#dropHeldOffer();\n if (held.from === this.#activeId) this.#handleOffer(held.from, held.sdp);\n }\n }\n\n peerPresent(participantId: string, media: MediaState): void {\n this.peersPresent([{ id: participantId, media }]);\n }\n\n peerMediaChanged(participantId: string, kind: MediaKind, enabled: boolean): void {\n const announced = this.#present.get(participantId);\n if (!this.#active() || !announced) return;\n this.#present.set(participantId, { ...announced, [kind]: enabled });\n this.#refreshRemote(participantId);\n }\n\n peerLeft(participantId: string): void {\n if (!this.#active()) return;\n this.#present.delete(participantId);\n this.#limitReported.delete(participantId);\n this.#dropEarly(participantId);\n if (this.#heldOffer?.from === participantId) this.#dropHeldOffer();\n if (participantId === this.#activeId) {\n this.#closeLink();\n this.#activeId = null;\n }\n this.#setStatus(participantId, null);\n this.#evaluate();\n }\n\n peerReconnected(participantId: string): void {\n if (!this.#active() || participantId !== this.#activeId) return;\n this.#dropEarly(participantId);\n this.#closeLink();\n this.#setStatus(participantId, null);\n this.#startPairing();\n }\n\n onPeerFrame(message: SignalingMessage): void {\n if (!this.#active()) return;\n const from = message.participantId;\n if (!this.#present.has(from)) {\n this.#holdEarly(message);\n return;\n }\n if (from !== this.#activeId) {\n this.#log.debug(\"frame ignored\", { messageType: message.type, reason: \"not_paired\" });\n return;\n }\n switch (message.type) {\n case \"webrtc.offer\":\n this.#handleOffer(from, message.payload.sdp);\n return;\n case \"webrtc.answer\":\n if (this.#link) this.#link.acceptAnswer(message.payload.sdp);\n else this.#log.debug(\"frame ignored\", { messageType: message.type, reason: \"no_connection\" });\n return;\n case \"webrtc.ice_candidate\":\n if (this.#link) this.#link.addRemoteCandidate(message.payload.candidate);\n else this.#addEarlyCandidate(from, message.payload.candidate);\n return;\n case \"webrtc.ice_restart\":\n if (this.#link?.role === \"offerer\") this.#link.restart(\"peer_request\");\n else this.#log.debug(\"frame ignored\", { messageType: message.type, reason: this.#link ? \"answerer\" : \"no_connection\" });\n return;\n default:\n return;\n }\n }\n\n iceServersUpdated(iceServers: readonly IceServerConfig[], expiresAt: number): void {\n if (!this.#active()) return;\n this.#iceServers = iceServers;\n const link = this.#link;\n if (!link) return;\n link.updateIceServers(iceServers);\n link.planSwitch(expiresAt);\n }\n\n localMediaChanged(kind: MediaKind, stream: MediaStream | null): void {\n if (this.#closed) return;\n if (kind === \"screen\") {\n const track = stream?.getVideoTracks()[0] ?? null;\n this.#local.screen = track;\n this.#link?.attachLocal(\"screen\", track);\n return;\n }\n const track = (kind === \"camera\" ? stream?.getVideoTracks()[0] : stream?.getAudioTracks()[0]) ?? null;\n // A muted microphone keeps its disabled track on the connection, so it sends silence.\n if (kind === \"microphone\" && track === null) return;\n this.#local[kind] = track;\n this.#link?.attachLocal(kind, track);\n }\n\n supportsScreenShare(): boolean {\n return this.#active();\n }\n\n remoteMedia(participantId: string): RemoteMedia {\n return this.#remote.get(participantId);\n }\n\n connectionStatus(participantId: string): MediaConnectionStatus | null {\n return this.#status.get(participantId) ?? null;\n }\n\n close(): void {\n if (this.#closed) return;\n this.#closed = true;\n const link = this.#link;\n this.#link = null;\n link?.close();\n for (const participantId of [...this.#early.keys()]) this.#dropEarly(participantId);\n this.#dropHeldOffer();\n this.#present.clear();\n this.#status.clear();\n this.#remote.clear();\n this.#activeId = null;\n }\n\n #active(): boolean {\n return this.#context !== undefined && !this.#inert && !this.#closed;\n }\n\n /** The single-peer rule, applied after every presence change. */\n #evaluate(): void {\n const others = this.#present.size;\n if (this.#activeId !== null && others >= 2 && !this.#keepsPair()) {\n const abandoned = this.#activeId;\n this.#closeLink();\n this.#activeId = null;\n this.#setStatus(abandoned, null);\n this.#log.debug(\"media connection abandoned\", { participantId: abandoned });\n }\n if (this.#activeId === null && others === 1) {\n const [only] = this.#present.keys();\n if (only !== undefined) {\n this.#activeId = only;\n this.#startPairing();\n }\n }\n if (others >= 2) {\n for (const participantId of this.#present.keys()) {\n if (participantId === this.#activeId && this.#keepsPair()) continue;\n if (this.#limitReported.has(participantId)) continue;\n this.#limitReported.add(participantId);\n this.#log.info(\"media not carried\", { participantId, code: \"media_participant_limit\" });\n this.#emit(\"error\", { error: new MeetingError(\"media_participant_limit\") });\n }\n }\n }\n\n /** A pair is kept once its link has connected, until the peer leaves, reconnects, or the link fails. */\n #keepsPair(): boolean {\n return this.#link !== null && this.#link.everConnected && this.#link.status !== \"failed\";\n }\n\n #startPairing(): void {\n const peerId = this.#activeId;\n const self = this.#context?.participantId;\n if (peerId === null || self === undefined) return;\n if (roleFor(self, peerId) !== \"offerer\") return;\n this.#createLink(peerId)?.start();\n }\n\n #handleOffer(from: string, sdp: string): void {\n const self = this.#context?.participantId;\n if (self === undefined) return;\n if (roleFor(self, from) === \"offerer\") {\n this.#log.debug(\"frame ignored\", { messageType: \"webrtc.offer\", reason: \"offerer\" });\n return;\n }\n const link = this.#link ?? this.#createLink(from);\n link?.acceptOffer(sdp);\n }\n\n #createLink(peerId: string): PeerLink | null {\n const context = this.#context;\n if (!context) return null;\n let link: PeerLink;\n try {\n link = new PeerLink({\n env: this.#env,\n log: this.#log,\n selfId: context.participantId,\n peerId,\n iceServers: this.#iceServers,\n timeoutMs: this.#timeoutMs,\n local: this.#local,\n callbacks: {\n sendOffer: (payload) => {\n if (this.#link === link) context.send(\"webrtc.offer\", payload);\n },\n sendAnswer: (payload) => {\n if (this.#link === link) context.send(\"webrtc.answer\", payload);\n },\n sendCandidate: (payload) => {\n if (this.#link === link) context.send(\"webrtc.ice_candidate\", payload);\n },\n statusChanged: (status, reason) => {\n if (this.#link === link) this.#onLinkStatus(link, status, reason);\n },\n connected: (report) => {\n if (this.#link === link) context.send(\"webrtc.connected\", { peerParticipantId: peerId, ...report });\n },\n requestRestart: () =>\n this.#link === link &&\n this.#serverSupportsRestart &&\n context.send(\"webrtc.ice_restart\", { targetParticipantId: peerId }),\n switchResult: (outcome) => {\n if (this.#link === link && this.#serverSupportsRestart) {\n context.send(\"webrtc.ice_restart_result\", { peerParticipantId: peerId, outcome });\n }\n },\n },\n });\n } catch {\n this.#log.debug(\"negotiation step failed\", { participantId: peerId, reason: \"create\" });\n this.#reportFailure(peerId, \"negotiation_failed\");\n return null;\n }\n this.#link = link;\n this.#setStatus(peerId, \"connecting\");\n const early = this.#early.get(peerId);\n if (early) {\n this.#dropEarly(peerId);\n for (const candidate of early.candidates) link.addRemoteCandidate(candidate);\n }\n return link;\n }\n\n #onLinkStatus(link: PeerLink, status: LinkStatus, reason: LinkFailure | undefined): void {\n const peerParticipantId = link.peerId;\n switch (status) {\n case \"connected\":\n this.#setStatus(peerParticipantId, \"connected\");\n this.#refreshRemote(peerParticipantId);\n return;\n case \"interrupted\":\n this.#context?.send(\"webrtc.disconnected\", { peerParticipantId });\n this.#setStatus(peerParticipantId, \"interrupted\");\n return;\n case \"failed\":\n this.#link = null;\n link.close();\n this.#reportFailure(peerParticipantId, reason ?? \"connection_failed\");\n return;\n default:\n return;\n }\n }\n\n /** Reports a failed link. The pair stays as it is; nothing is retried until the peer reconnects or rejoins. */\n #reportFailure(peerParticipantId: string, reason: LinkFailure): void {\n this.#log.warn(\"media connection failed\", { participantId: peerParticipantId, reason });\n this.#context?.send(\"webrtc.failed\", { peerParticipantId, reason });\n this.#setStatus(peerParticipantId, \"failed\");\n this.#refreshRemote(peerParticipantId);\n this.#emit(\"error\", { error: new MeetingError(\"media_connection_failed\") });\n }\n\n /** Closes the current link without reporting a failure, and reports its remote media as gone. */\n #closeLink(): void {\n const link = this.#link;\n if (!link) return;\n this.#link = null;\n link.close();\n this.#refreshRemote(link.peerId);\n }\n\n #refreshRemote(participantId: string): void {\n const link = this.#link;\n const active = participantId === this.#activeId && link !== null && link.peerId === participantId;\n const next = computeRemoteMedia({\n active,\n usable: active && link.usable,\n announced: this.#present.get(participantId) ?? NOTHING_ANNOUNCED,\n streams: {\n camera: link?.remoteStream(\"camera\") ?? null,\n microphone: link?.remoteStream(\"microphone\") ?? null,\n screen: link?.remoteStream(\"screen\") ?? null,\n },\n });\n this.#remote.update(participantId, next, (event) => this.#emit(\"remote_media_changed\", event));\n }\n\n #setStatus(participantId: string, status: MediaConnectionStatus | null): void {\n const previous = this.#status.get(participantId) ?? null;\n if (previous === status) return;\n if (status === null) this.#status.delete(participantId);\n else this.#status.set(participantId, status);\n this.#emit(\"media_connection_changed\", { participantId, status });\n }\n\n #holdEarly(message: SignalingMessage): void {\n switch (message.type) {\n case \"webrtc.offer\": {\n this.#dropHeldOffer();\n const from = message.participantId;\n this.#heldOffer = {\n from,\n sdp: message.payload.sdp,\n timer: this.#env.setTimeout(() => {\n if (this.#heldOffer?.from === from) this.#heldOffer = undefined;\n }, EARLY_FRAME_HOLD_MS),\n };\n return;\n }\n case \"webrtc.ice_candidate\":\n this.#addEarlyCandidate(message.participantId, message.payload.candidate);\n return;\n default:\n this.#log.debug(\"frame ignored\", { messageType: message.type, reason: \"unknown_participant\" });\n }\n }\n\n #addEarlyCandidate(participantId: string, candidate: IceCandidate): void {\n let early = this.#early.get(participantId);\n if (!early) {\n early = {\n candidates: [],\n timer: this.#env.setTimeout(() => this.#early.delete(participantId), EARLY_FRAME_HOLD_MS),\n };\n this.#early.set(participantId, early);\n }\n if (early.candidates.length >= MAX_EARLY_CANDIDATES) {\n this.#log.debug(\"late candidate dropped\", { participantId, reason: \"queue_full\" });\n return;\n }\n early.candidates.push(candidate);\n }\n\n #dropEarly(participantId: string): void {\n const early = this.#early.get(participantId);\n if (!early) return;\n this.#env.clearTimeout(early.timer);\n this.#early.delete(participantId);\n }\n\n #dropHeldOffer(): void {\n if (this.#heldOffer) this.#env.clearTimeout(this.#heldOffer.timer);\n this.#heldOffer = undefined;\n }\n\n #emit<K extends DeliveryEventType>(type: K, event: MeetingEventMap[K]): void {\n if (!this.#closed) this.#context?.emit(type, event);\n }\n}\n", "import { isCanonicalUlid } from \"@strevokit/signaling-protocol\";\nimport { MeetingError } from \"../public/errors.js\";\n\nexport type Addressing = { readonly meetingId: string; readonly participantId: string };\n\nconst BASE64URL = /^[A-Za-z0-9_-]+$/;\n\nfunction decodeSegment(segment: string): unknown {\n if (!BASE64URL.test(segment)) throw new MeetingError(\"join_token_invalid\");\n const padded = segment.replace(/-/g, \"+\").replace(/_/g, \"/\").padEnd(Math.ceil(segment.length / 4) * 4, \"=\");\n const binary = atob(padded);\n const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));\n return JSON.parse(new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes));\n}\n\n/**\n * Reads the meeting and participant IDs from a join token so the engine can address the connection. The\n * signature, expiry, and role are deliberately not checked here: the realtime service verifies the token.\n */\nexport function decodeAddressing(token: string): Addressing {\n const segments = token.split(\".\");\n if (segments.length !== 3) throw new MeetingError(\"join_token_invalid\");\n let claims: unknown;\n try {\n claims = decodeSegment(segments[1] ?? \"\");\n } catch {\n throw new MeetingError(\"join_token_invalid\");\n }\n if (typeof claims !== \"object\" || claims === null || Array.isArray(claims)) {\n throw new MeetingError(\"join_token_invalid\");\n }\n const { meeting_id: meetingId, participant_id: participantId } = claims as Record<string, unknown>;\n if (!isCanonicalUlid(meetingId) || !isCanonicalUlid(participantId)) {\n throw new MeetingError(\"join_token_invalid\");\n }\n return { meetingId, participantId };\n}\n", "import { currentEnvironment } from \"./internal/env.js\";\nimport { MeetingEngineImpl } from \"./internal/engine.js\";\nimport { SignalingOnlyMediaDelivery } from \"./internal/mediaDelivery.js\";\nimport { PeerMediaDelivery } from \"./internal/peerMediaDelivery.js\";\nimport { decodeAddressing } from \"./internal/token.js\";\nimport { MeetingError } from \"./public/errors.js\";\nimport type { MeetingEngine, MeetingEngineOptions } from \"./public/types.js\";\n\nconst DEFAULT_JOIN_TIMEOUT_MS = 15_000;\nconst MIN_JOIN_TIMEOUT_MS = 1_000;\nconst MAX_JOIN_TIMEOUT_MS = 60_000;\nconst LOOPBACK_HOSTS = new Set([\"localhost\", \"127.0.0.1\"]);\n\nfunction normalizeRealtimeUrl(value: unknown): string {\n const invalid = new TypeError(\n \"realtimeUrl must be wss://host[:port] (ws:// only for localhost) with no path, query, or fragment.\",\n );\n if (typeof value !== \"string\" || value.includes(\"?\") || value.includes(\"#\")) throw invalid;\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw invalid;\n }\n const secure = url.protocol === \"wss:\";\n const loopback = url.protocol === \"ws:\" && LOOPBACK_HOSTS.has(url.hostname);\n if (!secure && !loopback) throw invalid;\n if (url.username !== \"\" || url.password !== \"\" || (url.pathname !== \"\" && url.pathname !== \"/\")) throw invalid;\n return `${url.protocol}//${url.host}`;\n}\n\nfunction normalizeJoinTimeout(value: unknown): number {\n if (value === undefined) return DEFAULT_JOIN_TIMEOUT_MS;\n if (typeof value !== \"number\" || !Number.isInteger(value) || value < MIN_JOIN_TIMEOUT_MS || value > MAX_JOIN_TIMEOUT_MS) {\n throw new TypeError(`joinTimeoutMs must be an integer from ${MIN_JOIN_TIMEOUT_MS} to ${MAX_JOIN_TIMEOUT_MS}.`);\n }\n return value;\n}\n\n/**\n * Creates a meeting engine for one participant. Pass the join token your backend issued and the realtime\n * service URL, then call `join()`.\n *\n * @throws TypeError when `realtimeUrl` or `joinTimeoutMs` is malformed.\n * @throws MeetingError `join_token_invalid` when the token is not a valid join token, or\n * `unsupported_environment` when the browser has no WebSocket support.\n */\nexport function createMeetingEngine(options: MeetingEngineOptions): MeetingEngine {\n if (typeof options !== \"object\" || options === null) throw new TypeError(\"createMeetingEngine requires options.\");\n const realtimeUrl = normalizeRealtimeUrl(options.realtimeUrl);\n const joinTimeoutMs = normalizeJoinTimeout(options.joinTimeoutMs);\n const token: unknown = options.token;\n if (typeof token !== \"string\" || token.length === 0) throw new MeetingError(\"join_token_invalid\");\n const env = currentEnvironment();\n if (!env.WebSocket) throw new MeetingError(\"unsupported_environment\");\n const addressing = decodeAddressing(token);\n return new MeetingEngineImpl({\n token,\n realtimeUrl,\n joinTimeoutMs,\n logger: options.logger,\n addressing,\n env,\n createMediaDelivery: (mediaMode, deps) =>\n mediaMode === \"p2p\" ? new PeerMediaDelivery(deps) : new SignalingOnlyMediaDelivery(),\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["role", "role", "reject", "deferred", "iceServers", "iceServers", "sdp", "KINDS", "iceServers", "track", "sdp"]
|
|
7
|
+
}
|