Something went wrong. Try again.
Central platform for European atproto.<cc> country community websites atproto.eu
community atproto
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869// Generate SCOPES.md (the human-readable list of live domains) from the single source of truth,// src/config/scopes.ts. Docs must NOT hand-maintain the scope list: they drift the moment a domain// is added. Run://// npm run gen:scopes # regenerate SCOPES.md// npm run check:scopes # fail if SCOPES.md is out of sync (also enforced by a vitest test)//// Node imports the .ts source natively (>=22.6 strip-types; CI/dev are on 26). No new deps.// Output is deterministic (no timestamp) so the git-diff / test gate only trips on real changes.import { writeFile } from 'node:fs/promises';import { fileURLToPath, pathToFileURL } from 'node:url';import { dirname, resolve } from 'node:path';import { SCOPES } from '../src/config/scopes.ts';
/** Render SCOPES.md from a SCOPES map. Pure, so the vitest gate can compare it to the on-disk file. */export function renderScopesMd(scopes) { // No maintainer column: the config stores manager DIDs (per the "reference DIDs internally, // resolve handles at display time" hard rule), which are not human-readable, and resolving them // would add a nondeterministic network call that breaks the diff/test gate. Managers render as // avatars on the live site instead. const rows = Object.entries(scopes).map(([id, s]) => { const domain = new URL(s.site).host; const type = s.aggregate ? 'aggregate' : s.tier === 'city' ? 'city' : 'country'; const langs = s.locales.join(', '); const verifier = s.verify ? 'yes' : 'no'; return `| ${domain} | \`${id}\` | ${type} | ${langs} | ${verifier} |`; }); const count = Object.keys(scopes).length; return ( [ '# Live scopes', '', '<!-- GENERATED by scripts/gen-scopes.mjs from src/config/scopes.ts. Do NOT edit by hand.', ' Run `npm run gen:scopes` after changing scopes.ts. `npm run check:scopes` and the', ' scopes-doc vitest both fail if this file drifts. scopes.ts is the single source of truth. -->', '', 'Every domain below is a standalone build driven by `SITE_SCOPE`, deployed by the Tangled Spindle', 'to its own Codeberg Pages repo (`atproto<scope>-website`). Languages are the build locales,', 'default first. Deploy runbook: `AGENTS.md`. Colours per scope: `src/config/accents.ts`.', '', '| Domain | Scope | Type | Languages | Verifier |', '|--------|-------|------|-----------|----------|', ...rows, '', `${count} scopes.`, ].join('\n') + '\n' );}
/** The scope ids, space-separated, in declaration order. The deploy loop (deploy.yml) and any * manual fallback consume this so the publish set is derived from scopes.ts, never hand-listed: * adding a scope to scopes.ts is then a one-file change that the deployer picks up automatically. */export function scopeList(scopes) { return Object.keys(scopes).join(' ');}
// CLI. Guarded so importing this module (the test) never runs it.if (import.meta.url === pathToFileURL(process.argv[1]).href) { // `--list`: print the scope ids for the deployer to iterate. Prints ONLY the list (no extra // logging) so `for scope in $(node scripts/gen-scopes.mjs --list)` gets a clean word list. if (process.argv.includes('--list')) { process.stdout.write(scopeList(SCOPES) + '\n'); } else { const here = dirname(fileURLToPath(import.meta.url)); await writeFile(resolve(here, '../SCOPES.md'), renderScopesMd(SCOPES)); console.log(`wrote SCOPES.md (${Object.keys(SCOPES).length} scopes)`); }}