Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
71 lines
2.7 KiB
JavaScript
71 lines
2.7 KiB
JavaScript
"use strict";
|
|
|
|
const schema = require("./generated/plugin-contract.schema.json");
|
|
const { assertTerminalInterceptorFrameSchema } = require("./contractValidator.cjs");
|
|
|
|
const limits = schema.$defs.TerminalInterceptorLimits.const;
|
|
const TERMINAL_INTERCEPTOR_MAX_CHUNK_BYTES = limits.maxChunkBytes;
|
|
const TERMINAL_INTERCEPTOR_MAX_WINDOW_BYTES = limits.maxWindowBytes;
|
|
const arrayBufferByteLength = Object.getOwnPropertyDescriptor(
|
|
ArrayBuffer.prototype,
|
|
"byteLength",
|
|
)?.get;
|
|
|
|
function copyOwnDataRecord(value, label) {
|
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
throw new TypeError(`${label} must be a plain object`);
|
|
}
|
|
const copy = {};
|
|
for (const key of Object.keys(value)) {
|
|
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
if (!descriptor || !("value" in descriptor)) {
|
|
throw new TypeError(`${label} must contain data properties only`);
|
|
}
|
|
copy[key] = descriptor.value;
|
|
}
|
|
return copy;
|
|
}
|
|
|
|
function transferredByteLength(value) {
|
|
if (!arrayBufferByteLength) throw new TypeError("ArrayBuffer byteLength getter is unavailable");
|
|
try {
|
|
const byteLength = arrayBufferByteLength.call(value);
|
|
// The intrinsic getter reports zero for a detached zero-length buffer as
|
|
// well as for a valid empty buffer. Constructing a view distinguishes the
|
|
// two and also works for ArrayBuffers created in another realm.
|
|
new Uint8Array(value);
|
|
return byteLength;
|
|
} catch {
|
|
throw new TypeError("Terminal interceptor transfer requires a real, attached ArrayBuffer");
|
|
}
|
|
}
|
|
|
|
function createTerminalInterceptorEnvelope(frameValue, transfer) {
|
|
const frame = copyOwnDataRecord(frameValue, "Terminal interceptor frame");
|
|
assertTerminalInterceptorFrameSchema(frame);
|
|
const requiresTransfer = frame.type === "netcatty:terminal-interceptor:chunk"
|
|
|| (frame.type === "netcatty:terminal-interceptor:result" && frame.status === "ok");
|
|
if (!requiresTransfer) {
|
|
if (transfer !== undefined) {
|
|
throw new TypeError("This terminal interceptor frame must not include a transferred buffer");
|
|
}
|
|
return Object.freeze({ frame: Object.freeze(frame) });
|
|
}
|
|
if (transfer === undefined) {
|
|
throw new TypeError("This terminal interceptor frame requires a transferred ArrayBuffer");
|
|
}
|
|
const byteLength = transferredByteLength(transfer);
|
|
if (byteLength !== frame.byteLength) {
|
|
throw new RangeError(
|
|
`Terminal interceptor byteLength mismatch: declared ${frame.byteLength}, received ${byteLength}`,
|
|
);
|
|
}
|
|
return Object.freeze({ frame: Object.freeze(frame), transfer });
|
|
}
|
|
|
|
module.exports = {
|
|
TERMINAL_INTERCEPTOR_MAX_CHUNK_BYTES,
|
|
TERMINAL_INTERCEPTOR_MAX_WINDOW_BYTES,
|
|
createTerminalInterceptorEnvelope,
|
|
};
|