/** * T0 — typed error classes for relay-e2e (PLAN_RELAY_E2E §3 T0). * * Every error subclasses {@link E2EError} and carries a stable, greppable `code`. Per INV9, * a thrown message MUST NEVER embed key/nonce/plaintext material — callers surface the code, * not secret bytes. No `console` here; the caller decides how to handle. */ /** Base class for all relay-e2e crypto errors. */ export class E2EError extends Error { readonly code: string constructor(code: string, message: string) { super(message) this.name = new.target.name this.code = code } } /** Pinned enroll_fpr / registry pubkey disagreement ⇒ MITM abort (§4d). */ export class FingerprintMismatchError extends E2EError { constructor(message = 'host fingerprint mismatch') { super('E2E_FINGERPRINT_MISMATCH', message) } } /** AEAD tag verification failed ⇒ drop the frame and tear the session down. */ export class AeadOpenError extends E2EError { constructor(message = 'AEAD authentication failed') { super('E2E_AEAD_OPEN', message) } } /** Sequence number non-monotonic / duplicate / reordered / gapped (INV13). */ export class ReplayError extends E2EError { constructor(message = 'sequence replay/reorder rejected') { super('E2E_REPLAY', message) } } /** Illegal handshake transition, wrong phase, or unusable negotiation. */ export class HandshakeStateError extends E2EError { constructor(message = 'illegal handshake state transition') { super('E2E_HANDSHAKE_STATE', message) } } /** Malformed wire bytes / unsupported version / bad AEAD id. */ export class EnvelopeFormatError extends E2EError { constructor(message = 'malformed envelope') { super('E2E_ENVELOPE_FORMAT', message) } } /** No WebCrypto / CSPRNG available in the host environment (fail-fast boundary). */ export class CryptoUnavailableError extends E2EError { constructor(message = 'WebCrypto is unavailable in this environment') { super('E2E_CRYPTO_UNAVAILABLE', message) } }