Files
Miguel Ángel 9ef864d1f2 fix(docs): serve hyperframes.json / registry JSON schemas (#304) (#305)
Closes #304.

## Summary

The three `/schema/*.json` URLs baked into every Hyperframes project as `\$schema` references are 404ing on the live docs site — blocking editor autocomplete and validation.

- \`https://hyperframes.heygen.com/schema/hyperframes.json\` — **404** (missing entirely)
- \`https://hyperframes.heygen.com/schema/registry.json\` — **404** (only in npm package)
- \`https://hyperframes.heygen.com/schema/registry-item.json\` — **404** (only in npm package)

Mintlify serves top-level non-MDX dirs in \`docs/\` at \`/\<dir>/*\` (confirmed by \`docs/logo/*.svg\` → \`/logo/*.svg\`). This PR drops the three schemas into \`docs/schema/\` so the URLs resolve.

## What changed

| File | Role |
|---|---|
| \`docs/schema/hyperframes.json\` | **New.** Authored from the \`ProjectConfig\` type in \`packages/cli/src/utils/projectConfig.ts\`. |
| \`docs/schema/registry.json\` | Mirror of \`packages/core/schemas/registry.json\`. |
| \`docs/schema/registry-item.json\` | Mirror of \`packages/core/schemas/registry-item.json\`. |
| \`scripts/sync-schemas.ts\` | Keeps the registry mirrors in lockstep with their authoritative copies in \`packages/core/schemas/\`. \`--check\` mode fails the Docs workflow on drift. |
| \`.github/workflows/docs.yml\` | Runs \`tsx scripts/sync-schemas.ts --check\` on every PR touching docs or core schemas. |
| \`package.json\` | \`sync-schemas\` / \`sync-schemas:check\` npm scripts. |

## Why not make \`packages/core/schemas/\` authoritative for \`hyperframes.json\` too?

\`hyperframes.json\` is CLI config, not a core type. Keeping the schema in \`docs/\` avoids an artificial dependency between \`@hyperframes/core\` and \`@hyperframes/cli\`. If the two ever need to align, we can flip the direction then.

## Verification

- \`bun run sync-schemas:check\` → \`2/2 in sync\`.
- Ajv (draft 2020-12, in-process) validation against 9 cases:
  - ✓ real factory-series-c-video config
  - ✓ default shape from \`hyperframes init\`
  - ✓ \`\$schema\` is optional
  - ✓ missing registry → rejected
  - ✓ missing paths.assets → rejected
  - ✓ extra top-level key → rejected
  - ✓ empty registry string → rejected
  - ✓ empty block path → rejected
  - ✓ missing paths entirely → rejected

## Test plan

- [x] \`tsx scripts/sync-schemas.ts --check\` passes locally
- [x] Schemas parse as valid JSON and validate real/default project configs
- [x] After merge: \`curl -sI https://hyperframes.heygen.com/schema/hyperframes.json\` returns 200 once Mintlify redeploys
- [x] Same check for \`/schema/registry.json\` and \`/schema/registry-item.json\`
- [x] VS Code autocomplete and error-highlighting work on \`hyperframes.json\` without extra config

## Notes

- The Docs workflow now triggers on \`packages/core/schemas/**\` and \`scripts/sync-schemas.ts\` in addition to \`docs/**\`, so a core-schemas change that forgets to run \`sync-schemas\` will fail CI instead of silently publishing stale docs.
- No runtime / API changes to any package; ship independent of a version bump.
2026-04-17 17:43:43 +02:00

61 lines
1.8 KiB
TypeScript

#!/usr/bin/env tsx
/**
* Mirror JSON Schemas from `packages/core/schemas/` into `docs/schema/` so
* Mintlify serves them at `https://hyperframes.heygen.com/schema/*`. The core
* copies stay authoritative — they're exported from `@hyperframes/core` for
* npm consumers — and this script is the single contract that prevents the
* docs mirror from drifting.
*
* Usage:
* bun run sync-schemas # copy core → docs
* bun run sync-schemas --check # exit non-zero if copies are stale (CI)
*
* `docs/schema/hyperframes.json` is authored directly in docs (no source in
* core) so it's skipped by this script.
*/
import { readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
const ROOT = join(import.meta.dirname, "..");
const SOURCE_DIR = join(ROOT, "packages/core/schemas");
const TARGET_DIR = join(ROOT, "docs/schema");
const MIRRORED = ["registry.json", "registry-item.json"];
function main() {
const checkOnly = process.argv.includes("--check");
let drift = 0;
for (const name of MIRRORED) {
const source = readFileSync(join(SOURCE_DIR, name), "utf-8");
const targetPath = join(TARGET_DIR, name);
const target = (() => {
try {
return readFileSync(targetPath, "utf-8");
} catch {
return null;
}
})();
if (target === source) {
console.log(` ✓ ${name} in sync`);
continue;
}
drift++;
if (checkOnly) {
console.error(` ✗ ${name} out of sync (run \`bun run sync-schemas\` to fix)`);
continue;
}
writeFileSync(targetPath, source);
console.log(` → ${name} updated`);
}
if (checkOnly && drift > 0) {
console.error(`\n${drift} schema${drift === 1 ? "" : "s"} drifted from source.`);
process.exit(1);
}
}
main();