Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,113 @@
/**
* SDP offer / answer primitives.
*
* Pure async wrappers over the spec-standard
* `pc.createOffer() → pc.setLocalDescription()` pattern (and inverse).
* Every failure mode is translated into `DriveWebRtcError(PEER_HANDSHAKE_FAILED)`
* with the original DOMException attached as `cause` so callers never see
* raw browser errors leak past the package boundary.
*/
import {
DRIVE_WEBRTC_CODES,
DriveWebRtcError,
} from "../../error-codes/error-codes.js";
function throwIfAborted(signal: AbortSignal | undefined, where: string): void {
if (signal?.aborted === true) {
throw new DriveWebRtcError(
DRIVE_WEBRTC_CODES.PEER_HANDSHAKE_FAILED,
`${where} aborted`
);
}
}
function wrap(cause: unknown, message: string): DriveWebRtcError {
return new DriveWebRtcError(
DRIVE_WEBRTC_CODES.PEER_HANDSHAKE_FAILED,
message,
{ cause: cause as Error }
);
}
/**
* Create an SDP offer on `pc`, apply it as local description, and return it.
*/
export async function createOffer(
pc: RTCPeerConnection,
signal?: AbortSignal
): Promise<RTCSessionDescriptionInit> {
throwIfAborted(signal, "createOffer");
let offer: RTCSessionDescriptionInit;
try {
offer = await pc.createOffer();
} catch (cause) {
throw wrap(cause, "RTCPeerConnection.createOffer failed");
}
throwIfAborted(signal, "createOffer");
try {
await pc.setLocalDescription(offer);
} catch (cause) {
throw wrap(
cause,
"RTCPeerConnection.setLocalDescription(offer) failed"
);
}
return offer;
}
/**
* Apply a remote offer to `pc`, create an answer, apply it as local
* description, and return the answer.
*/
export async function handleOffer(
pc: RTCPeerConnection,
offer: RTCSessionDescriptionInit,
signal?: AbortSignal
): Promise<RTCSessionDescriptionInit> {
throwIfAborted(signal, "handleOffer");
try {
await pc.setRemoteDescription(offer);
} catch (cause) {
throw wrap(
cause,
"RTCPeerConnection.setRemoteDescription(offer) failed"
);
}
throwIfAborted(signal, "handleOffer");
let answer: RTCSessionDescriptionInit;
try {
answer = await pc.createAnswer();
} catch (cause) {
throw wrap(cause, "RTCPeerConnection.createAnswer failed");
}
throwIfAborted(signal, "handleOffer");
try {
await pc.setLocalDescription(answer);
} catch (cause) {
throw wrap(
cause,
"RTCPeerConnection.setLocalDescription(answer) failed"
);
}
return answer;
}
/**
* Apply a remote answer to an outbound offer we already sent.
*/
export async function handleAnswer(
pc: RTCPeerConnection,
answer: RTCSessionDescriptionInit,
signal?: AbortSignal
): Promise<void> {
throwIfAborted(signal, "handleAnswer");
try {
await pc.setRemoteDescription(answer);
} catch (cause) {
throw wrap(
cause,
"RTCPeerConnection.setRemoteDescription(answer) failed"
);
}
}