@etus/bhono-app 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (688) hide show
  1. package/dist/cli.d.ts +13 -0
  2. package/dist/cli.js +46 -0
  3. package/dist/cli.js.map +1 -0
  4. package/dist/cli.test.d.ts +1 -0
  5. package/dist/cli.test.js +26 -0
  6. package/dist/cli.test.js.map +1 -0
  7. package/dist/generator.d.ts +14 -0
  8. package/dist/generator.js +142 -0
  9. package/dist/generator.js.map +1 -0
  10. package/dist/generator.test.d.ts +1 -0
  11. package/dist/generator.test.js +127 -0
  12. package/dist/generator.test.js.map +1 -0
  13. package/dist/index.d.ts +2 -0
  14. package/dist/index.js +97 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/prompts.d.ts +25 -0
  17. package/dist/prompts.js +83 -0
  18. package/dist/prompts.js.map +1 -0
  19. package/dist/prompts.test.d.ts +1 -0
  20. package/dist/prompts.test.js +24 -0
  21. package/dist/prompts.test.js.map +1 -0
  22. package/dist/providers/cloudflare.d.ts +37 -0
  23. package/dist/providers/cloudflare.js +61 -0
  24. package/dist/providers/cloudflare.js.map +1 -0
  25. package/dist/providers/cloudflare.test.d.ts +1 -0
  26. package/dist/providers/cloudflare.test.js +29 -0
  27. package/dist/providers/cloudflare.test.js.map +1 -0
  28. package/dist/providers/github.d.ts +16 -0
  29. package/dist/providers/github.js +57 -0
  30. package/dist/providers/github.js.map +1 -0
  31. package/dist/providers/github.test.d.ts +1 -0
  32. package/dist/providers/github.test.js +16 -0
  33. package/dist/providers/github.test.js.map +1 -0
  34. package/dist/templates.d.ts +8 -0
  35. package/dist/templates.js +88 -0
  36. package/dist/templates.js.map +1 -0
  37. package/dist/templates.test.d.ts +1 -0
  38. package/dist/templates.test.js +26 -0
  39. package/dist/templates.test.js.map +1 -0
  40. package/package.json +36 -0
  41. package/templates/base/.claude/agents/architect-review.md +160 -0
  42. package/templates/base/.claude/agents/backend-architect.md +308 -0
  43. package/templates/base/.claude/agents/code-reviewer.md +170 -0
  44. package/templates/base/.claude/agents/performance-engineer.md +166 -0
  45. package/templates/base/.claude/agents/test-automator.md +219 -0
  46. package/templates/base/.claude/commands/check-skill-rules.md +53 -0
  47. package/templates/base/.claude/commands/claude-md.md +250 -0
  48. package/templates/base/.claude/commands/code-prompt.md +212 -0
  49. package/templates/base/.claude/commands/explain-code.md +194 -0
  50. package/templates/base/.claude/commands/init-projec.md +89 -0
  51. package/templates/base/.claude/commands/linear/README.md +297 -0
  52. package/templates/base/.claude/commands/linear/create-issue.md +190 -0
  53. package/templates/base/.claude/commands/linear/implement-issue.md +248 -0
  54. package/templates/base/.claude/commands/linear/process-triage.md +399 -0
  55. package/templates/base/.claude/commands/linear/setup.md +180 -0
  56. package/templates/base/.claude/commands/prime.md +9 -0
  57. package/templates/base/.claude/commands/review-gap.md +10 -0
  58. package/templates/base/.claude/commands/setup-aa.md +311 -0
  59. package/templates/base/.claude/commands/ship.md +262 -0
  60. package/templates/base/.claude/commands/tools.md +3 -0
  61. package/templates/base/.claude/docs/claude-progress.txt +107 -0
  62. package/templates/base/.claude/hooks/package-lock.json +556 -0
  63. package/templates/base/.claude/hooks/package.json +16 -0
  64. package/templates/base/.claude/hooks/skill-activation-prompt.sh +7 -0
  65. package/templates/base/.claude/hooks/skill-activation-prompt.ts +142 -0
  66. package/templates/base/.claude/hooks/tsconfig.json +19 -0
  67. package/templates/base/.claude/scripts/check-updates.sh +85 -0
  68. package/templates/base/.claude/scripts/install_pkgs.sh +66 -0
  69. package/templates/base/.claude/scripts/setup-project.sh +177 -0
  70. package/templates/base/.claude/scripts/validate-skill-rules.sh +94 -0
  71. package/templates/base/.claude/settings.json +113 -0
  72. package/templates/base/.claude/settings.local.json +11 -0
  73. package/templates/base/.claude/skills/architecture-analyzer/SKILL.md +531 -0
  74. package/templates/base/.claude/skills/architecture-analyzer/assets/report-template.md +215 -0
  75. package/templates/base/.claude/skills/architecture-analyzer/references/c4-templates.md +234 -0
  76. package/templates/base/.claude/skills/architecture-analyzer/references/confidence-levels.md +203 -0
  77. package/templates/base/.claude/skills/architecture-analyzer/scripts/analyze_structure.py +266 -0
  78. package/templates/base/.claude/skills/architecture-analyzer/scripts/analyze_tech_debt.py +776 -0
  79. package/templates/base/.claude/skills/architecture-analyzer/scripts/extract_apis.py +338 -0
  80. package/templates/base/.claude/skills/architecture-analyzer/scripts/generate_c4.py +283 -0
  81. package/templates/base/.claude/skills/architecture-analyzer/scripts/generate_erd.py +935 -0
  82. package/templates/base/.claude/skills/architecture-analyzer/scripts/map_dependencies.py +555 -0
  83. package/templates/base/.claude/skills/dev-browser/SKILL.md +318 -0
  84. package/templates/base/.claude/skills/dev-browser/bun.lock +443 -0
  85. package/templates/base/.claude/skills/dev-browser/package-lock.json +2927 -0
  86. package/templates/base/.claude/skills/dev-browser/package.json +27 -0
  87. package/templates/base/.claude/skills/dev-browser/scripts/start-server.ts +117 -0
  88. package/templates/base/.claude/skills/dev-browser/server.sh +24 -0
  89. package/templates/base/.claude/skills/dev-browser/src/client.ts +403 -0
  90. package/templates/base/.claude/skills/dev-browser/src/index.ts +281 -0
  91. package/templates/base/.claude/skills/dev-browser/src/snapshot/__tests__/snapshot.test.ts +223 -0
  92. package/templates/base/.claude/skills/dev-browser/src/snapshot/browser-script.ts +877 -0
  93. package/templates/base/.claude/skills/dev-browser/src/snapshot/index.ts +14 -0
  94. package/templates/base/.claude/skills/dev-browser/src/snapshot/inject.ts +13 -0
  95. package/templates/base/.claude/skills/dev-browser/src/types.ts +27 -0
  96. package/templates/base/.claude/skills/dev-browser/tsconfig.json +36 -0
  97. package/templates/base/.claude/skills/dev-browser/vitest.config.ts +12 -0
  98. package/templates/base/.claude/skills/linear/SKILL.md +440 -0
  99. package/templates/base/.claude/skills/linear/examples.md +262 -0
  100. package/templates/base/.claude/skills/linear/lib/client.ts +51 -0
  101. package/templates/base/.claude/skills/linear/lib/config.ts +106 -0
  102. package/templates/base/.claude/skills/linear/lib/output.ts +34 -0
  103. package/templates/base/.claude/skills/linear/package-lock.json +698 -0
  104. package/templates/base/.claude/skills/linear/package.json +27 -0
  105. package/templates/base/.claude/skills/linear/reference.md +263 -0
  106. package/templates/base/.claude/skills/linear/scripts/comments/create.ts +47 -0
  107. package/templates/base/.claude/skills/linear/scripts/comments/list.ts +47 -0
  108. package/templates/base/.claude/skills/linear/scripts/issues/archive.ts +30 -0
  109. package/templates/base/.claude/skills/linear/scripts/issues/create.ts +279 -0
  110. package/templates/base/.claude/skills/linear/scripts/issues/get.ts +68 -0
  111. package/templates/base/.claude/skills/linear/scripts/issues/list.ts +67 -0
  112. package/templates/base/.claude/skills/linear/scripts/issues/update.ts +281 -0
  113. package/templates/base/.claude/skills/linear/scripts/labels/add-to-issue.ts +63 -0
  114. package/templates/base/.claude/skills/linear/scripts/labels/create.ts +45 -0
  115. package/templates/base/.claude/skills/linear/scripts/labels/list.ts +30 -0
  116. package/templates/base/.claude/skills/linear/scripts/list-teams.ts +52 -0
  117. package/templates/base/.claude/skills/linear/scripts/setup/setup-credentials.ts +96 -0
  118. package/templates/base/.claude/skills/linear/scripts/status/list.ts +31 -0
  119. package/templates/base/.claude/skills/linear/scripts/status/set-by-name.ts +78 -0
  120. package/templates/base/.claude/skills/linear/scripts/status/update.ts +44 -0
  121. package/templates/base/.claude/skills/linear/scripts/users/list.ts +59 -0
  122. package/templates/base/.claude/skills/linear/scripts/users/me.ts +20 -0
  123. package/templates/base/.claude/skills/linear/templates/README.md +203 -0
  124. package/templates/base/.claude/skills/linear/templates/api-reference.md +258 -0
  125. package/templates/base/.claude/skills/linear/templates/bug-report.md +99 -0
  126. package/templates/base/.claude/skills/linear/templates/feature-request.md +118 -0
  127. package/templates/base/.claude/skills/linear/templates/security-issue.md +162 -0
  128. package/templates/base/.claude/skills/linear/templates/sprint-task.md +175 -0
  129. package/templates/base/.claude/skills/linear/templates/tech-debt.md +137 -0
  130. package/templates/base/.claude/skills/linear/tsconfig.json +17 -0
  131. package/templates/base/.claude/skills/linear/workflows/issue-lifecycle.md +317 -0
  132. package/templates/base/.claude/skills/playwright-e2e-testing/SKILL.md +113 -0
  133. package/templates/base/.claude/skills/playwright-e2e-testing/assets/global-setup.template.js +97 -0
  134. package/templates/base/.claude/skills/playwright-e2e-testing/assets/playwright.config.template.js +171 -0
  135. package/templates/base/.claude/skills/playwright-e2e-testing/assets/test-template.spec.js +163 -0
  136. package/templates/base/.claude/skills/playwright-e2e-testing/examples/README.md +26 -0
  137. package/templates/base/.claude/skills/playwright-e2e-testing/examples/ads.email-deeplink.spec.ts +12 -0
  138. package/templates/base/.claude/skills/playwright-e2e-testing/examples/mobile.realism.spec.ts +16 -0
  139. package/templates/base/.claude/skills/playwright-e2e-testing/examples/smoke.home.spec.ts +6 -0
  140. package/templates/base/.claude/skills/playwright-e2e-testing/references/architecture.md +578 -0
  141. package/templates/base/.claude/skills/playwright-e2e-testing/references/best-practices.md +260 -0
  142. package/templates/base/.claude/skills/playwright-e2e-testing/references/ci-reporting.md +86 -0
  143. package/templates/base/.claude/skills/playwright-e2e-testing/references/debugging.md +629 -0
  144. package/templates/base/.claude/skills/playwright-e2e-testing/references/mobile-realism.md +50 -0
  145. package/templates/base/.claude/skills/playwright-e2e-testing/references/optimization.md +488 -0
  146. package/templates/base/.claude/skills/playwright-e2e-testing/references/patterns.md +513 -0
  147. package/templates/base/.claude/skills/playwright-e2e-testing/references/resources.md +44 -0
  148. package/templates/base/.claude/skills/playwright-e2e-testing/references/visual-a11y.md +66 -0
  149. package/templates/base/.claude/skills/playwright-e2e-testing/scripts/auth-setup.js +202 -0
  150. package/templates/base/.claude/skills/playwright-e2e-testing/scripts/performance-analyzer.js +240 -0
  151. package/templates/base/.claude/skills/playwright-e2e-testing/scripts/trace-url.js +132 -0
  152. package/templates/base/.claude/skills/playwright-e2e-testing/templates/ci/github-actions.playwright.yml +78 -0
  153. package/templates/base/.claude/skills/playwright-e2e-testing/templates/fixtures.ts +44 -0
  154. package/templates/base/.claude/skills/playwright-e2e-testing/templates/global-setup.template.js +97 -0
  155. package/templates/base/.claude/skills/playwright-e2e-testing/templates/global.setup.ts +35 -0
  156. package/templates/base/.claude/skills/playwright-e2e-testing/templates/helpers/ad-gpt-observer.ts +80 -0
  157. package/templates/base/.claude/skills/playwright-e2e-testing/templates/helpers/chromium-mobile-profile.ts +93 -0
  158. package/templates/base/.claude/skills/playwright-e2e-testing/templates/playwright.config.template.js +171 -0
  159. package/templates/base/.claude/skills/playwright-e2e-testing/templates/playwright.config.ts +126 -0
  160. package/templates/base/.claude/skills/playwright-e2e-testing/templates/test-template.spec.js +163 -0
  161. package/templates/base/.claude/skills/playwright-e2e-testing/templates/tests/email-deeplink.ads.spec.ts +44 -0
  162. package/templates/base/.claude/skills/skill-rules.json +184 -0
  163. package/templates/base/.claude/skills/wrangler/SKILL.md +209 -0
  164. package/templates/base/.claude/skills/wrangler/resources/api.md +494 -0
  165. package/templates/base/.claude/skills/wrangler/resources/bundling.md +83 -0
  166. package/templates/base/.claude/skills/wrangler/resources/commands/cert.md +64 -0
  167. package/templates/base/.claude/skills/wrangler/resources/commands/check.md +66 -0
  168. package/templates/base/.claude/skills/wrangler/resources/commands/containers.md +157 -0
  169. package/templates/base/.claude/skills/wrangler/resources/commands/d1.md +843 -0
  170. package/templates/base/.claude/skills/wrangler/resources/commands/delete.md +27 -0
  171. package/templates/base/.claude/skills/wrangler/resources/commands/deploy.md +139 -0
  172. package/templates/base/.claude/skills/wrangler/resources/commands/deployments.md +56 -0
  173. package/templates/base/.claude/skills/wrangler/resources/commands/dev.md +157 -0
  174. package/templates/base/.claude/skills/wrangler/resources/commands/dispatch-namespace.md +69 -0
  175. package/templates/base/.claude/skills/wrangler/resources/commands/docs.md +61 -0
  176. package/templates/base/.claude/skills/wrangler/resources/commands/how-to-run.md +62 -0
  177. package/templates/base/.claude/skills/wrangler/resources/commands/hyperdrive.md +425 -0
  178. package/templates/base/.claude/skills/wrangler/resources/commands/init.md +31 -0
  179. package/templates/base/.claude/skills/wrangler/resources/commands/kv-bulk.md +265 -0
  180. package/templates/base/.claude/skills/wrangler/resources/commands/kv-key.md +353 -0
  181. package/templates/base/.claude/skills/wrangler/resources/commands/kv-namespace.md +265 -0
  182. package/templates/base/.claude/skills/wrangler/resources/commands/login.md +23 -0
  183. package/templates/base/.claude/skills/wrangler/resources/commands/logout.md +19 -0
  184. package/templates/base/.claude/skills/wrangler/resources/commands/mtls-certificate.md +69 -0
  185. package/templates/base/.claude/skills/wrangler/resources/commands/pages.md +175 -0
  186. package/templates/base/.claude/skills/wrangler/resources/commands/pipelines.md +76 -0
  187. package/templates/base/.claude/skills/wrangler/resources/commands/queues.md +132 -0
  188. package/templates/base/.claude/skills/wrangler/resources/commands/r2-bucket.md +342 -0
  189. package/templates/base/.claude/skills/wrangler/resources/commands/r2-object.md +267 -0
  190. package/templates/base/.claude/skills/wrangler/resources/commands/r2-sql.md +65 -0
  191. package/templates/base/.claude/skills/wrangler/resources/commands/rollback.md +40 -0
  192. package/templates/base/.claude/skills/wrangler/resources/commands/secret.md +308 -0
  193. package/templates/base/.claude/skills/wrangler/resources/commands/secrets-store-secret.md +100 -0
  194. package/templates/base/.claude/skills/wrangler/resources/commands/secrets-store-store.md +60 -0
  195. package/templates/base/.claude/skills/wrangler/resources/commands/setup.md +67 -0
  196. package/templates/base/.claude/skills/wrangler/resources/commands/tail.md +37 -0
  197. package/templates/base/.claude/skills/wrangler/resources/commands/telemetry.md +64 -0
  198. package/templates/base/.claude/skills/wrangler/resources/commands/triggers.md +39 -0
  199. package/templates/base/.claude/skills/wrangler/resources/commands/types.md +73 -0
  200. package/templates/base/.claude/skills/wrangler/resources/commands/vectorize.md +941 -0
  201. package/templates/base/.claude/skills/wrangler/resources/commands/versions.md +95 -0
  202. package/templates/base/.claude/skills/wrangler/resources/commands/whoami.md +49 -0
  203. package/templates/base/.claude/skills/wrangler/resources/commands/workflows.md +117 -0
  204. package/templates/base/.claude/skills/wrangler/resources/commands.md +138 -0
  205. package/templates/base/.claude/skills/wrangler/resources/configuration.md +2176 -0
  206. package/templates/base/.claude/skills/wrangler/resources/custom-builds.md +55 -0
  207. package/templates/base/.claude/skills/wrangler/resources/deprecations.md +279 -0
  208. package/templates/base/.claude/skills/wrangler/resources/enviroments.md +416 -0
  209. package/templates/base/.claude/skills/wrangler/resources/extract_sections.py +119 -0
  210. package/templates/base/.claude/skills/wrangler/resources/process_content.py +94 -0
  211. package/templates/base/.claude/skills/wrangler/resources/system-enviroments-variables.md +120 -0
  212. package/templates/base/.dev.vars.example +15 -0
  213. package/templates/base/.env.example +29 -0
  214. package/templates/base/.github/workflows/test.yml +127 -0
  215. package/templates/base/.nycrc.json +16 -0
  216. package/templates/base/CLAUDE.md +218 -0
  217. package/templates/base/README.md +670 -0
  218. package/templates/base/auth-setup-error.png +0 -0
  219. package/templates/base/config/drizzle.config.ts +10 -0
  220. package/templates/base/config/eslint.config.js +364 -0
  221. package/templates/base/config/wrangler.json +76 -0
  222. package/templates/base/docs/app_spec.txt +879 -0
  223. package/templates/base/docs/app_spec_template.md +681 -0
  224. package/templates/base/docs/architecture/README.md +8 -0
  225. package/templates/base/docs/architecture/data-requirements.md +109 -0
  226. package/templates/base/docs/architecture/erd.md +91 -0
  227. package/templates/base/docs/features/feature_list.json +3128 -0
  228. package/templates/base/docs/hono-boilerplate-plan.md +1774 -0
  229. package/templates/base/docs/test-coverage-gap-analysis.md +242 -0
  230. package/templates/base/docs/testing.md +188 -0
  231. package/templates/base/index.html +16 -0
  232. package/templates/base/package.json +115 -0
  233. package/templates/base/playwright.config.ts +158 -0
  234. package/templates/base/pnpm-lock.yaml +8175 -0
  235. package/templates/base/scripts/capture-prod-session.ts +250 -0
  236. package/templates/base/scripts/generate-openapi.ts +23 -0
  237. package/templates/base/scripts/init.sh +121 -0
  238. package/templates/base/src/client/__tests__/button.test.tsx +30 -0
  239. package/templates/base/src/client/__tests__/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-display-dashboard-stats-cards-1.png +0 -0
  240. package/templates/base/src/client/__tests__/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-display-quick-action-cards-1.png +0 -0
  241. package/templates/base/src/client/__tests__/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-display-recent-activity-section-1.png +0 -0
  242. package/templates/base/src/client/__tests__/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-display-user-first-name-in-welcome-message-1.png +0 -0
  243. package/templates/base/src/client/__tests__/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-display-user-information-in-sidebar-1.png +0 -0
  244. package/templates/base/src/client/__tests__/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-render-dashboard-when-authenticated-1.png +0 -0
  245. package/templates/base/src/client/__tests__/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-show-navigation-sidebar-1.png +0 -0
  246. package/templates/base/src/client/__tests__/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-unauthenticated-should-redirect-to-login-when-not-authenticated-1.png +0 -0
  247. package/templates/base/src/client/__tests__/routes/__screenshots__/login.test.tsx/Login-Page-should-display-Google-OAuth-login-button-1.png +0 -0
  248. package/templates/base/src/client/__tests__/routes/__screenshots__/login.test.tsx/Login-Page-should-have-a-link-back-to-home-page-1.png +0 -0
  249. package/templates/base/src/client/__tests__/routes/__screenshots__/login.test.tsx/Login-Page-should-render-login-content-without-waiting-for-authentication-1.png +0 -0
  250. package/templates/base/src/client/__tests__/routes/__screenshots__/login.test.tsx/Login-Page-should-render-login-page-at--login-route-1.png +0 -0
  251. package/templates/base/src/client/__tests__/routes/__screenshots__/login.test.tsx/Login-Page-should-show-Terms-of-Service-and-Privacy-Policy-links-1.png +0 -0
  252. package/templates/base/src/client/__tests__/routes/__screenshots__/login.test.tsx/Login-Page-should-trigger-OAuth-flow-when-clicking-login-button-1.png +0 -0
  253. package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-404-handling-should-display-404-text-on-not-found-page-1.png +0 -0
  254. package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-404-handling-should-have-navigation-options-on-404-page-1.png +0 -0
  255. package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-404-handling-should-render-404-page-for-unknown-routes-1.png +0 -0
  256. package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-authenticated-navigation-should-navigate-from-dashboard-to-account-page-1.png +0 -0
  257. package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-authenticated-navigation-should-navigate-from-dashboard-to-integrations-page-1.png +0 -0
  258. package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-authenticated-navigation-should-navigate-from-dashboard-to-settings-page-1.png +0 -0
  259. package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-authenticated-navigation-should-navigate-from-dashboard-to-team-page-1.png +0 -0
  260. package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-home-page-navigation-should-display-navigation-links-on-home-page-1.png +0 -0
  261. package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-home-page-navigation-should-have-correct-link-destinations-on-home-page-1.png +0 -0
  262. package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-unauthenticated-navigation-should-allow-access-to-home-page-without-authentication-1.png +0 -0
  263. package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-unauthenticated-navigation-should-allow-access-to-login-page-without-authentication-1.png +0 -0
  264. package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-unauthenticated-navigation-should-redirect-unauthenticated-users-from-dashboard-to-login-1.png +0 -0
  265. package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-unauthenticated-navigation-should-redirect-unauthenticated-users-from-settings-to-login-1.png +0 -0
  266. package/templates/base/src/client/__tests__/routes/__screenshots__/navigation.test.tsx/Navigation-unauthenticated-navigation-should-redirect-unauthenticated-users-from-team-to-login-1.png +0 -0
  267. package/templates/base/src/client/__tests__/routes/authenticated-layout.test.tsx +252 -0
  268. package/templates/base/src/client/__tests__/routes/dashboard.test.tsx +136 -0
  269. package/templates/base/src/client/__tests__/routes/error-components.test.tsx +186 -0
  270. package/templates/base/src/client/__tests__/routes/login.test.tsx +112 -0
  271. package/templates/base/src/client/__tests__/routes/navigation.test.tsx +272 -0
  272. package/templates/base/src/client/__tests__/routes/root-layout.test.tsx +65 -0
  273. package/templates/base/src/client/__tests__/setup-browser.ts +15 -0
  274. package/templates/base/src/client/__tests__/setup.ts +32 -0
  275. package/templates/base/src/client/__tests__/test-utils.tsx +135 -0
  276. package/templates/base/src/client/api/.gitkeep +0 -0
  277. package/templates/base/src/client/components/__tests__/__screenshots__/sidebar.test.tsx/Sidebar-can-be-collapsed-by-default-1.png +0 -0
  278. package/templates/base/src/client/components/__tests__/__screenshots__/sidebar.test.tsx/Sidebar-expands-when-collapsed-and-expand-button-is-clicked-1.png +0 -0
  279. package/templates/base/src/client/components/__tests__/__screenshots__/sidebar.test.tsx/Sidebar-handles-logout-button-click-1.png +0 -0
  280. package/templates/base/src/client/components/__tests__/__screenshots__/sidebar.test.tsx/Sidebar-handles-navigation-clicks-1.png +0 -0
  281. package/templates/base/src/client/components/__tests__/__screenshots__/sidebar.test.tsx/Sidebar-hides-navigation-labels-when-collapsed-1.png +0 -0
  282. package/templates/base/src/client/components/__tests__/__screenshots__/sidebar.test.tsx/Sidebar-highlights-active-route-1.png +0 -0
  283. package/templates/base/src/client/components/__tests__/__screenshots__/sidebar.test.tsx/Sidebar-renders-sidebar-navigation-items-1.png +0 -0
  284. package/templates/base/src/client/components/__tests__/__screenshots__/sidebar.test.tsx/Sidebar-shows-keyboard-shortcut-hint-when-expanded-1.png +0 -0
  285. package/templates/base/src/client/components/__tests__/__screenshots__/sidebar.test.tsx/Sidebar-shows-user-info-when-authenticated-1.png +0 -0
  286. package/templates/base/src/client/components/__tests__/__screenshots__/sidebar.test.tsx/Sidebar-shows-user-initials-in-avatar-fallback-1.png +0 -0
  287. package/templates/base/src/client/components/__tests__/error-boundary.test.tsx +97 -0
  288. package/templates/base/src/client/components/__tests__/sidebar.test.tsx +281 -0
  289. package/templates/base/src/client/components/error-boundary.tsx +68 -0
  290. package/templates/base/src/client/components/icons.tsx +106 -0
  291. package/templates/base/src/client/components/layout/.gitkeep +0 -0
  292. package/templates/base/src/client/components/sidebar.tsx +267 -0
  293. package/templates/base/src/client/components/ui/.gitkeep +0 -0
  294. package/templates/base/src/client/components/ui/__tests__/avatar.test.tsx +308 -0
  295. package/templates/base/src/client/components/ui/__tests__/card.test.tsx +214 -0
  296. package/templates/base/src/client/components/ui/__tests__/dialog.test.tsx +297 -0
  297. package/templates/base/src/client/components/ui/__tests__/error-fallback.test.tsx +145 -0
  298. package/templates/base/src/client/components/ui/__tests__/input.test.tsx +98 -0
  299. package/templates/base/src/client/components/ui/__tests__/loading-skeleton.test.tsx +139 -0
  300. package/templates/base/src/client/components/ui/__tests__/skeleton.test.tsx +44 -0
  301. package/templates/base/src/client/components/ui/__tests__/sonner.test.tsx +28 -0
  302. package/templates/base/src/client/components/ui/__tests__/tabs.test.tsx +233 -0
  303. package/templates/base/src/client/components/ui/avatar.tsx +101 -0
  304. package/templates/base/src/client/components/ui/badge.tsx +46 -0
  305. package/templates/base/src/client/components/ui/button.tsx +72 -0
  306. package/templates/base/src/client/components/ui/card.tsx +86 -0
  307. package/templates/base/src/client/components/ui/dialog.tsx +140 -0
  308. package/templates/base/src/client/components/ui/error-fallback.tsx +179 -0
  309. package/templates/base/src/client/components/ui/form.tsx +172 -0
  310. package/templates/base/src/client/components/ui/input.tsx +24 -0
  311. package/templates/base/src/client/components/ui/label.tsx +22 -0
  312. package/templates/base/src/client/components/ui/loading-skeleton.tsx +154 -0
  313. package/templates/base/src/client/components/ui/separator.tsx +33 -0
  314. package/templates/base/src/client/components/ui/skeleton.tsx +16 -0
  315. package/templates/base/src/client/components/ui/sonner.tsx +29 -0
  316. package/templates/base/src/client/components/ui/tabs.tsx +121 -0
  317. package/templates/base/src/client/hooks/.gitkeep +0 -0
  318. package/templates/base/src/client/hooks/__tests__/use-auth.test.tsx +306 -0
  319. package/templates/base/src/client/hooks/__tests__/use-theme.test.tsx +172 -0
  320. package/templates/base/src/client/hooks/use-auth.ts +53 -0
  321. package/templates/base/src/client/hooks/use-theme.tsx +78 -0
  322. package/templates/base/src/client/index.css +881 -0
  323. package/templates/base/src/client/lib/query-client.ts +11 -0
  324. package/templates/base/src/client/lib/utils.ts +7 -0
  325. package/templates/base/src/client/main.tsx +26 -0
  326. package/templates/base/src/client/routeTree.gen.ts +258 -0
  327. package/templates/base/src/client/router.ts +15 -0
  328. package/templates/base/src/client/routes/$.tsx +77 -0
  329. package/templates/base/src/client/routes/.gitkeep +0 -0
  330. package/templates/base/src/client/routes/__root.tsx +34 -0
  331. package/templates/base/src/client/routes/__tests__/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-display-accept-invitation-button-1.png +0 -0
  332. package/templates/base/src/client/routes/__tests__/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-display-decline-button-linking-to-homepage-1.png +0 -0
  333. package/templates/base/src/client/routes/__tests__/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-display-invitation-details--email--workspace--role--1.png +0 -0
  334. package/templates/base/src/client/routes/__tests__/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-have-a-logo-link-to-homepage-1.png +0 -0
  335. package/templates/base/src/client/routes/__tests__/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-render-invitation-page-with-inviter-name-and-workspace-1.png +0 -0
  336. package/templates/base/src/client/routes/__tests__/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-show-terms-of-service-and-privacy-policy-links-1.png +0 -0
  337. package/templates/base/src/client/routes/__tests__/invite.test.tsx +138 -0
  338. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/account.test.tsx/Account-Page-should-render-Active-Sessions-section-with-session-cards-1.png +0 -0
  339. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/account.test.tsx/Account-Page-should-render-page-with-correct-title--Account--1.png +0 -0
  340. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/account.test.tsx/Account-Page-should-show-API-Access-section-1.png +0 -0
  341. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/account.test.tsx/Account-Page-should-show-Connected-Accounts-section-with-Google-connected-1.png +0 -0
  342. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/account.test.tsx/Account-Page-should-show-Danger-Zone-section-with-delete-button-1.png +0 -0
  343. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/account.test.tsx/Account-Page-should-show-Security-section-with-Two-Factor-Authentication-1.png +0 -0
  344. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-API-documentation-section-should-display-API-documentation-link-section-1.png +0 -0
  345. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-Create-Webhook-Dialog-should-have-Add-Webhook-trigger-button-1.png +0 -0
  346. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-category-filters-should-display-all-category-buttons-1.png +0 -0
  347. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-integration-cards-should-display-all-integration-cards-with-names-1.png +0 -0
  348. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-integration-cards-should-display-category-badges-on-cards-1.png +0 -0
  349. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-integration-cards-should-show-Configure-button-for-connected-integrations-1.png +0 -0
  350. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-integration-cards-should-show-Connect-button-for-not-connected-integrations-1.png +0 -0
  351. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-integration-cards-should-show-Connected-badge-for-connected-integrations-1.png +0 -0
  352. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-display-Available-Integrations-section-1.png +0 -0
  353. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-display-Webhooks-section-1.png +0 -0
  354. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-display-connected-count-1.png +0 -0
  355. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-display-page-description-1.png +0 -0
  356. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-display-search-input-1.png +0 -0
  357. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-render-with-correct-title--Integrations--1.png +0 -0
  358. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-search-functionality-should-filter-integrations-based-on-search-query-1.png +0 -0
  359. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-search-functionality-should-search-by-description-1.png +0 -0
  360. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-search-functionality-should-show-no-results-message-when-search-has-no-matches-1.png +0 -0
  361. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-webhooks-section-should-display-existing-webhook-1.png +0 -0
  362. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-webhooks-section-should-display-webhook-events-1.png +0 -0
  363. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-webhooks-section-should-display-webhook-last-delivery-info-1.png +0 -0
  364. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-webhooks-section-should-display-webhook-success-status-1.png +0 -0
  365. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/integrations.test.tsx/Integrations-Page-webhooks-section-should-have-Add-Webhook-button-1.png +0 -0
  366. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Account-tab-should-display-connected-accounts-section-with-Google-provider-1.png +0 -0
  367. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Account-tab-should-display-sessions-and-danger-zone-sections-1.png +0 -0
  368. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Notifications-tab-should-display-all-notification-toggle-options-1.png +0 -0
  369. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Notifications-tab-should-display-email-notifications-section-1.png +0 -0
  370. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Notifications-tab-should-display-toggle-switches-for-notification-options-1.png +0 -0
  371. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Notifications-tab-should-have-toggles-checked-by-default-1.png +0 -0
  372. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display--Save-Changes--button-1.png +0 -0
  373. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display-personal-information-form-1.png +0 -0
  374. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display-profile-picture-section-1.png +0 -0
  375. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display-user-email-in-disabled-email-input-1.png +0 -0
  376. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display-user-initials-in-avatar-1.png +0 -0
  377. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display-user-name-in-the-name-input-1.png +0 -0
  378. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-page-rendering-should-display-all-three-tabs-1.png +0 -0
  379. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-page-rendering-should-display-page-description-1.png +0 -0
  380. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-page-rendering-should-render-with-correct-title--Settings--1.png +0 -0
  381. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-tab-navigation-should-show-Profile-tab-as-default-active-tab-1.png +0 -0
  382. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-tab-navigation-should-switch-to-Account-tab-when-clicked-1.png +0 -0
  383. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/settings.test.tsx/Settings-Page-tab-navigation-should-switch-to-Notifications-tab-when-clicked-1.png +0 -0
  384. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/team.test.tsx/Team-Page-should-display-Active-Members-section-with-member-count-1.png +0 -0
  385. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/team.test.tsx/Team-Page-should-display-Pending-Invitations-section-with-invitation-details-1.png +0 -0
  386. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/team.test.tsx/Team-Page-should-have-invite-member-button-that-can-be-clicked-1.png +0 -0
  387. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/team.test.tsx/Team-Page-should-render-page-with-correct-title-and-description-1.png +0 -0
  388. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/team.test.tsx/Team-Page-should-render-search-input-that-filters-team-members-1.png +0 -0
  389. package/templates/base/src/client/routes/_authenticated/__tests__/__screenshots__/team.test.tsx/Team-Page-should-show-current-user-with---you---indicator-and-role-badge-1.png +0 -0
  390. package/templates/base/src/client/routes/_authenticated/__tests__/account.test.tsx +324 -0
  391. package/templates/base/src/client/routes/_authenticated/__tests__/integrations.test.tsx +520 -0
  392. package/templates/base/src/client/routes/_authenticated/__tests__/settings.test.tsx +414 -0
  393. package/templates/base/src/client/routes/_authenticated/__tests__/team.test.tsx +374 -0
  394. package/templates/base/src/client/routes/_authenticated/account.tsx +416 -0
  395. package/templates/base/src/client/routes/_authenticated/dashboard.tsx +151 -0
  396. package/templates/base/src/client/routes/_authenticated/integrations.tsx +553 -0
  397. package/templates/base/src/client/routes/_authenticated/settings.tsx +310 -0
  398. package/templates/base/src/client/routes/_authenticated/team.tsx +395 -0
  399. package/templates/base/src/client/routes/_authenticated.tsx +69 -0
  400. package/templates/base/src/client/routes/index.tsx +155 -0
  401. package/templates/base/src/client/routes/invite.$token.tsx +191 -0
  402. package/templates/base/src/client/routes/login.tsx +92 -0
  403. package/templates/base/src/server/__tests__/fixtures.ts +461 -0
  404. package/templates/base/src/server/__tests__/mocks/__tests__/db.test.ts +239 -0
  405. package/templates/base/src/server/__tests__/mocks/__tests__/kv.test.ts +293 -0
  406. package/templates/base/src/server/__tests__/mocks/__tests__/r2.test.ts +363 -0
  407. package/templates/base/src/server/__tests__/mocks/db.ts +186 -0
  408. package/templates/base/src/server/__tests__/mocks/index.ts +33 -0
  409. package/templates/base/src/server/__tests__/mocks/kv.ts +286 -0
  410. package/templates/base/src/server/__tests__/mocks/r2.ts +397 -0
  411. package/templates/base/src/server/__tests__/setup.ts +281 -0
  412. package/templates/base/src/server/auth/__tests__/guards.test.ts +162 -0
  413. package/templates/base/src/server/auth/guards.ts +92 -0
  414. package/templates/base/src/server/auth/permissions.test.ts +45 -0
  415. package/templates/base/src/server/auth/permissions.ts +139 -0
  416. package/templates/base/src/server/auth/roles.test.ts +169 -0
  417. package/templates/base/src/server/auth/roles.ts +141 -0
  418. package/templates/base/src/server/db/client.ts +12 -0
  419. package/templates/base/src/server/db/schema/accounts.ts +20 -0
  420. package/templates/base/src/server/db/schema/audit-logs.ts +26 -0
  421. package/templates/base/src/server/db/schema/index.ts +7 -0
  422. package/templates/base/src/server/db/schema/invitations.ts +30 -0
  423. package/templates/base/src/server/db/schema/refresh-tokens.ts +22 -0
  424. package/templates/base/src/server/db/schema/user-accounts.ts +25 -0
  425. package/templates/base/src/server/db/schema/users.ts +33 -0
  426. package/templates/base/src/server/db/seed.ts +267 -0
  427. package/templates/base/src/server/env.test.ts +84 -0
  428. package/templates/base/src/server/env.ts +78 -0
  429. package/templates/base/src/server/index.ts +82 -0
  430. package/templates/base/src/server/lib/audit.ts +73 -0
  431. package/templates/base/src/server/lib/audited-db.test.ts +107 -0
  432. package/templates/base/src/server/lib/audited-db.ts +154 -0
  433. package/templates/base/src/server/lib/email.test.ts +116 -0
  434. package/templates/base/src/server/lib/email.ts +82 -0
  435. package/templates/base/src/server/lib/errors.test.ts +49 -0
  436. package/templates/base/src/server/lib/errors.ts +64 -0
  437. package/templates/base/src/server/lib/oauth.test.ts +238 -0
  438. package/templates/base/src/server/lib/oauth.ts +113 -0
  439. package/templates/base/src/server/lib/pagination.test.ts +52 -0
  440. package/templates/base/src/server/lib/pagination.ts +32 -0
  441. package/templates/base/src/server/lib/password.test.ts +151 -0
  442. package/templates/base/src/server/lib/password.ts +151 -0
  443. package/templates/base/src/server/lib/providers.test.ts +105 -0
  444. package/templates/base/src/server/lib/providers.ts +62 -0
  445. package/templates/base/src/server/lib/r2-storage.test.ts +202 -0
  446. package/templates/base/src/server/lib/r2-storage.ts +107 -0
  447. package/templates/base/src/server/lib/schema-helpers.ts +16 -0
  448. package/templates/base/src/server/lib/session.test.ts +758 -0
  449. package/templates/base/src/server/lib/session.ts +267 -0
  450. package/templates/base/src/server/lib/tokens.test.ts +208 -0
  451. package/templates/base/src/server/lib/tokens.ts +65 -0
  452. package/templates/base/src/server/lib/transaction.test.ts +45 -0
  453. package/templates/base/src/server/lib/transaction.ts +24 -0
  454. package/templates/base/src/server/middleware/account.test.ts +201 -0
  455. package/templates/base/src/server/middleware/account.ts +66 -0
  456. package/templates/base/src/server/middleware/auth.test.ts +345 -0
  457. package/templates/base/src/server/middleware/auth.ts +146 -0
  458. package/templates/base/src/server/middleware/cors.test.ts +88 -0
  459. package/templates/base/src/server/middleware/cors.ts +26 -0
  460. package/templates/base/src/server/middleware/error-handler.test.ts +69 -0
  461. package/templates/base/src/server/middleware/error-handler.ts +43 -0
  462. package/templates/base/src/server/middleware/index.ts +8 -0
  463. package/templates/base/src/server/middleware/rate-limit.test.ts +472 -0
  464. package/templates/base/src/server/middleware/rate-limit.ts +294 -0
  465. package/templates/base/src/server/middleware/request-context.test.ts +175 -0
  466. package/templates/base/src/server/middleware/request-context.ts +28 -0
  467. package/templates/base/src/server/middleware/request-logger.test.ts +92 -0
  468. package/templates/base/src/server/middleware/request-logger.ts +50 -0
  469. package/templates/base/src/server/routes/accounts/__tests__/handlers.test.ts +460 -0
  470. package/templates/base/src/server/routes/accounts/handlers.ts +179 -0
  471. package/templates/base/src/server/routes/accounts/index.ts +55 -0
  472. package/templates/base/src/server/routes/accounts/routes.ts +205 -0
  473. package/templates/base/src/server/routes/accounts/schemas.ts +31 -0
  474. package/templates/base/src/server/routes/api.ts +37 -0
  475. package/templates/base/src/server/routes/audits/__tests__/handlers.test.ts +349 -0
  476. package/templates/base/src/server/routes/audits/handlers.ts +37 -0
  477. package/templates/base/src/server/routes/audits/index.ts +14 -0
  478. package/templates/base/src/server/routes/audits/routes.ts +29 -0
  479. package/templates/base/src/server/routes/audits/schemas.ts +43 -0
  480. package/templates/base/src/server/routes/auth/__tests__/handlers.test.ts +381 -0
  481. package/templates/base/src/server/routes/auth/handlers.ts +222 -0
  482. package/templates/base/src/server/routes/auth/index.ts +37 -0
  483. package/templates/base/src/server/routes/auth/routes.ts +136 -0
  484. package/templates/base/src/server/routes/auth/schemas.ts +48 -0
  485. package/templates/base/src/server/routes/auth/test-login.ts +156 -0
  486. package/templates/base/src/server/routes/health/__tests__/handlers.test.ts +237 -0
  487. package/templates/base/src/server/routes/health/handlers.ts +83 -0
  488. package/templates/base/src/server/routes/health/index.ts +13 -0
  489. package/templates/base/src/server/routes/health/routes.ts +90 -0
  490. package/templates/base/src/server/routes/index.ts +53 -0
  491. package/templates/base/src/server/routes/invitations/__tests__/handlers.test.ts +473 -0
  492. package/templates/base/src/server/routes/invitations/handlers.ts +71 -0
  493. package/templates/base/src/server/routes/invitations/index.ts +25 -0
  494. package/templates/base/src/server/routes/invitations/routes.ts +69 -0
  495. package/templates/base/src/server/routes/invitations/schemas.ts +39 -0
  496. package/templates/base/src/server/routes/openapi.ts +14 -0
  497. package/templates/base/src/server/routes/schemas.ts +53 -0
  498. package/templates/base/src/server/routes/storage/__tests__/handlers.test.ts +408 -0
  499. package/templates/base/src/server/routes/storage/handlers.ts +100 -0
  500. package/templates/base/src/server/routes/storage/index.ts +42 -0
  501. package/templates/base/src/server/routes/storage/routes.ts +91 -0
  502. package/templates/base/src/server/routes/storage/schemas.ts +56 -0
  503. package/templates/base/src/server/routes/users/__tests__/handlers.test.ts +526 -0
  504. package/templates/base/src/server/routes/users/handlers.ts +228 -0
  505. package/templates/base/src/server/routes/users/index.ts +67 -0
  506. package/templates/base/src/server/routes/users/routes.ts +265 -0
  507. package/templates/base/src/server/routes/users/schemas.ts +67 -0
  508. package/templates/base/src/server/services/__tests__/accounts.test.ts +764 -0
  509. package/templates/base/src/server/services/__tests__/audits.test.ts +235 -0
  510. package/templates/base/src/server/services/__tests__/auth.test.ts +765 -0
  511. package/templates/base/src/server/services/__tests__/invitations.test.ts +704 -0
  512. package/templates/base/src/server/services/__tests__/users.test.ts +755 -0
  513. package/templates/base/src/server/services/accounts.ts +269 -0
  514. package/templates/base/src/server/services/audits.ts +82 -0
  515. package/templates/base/src/server/services/auth.ts +225 -0
  516. package/templates/base/src/server/services/index.ts +6 -0
  517. package/templates/base/src/server/services/invitations.ts +306 -0
  518. package/templates/base/src/server/services/users.ts +350 -0
  519. package/templates/base/src/server/types/auth.ts +36 -0
  520. package/templates/base/src/server/types/index.ts +117 -0
  521. package/templates/base/src/shared/schemas/.gitkeep +0 -0
  522. package/templates/base/src/shared/schemas/__tests__/schemas.test.ts +547 -0
  523. package/templates/base/src/shared/schemas/account.ts +15 -0
  524. package/templates/base/src/shared/schemas/index.ts +6 -0
  525. package/templates/base/src/shared/schemas/invitation.ts +9 -0
  526. package/templates/base/src/shared/schemas/profile.ts +10 -0
  527. package/templates/base/src/shared/schemas/user.ts +16 -0
  528. package/templates/base/src/shared/schemas/webhook.ts +12 -0
  529. package/templates/base/src/shared/types/.gitkeep +0 -0
  530. package/templates/base/src/shared/types/account.ts +12 -0
  531. package/templates/base/src/shared/types/api.ts +1399 -0
  532. package/templates/base/src/shared/types/auth.ts +24 -0
  533. package/templates/base/src/shared/types/index.ts +5 -0
  534. package/templates/base/src/shared/types/user.ts +31 -0
  535. package/templates/base/src/test/vitest-zod-matcher.ts +37 -0
  536. package/templates/base/src/test/vitest.d.ts +19 -0
  537. package/templates/base/tests/e2e/README.md +141 -0
  538. package/templates/base/tests/e2e/a11y/accessibility.spec.ts +925 -0
  539. package/templates/base/tests/e2e/a11y/keyboard-navigation.spec.ts +610 -0
  540. package/templates/base/tests/e2e/api/accounts.spec.ts +148 -0
  541. package/templates/base/tests/e2e/api/audit-logs.spec.ts +130 -0
  542. package/templates/base/tests/e2e/api/authenticated-api.spec.ts +311 -0
  543. package/templates/base/tests/e2e/api/storage.spec.ts +109 -0
  544. package/templates/base/tests/e2e/auth-flows.unauth.spec.ts +117 -0
  545. package/templates/base/tests/e2e/auth-logout.unauth.spec.ts +103 -0
  546. package/templates/base/tests/e2e/auth.setup.ts +115 -0
  547. package/templates/base/tests/e2e/auth.spec.ts +146 -0
  548. package/templates/base/tests/e2e/compatibility/cross-browser.spec.ts +152 -0
  549. package/templates/base/tests/e2e/compatibility/cross-browser.spec.ts-snapshots/login-chromium-chromium-darwin.png +0 -0
  550. package/templates/base/tests/e2e/crud/account.spec.ts +356 -0
  551. package/templates/base/tests/e2e/crud/integrations.spec.ts +419 -0
  552. package/templates/base/tests/e2e/crud/team.spec.ts +287 -0
  553. package/templates/base/tests/e2e/crud/users.spec.ts +239 -0
  554. package/templates/base/tests/e2e/errors/error-boundary.spec.ts +428 -0
  555. package/templates/base/tests/e2e/errors/error-handling.spec.ts +47 -0
  556. package/templates/base/tests/e2e/errors/error-handling.unauth.spec.ts +205 -0
  557. package/templates/base/tests/e2e/fixtures.ts +266 -0
  558. package/templates/base/tests/e2e/forms/validation.spec.ts +569 -0
  559. package/templates/base/tests/e2e/invitations/invite-flow.unauth.spec.ts +204 -0
  560. package/templates/base/tests/e2e/journeys/account-lifecycle.spec.ts +314 -0
  561. package/templates/base/tests/e2e/journeys/audit-investigation.spec.ts +299 -0
  562. package/templates/base/tests/e2e/journeys/auth-onboarding.spec.ts +232 -0
  563. package/templates/base/tests/e2e/journeys/critical-flows.spec.ts +281 -0
  564. package/templates/base/tests/e2e/journeys/error-recovery.spec.ts +354 -0
  565. package/templates/base/tests/e2e/journeys/file-management.spec.ts +307 -0
  566. package/templates/base/tests/e2e/journeys/integrations.spec.ts +372 -0
  567. package/templates/base/tests/e2e/journeys/multi-account.spec.ts +317 -0
  568. package/templates/base/tests/e2e/journeys/rbac-enforcement.spec.ts +389 -0
  569. package/templates/base/tests/e2e/journeys/settings-profile.spec.ts +400 -0
  570. package/templates/base/tests/e2e/journeys/team-collaboration.spec.ts +410 -0
  571. package/templates/base/tests/e2e/mobile/responsive.spec.ts +178 -0
  572. package/templates/base/tests/e2e/navigation/routing.spec.ts +371 -0
  573. package/templates/base/tests/e2e/navigation/sidebar.spec.ts +425 -0
  574. package/templates/base/tests/e2e/pages/ui-features.spec.ts +393 -0
  575. package/templates/base/tests/e2e/performance/baselines.spec.ts +162 -0
  576. package/templates/base/tests/e2e/performance/benchmarks.spec.ts +371 -0
  577. package/templates/base/tests/e2e/smoke.unauth.spec.ts +196 -0
  578. package/templates/base/tests/e2e/visual/components.spec.ts +650 -0
  579. package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/confirmation-dialog-visual-darwin.png +0 -0
  580. package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/dark-mode-background-visual-darwin.png +0 -0
  581. package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/dark-mode-card-visual-darwin.png +0 -0
  582. package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/dark-mode-sidebar-visual-darwin.png +0 -0
  583. package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/dashboard-card-single-visual-darwin.png +0 -0
  584. package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/dialog-content-visual-darwin.png +0 -0
  585. package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/dialog-with-backdrop-visual-darwin.png +0 -0
  586. package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/empty-search-results-visual-darwin.png +0 -0
  587. package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/input-default-visual-darwin.png +0 -0
  588. package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/input-focus-ring-visual-darwin.png +0 -0
  589. package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/primary-button-focus-visual-darwin.png +0 -0
  590. package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/primary-button-hover-visual-darwin.png +0 -0
  591. package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/primary-button-visual-darwin.png +0 -0
  592. package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/sidebar-active-nav-item-visual-darwin.png +0 -0
  593. package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/sidebar-collapsed-visual-darwin.png +0 -0
  594. package/templates/base/tests/e2e/visual/components.spec.ts-snapshots/sidebar-navigation-visual-darwin.png +0 -0
  595. package/templates/base/tests/e2e/visual/core-components.spec.ts +192 -0
  596. package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/account-page-visual-darwin.png +0 -0
  597. package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/create-webhook-dialog-visual-darwin.png +0 -0
  598. package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/dashboard-page-visual-darwin.png +0 -0
  599. package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/delete-account-dialog-visual-darwin.png +0 -0
  600. package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/integrations-page-visual-darwin.png +0 -0
  601. package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/invite-member-dialog-visual-darwin.png +0 -0
  602. package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/login-page-visual-darwin.png +0 -0
  603. package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/settings-account-tab-visual-darwin.png +0 -0
  604. package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/settings-profile-tab-visual-darwin.png +0 -0
  605. package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/sidebar-navigation-visual-darwin.png +0 -0
  606. package/templates/base/tests/e2e/visual/core-components.spec.ts-snapshots/team-page-visual-darwin.png +0 -0
  607. package/templates/base/tests/e2e/visual/screenshots.spec.ts +230 -0
  608. package/templates/base/tests/e2e/visual/screenshots.spec.ts-snapshots/404-page-chromium-darwin.png +0 -0
  609. package/templates/base/tests/e2e/visual/screenshots.spec.ts-snapshots/404-page-visual-darwin.png +0 -0
  610. package/templates/base/tests/e2e/visual/screenshots.spec.ts-snapshots/account-page-visual-darwin.png +0 -0
  611. package/templates/base/tests/e2e/visual/screenshots.spec.ts-snapshots/login-page-chromium-darwin.png +0 -0
  612. package/templates/base/tests/e2e/visual/screenshots.spec.ts-snapshots/login-page-visual-darwin.png +0 -0
  613. package/templates/base/tests/e2e/visual/screenshots.spec.ts-snapshots/settings-page-visual-darwin.png +0 -0
  614. package/templates/base/tests/e2e/visual/screenshots.spec.ts-snapshots/team-invite-dialog-visual-darwin.png +0 -0
  615. package/templates/base/tests/e2e/visual/screenshots.spec.ts-snapshots/team-page-visual-darwin.png +0 -0
  616. package/templates/base/tests/e2e/visual/screenshots.spec.ts-snapshots/webhook-create-dialog-visual-darwin.png +0 -0
  617. package/templates/base/tests/e2e/visual/theme-colors.spec.ts +293 -0
  618. package/templates/base/tests/e2e/visual/ui-components.spec.ts +502 -0
  619. package/templates/base/tests/integration/accounts/crud.test.ts +1402 -0
  620. package/templates/base/tests/integration/audits/list.test.ts +1133 -0
  621. package/templates/base/tests/integration/auth/auth-service.test.ts +415 -0
  622. package/templates/base/tests/integration/auth/invitation-token.test.ts +529 -0
  623. package/templates/base/tests/integration/auth/logout.test.ts +524 -0
  624. package/templates/base/tests/integration/auth/oauth.test.ts +768 -0
  625. package/templates/base/tests/integration/auth/refresh-token.test.ts +364 -0
  626. package/templates/base/tests/integration/auth/session-expiry.test.ts +569 -0
  627. package/templates/base/tests/integration/auth/session.test.ts +520 -0
  628. package/templates/base/tests/integration/auth/super-admin.test.ts +451 -0
  629. package/templates/base/tests/integration/authorization/analytics-role.test.ts +1026 -0
  630. package/templates/base/tests/integration/authorization/billing-role.test.ts +776 -0
  631. package/templates/base/tests/integration/authorization/guards-roles.test.ts +539 -0
  632. package/templates/base/tests/integration/authorization/multi-tenancy.test.ts +1112 -0
  633. package/templates/base/tests/integration/authorization/role-hierarchy.test.ts +931 -0
  634. package/templates/base/tests/integration/authorization/roles.test.ts +1347 -0
  635. package/templates/base/tests/integration/config/production-behavior.test.ts +536 -0
  636. package/templates/base/tests/integration/db/constraints.test.ts +695 -0
  637. package/templates/base/tests/integration/fixtures/accounts.ts +136 -0
  638. package/templates/base/tests/integration/fixtures/index.ts +232 -0
  639. package/templates/base/tests/integration/fixtures/invitations.ts +195 -0
  640. package/templates/base/tests/integration/fixtures/users.ts +144 -0
  641. package/templates/base/tests/integration/health/health.test.ts +351 -0
  642. package/templates/base/tests/integration/invitations/crud.test.ts +1457 -0
  643. package/templates/base/tests/integration/invitations/email.test.ts +506 -0
  644. package/templates/base/tests/integration/lib/email.test.ts +174 -0
  645. package/templates/base/tests/integration/lib/oauth.test.ts +368 -0
  646. package/templates/base/tests/integration/lib/password.test.ts +192 -0
  647. package/templates/base/tests/integration/lib/schema-helpers.test.ts +129 -0
  648. package/templates/base/tests/integration/lib/tokens.test.ts +304 -0
  649. package/templates/base/tests/integration/middleware/auth.test.ts +499 -0
  650. package/templates/base/tests/integration/middleware/cors.test.ts +334 -0
  651. package/templates/base/tests/integration/middleware/request-context.test.ts +156 -0
  652. package/templates/base/tests/integration/middleware/request-logger.test.ts +313 -0
  653. package/templates/base/tests/integration/performance/response-times.test.ts +509 -0
  654. package/templates/base/tests/integration/security/cookie-security.test.ts +567 -0
  655. package/templates/base/tests/integration/security/csrf-protection.test.ts +542 -0
  656. package/templates/base/tests/integration/security/jwt-validation.test.ts +209 -0
  657. package/templates/base/tests/integration/security/log-sanitization.test.ts +658 -0
  658. package/templates/base/tests/integration/security/rate-limiting.test.ts +1251 -0
  659. package/templates/base/tests/integration/security/sql-injection.test.ts +663 -0
  660. package/templates/base/tests/integration/security/token-hashing.test.ts +371 -0
  661. package/templates/base/tests/integration/security/xss-prevention.test.ts +541 -0
  662. package/templates/base/tests/integration/setup.ts +834 -0
  663. package/templates/base/tests/integration/smoke.test.ts +288 -0
  664. package/templates/base/tests/integration/storage/upload.test.ts +1162 -0
  665. package/templates/base/tests/integration/storage/validation.test.ts +746 -0
  666. package/templates/base/tests/integration/users/crud.test.ts +1297 -0
  667. package/templates/base/tests/integration/users/list.test.ts +698 -0
  668. package/templates/base/tests/integration/vitest.config.ts +80 -0
  669. package/templates/base/tsconfig.app.json +18 -0
  670. package/templates/base/tsconfig.json +39 -0
  671. package/templates/base/tsconfig.node.json +16 -0
  672. package/templates/base/tsconfig.server.json +26 -0
  673. package/templates/base/tsconfig.tsbuildinfo +1 -0
  674. package/templates/base/vite.config.ts +46 -0
  675. package/templates/base/vitest.config.browser.ts +47 -0
  676. package/templates/base/vitest.config.frontend.ts +47 -0
  677. package/templates/base/vitest.config.ts +82 -0
  678. package/templates/base/vitest.workspace.ts +22 -0
  679. package/templates/modules/audit-logs/.gitkeep +0 -0
  680. package/templates/modules/billing/.gitkeep +0 -0
  681. package/templates/modules/invitations/.gitkeep +0 -0
  682. package/templates/modules/storage/.gitkeep +0 -0
  683. package/templates/modules/webhooks/.gitkeep +0 -0
  684. package/templates/providers/auth-email/.gitkeep +0 -0
  685. package/templates/providers/auth-github/.gitkeep +0 -0
  686. package/templates/providers/auth-google/.gitkeep +0 -0
  687. package/templates/providers/email-resend/.gitkeep +0 -0
  688. package/templates/providers/email-sendgrid/.gitkeep +0 -0
