// songIds(), in its own module for one specific reason. // // It needs the WALK, and the walk needs the registry, and the registry needs // this kind's cut list -- so putting it in song.mjs closes the cycle // song -> walk -> kinds -> song. Under plain node that survives (the back edge // is only used at call time), but Turbopack evaluates the bundle in an order // where kinds.mjs reads CUT_NAMES while song.mjs is still initialising, and // every song page 500s with "Cannot access 'CUT_NAMES' before initialization". // // `pnpm build` does not catch it, because nothing prerenders. A page render // does. Hence a third module, which only the app's edge imports. import path from "node:path"; import { walkProjects } from "./walk.mjs"; import { SONG_KIND } from "./song.mjs"; /** * Every song, by the BASENAME the song routes are keyed on. * * A caller of the project walk rather than its own readdir, so there is one * enumerator and a song cannot be a project in one listing and absent from the * other. * * Filtered to songs that live directly under `browseRoot`, because every song * route resolves through songDir() -- path.join(BROWSE_ROOT, id). A song project * found anywhere else is still listed and summarised on /browse by the registry; * returning it here would hand those routes an id that resolves to a directory * that is not it, which is worse than omitting it. */ export async function songIdsUnder(reportsRoot, browseRoot) { const projects = await walkProjects(reportsRoot); return projects .filter((p) => p.kind === SONG_KIND && p.dir === path.join(browseRoot, p.name)) .map((p) => p.name) .sort(); }