import type { LibCrypto } from "../../cryptography/libcrypto"; import type { RatchetState } from "../../cryptography/ratchet"; import type { RatchetGateLease } from "../../handlers/ratchetGate"; import type { CoverRuntime } from "../../handlers/coverRuntime"; import type { SparsePqHealingState } from "../../handlers/pqHealingRuntime"; import type { PeerHandshakeFailureReason } from "../../reducers/roomSlice"; import type { PeerSocketGenerationSource } from "./peerSocketGeneration"; export interface IRTCPeerConnection extends RTCPeerConnection { /** The room this transport belongs to. A room/peer pair owns one PC. */ roomId: string; withPeerId: string; withPeerPublicKey: string; /** * The peer signaling socket this transport was built against. A different * generation for the same peerId means the peer's session was replaced, and * this transport can never be signalled again (C1). Absent against a * pre-generation server, where it must never be read as a change. */ peerSocketGeneration?: string; makingOffer: boolean; ignoreOffer: boolean; receiveMessageModule: LibCrypto; iceCandidates: RTCIceCandidateInit[]; /** Persistent control channel for this room/peer transport. */ mainChannel?: IRTCDataChannel; /** Gate ownership captured when this concrete transport is created. */ ratchetGateLease: RatchetGateLease; /** * Set when this edge's handshake failed for a reason a fresh transport * cannot fix (a wrong PIN, a PIN throttle, a policy/suite mismatch). The * `main` channel's close handler consults it so a terminal failure is never * followed by a re-dial. Cleared only by building a new transport. */ handshakeTerminalFailure?: PeerHandshakeFailureReason; /** * How many times this RTCPeerConnection has been re-bound IN PLACE onto a * new remote DTLS certificate since it last authenticated. The re-bind * budget (see decideRemoteTransportChangeResponse) reads it to guarantee * that a peer which keeps presenting fresh certificates converges on a * replacement transport instead of looping; the handshake success path * clears it. */ remoteTransportRebinds: number; /** * Deadline armed by the in-place re-bind above: if this transport has not * re-authenticated when it fires, the edge is torn down and rebuilt instead * of waiting out the peer's 30 s handshake step timeout. Cleared by the * handshake success path, by the teardown, and re-armed by a later re-bind. */ rebindDeadline?: ReturnType; /** * The `clearTimeout` that matches whatever scheduled `rebindDeadline`. The * arming site owns the scheduler (tests inject one), while the clearing * sites — handshake success, peer teardown — only hold the connection. */ rebindDeadlineClear?: (handle: ReturnType) => void; /** Resolves once the per-transport WASM dependency is ready. */ initialization?: Promise; /** * Re-proves signaling and applies the latest room ICE configuration before * any restart. Installed by the connection owner and shared by repair paths. */ ensureFreshIceConfiguration?: () => Promise; ratchetState?: RatchetState; ratchetEstablished?: Promise; messageKeyCache?: Map; /** Maps a live transfer root to its `(dhPub,N)` receive-cache key for cancel cleanup. */ messageKeyByMerkleRoot?: Map; /** All configured non-main channels, including connecting channels. */ messageChannels?: Set; /** * Protocol-v4 atomic edge checkpoint hook. The PQ runtime installs this * store-free serializer before the initial ratchet row is committed. */ serializeEdgeCryptoState?: () => Uint8Array; /** * Protocol-v4 live sparse-PQ runtime for this authenticated edge. Installed * synchronously with `ratchetState` after the initial row (ratchet + PQ * checkpoint) is durable; destroyed with it on teardown/replacement. */ pqHealingState?: SparsePqHealingState; /** * Protocol-v4 scheduled-cover runtime, present ONLY on edges of rooms whose * authenticated policy selects `coverMode: "scheduled"`. Its presence is the * scheduled-mode signal for the send/receive/receipt/cancel paths. */ coverRuntime?: CoverRuntime; /** * Protocol-v4 scheduled-cover lanes for this edge (both the outbound lanes * this peer opens and the inbound lanes the peer opens). Kept SEPARATE from * `messageChannels` so continuous cover lanes never block healing quiescence * or exhaust the per-edge message-channel budget; cells route purely by type. */ coverChannels?: Set; } export interface IRTCDataChannel extends RTCDataChannel { withPeerId: string; /** A data channel belongs to exactly one room. */ roomIds: [string]; /** Releases queue/channel accounting even when teardown nulls onclose. */ releaseProtocolResources?: () => void; /** * Abort an inbound message pipeline, retire its persisted receive key, and * delete its storage artifacts after the active handler reaches quiescence. */ cancelReceiveTransfer?: () => Promise; /** * Set by any close THIS side initiated (the pre-authentication frame guard, * the transfer's terminal-close runner, the resume path's cleanup). Read by * `isAuthenticatedPeerCancel` so our own close is never reported as the peer * cancelling the transfer (C7). */ closedLocally?: boolean; } export interface IRTCMessage { id: string; message: string; fromPeerId: string; toPeerId: string; channelLabel: string; timestamp: Date; } export interface IRTCIceCandidate extends RTCIceCandidateInit { roomId: string; withPeerId: string; } export interface RTCPeerConnectionParams { peerId: string; peerPublicKey: string; roomId: string; rtcConfig?: RTCConfiguration; /** The peer's signaling-socket generation, as last named by the server. */ peerSocketGeneration?: string; /** * Which inbound frame named that generation. Only a `connection` frame * proves a fresh remote transport; a roster introduction is record-only * while this side's transport is connected (see peerSocketGeneration). * Omitted means advisory. */ peerSocketGenerationSource?: PeerSocketGenerationSource; } export interface RTCSetDescriptionParams { peerId: string; peerPublicKey: string; roomId: string; description: RTCSessionDescription; rtcConfig?: RTCConfiguration; } export interface RTCSetCandidateParams { peerId: string; roomId: string; candidate: RTCIceCandidateInit | RTCIceCandidate; } export interface RTCApplyRoomConfigurationParams { roomId: string; rtcConfig: RTCConfiguration; /** Gather a new ICE generation after every live PC accepts the config. */ restartIce?: boolean; /** Expiry must close on failure; rollback would restore expired secrets. */ failurePolicy?: "rollback" | "close"; } export interface RTCOpenChannelParams { roomId: string; channel: string | RTCDataChannel; withPeers?: { peerId: string; peerPublicKey: string; }[]; } export interface RTCSendMessageParams { /** Random 32-byte lowercase-hex identity allocated by the public API. */ transferId: string; data?: string | File; label: string; roomId: string; minChunks?: number; chunkSize?: number; percentageFilledChunk?: number; metadataSchemaVersion?: number; } export interface RTCRoomInfoParams { roomId: string; } export interface ChannelData { label: string; peerId: string; } export interface PeerData { peerId: string; peerPublicKey: string; } export interface MessageData extends IRTCMessage { channel: string; } export interface RoomData { roomId: string; peers: PeerData[]; channels: ChannelData[]; messages: MessageData[]; } export interface RTCDisconnectParams { alsoDeleteDB: boolean; } export interface RTCDisconnectFromRoomParams { roomId: string; deleteMessages?: boolean; } export interface RTCDisconnectFromAllRoomsParams { deleteMessages?: boolean; exceptionRoomIds?: string[]; } export interface RTCDisconnectFromPeerParams { peerId: string; /** When present, tear down only this room/peer transport. */ roomId?: string; alsoDeleteData?: boolean; } /** Internal dependency injected into bulk teardown queries to avoid API cycles. */ export type DisconnectPeerTransport = (params: RTCDisconnectFromPeerParams) => Promise; export interface RTCDisconnectFromChannelLabelParams { roomId: string; label: string; messageHash?: Uint8Array; alsoDeleteData?: boolean; alsoSendFinishedMessage?: boolean; } export interface RTCDisconnectFromPeerChannelLabelParams { roomId: string; peerId: string; label: string; messageHash?: Uint8Array; alsoDeleteData?: boolean; alsoSendFinishedMessage?: boolean; /** Internal exact-object selector; prevents a stale callback closing a replacement. */ channel?: IRTCDataChannel; }