/**
* hosting/webSocketFrames — the frame codec the conversation door speaks, and
* nothing else.
*
* Pure bytes in, pure bytes out: no socket, no session, no handler, no port
* vocabulary. That is what makes it testable the only way protocol code is
* worth testing — against the byte sequences the specification itself
* publishes, rather than against a client we also wrote.
*
* ── Why this file exists instead of a dependency ─────────────────────────────
* The alternative was an optional peer dependency carrying a complete
* implementation. It was rejected for a reason that is about honesty rather
* than about lines of code: `capabilities` is declared at CONSTRUCTION and is
* static thereafter, so a host whose conversation door only works when an
* optional package happens to be installed can only either claim
* `'conversation'` and then refuse to do it — the library declaring a promise
* it cannot keep, which is the one thing the capability union forbids — or
* probe `node_modules` and let feature detection depend on install state, so a
* deployment that forgot the dependency silently gets a host that quietly does
* not do conversations. The shipped adapter honours what it declares, always,
* with nothing to install. That was worth these bytes.
*
* ── What is implemented, exactly ─────────────────────────────────────────────
* The server half of RFC 6455 for a text channel: the handshake, text frames,
* continuation frames, ping/pong, and close. Payloads are unmasked on the way
* in (client frames MUST be masked) and written unmasked on the way out (server
* frames MUST NOT be), which is the asymmetry the RFC requires.
*
* ── What is NOT, and how far the verification goes ───────────────────────────
* No extensions and no compression: `permessage-deflate` is negotiated, and
* this door never negotiates it, so the RSV bits must always be zero and a peer
* that sets one is refused. No binary frames — the port carries text, and
* binary is a capability nobody has minted evidence for. No client role.
*
* Verification is: the byte vectors published in RFC 6455 §5.7, which were
* authored by the specification and not by this repository, plus a live
* exchange against the platform's own WebSocket client where the runtime has
* one, plus the conversation conformance suite over a real socket. It is **not**
* run against the Autobahn test suite, and this file does not claim more
* coverage than the tests beside it actually execute.
*
* Pattern: pure codec. Role: innermost ring — imports nothing from this package.
*/
///
///
/** The frame kinds this door speaks. Numbers, because the wire uses numbers. */
export declare const OPCODE: {
readonly continuation: 0;
readonly text: 1;
readonly binary: 2;
readonly close: 8;
readonly ping: 9;
readonly pong: 10;
};
/**
* Close codes this door produces. The RFC's own numbers, named — a bare `1009`
* in a branch is a fact nobody can check without opening the specification.
*/
export declare const CLOSE_CODE: {
/** Ordinary end: the work is done. */
readonly normal: 1000;
/** The host is shutting down. */
readonly goingAway: 1001;
/** The peer broke the protocol. */
readonly protocolError: 1002;
/** Data this endpoint cannot accept — a binary frame, here. */
readonly unsupportedData: 1003;
/** Reserved: never sent on the wire, used only as "we were not told". */
readonly noStatus: 1005;
/** Text that is not valid UTF-8. */
readonly invalidPayload: 1007;
/** Past a declared ceiling. */
readonly tooBig: 1009;
/**
* Something went wrong on THIS side — the RFC's own word for a condition
* that stopped this endpoint fulfilling the request. Used where the fault is
* demonstrably not the peer's, so that a close code never blames them for it.
*/
readonly internalError: 1011;
};
/** One frame, as it came off the wire, already unmasked. */
export interface WebSocketFrame {
/** Last frame of its message? */
readonly fin: boolean;
/** One of {@link OPCODE}. */
readonly opcode: number;
/** The unmasked payload. */
readonly payload: Buffer;
}
/**
* A peer that broke the protocol, carrying the close code the RFC names for
* that breakage — so the caller does not have to re-derive which number means
* what at the point it has to write one.
*/
export declare class FrameProtocolError extends Error {
readonly closeCode: number;
constructor(closeCode: number, message: string);
}
/**
* The `Sec-WebSocket-Accept` value for a client's `Sec-WebSocket-Key`:
* base64(sha1(key + GUID)). Deterministic, and pinned against the RFC's own
* worked example.
*/
export declare function acceptKey(clientKey: string): string;
/**
* The 101 response, as bytes.
*
* `protocol` is echoed only when the caller selected one. Echoing a subprotocol
* the client did not offer would make the client fail the connection, so
* choosing one is the wire's job (it read the offer) and not this function's.
*/
export declare function handshakeResponse(clientKey: string, protocol?: string): Buffer;
/**
* One frame, ready to write. **Never masked**: a server that masks its frames
* is a server the client closes on, per RFC 6455 §5.1.
*/
export declare function encodeFrame(opcode: number, payload: Buffer, fin?: boolean): Buffer;
/** A text frame carrying one whole message. */
export declare function encodeText(text: string): Buffer;
/**
* A close frame carrying a code and, when there is one, a reason.
*
* The reason is truncated to 123 bytes because a control frame's payload may
* not exceed 125 and the code takes two of them. Truncating a REASON is safe in
* a way truncating a message never is: it is diagnostic prose about an ending
* that has already been decided.
*/
export declare function encodeClose(code: number, reason?: string): Buffer;
/** What a close frame said, pulled apart. */
export interface CloseFramePayload {
/** The peer's code, or `noStatus` when it sent none — which is legal. */
readonly code: number;
/** The peer's words, when it sent any. */
readonly reason?: string;
}
/** Read a close frame's payload. An empty payload is "no status", never an error. */
export declare function decodeClose(payload: Buffer): CloseFramePayload;
/** Is this one of the three control opcodes? */
export declare function isControlFrame(opcode: number): boolean;
/**
* Turns a stream of TCP chunks into whole frames.
*
* Stateful by necessity — a frame arrives in as many pieces as the network
* feels like, and two frames arrive in one piece just as often. Every branch
* that gives up does so by throwing a {@link FrameProtocolError} carrying the
* code to close with, so the layer above never has to invent one.
*/
export declare class FrameReader {
private buffered;
private readonly maxFrameBytes;
/**
* @param maxFrameBytes The declared ceiling, when there is one. Checked
* against the length in the HEADER — before the payload is buffered, so an
* announced 4GB frame costs nothing to refuse.
*/
constructor(maxFrameBytes?: number);
/** Feed one chunk; get back every frame that completed. */
push(chunk: Buffer): WebSocketFrame[];
/** One frame, or `undefined` when the bytes for a whole one are not here yet. */
private readOne;
}
/**
* Decode a whole message's bytes as UTF-8, refusing anything that is not.
*
* Strict on purpose (RFC 6455 §8.1): a text frame that is not valid UTF-8 is a
* protocol violation, and the lenient alternative silently replaces the bad
* bytes with `U+FFFD` — handing the consumer a string the far side never sent
* and no way to know it happened.
*/
export declare function decodeText(payload: Buffer): string;
//# sourceMappingURL=webSocketFrames.d.ts.map