Support hour-long uploads and videos: raise body limit, stream uploads to disk, cache up to 3 h, add deferred-ideas note

This commit is contained in:
Claude
2026-10-01 18:48:37 +00:00
parent 9d74769029
commit 08e95814e5
8 changed files with 232 additions and 66 deletions

View File

@@ -131,3 +131,37 @@ describe('uploads', () => {
expect((await app.request(`/api/uploads/${audioId}`)).status).toBe(404);
});
});
describe('streaming upload (large / long files)', () => {
const put = (path, body, headers = { 'x-admin': 'yes' }) => app.request(path, { method: 'PUT', headers, body });
test('raw body is streamed to disk and registered', async () => {
const buf = readFileSync(fx('clip.mp4'));
const r = await put('/api/admin/uploads/stream?name=Long%20Talk.mp4&title=Long%20Talk', buf);
const j = await r.json();
expect(r.status).toBe(200);
expect(j.upload).toMatchObject({ kind: 'video', title: 'Long Talk', size: buf.length });
expect(existsSync(join(root, 'uploads', `${j.upload.id}.mp4`))).toBe(true);
});
test('needs the admin, a known extension and a non-empty body', async () => {
const buf = readFileSync(fx('clip.mp4'));
expect((await put('/api/admin/uploads/stream?name=a.mp4', buf, {})).status).toBe(401);
expect((await put('/api/admin/uploads/stream?name=a.exe', buf)).status).toBe(415);
expect((await put('/api/admin/uploads/stream?name=a.mp4', '')).status).toBe(400);
});
test('a file that is not media is rejected and leaves nothing behind', async () => {
const before = (await db.listUploads({ limit: 500 })).length;
const r = await put('/api/admin/uploads/stream?name=junk.mp4', new Uint8Array(5000).fill(7));
expect(r.status).toBe(500);
expect((await db.listUploads({ limit: 500 })).length).toBe(before);
});
test('cover image can be attached afterwards', async () => {
const up = await (await put('/api/admin/uploads/stream?name=song.mp3', readFileSync(fx('song.mp3')))).json();
const r = await put(`/api/admin/uploads/${up.upload.id}/art`, readFileSync(fx('cover.png')));
expect((await r.json()).ok).toBe(true);
expect((await db.getUpload(up.upload.id)).art).toBeTruthy();
});
});