mirror of
https://github.com/hanzoai/frames.git
synced 2026-09-24 00:08:03 +00:00
@hanzo/frame is taken by the hero video primitive — one full-bleed video element — which has held that name on npm since it shipped. This repo is the video toolchain: a CLI, a renderer, a studio, a player. Plural is what it is, so the CLI publishes as @hanzo/frames and the workspace packages follow it (@hanzo/frames-core, @hanzo/frames-engine, and the rest). The binary stays `frames`, and now actually ships. The manifest mapped it to bin/frames.mjs while the file on disk was bin/hyperframes.mjs, so a global install produced no working command. The paths that name a package to fetch were pointing elsewhere. The update check read registry.npmjs.org/frames, a different author's package, and the npm, bun and pnpm installers would have pulled it over the CLI; the render image installed the upstream hyperframes; scaffolded projects and the docs pinned the unscoped name. All of them now name @hanzo/frames.
48 lines
1.3 KiB
TypeScript
48 lines
1.3 KiB
TypeScript
import { execFileSync } from "node:child_process";
|
|
import { existsSync } from "node:fs";
|
|
import { resolve } from "node:path";
|
|
|
|
export function resolveProducerDistEntry(studioDir: string): string {
|
|
return resolve(studioDir, "../producer/dist/index.js");
|
|
}
|
|
|
|
export function resolveWorkspaceRoot(studioDir: string): string {
|
|
return resolve(studioDir, "../..");
|
|
}
|
|
|
|
export function ensureProducerDist(opts: {
|
|
studioDir: string;
|
|
existsSyncImpl?: (path: string) => boolean;
|
|
execFileSyncImpl?: typeof execFileSync;
|
|
env?: NodeJS.ProcessEnv;
|
|
}): { built: boolean; producerDistEntry: string } {
|
|
const producerDistEntry = resolveProducerDistEntry(opts.studioDir);
|
|
const exists = opts.existsSyncImpl ?? existsSync;
|
|
if (exists(producerDistEntry)) {
|
|
return { built: false, producerDistEntry };
|
|
}
|
|
|
|
const exec = opts.execFileSyncImpl ?? execFileSync;
|
|
exec("bun", ["run", "--filter", "@hanzo/frames-producer", "build"], {
|
|
cwd: resolveWorkspaceRoot(opts.studioDir),
|
|
stdio: "pipe",
|
|
env: opts.env,
|
|
});
|
|
|
|
return { built: true, producerDistEntry };
|
|
}
|
|
|
|
export function createRetryingModuleLoader<T>(load: () => Promise<T>): () => Promise<T> {
|
|
let promise: Promise<T> | null = null;
|
|
|
|
return async () => {
|
|
if (!promise) {
|
|
promise = load().catch((error) => {
|
|
promise = null;
|
|
throw error;
|
|
});
|
|
}
|
|
return promise;
|
|
};
|
|
}
|