mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-07 01:56:04 +00:00
refactor: frame reorder buffer + port probe cleanup; add CREDITS.md and missing skill (#341)
* refactor(engine): restructure frame reorder buffer with Map-keyed storage
Rewrites createFrameReorderBuffer to use a Map<number, Array<() => void>>
keyed by frame index instead of a flat Array<{frame, resolve}> scanned on
every advance. O(1) lookups in enqueue/flush, fast-paths for the matching-
cursor and overshoot cases, and a small fix: waitForAllDone now coexists
with the writer still waiting on the final frame instead of colliding on
the same waiter slot.
Also adds 5 unit tests (there were none before) covering the fast-path,
out-of-order gating, multi-waiter-per-frame semantics, waitForAllDone
normal path, and the overshoot case.
Comment tweaks on buildChromeArgs — the flag profile is the standard
headless-for-capture set (Puppeteer / Playwright / Chrome headless-shell
all converge on similar flags); rephrased for clarity.
* refactor(cli): simplify port availability probe with async/await
Rewrites isPortAvailableOnHost from a single new-Promise callback into an
async/await form with an intermediate `bindError: ErrnoException | null`
variable. Makes the bind-then-release flow explicit as two sequential
awaits, and broadens the non-EADDRINUSE errno commentary (EADDRNOTAVAIL
for disabled IPv6, EACCES for privileged ports, EAFNOSUPPORT for missing
address families — all treated as "this host doesn't apply", not "port
occupied").
No behavior change to existing callers; all four portUtils tests still
pass.
* docs: add CREDITS.md and surface website-to-hyperframes skill
- New CREDITS.md acknowledging prior art in the browser-based video
rendering space (Remotion) and the ecosystem HyperFrames builds on
(Puppeteer, FFmpeg, GSAP, Hono). Standard OSS practice.
- Adds the `website-to-hyperframes` skill to the skills tables in
README.md, docs/guides/prompting.mdx, and the project template at
packages/cli/src/templates/_shared/CLAUDE.md. The skill ships in
skills/ but was missing from every table.
- Adds `/hyperframes-registry` to the prose mention in the repo
CLAUDE.md.
This commit is contained in:
@@ -11,7 +11,11 @@
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { buildStreamingArgs, type StreamingEncoderOptions } from "./streamingEncoder.js";
|
||||
import {
|
||||
buildStreamingArgs,
|
||||
createFrameReorderBuffer,
|
||||
type StreamingEncoderOptions,
|
||||
} from "./streamingEncoder.js";
|
||||
import { DEFAULT_HDR10_MASTERING } from "../utils/hdr.js";
|
||||
|
||||
const baseHdrPq: StreamingEncoderOptions = {
|
||||
@@ -158,3 +162,67 @@ describe("buildStreamingArgs", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("createFrameReorderBuffer", () => {
|
||||
it("fast-paths waitForFrame(cursor) without queueing", async () => {
|
||||
const buf = createFrameReorderBuffer(0, 3);
|
||||
await buf.waitForFrame(0);
|
||||
});
|
||||
|
||||
it("gates out-of-order writers into cursor order", async () => {
|
||||
const buf = createFrameReorderBuffer(0, 4);
|
||||
const writeOrder: number[] = [];
|
||||
|
||||
const writer = async (frame: number) => {
|
||||
await buf.waitForFrame(frame);
|
||||
writeOrder.push(frame);
|
||||
buf.advanceTo(frame + 1);
|
||||
};
|
||||
|
||||
const p3 = writer(3);
|
||||
const p1 = writer(1);
|
||||
const p2 = writer(2);
|
||||
const p0 = writer(0);
|
||||
|
||||
await Promise.all([p0, p1, p2, p3]);
|
||||
expect(writeOrder).toEqual([0, 1, 2, 3]);
|
||||
});
|
||||
|
||||
it("supports multiple waiters registered for the same frame", async () => {
|
||||
const buf = createFrameReorderBuffer(0, 2);
|
||||
const resolved: string[] = [];
|
||||
|
||||
const a = buf.waitForFrame(1).then(() => resolved.push("a"));
|
||||
const b = buf.waitForFrame(1).then(() => resolved.push("b"));
|
||||
|
||||
buf.advanceTo(0);
|
||||
await Promise.resolve();
|
||||
expect(resolved).toEqual([]);
|
||||
|
||||
buf.advanceTo(1);
|
||||
await Promise.all([a, b]);
|
||||
expect(resolved.sort()).toEqual(["a", "b"]);
|
||||
});
|
||||
|
||||
it("waitForAllDone resolves when cursor reaches endFrame", async () => {
|
||||
const buf = createFrameReorderBuffer(0, 3);
|
||||
let done = false;
|
||||
const allDone = buf.waitForAllDone().then(() => {
|
||||
done = true;
|
||||
});
|
||||
|
||||
buf.advanceTo(1);
|
||||
await Promise.resolve();
|
||||
expect(done).toBe(false);
|
||||
|
||||
buf.advanceTo(3);
|
||||
await allDone;
|
||||
expect(done).toBe(true);
|
||||
});
|
||||
|
||||
it("waitForAllDone fast-paths when cursor already past endFrame", async () => {
|
||||
const buf = createFrameReorderBuffer(0, 3);
|
||||
buf.advanceTo(5);
|
||||
await buf.waitForAllDone();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user