Files
hyperframes/packages/studio-server/src/helpers/proxyCache.test.ts
T
Miguel Ángel e8371a7acc feat(media): alpha-capable authoring proxies (#2598)
* feat(media): alpha-capable authoring proxies

Alpha sources were refused a proxy before the codec map ever asked whether the
browser could decode them, so a ProRes 4444 alpha file (which no browser
previews at all) rendered black forever, while an alpha WebM (which previews
fine) was already covered by the browser-safe check on the next line. The alpha
veto earned nothing and cost the one case that needed help.

Alpha is now a target-codec choice rather than a veto: alpha sources transcode
to VP9 + yuva420p in WebM, everything else keeps the existing H.264/MP4 path
byte for byte. Only files no browser can preview are proxied, which is the rule
the runtime already followed everywhere else.

WebM cannot carry AAC, so the VP9 path uses Opus and drops the MP4-only
faststart flag. PROXY_PARAMS_VERSION moves to v3 so clients stop serving the
previously cached proxies.

Safari does not decode VP9 alpha and still shows black for alpha sources, as it
does today: this is better on Chromium and Firefox and no worse anywhere.

* fix(media): infer proxy variant for rescue

* fix(media): preserve alpha proxy hardening after restack
2026-07-17 03:26:55 -04:00

117 lines
3.5 KiB
TypeScript

import { existsSync, mkdirSync, mkdtempSync, rmSync, utimesSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { cleanupProxyCache } from "./proxyCache.js";
const tempDirs: string[] = [];
function cacheDir(): string {
const root = mkdtempSync(join(tmpdir(), "hf-proxy-cache-"));
tempDirs.push(root);
const cache = join(root, ".transcode-cache");
mkdirSync(cache);
return cache;
}
function writeEntry(path: string, bytes: number, modifiedAt: number): void {
writeFileSync(path, Buffer.alloc(bytes));
const date = new Date(modifiedAt);
utimesSync(path, date, date);
}
afterEach(() => {
for (const dir of tempDirs.splice(0)) rmSync(dir, { recursive: true, force: true });
});
describe("cleanupProxyCache", () => {
it("removes idle and oldest entries until the cache is within its byte budget", () => {
const cache = cacheDir();
const now = 1_800_000_000_000;
const expired = join(cache, "expired.mp4");
const oldest = join(cache, "oldest.mp4");
const newest = join(cache, "newest.mp4");
writeEntry(expired, 4, now - 31 * 24 * 60 * 60 * 1000);
writeEntry(oldest, 6, now - 3_000);
writeEntry(newest, 6, now - 1_000);
const result = cleanupProxyCache(cache, {
now,
maxBytes: 8,
maxIdleMs: 30 * 24 * 60 * 60 * 1000,
minSweepIntervalMs: 0,
});
expect(result.removed).toEqual([expired, oldest]);
expect(result.bytesAfter).toBe(6);
expect(existsSync(expired)).toBe(false);
expect(existsSync(oldest)).toBe(false);
expect(existsSync(newest)).toBe(true);
});
it("counts and evicts WebM proxies alongside MP4 proxies", () => {
const cache = cacheDir();
const now = 1_800_000_000_000;
const webm = join(cache, "alpha.webm");
const mp4 = join(cache, "opaque.mp4");
writeEntry(webm, 6, now - 2_000);
writeEntry(mp4, 6, now - 1_000);
const result = cleanupProxyCache(cache, {
now,
maxBytes: 6,
maxIdleMs: 10_000,
minSweepIntervalMs: 0,
});
expect(result.bytesBefore).toBe(12);
expect(result.removed).toEqual([webm]);
expect(result.bytesAfter).toBe(6);
});
it("preserves in-flight entries and removes stale temporary files", () => {
const cache = cacheDir();
const now = 1_800_000_000_000;
const inFlight = join(cache, "active.mp4");
const staleTemp = join(cache, ".tmp-crashed-active.mp4");
writeEntry(inFlight, 12, now - 40 * 24 * 60 * 60 * 1000);
writeEntry(staleTemp, 3, now - 2 * 60 * 60 * 1000);
const result = cleanupProxyCache(cache, {
now,
maxBytes: 1,
maxIdleMs: 30 * 24 * 60 * 60 * 1000,
staleTempMs: 60 * 60 * 1000,
minSweepIntervalMs: 0,
protectedPaths: new Set([inFlight]),
});
expect(result.removed).toEqual([staleTemp]);
expect(result.bytesAfter).toBe(12);
expect(existsSync(inFlight)).toBe(true);
});
it("rate-limits repeated directory sweeps", () => {
const cache = cacheDir();
const path = join(cache, "entry.mp4");
writeEntry(path, 2, 1_000);
const first = cleanupProxyCache(cache, {
now: 2_000,
maxBytes: 10,
maxIdleMs: 10_000,
minSweepIntervalMs: 5_000,
});
const second = cleanupProxyCache(cache, {
now: 3_000,
maxBytes: 1,
maxIdleMs: 10_000,
minSweepIntervalMs: 5_000,
});
expect(first.skipped).toBe(false);
expect(second.skipped).toBe(true);
expect(existsSync(path)).toBe(true);
});
});