[Init] Initial commit - NetMesh terminal manager
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

This commit is contained in:
2026-09-13 18:24:01 +08:00
commit 3c72efcb7f
3255 changed files with 907009 additions and 0 deletions

View File

@@ -0,0 +1,430 @@
"use strict";
const {
PLUGIN_RPC_DEFAULT_TIMEOUT_MS,
PLUGIN_RPC_MAX_PENDING,
} = require("./constants.cjs");
const { assertStreamFrameSchema } = require("./contractValidator.cjs");
let contractRuntimePromise;
function loadContractRuntime() {
contractRuntimePromise ??= import("@netcatty/plugin-contract");
return contractRuntimePromise;
}
function getTransferredBuffer(envelope) {
return envelope && Object.prototype.hasOwnProperty.call(envelope, "transfer")
? envelope.transfer
: undefined;
}
function assertStreamEnvelopeShape(envelope) {
if (!envelope || typeof envelope !== "object" || Array.isArray(envelope)) {
throw new TypeError("Invalid plugin stream envelope");
}
const keys = Reflect.ownKeys(envelope);
if (keys.some((key) => typeof key !== "string" || (key !== "frame" && key !== "transfer"))) {
throw new TypeError("Plugin stream envelope contains unknown properties");
}
for (const key of keys) {
const descriptor = Object.getOwnPropertyDescriptor(envelope, key);
if (!descriptor || !("value" in descriptor) || !descriptor.enumerable) {
throw new TypeError("Plugin stream envelope must contain enumerable data properties");
}
}
if (!Object.hasOwn(envelope, "frame")) throw new TypeError("Plugin stream envelope is missing its frame");
return envelope;
}
function raceWithSignal(operation, signal) {
if (signal.aborted) return Promise.reject(signal.reason);
return new Promise((resolve, reject) => {
const onAbort = () => reject(signal.reason);
signal.addEventListener("abort", onAbort, { once: true });
operation.then(
(value) => {
signal.removeEventListener("abort", onAbort);
resolve(value);
},
(error) => {
signal.removeEventListener("abort", onAbort);
reject(error);
},
);
});
}
class PluginStreamRouter {
constructor(options) {
this.send = options.send;
this.onIncomingStream = options.onIncomingStream ?? (() => false);
this.incoming = new Map();
this.outgoing = new Map();
this.maxStreams = options.maxStreams ?? PLUGIN_RPC_MAX_PENDING;
this.openTimeoutMs = options.openTimeoutMs ?? PLUGIN_RPC_DEFAULT_TIMEOUT_MS;
this.closed = false;
}
async accept(rawEnvelope) {
if (this.closed) throw new Error("Plugin stream router is closed");
assertStreamEnvelopeShape(rawEnvelope);
assertStreamFrameSchema(rawEnvelope.frame);
const contract = await loadContractRuntime();
if (this.closed) throw new Error("Plugin stream router is closed");
const envelope = contract.createMessagePortStreamEnvelope(
rawEnvelope.frame,
getTransferredBuffer(rawEnvelope),
);
const frame = envelope.frame;
if (frame.kind === "open") {
if (
this.incoming.has(frame.streamId)
|| this.outgoing.has(frame.streamId)
|| this.incoming.size + this.outgoing.size >= this.maxStreams
) {
throw new Error(`Plugin stream cannot be opened: ${frame.streamId}`);
}
const state = {
streamId: frame.streamId,
nextSequence: 1,
availableBytes: frame.windowBytes,
updateSequence: -1,
openController: new AbortController(),
closed: false,
};
this.incoming.set(frame.streamId, state);
let accepted;
let openTimedOut = false;
const openTimer = setTimeout(() => {
openTimedOut = true;
state.openController.abort(new Error(`Plugin stream owner timed out: ${frame.streamId}`));
}, this.openTimeoutMs);
try {
accepted = await raceWithSignal(Promise.resolve(this.onIncomingStream({
streamId: frame.streamId,
windowBytes: frame.windowBytes,
signal: state.openController.signal,
bind: (handlers) => this.bindIncoming(frame.streamId, handlers),
cancel: () => this.#cancelIncoming(state),
})), state.openController.signal);
} catch (error) {
if (!this.closed) {
try {
await this.#cancelIncoming(state, error);
} catch {
// The owner-selection error remains the primary protocol failure.
}
} else {
state.closed = true;
this.incoming.delete(frame.streamId);
}
if (openTimedOut) return;
throw error;
} finally {
clearTimeout(openTimer);
}
if (accepted !== true) {
await this.#cancelIncoming(state, new Error(`Plugin stream was not accepted: ${frame.streamId}`));
}
return;
}
if (frame.kind === "windowUpdate") {
const outgoing = this.outgoing.get(frame.streamId);
if (!outgoing) throw new Error(`Unknown outgoing plugin stream: ${frame.streamId}`);
if (frame.sequence !== outgoing.lastUpdateSequence + 1) {
throw new Error(`Out-of-order stream credit update: ${frame.streamId}`);
}
outgoing.lastUpdateSequence = frame.sequence;
outgoing.availableBytes += frame.creditBytes;
if (outgoing.availableBytes > outgoing.maxCreditBytes) {
throw new Error(`Plugin stream credit exceeds its negotiated window: ${frame.streamId}`);
}
if (outgoing.terminalKind === "end") {
if (outgoing.availableBytes === outgoing.maxCreditBytes) {
this.outgoing.delete(frame.streamId);
}
return;
}
if (outgoing.closed) throw new Error(`Unknown outgoing plugin stream: ${frame.streamId}`);
this.#flushOutgoing(outgoing);
return;
}
if (frame.kind === "cancel" && this.outgoing.has(frame.streamId)) {
const outgoing = this.outgoing.get(frame.streamId);
if (frame.sequence !== Math.max(1, outgoing.lastUpdateSequence + 1)) {
throw new Error(`Out-of-order stream cancellation: ${frame.streamId}`);
}
outgoing.closed = true;
this.outgoing.delete(frame.streamId);
for (const pending of outgoing.queue) pending.reject(new Error(`Plugin stream cancelled: ${frame.streamId}`));
outgoing.queue.length = 0;
return;
}
const state = this.incoming.get(frame.streamId);
if (!state || state.closed) throw new Error(`Unknown incoming plugin stream: ${frame.streamId}`);
if (frame.sequence !== state.nextSequence) {
throw new Error(`Out-of-order plugin stream frame: ${frame.streamId}`);
}
state.nextSequence += 1;
if (frame.kind === "chunk") {
const creditBytes = frame.data.byteLength;
if (creditBytes > state.availableBytes) {
throw new Error(`Plugin stream exceeded receive credit: ${frame.streamId}`);
}
state.availableBytes -= creditBytes;
const materialized = contract.materializeStreamChunk(frame.data, envelope.transfer);
const listener = state.onChunk;
if (!listener) {
await this.#cancelIncoming(state);
return;
}
let released = false;
const release = () => {
if (released || state.closed) return;
released = true;
state.availableBytes += creditBytes;
state.updateSequence += 1;
try {
this.send({
frame: {
streamId: state.streamId,
sequence: state.updateSequence,
kind: "windowUpdate",
creditBytes,
},
});
} catch (error) {
state.closed = true;
this.incoming.delete(state.streamId);
state.openController.abort(error);
try {
const closing = state.onClose?.(error);
if (closing && typeof closing.then === "function") void closing.catch(() => {});
} catch {}
throw error;
}
};
await listener(materialized, release);
return;
}
state.closed = true;
this.incoming.delete(frame.streamId);
const closeReason = frame.kind === "error" ? frame.error : frame.kind;
const abortReason = frame.kind === "error"
? frame.error
: new Error(`Plugin stream ${frame.kind}: ${frame.streamId}`);
state.openController.abort(abortReason);
await state.onClose?.(closeReason);
}
bindIncoming(streamId, handlers) {
const state = this.incoming.get(streamId);
if (!state || state.closed) throw new Error(`Unknown incoming plugin stream: ${streamId}`);
if (!handlers || typeof handlers !== "object" || Array.isArray(handlers)) {
throw new TypeError("Plugin incoming stream handlers must be an object");
}
if (typeof handlers.onChunk !== "function") {
throw new TypeError("Plugin incoming stream onChunk handler is required");
}
if (handlers.onClose != null && typeof handlers.onClose !== "function") {
throw new TypeError("Plugin incoming stream onClose handler must be a function");
}
state.onChunk = handlers.onChunk;
state.onClose = handlers.onClose;
}
async openOutgoing(streamId, windowBytes) {
if (
this.closed
|| this.outgoing.has(streamId)
|| this.incoming.has(streamId)
|| this.incoming.size + this.outgoing.size >= this.maxStreams
) {
throw new Error(`Plugin stream cannot be opened: ${streamId}`);
}
const contract = await loadContractRuntime();
if (
this.closed
|| this.outgoing.has(streamId)
|| this.incoming.has(streamId)
|| this.incoming.size + this.outgoing.size >= this.maxStreams
) {
throw new Error(`Plugin stream cannot be opened: ${streamId}`);
}
const envelope = contract.createMessagePortStreamEnvelope({
streamId,
sequence: 0,
kind: "open",
windowBytes,
});
const state = {
streamId,
nextSequence: 1,
availableBytes: windowBytes,
maxCreditBytes: windowBytes,
lastUpdateSequence: -1,
contract,
queue: [],
queuedBytes: 0,
closed: false,
terminalKind: null,
};
this.outgoing.set(streamId, state);
try {
this.send(envelope);
} catch (error) {
state.closed = true;
this.outgoing.delete(streamId);
throw error;
}
return {
write: (data) => this.#queueOutgoing(state, data),
end: () => this.#endOutgoing(state),
cancel: () => this.#cancelOutgoing(state),
};
}
async #queueOutgoing(state, data) {
if (state.closed) throw new Error(`Plugin stream is closed: ${state.streamId}`);
const contract = await loadContractRuntime();
if (this.closed || state.closed || this.outgoing.get(state.streamId) !== state) {
throw new Error(`Plugin stream is closed: ${state.streamId}`);
}
let chunk;
if (data instanceof Uint8Array) {
const copy = new Uint8Array(data.byteLength);
copy.set(data);
const buffer = copy.buffer;
if (buffer.byteLength > contract.PLUGIN_STREAM_MAX_CHUNK_BYTES) {
throw new Error(`Plugin stream chunk exceeds ${contract.PLUGIN_STREAM_MAX_CHUNK_BYTES} bytes`);
}
chunk = { encoding: "transfer", byteLength: buffer.byteLength, transfer: buffer };
} else {
chunk = contract.createJsonStreamChunk(data);
}
if (state.queuedBytes + chunk.byteLength > state.maxCreditBytes) {
throw new Error(`Plugin stream pending queue exceeds its negotiated window: ${state.streamId}`);
}
return new Promise((resolve, reject) => {
state.queue.push({ chunk, resolve, reject });
state.queuedBytes += chunk.byteLength;
this.#flushOutgoing(state);
});
}
#flushOutgoing(state) {
while (!state.closed && state.queue.length > 0) {
const pending = state.queue[0];
if (pending.chunk.byteLength > state.availableBytes) break;
state.queue.shift();
state.queuedBytes -= pending.chunk.byteLength;
state.availableBytes -= pending.chunk.byteLength;
const frame = {
streamId: state.streamId,
sequence: state.nextSequence,
kind: "chunk",
data: pending.chunk.encoding === "transfer"
? { encoding: "transfer", byteLength: pending.chunk.byteLength }
: pending.chunk,
};
state.nextSequence += 1;
try {
const envelope = state.contract.createMessagePortStreamEnvelope(frame, pending.chunk.transfer);
this.send(envelope, pending.chunk.transfer ? [pending.chunk.transfer] : []);
pending.resolve();
} catch (error) {
pending.reject(error);
this.#failOutgoing(state, error);
throw error;
}
}
}
#failOutgoing(state, error) {
if (state.closed) return;
state.closed = true;
this.outgoing.delete(state.streamId);
for (const pending of state.queue) pending.reject(error);
state.queue.length = 0;
state.queuedBytes = 0;
}
#finishOutgoing(state, kind) {
if (state.closed) return;
state.closed = true;
state.terminalKind = kind;
const error = new Error(`Plugin stream ${kind}`);
let terminalSent = false;
try {
this.send(state.contract.createMessagePortStreamEnvelope({
streamId: state.streamId,
sequence: state.nextSequence,
kind,
}));
terminalSent = true;
} finally {
for (const pending of state.queue) pending.reject(error);
state.queue.length = 0;
state.queuedBytes = 0;
if (
!terminalSent
|| kind !== "end"
|| state.availableBytes === state.maxCreditBytes
) {
this.outgoing.delete(state.streamId);
}
}
}
#endOutgoing(state) {
if (state.queue.length > 0) throw new Error("Cannot end a plugin stream with pending backpressure");
this.#finishOutgoing(state, "end");
}
#cancelOutgoing(state) {
this.#finishOutgoing(state, "cancel");
}
async #cancelIncoming(state, reason = new Error(`Plugin stream cancelled: ${state.streamId}`)) {
if (state.closed) return;
state.closed = true;
this.incoming.delete(state.streamId);
state.openController.abort(reason);
state.updateSequence = Math.max(1, state.updateSequence + 1);
let sendError;
try {
this.send({ frame: { streamId: state.streamId, sequence: state.updateSequence, kind: "cancel" } });
} catch (error) {
sendError = error;
}
let closeError;
try {
await state.onClose?.(sendError ?? reason);
} catch (error) {
closeError = error;
}
if (sendError) throw sendError;
if (closeError) throw closeError;
}
close(error = new Error("Plugin runtime closed")) {
if (this.closed) return;
this.closed = true;
for (const state of this.outgoing.values()) {
state.closed = true;
for (const pending of state.queue) pending.reject(error);
}
this.outgoing.clear();
for (const state of this.incoming.values()) {
state.closed = true;
state.openController?.abort(error);
try {
const closing = state.onClose?.(error);
if (closing && typeof closing.then === "function") void closing.catch(() => {});
} catch {}
}
this.incoming.clear();
}
}
module.exports = { PluginStreamRouter, assertStreamEnvelopeShape, raceWithSignal };