SnowLuma v2.4.2 source snapshot
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run

This commit is contained in:
TanTan committed 2026-11-13 09:02:00 +08:00
commit fa9c73363d
1367 files changed
+355735

No files matched your search

@@ -0,0 +1,211 @@
import { afterAll, describe, expect, it } from 'vitest';
import { readdir, readFile, rm } from 'fs/promises';
import path from 'path';
import {
buildStreamInvokeResponse,
DEBUG_UPLOAD_DIR,
safeUploadName,
streamUploadToDisk,
uploadDestPath,
} from '../src/webui/debug-tools';
const written: string[] = [];
afterAll(async () => {
await Promise.all(written.map((p) => rm(p, { force: true }).catch(() => {})));
});
function streamOf(...chunks: Uint8Array[]): ReadableStream<Uint8Array> {
let i = 0;
return new ReadableStream<Uint8Array>({
pull(controller) {
if (i < chunks.length) {
controller.enqueue(chunks[i++]);
} else {
controller.close();
}
},
});
}
async function readSse(res: Response): Promise<string[]> {
const text = await res.text();
return text
.split('\n\n')
.filter((s) => s.startsWith('data: '))
.map((s) => s.slice('data: '.length));
}
describe('safeUploadName', () => {
it('strips path traversal and separators to a bare basename', () => {
expect(safeUploadName('../../etc/passwd')).toBe('passwd');
expect(safeUploadName('/abs/secret.key')).toBe('secret.key');
expect(safeUploadName('a\\b\\c.png')).toBe('c.png');
expect(safeUploadName('..')).toBe('file'); // leading dots stripped → empty → fallback
expect(safeUploadName('...hidden')).toBe('hidden');
});
it('collapses exotic chars and falls back for empties', () => {
expect(safeUploadName('my pic!@#.jpg')).toBe('my_pic_.jpg');
expect(safeUploadName('')).toBe('file');
expect(safeUploadName(undefined)).toBe('file');
});
it('keeps the extension and caps length', () => {
const long = 'x'.repeat(500) + '.mp4';
const out = safeUploadName(long);
expect(out.length).toBeLessThanOrEqual(120);
expect(out.startsWith('x')).toBe(true);
});
});
describe('uploadDestPath', () => {
it('uses a neutral temporary directory name', () => {
expect(path.basename(DEBUG_UPLOAD_DIR)).toBe('webui-upload');
});
it('produces a unique path inside the upload dir', () => {
const a = uploadDestPath('pic.png');
const b = uploadDestPath('pic.png');
expect(a).not.toBe(b); // random id prefix
expect(path.dirname(a)).toBe(DEBUG_UPLOAD_DIR);
expect(a.endsWith('__pic.png')).toBe(true);
const rel = path.relative(DEBUG_UPLOAD_DIR, a);
expect(rel.startsWith('..')).toBe(false);
expect(path.isAbsolute(rel)).toBe(false);
});
});
describe('streamUploadToDisk', () => {
it('streams bytes to disk and reports the size', async () => {
const data = new TextEncoder().encode('hello debug upload');
const res = await streamUploadToDisk(streamOf(data.slice(0, 5), data.slice(5)), 'note.txt');
written.push(res.path);
expect(res.size).toBe(data.byteLength);
expect(path.dirname(res.path)).toBe(DEBUG_UPLOAD_DIR);
expect(await readFile(res.path, 'utf8')).toBe('hello debug upload');
});
it('rejects and removes the partial file when the cap is exceeded', async () => {
const big = new Uint8Array(64);
await expect(
streamUploadToDisk(streamOf(big, big), 'big.bin', { maxBytes: 100 }),
).rejects.toThrow(/大小上限/);
// the partial must not survive — no leftover `__big.bin` in the dir
const names = await readdir(DEBUG_UPLOAD_DIR).catch(() => [] as string[]);
expect(names.filter((n) => n.endsWith('__big.bin'))).toEqual([]);
});
it('rejects an empty body', async () => {
await expect(streamUploadToDisk(null, 'x')).rejects.toThrow(/empty/);
await expect(streamUploadToDisk(streamOf(), 'x')).rejects.toThrow(/empty/);
});
it('propagates a mid-transfer source error and removes the partial', async () => {
const failing = new ReadableStream<Uint8Array>({
start(controller) {
controller.enqueue(new TextEncoder().encode('partial-bytes'));
controller.error(new Error('source aborted'));
},
});
await expect(streamUploadToDisk(failing, 'oops.bin')).rejects.toThrow(/source aborted/);
const names = await readdir(DEBUG_UPLOAD_DIR).catch(() => [] as string[]);
expect(names.filter((n) => n.endsWith('__oops.bin'))).toEqual([]);
});
});
describe('buildStreamInvokeResponse', () => {
const noDelay = async () => {};
it('cancels delivery while the action is still pending', async () => {
let finish!: () => void;
const pending = new Promise<void>((resolve) => {
finish = resolve;
});
let isAlive!: () => boolean;
const response = buildStreamInvokeResponse(
async (_request, _emit, alive) => {
isAlive = alive;
await pending;
},
'{}',
new AbortController().signal,
);
const canceled = response.body!.cancel();
try {
expect(isAlive()).toBe(false);
} finally {
finish();
await canceled;
}
});
it('does not invoke an action for an already aborted request', async () => {
const controller = new AbortController();
controller.abort();
let invoked = false;
const response = buildStreamInvokeResponse(
async () => {
invoked = true;
},
'{}',
controller.signal,
);
await readSse(response);
expect(invoked).toBe(false);
});
it('relays each emitted frame as one SSE event, in order', async () => {
const ac = new AbortController();
const driver = async (_rq: string, emit: (j: string) => Promise<void>) => {
await emit(JSON.stringify({ data: { type: 'stream', i: 1 } }));
await emit(JSON.stringify({ data: { type: 'stream', i: 2 } }));
await emit(JSON.stringify({ status: 'ok', data: { type: 'response' } }));
};
const res = buildStreamInvokeResponse(driver, '{"action":"x"}', ac.signal, noDelay);
const frames = (await readSse(res)).map((s) => JSON.parse(s));
expect(frames).toHaveLength(3);
expect(frames[0].data.i).toBe(1);
expect(frames[2].data.type).toBe('response');
});
it('turns a driver error into a terminal failed frame', async () => {
const ac = new AbortController();
const driver = async (_rq: string, emit: (j: string) => Promise<void>) => {
await emit(JSON.stringify({ data: { type: 'stream' } }));
throw new Error('disk exploded');
};
const res = buildStreamInvokeResponse(driver, '{}', ac.signal, noDelay);
const frames = (await readSse(res)).map((s) => JSON.parse(s));
expect(frames).toHaveLength(2);
expect(frames[1].status).toBe('failed');
expect(frames[1].message).toMatch(/disk exploded/);
});
it('passes the raw request through to the driver', async () => {
const ac = new AbortController();
let seen = '';
const driver = async (rq: string, emit: (j: string) => Promise<void>) => {
seen = rq;
await emit('{"data":{"type":"response"}}');
};
const res = buildStreamInvokeResponse(
driver,
'{"action":"test_download_stream"}',
ac.signal,
noDelay,
);
await readSse(res);
expect(seen).toBe('{"action":"test_download_stream"}');
});
it('exposes an SSE content-type', () => {
const ac = new AbortController();
const res = buildStreamInvokeResponse(async () => {}, '{}', ac.signal, noDelay);
expect(res.headers.get('Content-Type')).toBe('text/event-stream');
});
});