[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,246 @@
"use strict";
const assert = require("node:assert/strict");
const fs = require("node:fs");
const os = require("node:os");
const path = require("node:path");
const test = require("node:test");
const { stageRendererFileToTemp } = require("./stageUploadFile.cjs");
function createChunkedFile(chunks) {
return {
stream: () => new ReadableStream({
start(controller) {
for (const chunk of chunks) controller.enqueue(new Uint8Array(chunk));
controller.close();
},
}),
};
}
function createShortWriteFs(writeSizes, onWrite = null) {
const writeCalls = [];
let writeIndex = 0;
return {
writeCalls,
fsImpl: {
promises: {
open: async (...args) => {
const handle = await fs.promises.open(...args);
return {
write: async (buffer, offset = 0, length = buffer.length - offset, position = null) => {
const requestedLength = Math.max(0, Number(length));
const configuredLength = writeSizes[writeIndex] ?? requestedLength;
const actualLength = Math.min(requestedLength, configuredLength);
writeCalls.push({ offset, length: requestedLength, position, actualLength });
const result = await handle.write(buffer, offset, actualLength, position);
writeIndex += 1;
await onWrite?.({ writeIndex, result });
return result;
},
close: () => handle.close(),
};
},
unlink: (...args) => fs.promises.unlink(...args),
},
},
};
}
test("pathless renderer files stream into a controlled temp file without arrayBuffer", async (t) => {
const dir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "netcatty-stage-upload-"));
t.after(() => fs.promises.rm(dir, { recursive: true, force: true }));
const localPath = path.join(dir, "upload.part");
let arrayBufferCalls = 0;
const chunks = [new Uint8Array([1, 2]), new Uint8Array([3, 4, 5])];
const file = {
arrayBuffer: async () => { arrayBufferCalls += 1; return new ArrayBuffer(0); },
stream: () => new ReadableStream({
start(controller) {
for (const chunk of chunks) controller.enqueue(chunk);
controller.close();
},
}),
};
assert.equal(await stageRendererFileToTemp(file, localPath, fs), localPath);
assert.deepEqual(await fs.promises.readFile(localPath), Buffer.from([1, 2, 3, 4, 5]));
assert.equal(arrayBufferCalls, 0);
});
test("a partial file-handle write retries the unwritten suffix", async (t) => {
const dir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "netcatty-stage-upload-short-write-"));
t.after(() => fs.promises.rm(dir, { recursive: true, force: true }));
const localPath = path.join(dir, "upload.part");
const { fsImpl, writeCalls } = createShortWriteFs([2]);
assert.equal(
await stageRendererFileToTemp(createChunkedFile([[1, 2, 3, 4, 5]]), localPath, fsImpl),
localPath,
);
assert.deepEqual(await fs.promises.readFile(localPath), Buffer.from([1, 2, 3, 4, 5]));
assert.deepEqual(writeCalls.map(({ offset, length, position }) => ({ offset, length, position })), [
{ offset: 0, length: 5, position: 0 },
{ offset: 2, length: 3, position: 2 },
]);
});
test("multiple partial writes across chunks preserve every byte and advance offsets", async (t) => {
const dir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "netcatty-stage-upload-many-short-writes-"));
t.after(() => fs.promises.rm(dir, { recursive: true, force: true }));
const localPath = path.join(dir, "upload.part");
const { fsImpl, writeCalls } = createShortWriteFs([1, 2, 1, 1]);
await stageRendererFileToTemp(
createChunkedFile([[10, 11, 12, 13], [20, 21]]),
localPath,
fsImpl,
);
assert.deepEqual(await fs.promises.readFile(localPath), Buffer.from([10, 11, 12, 13, 20, 21]));
assert.deepEqual(writeCalls.map(({ offset, length, position }) => ({ offset, length, position })), [
{ offset: 0, length: 4, position: 0 },
{ offset: 1, length: 3, position: 1 },
{ offset: 3, length: 1, position: 3 },
{ offset: 0, length: 2, position: 4 },
{ offset: 1, length: 1, position: 5 },
]);
});
test("a zero-byte file-handle write fails instead of spinning and removes the temp file", async (t) => {
const dir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "netcatty-stage-upload-zero-write-"));
t.after(() => fs.promises.rm(dir, { recursive: true, force: true }));
const localPath = path.join(dir, "upload.part");
const { fsImpl, writeCalls } = createShortWriteFs([0]);
await assert.rejects(
stageRendererFileToTemp(createChunkedFile([[1, 2, 3]]), localPath, fsImpl),
/Unable to stage the complete upload file/,
);
assert.equal(writeCalls.length, 1);
await assert.rejects(fs.promises.stat(localPath), { code: "ENOENT" });
});
test("cancelling after a partial write stops the current chunk and removes the temp file", async (t) => {
const dir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "netcatty-stage-upload-cancel-short-write-"));
t.after(() => fs.promises.rm(dir, { recursive: true, force: true }));
const localPath = path.join(dir, "upload.part");
const controller = new AbortController();
const { fsImpl, writeCalls } = createShortWriteFs([2], ({ writeIndex }) => {
if (writeIndex === 1) controller.abort(new Error("cancel mid-chunk"));
});
await assert.rejects(
stageRendererFileToTemp(
createChunkedFile([[1, 2, 3, 4, 5]]),
localPath,
fsImpl,
controller.signal,
),
/cancel mid-chunk/,
);
assert.equal(writeCalls.length, 1);
await assert.rejects(fs.promises.stat(localPath), { code: "ENOENT" });
});
test("failed pathless-file staging removes its partial temp file", async (t) => {
const dir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "netcatty-stage-upload-fail-"));
t.after(() => fs.promises.rm(dir, { recursive: true, force: true }));
const localPath = path.join(dir, "upload.part");
let reads = 0;
const file = {
stream: () => ({
getReader: () => ({
read: async () => {
reads += 1;
if (reads === 1) return { done: false, value: new Uint8Array([1]) };
throw new Error("source failed");
},
releaseLock: () => {},
}),
}),
};
await assert.rejects(stageRendererFileToTemp(file, localPath, fs), /source failed/);
await assert.rejects(fs.promises.stat(localPath), { code: "ENOENT" });
});
test("a synchronous File.stream failure closes the new handle and removes the temp file", async (t) => {
const dir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "netcatty-stage-upload-stream-init-"));
t.after(() => fs.promises.rm(dir, { recursive: true, force: true }));
const localPath = path.join(dir, "upload.part");
await assert.rejects(stageRendererFileToTemp({
stream() {
throw new Error("stream init failed");
},
}, localPath, fs), /stream init failed/);
await assert.rejects(fs.promises.stat(localPath), { code: "ENOENT" });
});
test("a synchronous getReader failure closes the new handle and removes the temp file", async (t) => {
const dir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "netcatty-stage-upload-reader-init-"));
t.after(() => fs.promises.rm(dir, { recursive: true, force: true }));
const localPath = path.join(dir, "upload.part");
await assert.rejects(stageRendererFileToTemp({
stream: () => ({
getReader() {
throw new Error("reader init failed");
},
}),
}, localPath, fs), /reader init failed/);
await assert.rejects(fs.promises.stat(localPath), { code: "ENOENT" });
});
test("stream initialization failure still closes the handle when temp deletion fails", async () => {
let closeCalls = 0;
let unlinkCalls = 0;
const fakeFs = {
promises: {
open: async () => ({
close: async () => { closeCalls += 1; },
}),
unlink: async () => {
unlinkCalls += 1;
throw new Error("delete denied");
},
},
};
await assert.rejects(stageRendererFileToTemp({
stream() {
throw new Error("stream init failed");
},
}, "/controlled/upload.part", fakeFs), /stream init failed/);
assert.equal(unlinkCalls, 1);
assert.ok(closeCalls >= 1, "the file handle must close even if cleanup unlink fails");
});
test("cancelling a blocked pathless-file read closes it and removes the partial file", async (t) => {
const dir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "netcatty-stage-upload-cancel-"));
t.after(() => fs.promises.rm(dir, { recursive: true, force: true }));
const localPath = path.join(dir, "upload.part");
const controller = new AbortController();
let cancelCalls = 0;
let finishRead;
const file = {
stream: () => ({
getReader: () => ({
read: () => new Promise((resolve) => { finishRead = resolve; }),
cancel: async () => {
cancelCalls += 1;
finishRead?.({ done: true });
},
releaseLock: () => {},
}),
}),
};
const staging = stageRendererFileToTemp(file, localPath, fs, controller.signal);
while (!finishRead) await new Promise((resolve) => setImmediate(resolve));
controller.abort(new Error("cancel now"));
await assert.rejects(staging, /cancel now/);
assert.equal(cancelCalls, 1);
await assert.rejects(fs.promises.stat(localPath), { code: "ENOENT" });
});