{"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"}