@@ -0,0 +1,931 @@
1
+ /**
2
+ * Role Hierarchy Unit/Integration Tests
3
+ *
4
+ * Tests the complete role hierarchy system and all related functions.
5
+ * This tests the LOGIC of roles, not API endpoint access (those are tested elsewhere).
6
+ *
7
+ * Role Hierarchy (hierarchical roles):
8
+ * - ADMIN: Level 0 (highest privilege)
9
+ * - MANAGER: Level 1
10
+ * - EDITOR: Level 2
11
+ * - AUTHOR: Level 3
12
+ * - VIEWER: Level 4 (lowest hierarchical privilege)
13
+ *
14
+ * Non-hierarchical (specialized) roles:
15
+ * - BILLING: Level -1 (separate domain, no inheritance)
16
+ * - ANALYTICS: Level -1 (separate domain, no inheritance)
17
+ */
18
+
19
+ import { describe, it, expect } from 'vitest'
20
+ import {
21
+ Role,
22
+ ROLE_HIERARCHY,
23
+ hasMinimumRole,
24
+ isHierarchicalRole,
25
+ getRoleLevel,
26
+ getRolesWithMinimumAccess,
27
+ getAllRoles,
28
+ compareRoles,
29
+ isRoleHigherThan,
30
+ } from '../../../src/server/auth/roles'
31
+
32
+ // ============================================================================
33
+ // ROLE HIERARCHY CONSTANTS TESTS
34
+ // ============================================================================
35
+
36
+ describe('Role Hierarchy Constants', () => {
37
+ describe('ROLE_HIERARCHY values', () => {
38
+ it('should define ADMIN as level 0 (highest hierarchical privilege)', () => {
39
+ expect(ROLE_HIERARCHY.ADMIN).toBe(0)
40
+ })
41
+
42
+ it('should define MANAGER as level 1', () => {
43
+ expect(ROLE_HIERARCHY.MANAGER).toBe(1)
44
+ })
45
+
46
+ it('should define EDITOR as level 2', () => {
47
+ expect(ROLE_HIERARCHY.EDITOR).toBe(2)
48
+ })
49
+
50
+ it('should define AUTHOR as level 3', () => {
51
+ expect(ROLE_HIERARCHY.AUTHOR).toBe(3)
52
+ })
53
+
54
+ it('should define VIEWER as level 4 (lowest hierarchical privilege)', () => {
55
+ expect(ROLE_HIERARCHY.VIEWER).toBe(4)
56
+ })
57
+
58
+ it('should define BILLING as level -1 (non-hierarchical)', () => {
59
+ expect(ROLE_HIERARCHY.BILLING).toBe(-1)
60
+ })
61
+
62
+ it('should define ANALYTICS as level -1 (non-hierarchical)', () => {
63
+ expect(ROLE_HIERARCHY.ANALYTICS).toBe(-1)
64
+ })
65
+
66
+ it('should have exactly 7 roles defined', () => {
67
+ expect(Object.keys(ROLE_HIERARCHY)).toHaveLength(7)
68
+ })
69
+ })
70
+
71
+ describe('Role enum values', () => {
72
+ it('should have ADMIN role', () => {
73
+ expect(Role.ADMIN).toBe('ADMIN')
74
+ })
75
+
76
+ it('should have MANAGER role', () => {
77
+ expect(Role.MANAGER).toBe('MANAGER')
78
+ })
79
+
80
+ it('should have EDITOR role', () => {
81
+ expect(Role.EDITOR).toBe('EDITOR')
82
+ })
83
+
84
+ it('should have AUTHOR role', () => {
85
+ expect(Role.AUTHOR).toBe('AUTHOR')
86
+ })
87
+
88
+ it('should have VIEWER role', () => {
89
+ expect(Role.VIEWER).toBe('VIEWER')
90
+ })
91
+
92
+ it('should have BILLING role', () => {
93
+ expect(Role.BILLING).toBe('BILLING')
94
+ })
95
+
96
+ it('should have ANALYTICS role', () => {
97
+ expect(Role.ANALYTICS).toBe('ANALYTICS')
98
+ })
99
+ })
100
+ })
101
+
102
+ // ============================================================================
103
+ // getRoleLevel FUNCTION TESTS
104
+ // ============================================================================
105
+
106
+ describe('getRoleLevel()', () => {
107
+ describe('hierarchical roles', () => {
108
+ it('should return 0 for ADMIN', () => {
109
+ expect(getRoleLevel('ADMIN')).toBe(0)
110
+ })
111
+
112
+ it('should return 1 for MANAGER', () => {
113
+ expect(getRoleLevel('MANAGER')).toBe(1)
114
+ })
115
+
116
+ it('should return 2 for EDITOR', () => {
117
+ expect(getRoleLevel('EDITOR')).toBe(2)
118
+ })
119
+
120
+ it('should return 3 for AUTHOR', () => {
121
+ expect(getRoleLevel('AUTHOR')).toBe(3)
122
+ })
123
+
124
+ it('should return 4 for VIEWER', () => {
125
+ expect(getRoleLevel('VIEWER')).toBe(4)
126
+ })
127
+ })
128
+
129
+ describe('non-hierarchical roles', () => {
130
+ it('should return -1 for BILLING', () => {
131
+ expect(getRoleLevel('BILLING')).toBe(-1)
132
+ })
133
+
134
+ it('should return -1 for ANALYTICS', () => {
135
+ expect(getRoleLevel('ANALYTICS')).toBe(-1)
136
+ })
137
+ })
138
+
139
+ describe('hierarchy order verification', () => {
140
+ it('should have ADMIN with lower level than MANAGER (higher privilege)', () => {
141
+ expect(getRoleLevel('ADMIN')).toBeLessThan(getRoleLevel('MANAGER'))
142
+ })
143
+
144
+ it('should have MANAGER with lower level than EDITOR (higher privilege)', () => {
145
+ expect(getRoleLevel('MANAGER')).toBeLessThan(getRoleLevel('EDITOR'))
146
+ })
147
+
148
+ it('should have EDITOR with lower level than AUTHOR (higher privilege)', () => {
149
+ expect(getRoleLevel('EDITOR')).toBeLessThan(getRoleLevel('AUTHOR'))
150
+ })
151
+
152
+ it('should have AUTHOR with lower level than VIEWER (higher privilege)', () => {
153
+ expect(getRoleLevel('AUTHOR')).toBeLessThan(getRoleLevel('VIEWER'))
154
+ })
155
+ })
156
+ })
157
+
158
+ // ============================================================================
159
+ // isHierarchicalRole FUNCTION TESTS
160
+ // ============================================================================
161
+
162
+ describe('isHierarchicalRole()', () => {
163
+ describe('hierarchical roles', () => {
164
+ it('should return true for ADMIN', () => {
165
+ expect(isHierarchicalRole('ADMIN')).toBe(true)
166
+ })
167
+
168
+ it('should return true for MANAGER', () => {
169
+ expect(isHierarchicalRole('MANAGER')).toBe(true)
170
+ })
171
+
172
+ it('should return true for EDITOR', () => {
173
+ expect(isHierarchicalRole('EDITOR')).toBe(true)
174
+ })
175
+
176
+ it('should return true for AUTHOR', () => {
177
+ expect(isHierarchicalRole('AUTHOR')).toBe(true)
178
+ })
179
+
180
+ it('should return true for VIEWER', () => {
181
+ expect(isHierarchicalRole('VIEWER')).toBe(true)
182
+ })
183
+ })
184
+
185
+ describe('non-hierarchical roles', () => {
186
+ it('should return false for BILLING', () => {
187
+ expect(isHierarchicalRole('BILLING')).toBe(false)
188
+ })
189
+
190
+ it('should return false for ANALYTICS', () => {
191
+ expect(isHierarchicalRole('ANALYTICS')).toBe(false)
192
+ })
193
+ })
194
+
195
+ describe('complete coverage', () => {
196
+ it('should correctly classify all roles', () => {
197
+ const hierarchical = ['ADMIN', 'MANAGER', 'EDITOR', 'AUTHOR', 'VIEWER'] as const
198
+ const nonHierarchical = ['BILLING', 'ANALYTICS'] as const
199
+
200
+ for (const role of hierarchical) {
201
+ expect(isHierarchicalRole(role)).toBe(true)
202
+ }
203
+
204
+ for (const role of nonHierarchical) {
205
+ expect(isHierarchicalRole(role)).toBe(false)
206
+ }
207
+ })
208
+ })
209
+ })
210
+
211
+ // ============================================================================
212
+ // hasMinimumRole FUNCTION TESTS - HIERARCHICAL ROLES
213
+ // ============================================================================
214
+
215
+ describe('hasMinimumRole() - Hierarchical Roles', () => {
216
+ describe('ADMIN access', () => {
217
+ it('should satisfy ADMIN requirement', () => {
218
+ expect(hasMinimumRole('ADMIN', 'ADMIN')).toBe(true)
219
+ })
220
+
221
+ it('should satisfy MANAGER requirement', () => {
222
+ expect(hasMinimumRole('ADMIN', 'MANAGER')).toBe(true)
223
+ })
224
+
225
+ it('should satisfy EDITOR requirement', () => {
226
+ expect(hasMinimumRole('ADMIN', 'EDITOR')).toBe(true)
227
+ })
228
+
229
+ it('should satisfy AUTHOR requirement', () => {
230
+ expect(hasMinimumRole('ADMIN', 'AUTHOR')).toBe(true)
231
+ })
232
+
233
+ it('should satisfy VIEWER requirement', () => {
234
+ expect(hasMinimumRole('ADMIN', 'VIEWER')).toBe(true)
235
+ })
236
+ })
237
+
238
+ describe('MANAGER access', () => {
239
+ it('should NOT satisfy ADMIN requirement', () => {
240
+ expect(hasMinimumRole('MANAGER', 'ADMIN')).toBe(false)
241
+ })
242
+
243
+ it('should satisfy MANAGER requirement', () => {
244
+ expect(hasMinimumRole('MANAGER', 'MANAGER')).toBe(true)
245
+ })
246
+
247
+ it('should satisfy EDITOR requirement', () => {
248
+ expect(hasMinimumRole('MANAGER', 'EDITOR')).toBe(true)
249
+ })
250
+
251
+ it('should satisfy AUTHOR requirement', () => {
252
+ expect(hasMinimumRole('MANAGER', 'AUTHOR')).toBe(true)
253
+ })
254
+
255
+ it('should satisfy VIEWER requirement', () => {
256
+ expect(hasMinimumRole('MANAGER', 'VIEWER')).toBe(true)
257
+ })
258
+ })
259
+
260
+ describe('EDITOR access', () => {
261
+ it('should NOT satisfy ADMIN requirement', () => {
262
+ expect(hasMinimumRole('EDITOR', 'ADMIN')).toBe(false)
263
+ })
264
+
265
+ it('should NOT satisfy MANAGER requirement', () => {
266
+ expect(hasMinimumRole('EDITOR', 'MANAGER')).toBe(false)
267
+ })
268
+
269
+ it('should satisfy EDITOR requirement', () => {
270
+ expect(hasMinimumRole('EDITOR', 'EDITOR')).toBe(true)
271
+ })
272
+
273
+ it('should satisfy AUTHOR requirement', () => {
274
+ expect(hasMinimumRole('EDITOR', 'AUTHOR')).toBe(true)
275
+ })
276
+
277
+ it('should satisfy VIEWER requirement', () => {
278
+ expect(hasMinimumRole('EDITOR', 'VIEWER')).toBe(true)
279
+ })
280
+ })
281
+
282
+ describe('AUTHOR access', () => {
283
+ it('should NOT satisfy ADMIN requirement', () => {
284
+ expect(hasMinimumRole('AUTHOR', 'ADMIN')).toBe(false)
285
+ })
286
+
287
+ it('should NOT satisfy MANAGER requirement', () => {
288
+ expect(hasMinimumRole('AUTHOR', 'MANAGER')).toBe(false)
289
+ })
290
+
291
+ it('should NOT satisfy EDITOR requirement', () => {
292
+ expect(hasMinimumRole('AUTHOR', 'EDITOR')).toBe(false)
293
+ })
294
+
295
+ it('should satisfy AUTHOR requirement', () => {
296
+ expect(hasMinimumRole('AUTHOR', 'AUTHOR')).toBe(true)
297
+ })
298
+
299
+ it('should satisfy VIEWER requirement', () => {
300
+ expect(hasMinimumRole('AUTHOR', 'VIEWER')).toBe(true)
301
+ })
302
+ })
303
+
304
+ describe('VIEWER access', () => {
305
+ it('should NOT satisfy ADMIN requirement', () => {
306
+ expect(hasMinimumRole('VIEWER', 'ADMIN')).toBe(false)
307
+ })
308
+
309
+ it('should NOT satisfy MANAGER requirement', () => {
310
+ expect(hasMinimumRole('VIEWER', 'MANAGER')).toBe(false)
311
+ })
312
+
313
+ it('should NOT satisfy EDITOR requirement', () => {
314
+ expect(hasMinimumRole('VIEWER', 'EDITOR')).toBe(false)
315
+ })
316
+
317
+ it('should NOT satisfy AUTHOR requirement', () => {
318
+ expect(hasMinimumRole('VIEWER', 'AUTHOR')).toBe(false)
319
+ })
320
+
321
+ it('should satisfy VIEWER requirement', () => {
322
+ expect(hasMinimumRole('VIEWER', 'VIEWER')).toBe(true)
323
+ })
324
+ })
325
+ })
326
+
327
+ // ============================================================================
328
+ // hasMinimumRole FUNCTION TESTS - NON-HIERARCHICAL ROLES
329
+ // ============================================================================
330
+
331
+ describe('hasMinimumRole() - Non-Hierarchical Roles', () => {
332
+ describe('BILLING role behavior', () => {
333
+ it('should only satisfy its own exact requirement', () => {
334
+ expect(hasMinimumRole('BILLING', 'BILLING')).toBe(true)
335
+ })
336
+
337
+ it('should NOT satisfy any hierarchical role requirement', () => {
338
+ expect(hasMinimumRole('BILLING', 'ADMIN')).toBe(false)
339
+ expect(hasMinimumRole('BILLING', 'MANAGER')).toBe(false)
340
+ expect(hasMinimumRole('BILLING', 'EDITOR')).toBe(false)
341
+ expect(hasMinimumRole('BILLING', 'AUTHOR')).toBe(false)
342
+ expect(hasMinimumRole('BILLING', 'VIEWER')).toBe(false)
343
+ })
344
+
345
+ it('should NOT satisfy ANALYTICS requirement', () => {
346
+ expect(hasMinimumRole('BILLING', 'ANALYTICS')).toBe(false)
347
+ })
348
+ })
349
+
350
+ describe('ANALYTICS role behavior', () => {
351
+ it('should only satisfy its own exact requirement', () => {
352
+ expect(hasMinimumRole('ANALYTICS', 'ANALYTICS')).toBe(true)
353
+ })
354
+
355
+ it('should NOT satisfy any hierarchical role requirement', () => {
356
+ expect(hasMinimumRole('ANALYTICS', 'ADMIN')).toBe(false)
357
+ expect(hasMinimumRole('ANALYTICS', 'MANAGER')).toBe(false)
358
+ expect(hasMinimumRole('ANALYTICS', 'EDITOR')).toBe(false)
359
+ expect(hasMinimumRole('ANALYTICS', 'AUTHOR')).toBe(false)
360
+ expect(hasMinimumRole('ANALYTICS', 'VIEWER')).toBe(false)
361
+ })
362
+
363
+ it('should NOT satisfy BILLING requirement', () => {
364
+ expect(hasMinimumRole('ANALYTICS', 'BILLING')).toBe(false)
365
+ })
366
+ })
367
+
368
+ describe('hierarchical roles vs non-hierarchical requirements', () => {
369
+ it('ADMIN should NOT satisfy BILLING requirement', () => {
370
+ expect(hasMinimumRole('ADMIN', 'BILLING')).toBe(false)
371
+ })
372
+
373
+ it('ADMIN should NOT satisfy ANALYTICS requirement', () => {
374
+ expect(hasMinimumRole('ADMIN', 'ANALYTICS')).toBe(false)
375
+ })
376
+
377
+ it('VIEWER should NOT satisfy BILLING requirement', () => {
378
+ expect(hasMinimumRole('VIEWER', 'BILLING')).toBe(false)
379
+ })
380
+
381
+ it('VIEWER should NOT satisfy ANALYTICS requirement', () => {
382
+ expect(hasMinimumRole('VIEWER', 'ANALYTICS')).toBe(false)
383
+ })
384
+ })
385
+ })
386
+
387
+ // ============================================================================
388
+ // hasMinimumRole FUNCTION TESTS - ADDITIONAL ROLES
389
+ // ============================================================================
390
+
391
+ describe('hasMinimumRole() - Additional Roles Parameter', () => {
392
+ describe('non-hierarchical role bypass via additionalRoles', () => {
393
+ it('should allow BILLING to satisfy ADMIN requirement when in additionalRoles', () => {
394
+ expect(hasMinimumRole('BILLING', 'ADMIN', ['BILLING'])).toBe(true)
395
+ })
396
+
397
+ it('should allow BILLING to satisfy VIEWER requirement when in additionalRoles', () => {
398
+ expect(hasMinimumRole('BILLING', 'VIEWER', ['BILLING'])).toBe(true)
399
+ })
400
+
401
+ it('should allow ANALYTICS to satisfy ADMIN requirement when in additionalRoles', () => {
402
+ expect(hasMinimumRole('ANALYTICS', 'ADMIN', ['ANALYTICS'])).toBe(true)
403
+ })
404
+
405
+ it('should allow ANALYTICS to satisfy VIEWER requirement when in additionalRoles', () => {
406
+ expect(hasMinimumRole('ANALYTICS', 'VIEWER', ['ANALYTICS'])).toBe(true)
407
+ })
408
+ })
409
+
410
+ describe('hierarchical role with additionalRoles (no change expected)', () => {
411
+ it('should still work for ADMIN even if in additionalRoles (redundant)', () => {
412
+ expect(hasMinimumRole('ADMIN', 'VIEWER', ['ADMIN'])).toBe(true)
413
+ })
414
+
415
+ it('should still NOT allow VIEWER to satisfy ADMIN even with empty additionalRoles', () => {
416
+ expect(hasMinimumRole('VIEWER', 'ADMIN', [])).toBe(false)
417
+ })
418
+ })
419
+
420
+ describe('cross-non-hierarchical bypass', () => {
421
+ it('should allow BILLING to satisfy ANALYTICS requirement when BILLING in additionalRoles', () => {
422
+ expect(hasMinimumRole('BILLING', 'ANALYTICS', ['BILLING'])).toBe(true)
423
+ })
424
+
425
+ it('should allow ANALYTICS to satisfy BILLING requirement when ANALYTICS in additionalRoles', () => {
426
+ expect(hasMinimumRole('ANALYTICS', 'BILLING', ['ANALYTICS'])).toBe(true)
427
+ })
428
+ })
429
+
430
+ describe('additionalRoles does not affect mismatch', () => {
431
+ it('should NOT allow BILLING to satisfy ADMIN when different role in additionalRoles', () => {
432
+ expect(hasMinimumRole('BILLING', 'ADMIN', ['ANALYTICS'])).toBe(false)
433
+ })
434
+
435
+ it('should NOT allow VIEWER to satisfy ADMIN when BILLING in additionalRoles', () => {
436
+ expect(hasMinimumRole('VIEWER', 'ADMIN', ['BILLING'])).toBe(false)
437
+ })
438
+ })
439
+ })
440
+
441
+ // ============================================================================
442
+ // getRolesWithMinimumAccess FUNCTION TESTS
443
+ // ============================================================================
444
+
445
+ describe('getRolesWithMinimumAccess()', () => {
446
+ describe('hierarchical role minimums', () => {
447
+ it('should return only ADMIN for ADMIN minimum', () => {
448
+ const roles = getRolesWithMinimumAccess('ADMIN')
449
+ expect(roles).toContain('ADMIN')
450
+ expect(roles).not.toContain('MANAGER')
451
+ expect(roles).not.toContain('EDITOR')
452
+ expect(roles).not.toContain('AUTHOR')
453
+ expect(roles).not.toContain('VIEWER')
454
+ expect(roles).not.toContain('BILLING')
455
+ expect(roles).not.toContain('ANALYTICS')
456
+ })
457
+
458
+ it('should return ADMIN and MANAGER for MANAGER minimum', () => {
459
+ const roles = getRolesWithMinimumAccess('MANAGER')
460
+ expect(roles).toContain('ADMIN')
461
+ expect(roles).toContain('MANAGER')
462
+ expect(roles).not.toContain('EDITOR')
463
+ expect(roles).not.toContain('AUTHOR')
464
+ expect(roles).not.toContain('VIEWER')
465
+ })
466
+
467
+ it('should return ADMIN, MANAGER, EDITOR for EDITOR minimum', () => {
468
+ const roles = getRolesWithMinimumAccess('EDITOR')
469
+ expect(roles).toContain('ADMIN')
470
+ expect(roles).toContain('MANAGER')
471
+ expect(roles).toContain('EDITOR')
472
+ expect(roles).not.toContain('AUTHOR')
473
+ expect(roles).not.toContain('VIEWER')
474
+ })
475
+
476
+ it('should return ADMIN, MANAGER, EDITOR, AUTHOR for AUTHOR minimum', () => {
477
+ const roles = getRolesWithMinimumAccess('AUTHOR')
478
+ expect(roles).toContain('ADMIN')
479
+ expect(roles).toContain('MANAGER')
480
+ expect(roles).toContain('EDITOR')
481
+ expect(roles).toContain('AUTHOR')
482
+ expect(roles).not.toContain('VIEWER')
483
+ })
484
+
485
+ it('should return all hierarchical roles for VIEWER minimum', () => {
486
+ const roles = getRolesWithMinimumAccess('VIEWER')
487
+ expect(roles).toContain('ADMIN')
488
+ expect(roles).toContain('MANAGER')
489
+ expect(roles).toContain('EDITOR')
490
+ expect(roles).toContain('AUTHOR')
491
+ expect(roles).toContain('VIEWER')
492
+ // Non-hierarchical should NOT be included
493
+ expect(roles).not.toContain('BILLING')
494
+ expect(roles).not.toContain('ANALYTICS')
495
+ })
496
+ })
497
+
498
+ describe('non-hierarchical role minimums', () => {
499
+ it('should return empty array for BILLING minimum (use additionalRoles)', () => {
500
+ const roles = getRolesWithMinimumAccess('BILLING')
501
+ expect(roles).toHaveLength(0)
502
+ })
503
+
504
+ it('should return empty array for ANALYTICS minimum (use additionalRoles)', () => {
505
+ const roles = getRolesWithMinimumAccess('ANALYTICS')
506
+ expect(roles).toHaveLength(0)
507
+ })
508
+ })
509
+
510
+ describe('with additionalRoles', () => {
511
+ it('should include BILLING when specified in additionalRoles for ADMIN minimum', () => {
512
+ const roles = getRolesWithMinimumAccess('ADMIN', ['BILLING'])
513
+ expect(roles).toContain('ADMIN')
514
+ expect(roles).toContain('BILLING')
515
+ expect(roles).toHaveLength(2)
516
+ })
517
+
518
+ it('should include ANALYTICS when specified in additionalRoles for VIEWER minimum', () => {
519
+ const roles = getRolesWithMinimumAccess('VIEWER', ['ANALYTICS'])
520
+ expect(roles).toContain('ADMIN')
521
+ expect(roles).toContain('MANAGER')
522
+ expect(roles).toContain('EDITOR')
523
+ expect(roles).toContain('AUTHOR')
524
+ expect(roles).toContain('VIEWER')
525
+ expect(roles).toContain('ANALYTICS')
526
+ expect(roles).toHaveLength(6)
527
+ })
528
+
529
+ it('should include both BILLING and ANALYTICS when both specified', () => {
530
+ const roles = getRolesWithMinimumAccess('EDITOR', ['BILLING', 'ANALYTICS'])
531
+ expect(roles).toContain('ADMIN')
532
+ expect(roles).toContain('MANAGER')
533
+ expect(roles).toContain('EDITOR')
534
+ expect(roles).toContain('BILLING')
535
+ expect(roles).toContain('ANALYTICS')
536
+ expect(roles).toHaveLength(5)
537
+ })
538
+
539
+ it('should return additionalRoles for non-hierarchical minimum', () => {
540
+ const roles = getRolesWithMinimumAccess('BILLING', ['BILLING'])
541
+ expect(roles).toContain('BILLING')
542
+ expect(roles).toHaveLength(1)
543
+ })
544
+ })
545
+ })
546
+
547
+ // ============================================================================
548
+ // getAllRoles FUNCTION TESTS
549
+ // ============================================================================
550
+
551
+ describe('getAllRoles()', () => {
552
+ it('should return all 7 roles', () => {
553
+ const roles = getAllRoles()
554
+ expect(roles).toHaveLength(7)
555
+ })
556
+
557
+ it('should include all hierarchical roles', () => {
558
+ const roles = getAllRoles()
559
+ expect(roles).toContain('ADMIN')
560
+ expect(roles).toContain('MANAGER')
561
+ expect(roles).toContain('EDITOR')
562
+ expect(roles).toContain('AUTHOR')
563
+ expect(roles).toContain('VIEWER')
564
+ })
565
+
566
+ it('should include all non-hierarchical roles', () => {
567
+ const roles = getAllRoles()
568
+ expect(roles).toContain('BILLING')
569
+ expect(roles).toContain('ANALYTICS')
570
+ })
571
+ })
572
+
573
+ // ============================================================================
574
+ // compareRoles FUNCTION TESTS
575
+ // ============================================================================
576
+
577
+ describe('compareRoles()', () => {
578
+ describe('hierarchical comparisons', () => {
579
+ it('should return -1 when ADMIN compared to MANAGER (ADMIN > MANAGER)', () => {
580
+ expect(compareRoles('ADMIN', 'MANAGER')).toBe(-1)
581
+ })
582
+
583
+ it('should return 1 when MANAGER compared to ADMIN (MANAGER < ADMIN)', () => {
584
+ expect(compareRoles('MANAGER', 'ADMIN')).toBe(1)
585
+ })
586
+
587
+ it('should return 0 when comparing same role', () => {
588
+ expect(compareRoles('ADMIN', 'ADMIN')).toBe(0)
589
+ expect(compareRoles('VIEWER', 'VIEWER')).toBe(0)
590
+ })
591
+
592
+ it('should return -1 when ADMIN compared to VIEWER', () => {
593
+ expect(compareRoles('ADMIN', 'VIEWER')).toBe(-1)
594
+ })
595
+
596
+ it('should return 1 when VIEWER compared to ADMIN', () => {
597
+ expect(compareRoles('VIEWER', 'ADMIN')).toBe(1)
598
+ })
599
+
600
+ it('should return -1 when EDITOR compared to AUTHOR', () => {
601
+ expect(compareRoles('EDITOR', 'AUTHOR')).toBe(-1)
602
+ })
603
+
604
+ it('should return 1 when AUTHOR compared to EDITOR', () => {
605
+ expect(compareRoles('AUTHOR', 'EDITOR')).toBe(1)
606
+ })
607
+ })
608
+
609
+ describe('non-hierarchical comparisons', () => {
610
+ it('should return 0 when comparing two non-hierarchical roles', () => {
611
+ expect(compareRoles('BILLING', 'ANALYTICS')).toBe(0)
612
+ expect(compareRoles('ANALYTICS', 'BILLING')).toBe(0)
613
+ })
614
+
615
+ it('should return 0 when comparing same non-hierarchical role', () => {
616
+ expect(compareRoles('BILLING', 'BILLING')).toBe(0)
617
+ expect(compareRoles('ANALYTICS', 'ANALYTICS')).toBe(0)
618
+ })
619
+ })
620
+
621
+ describe('mixed hierarchical and non-hierarchical', () => {
622
+ it('should return -1 when hierarchical compared to non-hierarchical', () => {
623
+ expect(compareRoles('ADMIN', 'BILLING')).toBe(-1)
624
+ expect(compareRoles('VIEWER', 'ANALYTICS')).toBe(-1)
625
+ })
626
+
627
+ it('should return 1 when non-hierarchical compared to hierarchical', () => {
628
+ expect(compareRoles('BILLING', 'ADMIN')).toBe(1)
629
+ expect(compareRoles('ANALYTICS', 'VIEWER')).toBe(1)
630
+ })
631
+ })
632
+ })
633
+
634
+ // ============================================================================
635
+ // isRoleHigherThan FUNCTION TESTS
636
+ // ============================================================================
637
+
638
+ describe('isRoleHigherThan()', () => {
639
+ describe('hierarchical role comparisons', () => {
640
+ it('should return true when ADMIN is higher than MANAGER', () => {
641
+ expect(isRoleHigherThan('ADMIN', 'MANAGER')).toBe(true)
642
+ })
643
+
644
+ it('should return true when ADMIN is higher than VIEWER', () => {
645
+ expect(isRoleHigherThan('ADMIN', 'VIEWER')).toBe(true)
646
+ })
647
+
648
+ it('should return true when MANAGER is higher than EDITOR', () => {
649
+ expect(isRoleHigherThan('MANAGER', 'EDITOR')).toBe(true)
650
+ })
651
+
652
+ it('should return true when EDITOR is higher than AUTHOR', () => {
653
+ expect(isRoleHigherThan('EDITOR', 'AUTHOR')).toBe(true)
654
+ })
655
+
656
+ it('should return true when AUTHOR is higher than VIEWER', () => {
657
+ expect(isRoleHigherThan('AUTHOR', 'VIEWER')).toBe(true)
658
+ })
659
+
660
+ it('should return false when VIEWER is NOT higher than ADMIN', () => {
661
+ expect(isRoleHigherThan('VIEWER', 'ADMIN')).toBe(false)
662
+ })
663
+
664
+ it('should return false when MANAGER is NOT higher than ADMIN', () => {
665
+ expect(isRoleHigherThan('MANAGER', 'ADMIN')).toBe(false)
666
+ })
667
+
668
+ it('should return false when comparing same role (not strictly higher)', () => {
669
+ expect(isRoleHigherThan('ADMIN', 'ADMIN')).toBe(false)
670
+ expect(isRoleHigherThan('VIEWER', 'VIEWER')).toBe(false)
671
+ })
672
+ })
673
+
674
+ describe('non-hierarchical role comparisons', () => {
675
+ it('should return false for any comparison involving non-hierarchical roles', () => {
676
+ // Non-hierarchical vs non-hierarchical
677
+ expect(isRoleHigherThan('BILLING', 'ANALYTICS')).toBe(false)
678
+ expect(isRoleHigherThan('ANALYTICS', 'BILLING')).toBe(false)
679
+
680
+ // Non-hierarchical vs hierarchical
681
+ expect(isRoleHigherThan('BILLING', 'ADMIN')).toBe(false)
682
+ expect(isRoleHigherThan('BILLING', 'VIEWER')).toBe(false)
683
+
684
+ // Hierarchical vs non-hierarchical
685
+ expect(isRoleHigherThan('ADMIN', 'BILLING')).toBe(false)
686
+ expect(isRoleHigherThan('VIEWER', 'ANALYTICS')).toBe(false)
687
+ })
688
+
689
+ it('should return false when comparing same non-hierarchical role', () => {
690
+ expect(isRoleHigherThan('BILLING', 'BILLING')).toBe(false)
691
+ expect(isRoleHigherThan('ANALYTICS', 'ANALYTICS')).toBe(false)
692
+ })
693
+ })
694
+ })
695
+
696
+ // ============================================================================
697
+ // COMPLETE ROLE MATRIX TESTS
698
+ // ============================================================================
699
+
700
+ describe('Complete Role Matrix', () => {
701
+ const hierarchicalRoles = ['ADMIN', 'MANAGER', 'EDITOR', 'AUTHOR', 'VIEWER'] as const
702
+ const nonHierarchicalRoles = ['BILLING', 'ANALYTICS'] as const
703
+ const allRoles = [...hierarchicalRoles, ...nonHierarchicalRoles] as const
704
+
705
+ describe('hasMinimumRole complete matrix for hierarchical roles', () => {
706
+ const expectedResults: Record<string, Record<string, boolean>> = {
707
+ ADMIN: { ADMIN: true, MANAGER: true, EDITOR: true, AUTHOR: true, VIEWER: true },
708
+ MANAGER: { ADMIN: false, MANAGER: true, EDITOR: true, AUTHOR: true, VIEWER: true },
709
+ EDITOR: { ADMIN: false, MANAGER: false, EDITOR: true, AUTHOR: true, VIEWER: true },
710
+ AUTHOR: { ADMIN: false, MANAGER: false, EDITOR: false, AUTHOR: true, VIEWER: true },
711
+ VIEWER: { ADMIN: false, MANAGER: false, EDITOR: false, AUTHOR: false, VIEWER: true },
712
+ }
713
+
714
+ for (const userRole of hierarchicalRoles) {
715
+ for (const requiredRole of hierarchicalRoles) {
716
+ it(`${userRole} ${expectedResults[userRole][requiredRole] ? 'SHOULD' : 'should NOT'} satisfy ${requiredRole} requirement`, () => {
717
+ expect(hasMinimumRole(userRole, requiredRole)).toBe(expectedResults[userRole][requiredRole])
718
+ })
719
+ }
720
+ }
721
+ })
722
+
723
+ describe('hasMinimumRole matrix: non-hierarchical cannot satisfy hierarchical', () => {
724
+ for (const userRole of nonHierarchicalRoles) {
725
+ for (const requiredRole of hierarchicalRoles) {
726
+ it(`${userRole} should NOT satisfy ${requiredRole} requirement`, () => {
727
+ expect(hasMinimumRole(userRole, requiredRole)).toBe(false)
728
+ })
729
+ }
730
+ }
731
+ })
732
+
733
+ describe('hasMinimumRole matrix: hierarchical cannot satisfy non-hierarchical', () => {
734
+ for (const userRole of hierarchicalRoles) {
735
+ for (const requiredRole of nonHierarchicalRoles) {
736
+ it(`${userRole} should NOT satisfy ${requiredRole} requirement`, () => {
737
+ expect(hasMinimumRole(userRole, requiredRole)).toBe(false)
738
+ })
739
+ }
740
+ }
741
+ })
742
+
743
+ describe('hasMinimumRole matrix: non-hierarchical exact match only', () => {
744
+ for (const userRole of nonHierarchicalRoles) {
745
+ for (const requiredRole of nonHierarchicalRoles) {
746
+ const shouldMatch = userRole === requiredRole
747
+ it(`${userRole} ${shouldMatch ? 'SHOULD' : 'should NOT'} satisfy ${requiredRole} requirement`, () => {
748
+ expect(hasMinimumRole(userRole, requiredRole)).toBe(shouldMatch)
749
+ })
750
+ }
751
+ }
752
+ })
753
+ })
754
+
755
+ // ============================================================================
756
+ // EDGE CASES AND BOUNDARY CONDITIONS
757
+ // ============================================================================
758
+
759
+ describe('Edge Cases and Boundary Conditions', () => {
760
+ describe('role level boundaries', () => {
761
+ it('should maintain strict ordering between consecutive hierarchical levels', () => {
762
+ const orderedRoles = ['ADMIN', 'MANAGER', 'EDITOR', 'AUTHOR', 'VIEWER'] as const
763
+ for (let i = 0; i < orderedRoles.length - 1; i++) {
764
+ const higherRole = orderedRoles[i]
765
+ const lowerRole = orderedRoles[i + 1]
766
+
767
+ // Higher role should have lower level number
768
+ expect(getRoleLevel(higherRole)).toBeLessThan(getRoleLevel(lowerRole))
769
+
770
+ // Higher role should satisfy lower role requirement
771
+ expect(hasMinimumRole(higherRole, lowerRole)).toBe(true)
772
+
773
+ // Lower role should NOT satisfy higher role requirement
774
+ expect(hasMinimumRole(lowerRole, higherRole)).toBe(false)
775
+ }
776
+ })
777
+
778
+ it('should handle the boundary between hierarchical and non-hierarchical correctly', () => {
779
+ // VIEWER is the lowest hierarchical (level 4)
780
+ // BILLING and ANALYTICS are non-hierarchical (level -1)
781
+
782
+ // VIEWER can access VIEWER-level things
783
+ expect(hasMinimumRole('VIEWER', 'VIEWER')).toBe(true)
784
+
785
+ // But VIEWER cannot access BILLING or ANALYTICS
786
+ expect(hasMinimumRole('VIEWER', 'BILLING')).toBe(false)
787
+ expect(hasMinimumRole('VIEWER', 'ANALYTICS')).toBe(false)
788
+
789
+ // And BILLING/ANALYTICS cannot access even VIEWER
790
+ expect(hasMinimumRole('BILLING', 'VIEWER')).toBe(false)
791
+ expect(hasMinimumRole('ANALYTICS', 'VIEWER')).toBe(false)
792
+ })
793
+ })
794
+
795
+ describe('additionalRoles edge cases', () => {
796
+ it('should handle empty additionalRoles array', () => {
797
+ expect(hasMinimumRole('ADMIN', 'VIEWER', [])).toBe(true)
798
+ expect(hasMinimumRole('BILLING', 'VIEWER', [])).toBe(false)
799
+ })
800
+
801
+ it('should handle additionalRoles with duplicates', () => {
802
+ expect(hasMinimumRole('BILLING', 'ADMIN', ['BILLING', 'BILLING'])).toBe(true)
803
+ })
804
+
805
+ it('should handle additionalRoles with multiple non-hierarchical roles', () => {
806
+ expect(hasMinimumRole('BILLING', 'ADMIN', ['BILLING', 'ANALYTICS'])).toBe(true)
807
+ expect(hasMinimumRole('ANALYTICS', 'ADMIN', ['BILLING', 'ANALYTICS'])).toBe(true)
808
+ })
809
+ })
810
+
811
+ describe('self-reference consistency', () => {
812
+ it('every role should satisfy its own requirement', () => {
813
+ const allRoles = getAllRoles()
814
+ for (const role of allRoles) {
815
+ expect(hasMinimumRole(role as Role, role as Role)).toBe(true)
816
+ }
817
+ })
818
+
819
+ it('every role compared to itself should return 0', () => {
820
+ const allRoles = getAllRoles()
821
+ for (const role of allRoles) {
822
+ expect(compareRoles(role as Role, role as Role)).toBe(0)
823
+ }
824
+ })
825
+
826
+ it('no role should be strictly higher than itself', () => {
827
+ const allRoles = getAllRoles()
828
+ for (const role of allRoles) {
829
+ expect(isRoleHigherThan(role as Role, role as Role)).toBe(false)
830
+ }
831
+ })
832
+ })
833
+ })
834
+
835
+ // ============================================================================
836
+ // TRANSITIVITY TESTS
837
+ // ============================================================================
838
+
839
+ describe('Transitivity Properties', () => {
840
+ describe('hasMinimumRole transitivity for hierarchical roles', () => {
841
+ it('if ADMIN satisfies MANAGER and MANAGER satisfies EDITOR, then ADMIN satisfies EDITOR', () => {
842
+ expect(hasMinimumRole('ADMIN', 'MANAGER')).toBe(true)
843
+ expect(hasMinimumRole('MANAGER', 'EDITOR')).toBe(true)
844
+ expect(hasMinimumRole('ADMIN', 'EDITOR')).toBe(true)
845
+ })
846
+
847
+ it('if MANAGER satisfies EDITOR and EDITOR satisfies AUTHOR, then MANAGER satisfies AUTHOR', () => {
848
+ expect(hasMinimumRole('MANAGER', 'EDITOR')).toBe(true)
849
+ expect(hasMinimumRole('EDITOR', 'AUTHOR')).toBe(true)
850
+ expect(hasMinimumRole('MANAGER', 'AUTHOR')).toBe(true)
851
+ })
852
+
853
+ it('if EDITOR satisfies AUTHOR and AUTHOR satisfies VIEWER, then EDITOR satisfies VIEWER', () => {
854
+ expect(hasMinimumRole('EDITOR', 'AUTHOR')).toBe(true)
855
+ expect(hasMinimumRole('AUTHOR', 'VIEWER')).toBe(true)
856
+ expect(hasMinimumRole('EDITOR', 'VIEWER')).toBe(true)
857
+ })
858
+
859
+ it('full chain: ADMIN satisfies all through transitivity', () => {
860
+ // ADMIN -> MANAGER -> EDITOR -> AUTHOR -> VIEWER
861
+ expect(hasMinimumRole('ADMIN', 'VIEWER')).toBe(true)
862
+ })
863
+ })
864
+
865
+ describe('isRoleHigherThan transitivity for hierarchical roles', () => {
866
+ it('if ADMIN > MANAGER and MANAGER > EDITOR, then ADMIN > EDITOR', () => {
867
+ expect(isRoleHigherThan('ADMIN', 'MANAGER')).toBe(true)
868
+ expect(isRoleHigherThan('MANAGER', 'EDITOR')).toBe(true)
869
+ expect(isRoleHigherThan('ADMIN', 'EDITOR')).toBe(true)
870
+ })
871
+
872
+ it('if EDITOR > AUTHOR and AUTHOR > VIEWER, then EDITOR > VIEWER', () => {
873
+ expect(isRoleHigherThan('EDITOR', 'AUTHOR')).toBe(true)
874
+ expect(isRoleHigherThan('AUTHOR', 'VIEWER')).toBe(true)
875
+ expect(isRoleHigherThan('EDITOR', 'VIEWER')).toBe(true)
876
+ })
877
+ })
878
+ })
879
+
880
+ // ============================================================================
881
+ // ANTI-SYMMETRY TESTS
882
+ // ============================================================================
883
+
884
+ describe('Anti-Symmetry Properties', () => {
885
+ describe('hasMinimumRole anti-symmetry for hierarchical roles', () => {
886
+ it('if ADMIN satisfies VIEWER, then VIEWER does NOT satisfy ADMIN', () => {
887
+ expect(hasMinimumRole('ADMIN', 'VIEWER')).toBe(true)
888
+ expect(hasMinimumRole('VIEWER', 'ADMIN')).toBe(false)
889
+ })
890
+
891
+ it('if MANAGER satisfies AUTHOR, then AUTHOR does NOT satisfy MANAGER', () => {
892
+ expect(hasMinimumRole('MANAGER', 'AUTHOR')).toBe(true)
893
+ expect(hasMinimumRole('AUTHOR', 'MANAGER')).toBe(false)
894
+ })
895
+ })
896
+
897
+ describe('compareRoles anti-symmetry', () => {
898
+ it('compareRoles(A, B) = -compareRoles(B, A) for hierarchical roles', () => {
899
+ expect(compareRoles('ADMIN', 'VIEWER')).toBe(-1)
900
+ expect(compareRoles('VIEWER', 'ADMIN')).toBe(1)
901
+ expect(compareRoles('ADMIN', 'VIEWER') + compareRoles('VIEWER', 'ADMIN')).toBe(0)
902
+ })
903
+
904
+ it('compareRoles(A, B) = -compareRoles(B, A) for mixed roles', () => {
905
+ expect(compareRoles('ADMIN', 'BILLING')).toBe(-1)
906
+ expect(compareRoles('BILLING', 'ADMIN')).toBe(1)
907
+ expect(compareRoles('ADMIN', 'BILLING') + compareRoles('BILLING', 'ADMIN')).toBe(0)
908
+ })
909
+ })
910
+
911
+ describe('isRoleHigherThan anti-symmetry', () => {
912
+ it('if ADMIN is higher than VIEWER, then VIEWER is NOT higher than ADMIN', () => {
913
+ expect(isRoleHigherThan('ADMIN', 'VIEWER')).toBe(true)
914
+ expect(isRoleHigherThan('VIEWER', 'ADMIN')).toBe(false)
915
+ })
916
+
917
+ it('mutual exclusion: if A > B then NOT B > A', () => {
918
+ const pairs = [
919
+ ['ADMIN', 'MANAGER'],
920
+ ['MANAGER', 'EDITOR'],
921
+ ['EDITOR', 'AUTHOR'],
922
+ ['AUTHOR', 'VIEWER'],
923
+ ] as const
924
+
925
+ for (const [higher, lower] of pairs) {
926
+ expect(isRoleHigherThan(higher, lower)).toBe(true)
927
+ expect(isRoleHigherThan(lower, higher)).toBe(false)
928
+ }
929
+ })
930
+ })
931
+ })