everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
1 lines • 3.52 kB
Source Map (JSON)
{"version":3,"file":"route-guards.cjs","names":["Effect","listFiles","readText","Finding"],"sources":["../../../../../src/services/scaffold/upgrade-audit/checks/route-guards.ts"],"sourcesContent":["import { Effect } from \"effect\";\nimport { Finding } from \"../domain\";\nimport { listFiles, readText } from \"../fs\";\n\n/**\n * Flags session-resolution drift that the redirect-loop class of bug feeds\n * on. Two shapes are wrong:\n *\n * 1. An authed mount (`_authenticated`, `_admin`, `_anon`, `_organization`)\n * reimplementing session resolution inline (sessionQueryOptions /\n * authClient.getSession) instead of delegating to requireSession from\n * \"everything-dev/ui/auth\" — guards that disagree about the same\n * [\"session\"] query key can ping-pong /login ↔ the protected route until\n * the router's redirect budget is exhausted (\"Too many redirects\").\n * 2. The root passing the raw context.session through without\n * resolveSessionFromCache — a stale truthy session can survive sign-out\n * and resurrect authed state.\n */\nconst INLINE_RESOLUTION = /sessionQueryOptions\\(|authClient\\.getSession\\(/;\n\nconst AUTHED_MOUNTS = new Set([\"authenticated\", \"admin\", \"anon\", \"organization\"]);\n\nexport const checkRouteGuards = (projectDir: string): Effect.Effect<Finding[], Error> =>\n Effect.gen(function* () {\n const files = (yield* listFiles(projectDir, \"ui/src/routes/_*.tsx\")).filter(\n (file) => !file.endsWith(\".test.ts\"),\n );\n\n const findings: Finding[] = [];\n\n for (const file of files) {\n const source = yield* readText(projectDir, file);\n const mountId = file.match(/ui\\/src\\/routes\\/_([a-z]+)\\.tsx$/)?.[1];\n\n if (mountId === undefined) continue;\n\n if (AUTHED_MOUNTS.has(mountId) && INLINE_RESOLUTION.test(source)) {\n findings.push(\n new Finding({\n check: \"route-guards\",\n path: file,\n severity: \"warn\",\n message: `authed mount \"_${mountId}\" resolves the session inline (sessionQueryOptions/authClient.getSession) — delegate to requireSession from \"everything-dev/ui/auth\" so all guards share one resolution semantics`,\n }),\n );\n }\n }\n\n const rootSource = yield* readText(projectDir, \"ui/src/routes/__root.tsx\");\n if (/const session = context\\.session;/.test(rootSource)) {\n findings.push(\n new Finding({\n check: \"route-guards\",\n path: \"ui/src/routes/__root.tsx\",\n severity: \"warn\",\n message:\n \"root passes the raw context.session through — resolve it with resolveSessionFromCache so an explicit signed-out cache entry is honored\",\n }),\n );\n }\n\n return findings;\n });\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAkBA,MAAM,oBAAoB;AAE1B,MAAM,gCAAgB,IAAI,IAAI;CAAC;CAAiB;CAAS;CAAQ;AAAc,CAAC;AAEhF,MAAa,oBAAoB,eAC/BA,cAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAOC,qBAAU,YAAY,sBAAsB,EAAC,CAAE,QAClE,SAAS,CAAC,KAAK,SAAS,UAAU,CACrC;CAEA,MAAM,WAAsB,CAAC;CAE7B,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,SAAS,OAAOC,oBAAS,YAAY,IAAI;EAC/C,MAAM,UAAU,KAAK,MAAM,kCAAkC,CAAC,GAAG;EAEjE,IAAI,YAAY,QAAW;EAE3B,IAAI,cAAc,IAAI,OAAO,KAAK,kBAAkB,KAAK,MAAM,GAC7D,SAAS,KACP,IAAIC,uBAAQ;GACV,OAAO;GACP,MAAM;GACN,UAAU;GACV,SAAS,kBAAkB,QAAQ;EACrC,CAAC,CACH;CAEJ;CAEA,MAAM,aAAa,OAAOD,oBAAS,YAAY,0BAA0B;CACzE,IAAI,oCAAoC,KAAK,UAAU,GACrD,SAAS,KACP,IAAIC,uBAAQ;EACV,OAAO;EACP,MAAM;EACN,UAAU;EACV,SACE;CACJ,CAAC,CACH;CAGF,OAAO;AACT,CAAC"}