diff --git a/docs/plans/2026-08-04-authz-permissions-implementation.md b/docs/plans/2026-08-04-authz-permissions-implementation.md index 50fb10b7..d015cef8 100644 --- a/docs/plans/2026-08-04-authz-permissions-implementation.md +++ b/docs/plans/2026-08-04-authz-permissions-implementation.md @@ -2563,8 +2563,14 @@ Add the scan immediately after the existing `schemas` loop: // Authorization declarations: app/authz/.{ts,js}, each default-exporting // a defineAuthz() module. Merged into the catalog at boot. const authz: ComponentRef[] = []; -for (const f of scanDir(join(appDir, "authz"))) { +// scanDir's extension allow-list is route-oriented; passing [".js"] here keeps +// .js out of app/pages scanning, where it would leak into route URLs. +for (const f of scanDir(join(appDir, "authz"), [".js"])) { if (!/\.(ts|js)$/.test(f.file)) continue; + // Generated type files (permissions.gen.ts) live here too. Skip them quietly: + // they export types only, and isSafeIslandName would otherwise reject the dot + // and warn on every boot. + if (/[.]gen[.](ts|js)$/.test(f.file)) continue; const name = basename(f.file).replace(/\.(ts|js)$/, ""); if (!isSafeIslandName(name)) { console.warn(`[wrnexus] skipping authz declaration with unsafe name: ${name}`); @@ -3243,7 +3249,7 @@ export async function loadAppAuthzCatalog(appDir: string): Promise if (!router.authz.length) return emptyCatalog(); const sources: CatalogSource[] = []; for (const entry of router.authz) { - if (entry.name === "permissions.gen") continue; // generated types, not a declaration + // buildRouter already skips *.gen.ts, so only real declarations arrive here. const imported = (await import(pathToFileURL(entry.file).href)) as { default?: AuthzModule }; if (!imported.default) continue; sources.push({ source: entry.file, module: imported.default });