release: WRNexusJS 0.8.0
Quality / quality (ubuntu-latest) (push) Failing after 21s
Quality / quality (windows-latest) (push) Canceled after 0s

This commit is contained in:
2026-08-02 23:18:51 +05:30
parent 87507edf59
commit 586a6db8ff
625 changed files with 243608 additions and 11210 deletions
+21
View File
@@ -0,0 +1,21 @@
import { describe, expect, test } from "bun:test";
import {
assertUploadedFiles,
formatFileSize,
uploadAccept,
uploaderAttributes,
} from "../src/index.ts";
describe("uploader helper kit", () => {
test("formats sizes and builds uploader attributes", () => {
expect(formatFileSize(1024)).toContain("KB");
expect(uploadAccept(["image/png", ".jpg"])).toBe("image/png,.jpg");
expect(uploaderAttributes({ store: "public", multiple: true })["data-uploader"]).toBe("public");
});
test("asserts uploaded file count and status", () => {
const files = [{ name: "a.png", size: 10, type: "image/png", key: "a", url: "/a" }];
expect(assertUploadedFiles(files, { min: 1, max: 1 })).toEqual(files);
expect(() => assertUploadedFiles([], { min: 1 })).toThrow();
});
});
+89
View File
@@ -0,0 +1,89 @@
import { expect, test } from "bun:test";
import {
createTemporaryObjectCleaner,
ffmpegVideoTranscoder,
memoryQuotaStore,
multipartUpload,
postgresQuotaStore,
} from "../src/index.ts";
test("quota stores enforce durable byte and object limits", async () => {
const quota = memoryQuotaStore();
expect(await quota.reserve("tenant", 60, { bytes: 100, objects: 2 })).toBeTrue();
expect(await quota.reserve("tenant", 50, { bytes: 100, objects: 2 })).toBeFalse();
await quota.release("tenant", 60);
expect(await quota.get("tenant")).toMatchObject({ bytes: 0, objects: 0 });
const calls: unknown[][] = [];
const sql = postgresQuotaStore({
async query<T>(_sql: string, parameters?: unknown[]) {
calls.push(parameters ?? []);
return { rows: [{ owner: "tenant" } as T] };
},
});
expect(await sql.reserve("tenant", 10, { bytes: 20 })).toBeTrue();
expect(calls[0]?.[0]).toBe("tenant");
});
test("multipart uploader limits concurrency, completes and aborts failures", async () => {
const uploaded: number[] = [];
let completed = false;
let aborted = false;
const client = {
async create() {
return "upload";
},
async uploadPart(_id: string, _key: string, part: number) {
uploaded.push(part);
return `etag-${part}`;
},
async complete() {
completed = true;
},
async abort() {
aborted = true;
},
};
await multipartUpload(
client,
"video",
new Uint8Array(11 * 1024 * 1024),
{ contentType: "video/mp4" },
{ partBytes: 5 * 1024 * 1024, concurrency: 2 },
);
expect(uploaded).toEqual([1, 2, 3]);
expect(completed).toBeTrue();
expect(aborted).toBeFalse();
});
test("temporary cleanup and video transcoding are bounded and injectable", async () => {
let now = 10;
const deleted: string[] = [];
const cleaner = createTemporaryObjectCleaner(
{
async put() {},
async get() {
return null;
},
async delete(key) {
deleted.push(key);
},
publicUrl() {
return null;
},
},
{ now: () => now },
);
cleaner.track("tmp/a", 5);
expect(await cleaner.cleanup()).toBe(0);
now = 15;
expect(await cleaner.cleanup()).toBe(1);
expect(deleted).toEqual(["tmp/a"]);
let command: string[] = [];
await ffmpegVideoTranscoder({
spawn(args) {
command = args;
return { exited: Promise.resolve(0) };
},
})("input.mov", "output.mp4", { format: "mp4", width: 1280, videoBitrateKbps: 2000 });
expect(command).toContain("scale=1280:-2");
});
+73
View File
@@ -0,0 +1,73 @@
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<string, Uint8Array>();
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",
);
});
+27
View File
@@ -61,3 +61,30 @@ test("signed file tokens reject tampering and expired payloads", async () => {
expect(await verifySignedFileToken(`${token}x`, secret, 1_000)).toBeNull();
expect(await verifySignedFileToken(token, secret, 2_000)).toBeNull();
});
test("upload scanning rejects unsafe bytes before storage", async () => {
const form = new FormData();
form.set("file", new File(["virus"], "bad.txt", { type: "text/plain" }));
await expect(
upload("public", new Request("http://test/upload", { method: "POST", body: form }), {
scan: async () => ({ safe: false, scanner: "test-av", reason: "signature" }),
}),
).rejects.toMatchObject({ status: 422 });
expect(await getStore("public").driver.get("bad.txt")).toBeNull();
});
test("post-storage processor failure rolls back the object", async () => {
const form = new FormData();
form.set("file", new File(["image"], "photo.png", { type: "image/png" }));
let key = "";
await expect(
upload("public", new Request("http://test/upload", { method: "POST", body: form }), {
afterStore(file) {
key = file.key;
throw new Error("transform failed");
},
}),
).rejects.toMatchObject({ status: 422 });
expect(key).not.toBe("");
expect(await getStore("public").driver.get(key)).toBeNull();
});