import { expect, test } from "bun:test"; import { createResumableUploadManager, memoryResumableSessionStore } from "../src/index.ts"; import type { StorageDriver } from "../src/index.ts"; function driver() { const objects = new Map(); const storage: StorageDriver = { async put(key, data) { objects.set(key, data.slice()); }, async get(key) { const body = objects.get(key); return body ? { body, contentType: "application/octet-stream", size: body.length } : null; }, async delete(key) { objects.delete(key); }, publicUrl: () => null, }; return { storage, objects }; } test("resumable uploads accept out-of-order idempotent chunks and assemble once", async () => { const { storage, objects } = driver(); const manager = createResumableUploadManager({ driver: storage, chunkSize: 3, maxBytes: 20, accept: ["text/plain"], }); const session = await manager.create({ name: "hello.txt", type: "text/plain", size: 8 }); expect(session.totalChunks).toBe(3); expect((await manager.uploadChunk(session.id, 1, new TextEncoder().encode("lo "))).complete).toBe( false, ); await manager.uploadChunk(session.id, 0, new TextEncoder().encode("hel")); await manager.uploadChunk(session.id, 0, new TextEncoder().encode("hel")); const result = await manager.uploadChunk(session.id, 2, new TextEncoder().encode("!!")); expect(result.complete).toBe(true); expect(new TextDecoder().decode(objects.get(result.file!.key))).toBe("hello !!"); expect(await manager.status(session.id)).toBeNull(); }); test("resumable uploads enforce checksums, conflicts, limits, expiry, and cancellation", async () => { let now = 0; const { storage } = driver(); const sessions = memoryResumableSessionStore(); const manager = createResumableUploadManager({ driver: storage, sessions, chunkSize: 2, maxBytes: 4, maxSessions: 1, ttlMs: 10, now: () => now, }); const session = await manager.create({ name: "data.bin", size: 4 }); await expect(manager.create({ name: "other.bin", size: 1 })).rejects.toThrow("too many"); await expect(manager.uploadChunk(session.id, 0, new Uint8Array([1, 2]), "bad")).rejects.toThrow( "checksum", ); await manager.uploadChunk(session.id, 0, new Uint8Array([1, 2])); await expect(manager.uploadChunk(session.id, 0, new Uint8Array([2, 1]))).rejects.toThrow( "different content", ); expect(await manager.cancel(session.id)).toBe(true); const expiring = await manager.create({ name: "expire.bin", size: 2 }); now = 11; expect(await manager.prune()).toBe(1); await expect(manager.uploadChunk(expiring.id, 0, new Uint8Array([1, 2]))).rejects.toThrow( "expired", ); });