Files
paseo/packages/protocol/src/binary-frames/demux.test.ts
T
Mohamed Boudra 9c926ed126 fix(terminal): preserve 10,000 rows with direct ANSI replay (#8282)
Restore configured terminal history on reconnect, retaining 10,000 rows plus the screen. Serialize the worker-owned xterm buffer directly to ANSI and forward negotiated bounded replay chunks while preserving ANSI-era clients and per-viewer live ordering.

Preserve captured geometry through replay, bound pressure recovery to 500 rows, and keep the omitted visible-history default at 200. Remove the full cell-grid copy and obsolete JSON rendering.

All 21 CI checks pass. Real browser, native Debug emulator/simulator and Linux Electron coverage and platform limits are documented in the PR. The Android Debug invalid native delegate dispatch also reproduces on upstream main; its cause and any change in frequency remain unproven.

Credit Manav Dhindsa (DrakenKor), #6139 and #6148, and Lennart Schoch, #6743, for prior ANSI replay and retention work informing this change.

Closes #6137.
Closes #6147.
2026-10-31 10:51:45 +07:00

107 lines
3.4 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
decodeBinaryFrame,
encodeHostRouteFrame,
decodeHostRouteFrame,
MAX_HOST_ROUTE_ID_BYTES,
encodeFileTransferFrame,
encodeTerminalStreamFrame,
FileTransferOpcode,
TerminalStreamOpcode,
} from "./index.js";
describe("binary frame demux", () => {
it("routes terminal frames by opcode", () => {
expect(
decodeBinaryFrame(
encodeTerminalStreamFrame({
opcode: TerminalStreamOpcode.Input,
slot: 7,
payload: "ls",
}),
),
).toEqual({
kind: "terminal",
frame: {
opcode: TerminalStreamOpcode.Input,
slot: 7,
payload: new TextEncoder().encode("ls"),
},
});
});
it("routes file-transfer frames by opcode", () => {
expect(
decodeBinaryFrame(
encodeFileTransferFrame({
opcode: FileTransferOpcode.FileChunk,
requestId: "req-upload",
payload: new TextEncoder().encode("hello"),
}),
),
).toEqual({
kind: "file_transfer",
frame: {
opcode: FileTransferOpcode.FileChunk,
requestId: "req-upload",
payload: new TextEncoder().encode("hello"),
},
});
});
it("rejects unknown binary opcodes", () => {
expect(decodeBinaryFrame(new Uint8Array([0xff, 0]))).toBeNull();
});
});
describe("host route binary framing", () => {
it("wraps terminal and file frames unchanged and leaves their direct interpretation intact", () => {
const frames = [
encodeTerminalStreamFrame({ opcode: TerminalStreamOpcode.Input, slot: 7, payload: "echo" }),
encodeFileTransferFrame({
opcode: FileTransferOpcode.FileChunk,
requestId: "upload",
payload: new Uint8Array([0, 255, 128, 1]),
}),
];
for (const payload of frames) {
const wire = encodeHostRouteFrame("channel", payload);
const decoded = decodeBinaryFrame(wire);
expect(decoded).toEqual({ kind: "host_route", frame: { routeId: "channel", payload } });
expect(wire.subarray(10)).toEqual(payload);
expect(decodeBinaryFrame(decodeHostRouteFrame(wire)!.payload)).toEqual(
decodeBinaryFrame(payload),
);
}
});
it("rejects truncated, oversized identifiers and invalid UTF-8 without throwing", () => {
for (const bytes of [
new Uint8Array([0x30]),
new Uint8Array([0x30, 0, 4, 65]),
new Uint8Array([0x30, 0, 0]),
new Uint8Array([0x30, 1, 1]),
new Uint8Array([0x30, 0, 1, 255]),
])
expect(decodeBinaryFrame(bytes)).toBeNull();
expect(() =>
encodeHostRouteFrame("a".repeat(MAX_HOST_ROUTE_ID_BYTES + 1), new Uint8Array()),
).toThrow("Invalid host route ID");
});
});
it.each([
TerminalStreamOpcode.ReplayBegin,
TerminalStreamOpcode.ReplayData,
TerminalStreamOpcode.ReplayEnd,
])("decodes replay opcode %s directly and inside a host route", (opcode) => {
const payload = new TextEncoder().encode("界 replay");
const bytes = encodeTerminalStreamFrame({ opcode, slot: 12, payload });
const expected = { kind: "terminal", frame: { opcode, slot: 12, payload } };
expect(decodeBinaryFrame(bytes)).toEqual(expected);
const routed = decodeBinaryFrame(encodeHostRouteFrame("host", bytes));
expect(routed?.kind).toBe("host_route");
if (routed?.kind !== "host_route") throw new Error("Missing host route");
expect(decodeBinaryFrame(routed.frame.payload)).toEqual(expected);
});