/** * Regenerate packages/lexicon-resolver/src/schemas/published.js. * * Walks the network resolution chain from every NSID in knownRecords, follows * each schema's refs, and writes the closure to disk. Run it when Bluesky * publishes a lexicon change worth shipping early: * * node scripts/gen-bundled-lexicons.mjs * * The resolver refreshes these from the network on its own TTL, so the file is * a warm start rather than the authority. */ import { execFileSync } from 'node:child_process'; import { writeFileSync } from 'node:fs'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; import { LexiconResolver } from '../packages/lexicon-resolver/src/resolver.js'; import { coreSchemas } from '../packages/lexicon-resolver/src/schemas/com-atproto.js'; import { knownRecords } from '../packages/lexicon-resolver/src/schemas/known-records.js'; const OUT = join( dirname(fileURLToPath(import.meta.url)), '../packages/lexicon-resolver/src/schemas/published.js', ); const resolver = new LexiconResolver({ fetch: (url, init) => fetch(url, init), }); /** @type {string[]} */ const missing = []; for (const nsid of knownRecords) { const unresolved = new Set(); await resolver.ensureSchemaWithRefs(nsid, unresolved); missing.push(...unresolved); } if (missing.length) { console.error(`unresolved: ${[...new Set(missing)].join(', ')}`); process.exit(1); } const bundled = new Set(coreSchemas.map((s) => s.id)); const ids = [...resolver.schemas.keys()] .filter((id) => !bundled.has(id)) .sort(); const header = `/** * Lexicons for the record types this PDS enforces, and every schema they * reference. Generated by scripts/gen-bundled-lexicons.mjs. * * The resolver preloads these so the common write path costs no network calls. * Each one carries the resolver's TTL like any other cache entry, so the * network answer replaces it once the entry goes stale. Enforcement comes from * known-records.js, not from this file. * * Do not edit by hand. */ /** @type {import('@bigmoves/lexicon').Lexicon[]} */ export const publishedSchemas = ${JSON.stringify( // An authority publishes its lexicon as a record, so the document arrives // carrying the collection it was stored in. That is not part of a Lexicon. ids.map((id) => { const { $type, ...schema } = /** @type {Record} */ ( resolver.schemas.get(id) ); return schema; }), null, 2, )}; `; writeFileSync(OUT, header); // JSON.stringify does not produce the house style, and `npm run ci` checks it. execFileSync('npx', ['biome', 'format', '--write', OUT], { stdio: 'inherit' }); console.log(`wrote ${ids.length} schemas to ${OUT}`);