Replace the ad-hoc `worker.js` with a self-contained `linearvoid-media` worker under `infrastructure/cloudflare/` that owns `media.linearvoid.tv`. It serves HLS objects from the R2 bucket, enforcing immutable Cache-Control on segments, a short TTL on live manifests, plus HLS CORS, OPTIONS preflight, Range support, and a `/health` probe. Includes wrapper config with production domain, Vitest unit tests, Miniflare R2 integration tests, automated deploy workflow, and docs updates.
55 lines
2.2 KiB
JavaScript
55 lines
2.2 KiB
JavaScript
import { describe, it, expect } from "vitest";
|
|
import { cacheControlForPath, contentTypeForPath, parseByteRange } from "../src/worker.js";
|
|
|
|
const IMMUTABLE = "public, max-age=31536000, immutable";
|
|
const MANIFEST = "public, max-age=1, s-maxage=2, must-revalidate";
|
|
const DEFAULT = "public, max-age=60";
|
|
|
|
describe("cacheControlForPath", () => {
|
|
it("marks media segments as immutable", () => {
|
|
expect(cacheControlForPath("/hls/seg-000001.m4s")).toBe(IMMUTABLE);
|
|
expect(cacheControlForPath("/hls/init.mp4")).toBe(IMMUTABLE);
|
|
expect(cacheControlForPath("/hls/seg-000001.ts")).toBe(IMMUTABLE);
|
|
expect(cacheControlForPath("/media/audio.m4a")).toBe(IMMUTABLE);
|
|
});
|
|
|
|
it("keeps live manifests short-lived", () => {
|
|
expect(cacheControlForPath("/hls/playlist.m3u8")).toBe(MANIFEST);
|
|
expect(cacheControlForPath("/hls/master.m3u8")).toBe(MANIFEST);
|
|
});
|
|
|
|
it("falls back to a sane default for other paths", () => {
|
|
expect(cacheControlForPath("/hls/unknown.txt")).toBe(DEFAULT);
|
|
});
|
|
});
|
|
|
|
describe("contentTypeForPath", () => {
|
|
it("maps known media types", () => {
|
|
expect(contentTypeForPath("/hls/playlist.m3u8")).toBe("application/vnd.apple.mpegurl");
|
|
expect(contentTypeForPath("/hls/seg-000001.m4s")).toBe("video/mp4");
|
|
expect(contentTypeForPath("/hls/init.mp4")).toBe("video/mp4");
|
|
expect(contentTypeForPath("/hls/seg-000001.ts")).toBe("video/MP2T");
|
|
expect(contentTypeForPath("/media/audio.m4a")).toBe("audio/mp4");
|
|
});
|
|
|
|
it("falls back to octet-stream", () => {
|
|
expect(contentTypeForPath("/hls/unknown.bin")).toBe("application/octet-stream");
|
|
});
|
|
});
|
|
|
|
describe("parseByteRange", () => {
|
|
it("parses a closed byte range", () => {
|
|
expect(parseByteRange("bytes=0-2")).toEqual({ offset: 0, length: 3 });
|
|
expect(parseByteRange("bytes=10-19")).toEqual({ offset: 10, length: 10 });
|
|
});
|
|
|
|
it("rejects open, suffix, multi, or malformed ranges", () => {
|
|
expect(parseByteRange("bytes=0-")).toBeNull();
|
|
expect(parseByteRange("bytes=-500")).toBeNull();
|
|
expect(parseByteRange("bytes=0-1,3-4")).toBeNull();
|
|
expect(parseByteRange("items=0-2")).toBeNull();
|
|
expect(parseByteRange("")).toBeNull();
|
|
expect(parseByteRange(null)).toBeNull();
|
|
});
|
|
});
|