@etus/bhono-app 0.1.5 → 0.1.6

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 (269) hide show
  1. package/dist/index.js +0 -0
  2. package/package.json +5 -1
  3. package/templates/base/.husky/pre-push +26 -0
  4. package/templates/base/CLAUDE.md +5 -5
  5. package/templates/base/README.md +31 -20
  6. package/templates/base/docs/app_spec.txt +13 -10
  7. package/templates/base/docs/architecture/README.md +3 -0
  8. package/templates/base/docs/architecture/data-requirements.md +4 -3
  9. package/templates/base/docs/architecture/db-bootstrap.md +39 -0
  10. package/templates/base/docs/architecture/drizzle-migration-plan.md +125 -0
  11. package/templates/base/docs/architecture/erd.md +1 -1
  12. package/templates/base/docs/architecture/sql-standards.md +100 -0
  13. package/templates/base/docs/testing.md +36 -29
  14. package/templates/base/package.json +6 -5
  15. package/templates/base/pnpm-lock.yaml +0 -123
  16. package/templates/base/schema.sql +84 -0
  17. package/templates/base/scripts/init.sh +244 -59
  18. package/templates/base/src/client/hooks/use-auth.ts +5 -0
  19. package/templates/base/src/client/routes/_authenticated/dashboard.tsx +1 -1
  20. package/templates/base/src/client/routes/index.tsx +1 -1
  21. package/templates/base/src/server/db/client.ts +3 -5
  22. package/templates/base/src/server/db/records.ts +81 -0
  23. package/templates/base/src/server/db/seed.ts +3 -2
  24. package/templates/base/src/server/db/sql.ts +96 -0
  25. package/templates/base/src/server/index.ts +16 -2
  26. package/templates/base/src/server/lib/audit.ts +74 -26
  27. package/templates/base/src/server/lib/audited-db.ts +219 -109
  28. package/templates/base/src/server/lib/transaction.ts +10 -16
  29. package/templates/base/src/server/middleware/account.ts +8 -15
  30. package/templates/base/src/server/middleware/auth.ts +102 -38
  31. package/templates/base/src/server/middleware/rate-limit.ts +6 -1
  32. package/templates/base/src/server/routes/accounts/handlers.ts +18 -6
  33. package/templates/base/src/server/routes/audits/handlers.ts +3 -1
  34. package/templates/base/src/server/routes/auth/handlers.ts +14 -9
  35. package/templates/base/src/server/routes/auth/test-login.ts +99 -45
  36. package/templates/base/src/server/routes/health/handlers.ts +4 -4
  37. package/templates/base/src/server/routes/invitations/handlers.ts +6 -3
  38. package/templates/base/src/server/routes/users/handlers.ts +21 -14
  39. package/templates/base/src/server/services/accounts.ts +242 -217
  40. package/templates/base/src/server/services/audits.ts +114 -61
  41. package/templates/base/src/server/services/auth.ts +310 -180
  42. package/templates/base/src/server/services/invitations.ts +282 -222
  43. package/templates/base/src/server/services/users.ts +383 -293
  44. package/templates/base/src/server/types/index.ts +1 -2
  45. package/templates/base/{src/server/__tests__/fixtures.ts → tests/fixtures/server.ts} +3 -3
  46. package/templates/base/{src/client/__tests__/setup-browser.ts → tests/helpers/client-setup-browser.ts} +2 -2
  47. package/templates/base/{src/client/__tests__/setup.ts → tests/helpers/client-setup.ts} +1 -1
  48. package/templates/base/{src/client/__tests__/test-utils.tsx → tests/helpers/client-test-utils.tsx} +2 -2
  49. package/templates/base/{src/server/__tests__/setup.ts → tests/helpers/server.ts} +9 -9
  50. package/templates/base/tests/integration/accounts/crud.test.ts +2 -11
  51. package/templates/base/tests/integration/audits/list.test.ts +2 -11
  52. package/templates/base/tests/integration/auth/auth-service.test.ts +1 -10
  53. package/templates/base/tests/integration/auth/invitation-token.test.ts +2 -11
  54. package/templates/base/tests/integration/auth/logout.test.ts +2 -11
  55. package/templates/base/tests/integration/auth/oauth.test.ts +23 -42
  56. package/templates/base/tests/integration/auth/refresh-token.test.ts +1 -9
  57. package/templates/base/tests/integration/auth/session-expiry.test.ts +1 -9
  58. package/templates/base/tests/integration/auth/session.test.ts +2 -11
  59. package/templates/base/tests/integration/auth/super-admin.test.ts +1 -9
  60. package/templates/base/tests/integration/authorization/analytics-role.test.ts +2 -11
  61. package/templates/base/tests/integration/authorization/billing-role.test.ts +2 -11
  62. package/templates/base/tests/integration/authorization/guards-roles.test.ts +1 -9
  63. package/templates/base/tests/integration/authorization/multi-tenancy.test.ts +2 -11
  64. package/templates/base/tests/integration/authorization/roles.test.ts +2 -11
  65. package/templates/base/tests/integration/config/production-behavior.test.ts +2 -11
  66. package/templates/base/tests/integration/health/health.test.ts +25 -44
  67. package/templates/base/tests/integration/invitations/crud.test.ts +2 -11
  68. package/templates/base/tests/integration/invitations/email.test.ts +1 -9
  69. package/templates/base/tests/integration/middleware/auth.test.ts +3 -12
  70. package/templates/base/tests/integration/middleware/request-logger.test.ts +1 -9
  71. package/templates/base/tests/integration/performance/response-times.test.ts +1 -9
  72. package/templates/base/tests/integration/security/cookie-security.test.ts +2 -11
  73. package/templates/base/tests/integration/security/csrf-protection.test.ts +2 -11
  74. package/templates/base/tests/integration/security/log-sanitization.test.ts +1 -9
  75. package/templates/base/tests/integration/security/rate-limiting.test.ts +1 -9
  76. package/templates/base/tests/integration/security/sql-injection.test.ts +7 -18
  77. package/templates/base/tests/integration/security/xss-prevention.test.ts +2 -11
  78. package/templates/base/tests/integration/setup.ts +13 -90
  79. package/templates/base/tests/integration/smoke.test.ts +3 -2
  80. package/templates/base/tests/integration/storage/upload.test.ts +2 -11
  81. package/templates/base/tests/integration/storage/validation.test.ts +2 -11
  82. package/templates/base/tests/integration/users/crud.test.ts +2 -11
  83. package/templates/base/tests/integration/users/list.test.ts +2 -11
  84. package/templates/base/tests/integration/vitest.config.ts +2 -9
  85. package/templates/base/{src/server/__tests__ → tests}/mocks/db.ts +1 -1
  86. package/templates/base/{src/server/__tests__ → tests}/mocks/index.ts +1 -1
  87. package/templates/base/{src/server/__tests__ → tests}/mocks/kv.ts +1 -1
  88. package/templates/base/{src/server/__tests__ → tests}/mocks/r2.ts +1 -1
  89. package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/sidebar.test.tsx +1 -1
  90. package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/avatar.test.tsx +1 -1
  91. package/templates/base/{src/client/__tests__ → tests/unit/client/components/ui}/button.test.tsx +1 -1
  92. package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/card.test.tsx +1 -1
  93. package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/dialog.test.tsx +1 -1
  94. package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/input.test.tsx +1 -1
  95. package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/loading-skeleton.test.tsx +1 -1
  96. package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/skeleton.test.tsx +1 -1
  97. package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/sonner.test.tsx +1 -1
  98. package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/tabs.test.tsx +1 -1
  99. package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/account.test.tsx +1 -1
  100. package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/integrations.test.tsx +1 -1
  101. package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/settings.test.tsx +1 -1
  102. package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/team.test.tsx +1 -1
  103. package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/authenticated-layout.test.tsx +1 -1
  104. package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/dashboard.test.tsx +1 -1
  105. package/templates/base/{src/client/routes/__tests__ → tests/unit/client/routes}/invite.test.tsx +1 -1
  106. package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/login.test.tsx +1 -1
  107. package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/navigation.test.tsx +1 -1
  108. package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/root-layout.test.tsx +1 -1
  109. package/templates/base/{src/server/auth/__tests__ → tests/unit/server/auth}/guards.test.ts +2 -2
  110. package/templates/base/{src → tests/unit}/server/auth/permissions.test.ts +1 -1
  111. package/templates/base/{src → tests/unit}/server/auth/roles.test.ts +1 -1
  112. package/templates/base/tests/unit/server/db/sql.test.ts +68 -0
  113. package/templates/base/{src → tests/unit}/server/env.test.ts +1 -1
  114. package/templates/base/tests/unit/server/lib/audited-db.test.ts +78 -0
  115. package/templates/base/{src → tests/unit}/server/lib/email.test.ts +1 -1
  116. package/templates/base/{src → tests/unit}/server/lib/errors.test.ts +1 -1
  117. package/templates/base/{src → tests/unit}/server/lib/oauth.test.ts +1 -1
  118. package/templates/base/{src → tests/unit}/server/lib/pagination.test.ts +1 -1
  119. package/templates/base/{src → tests/unit}/server/lib/password.test.ts +1 -1
  120. package/templates/base/{src → tests/unit}/server/lib/providers.test.ts +1 -1
  121. package/templates/base/{src → tests/unit}/server/lib/r2-storage.test.ts +2 -2
  122. package/templates/base/{src → tests/unit}/server/lib/session.test.ts +2 -2
  123. package/templates/base/{src → tests/unit}/server/lib/tokens.test.ts +1 -1
  124. package/templates/base/{src → tests/unit}/server/lib/transaction.test.ts +5 -14
  125. package/templates/base/{src → tests/unit}/server/middleware/account.test.ts +16 -24
  126. package/templates/base/{src → tests/unit}/server/middleware/auth.test.ts +71 -42
  127. package/templates/base/{src → tests/unit}/server/middleware/cors.test.ts +1 -1
  128. package/templates/base/{src → tests/unit}/server/middleware/error-handler.test.ts +2 -2
  129. package/templates/base/{src → tests/unit}/server/middleware/rate-limit.test.ts +3 -2
  130. package/templates/base/{src → tests/unit}/server/middleware/request-context.test.ts +1 -1
  131. package/templates/base/{src → tests/unit}/server/middleware/request-logger.test.ts +1 -1
  132. package/templates/base/{src/server/__tests__/mocks/__tests__ → tests/unit/server/mocks}/db.test.ts +1 -1
  133. package/templates/base/{src/server/__tests__/mocks/__tests__ → tests/unit/server/mocks}/kv.test.ts +1 -1
  134. package/templates/base/{src/server/__tests__/mocks/__tests__ → tests/unit/server/mocks}/r2.test.ts +1 -1
  135. package/templates/base/{src/server/routes/accounts/__tests__ → tests/unit/server/routes/accounts}/handlers.test.ts +12 -12
  136. package/templates/base/{src/server/routes/audits/__tests__ → tests/unit/server/routes/audits}/handlers.test.ts +11 -11
  137. package/templates/base/{src/server/routes/auth/__tests__ → tests/unit/server/routes/auth}/handlers.test.ts +13 -13
  138. package/templates/base/{src/server/routes/health/__tests__ → tests/unit/server/routes/health}/handlers.test.ts +27 -23
  139. package/templates/base/{src/server/routes/invitations/__tests__ → tests/unit/server/routes/invitations}/handlers.test.ts +14 -17
  140. package/templates/base/{src/server/routes/storage/__tests__ → tests/unit/server/routes/storage}/handlers.test.ts +6 -6
  141. package/templates/base/{src/server/routes/users/__tests__ → tests/unit/server/routes/users}/handlers.test.ts +12 -12
  142. package/templates/base/tests/unit/server/services/accounts.test.ts +258 -0
  143. package/templates/base/tests/unit/server/services/audits.test.ts +141 -0
  144. package/templates/base/tests/unit/server/services/auth.test.ts +179 -0
  145. package/templates/base/tests/unit/server/services/invitations.test.ts +165 -0
  146. package/templates/base/tests/unit/server/services/users.test.ts +351 -0
  147. package/templates/base/tsconfig.json +2 -1
  148. package/templates/base/vitest.config.browser.ts +3 -2
  149. package/templates/base/vitest.config.frontend.ts +3 -2
  150. package/templates/base/vitest.config.ts +7 -14
  151. package/templates/base/.claude/settings.local.json +0 -11
  152. package/templates/base/config/drizzle.config.ts +0 -10
  153. package/templates/base/src/server/db/schema/accounts.ts +0 -20
  154. package/templates/base/src/server/db/schema/audit-logs.ts +0 -26
  155. package/templates/base/src/server/db/schema/index.ts +0 -7
  156. package/templates/base/src/server/db/schema/invitations.ts +0 -30
  157. package/templates/base/src/server/db/schema/refresh-tokens.ts +0 -22
  158. package/templates/base/src/server/db/schema/user-accounts.ts +0 -25
  159. package/templates/base/src/server/db/schema/users.ts +0 -33
  160. package/templates/base/src/server/lib/audited-db.test.ts +0 -107
  161. package/templates/base/src/server/lib/schema-helpers.ts +0 -16
  162. package/templates/base/src/server/services/__tests__/accounts.test.ts +0 -764
  163. package/templates/base/src/server/services/__tests__/audits.test.ts +0 -235
  164. package/templates/base/src/server/services/__tests__/auth.test.ts +0 -765
  165. package/templates/base/src/server/services/__tests__/invitations.test.ts +0 -704
  166. package/templates/base/src/server/services/__tests__/users.test.ts +0 -755
  167. package/templates/base/tests/integration/lib/schema-helpers.test.ts +0 -129
  168. /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-can-be-collapsed-by-default-1.png +0 -0
  169. /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-expands-when-collapsed-and-expand-button-is-clicked-1.png +0 -0
  170. /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-handles-logout-button-click-1.png +0 -0
  171. /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-handles-navigation-clicks-1.png +0 -0
  172. /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-hides-navigation-labels-when-collapsed-1.png +0 -0
  173. /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-highlights-active-route-1.png +0 -0
  174. /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-renders-sidebar-navigation-items-1.png +0 -0
  175. /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-shows-keyboard-shortcut-hint-when-expanded-1.png +0 -0
  176. /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-shows-user-info-when-authenticated-1.png +0 -0
  177. /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-shows-user-initials-in-avatar-fallback-1.png +0 -0
  178. /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/error-boundary.test.tsx +0 -0
  179. /package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/error-fallback.test.tsx +0 -0
  180. /package/templates/base/{src/client/hooks/__tests__ → tests/unit/client/hooks}/use-auth.test.tsx +0 -0
  181. /package/templates/base/{src/client/hooks/__tests__ → tests/unit/client/hooks}/use-theme.test.tsx +0 -0
  182. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-display-dashboard-stats-cards-1.png +0 -0
  183. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-display-quick-action-cards-1.png +0 -0
  184. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-display-recent-activity-section-1.png +0 -0
  185. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-display-user-first-name-in-welcome-message-1.png +0 -0
  186. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-display-user-information-in-sidebar-1.png +0 -0
  187. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-render-dashboard-when-authenticated-1.png +0 -0
  188. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-authenticated-should-show-navigation-sidebar-1.png +0 -0
  189. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/dashboard.test.tsx/Dashboard-Page-when-unauthenticated-should-redirect-to-login-when-not-authenticated-1.png +0 -0
  190. /package/templates/base/{src/client/routes/__tests__ → tests/unit/client/routes}/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-display-accept-invitation-button-1.png +0 -0
  191. /package/templates/base/{src/client/routes/__tests__ → tests/unit/client/routes}/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-display-decline-button-linking-to-homepage-1.png +0 -0
  192. /package/templates/base/{src/client/routes/__tests__ → tests/unit/client/routes}/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-display-invitation-details--email--workspace--role--1.png +0 -0
  193. /package/templates/base/{src/client/routes/__tests__ → tests/unit/client/routes}/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-have-a-logo-link-to-homepage-1.png +0 -0
  194. /package/templates/base/{src/client/routes/__tests__ → tests/unit/client/routes}/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-render-invitation-page-with-inviter-name-and-workspace-1.png +0 -0
  195. /package/templates/base/{src/client/routes/__tests__ → tests/unit/client/routes}/__screenshots__/invite.test.tsx/Invite-Token-Page-pending-invitation-state-should-show-terms-of-service-and-privacy-policy-links-1.png +0 -0
  196. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/login.test.tsx/Login-Page-should-display-Google-OAuth-login-button-1.png +0 -0
  197. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/login.test.tsx/Login-Page-should-have-a-link-back-to-home-page-1.png +0 -0
  198. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/login.test.tsx/Login-Page-should-render-login-content-without-waiting-for-authentication-1.png +0 -0
  199. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/login.test.tsx/Login-Page-should-render-login-page-at--login-route-1.png +0 -0
  200. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/login.test.tsx/Login-Page-should-show-Terms-of-Service-and-Privacy-Policy-links-1.png +0 -0
  201. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/login.test.tsx/Login-Page-should-trigger-OAuth-flow-when-clicking-login-button-1.png +0 -0
  202. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-404-handling-should-display-404-text-on-not-found-page-1.png +0 -0
  203. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-404-handling-should-have-navigation-options-on-404-page-1.png +0 -0
  204. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-404-handling-should-render-404-page-for-unknown-routes-1.png +0 -0
  205. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-authenticated-navigation-should-navigate-from-dashboard-to-account-page-1.png +0 -0
  206. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-authenticated-navigation-should-navigate-from-dashboard-to-integrations-page-1.png +0 -0
  207. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-authenticated-navigation-should-navigate-from-dashboard-to-settings-page-1.png +0 -0
  208. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-authenticated-navigation-should-navigate-from-dashboard-to-team-page-1.png +0 -0
  209. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-home-page-navigation-should-display-navigation-links-on-home-page-1.png +0 -0
  210. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-home-page-navigation-should-have-correct-link-destinations-on-home-page-1.png +0 -0
  211. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-unauthenticated-navigation-should-allow-access-to-home-page-without-authentication-1.png +0 -0
  212. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-unauthenticated-navigation-should-allow-access-to-login-page-without-authentication-1.png +0 -0
  213. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-unauthenticated-navigation-should-redirect-unauthenticated-users-from-dashboard-to-login-1.png +0 -0
  214. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-unauthenticated-navigation-should-redirect-unauthenticated-users-from-settings-to-login-1.png +0 -0
  215. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/__screenshots__/navigation.test.tsx/Navigation-unauthenticated-navigation-should-redirect-unauthenticated-users-from-team-to-login-1.png +0 -0
  216. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/account.test.tsx/Account-Page-should-render-Active-Sessions-section-with-session-cards-1.png +0 -0
  217. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/account.test.tsx/Account-Page-should-render-page-with-correct-title--Account--1.png +0 -0
  218. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/account.test.tsx/Account-Page-should-show-API-Access-section-1.png +0 -0
  219. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/account.test.tsx/Account-Page-should-show-Connected-Accounts-section-with-Google-connected-1.png +0 -0
  220. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/account.test.tsx/Account-Page-should-show-Danger-Zone-section-with-delete-button-1.png +0 -0
  221. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/account.test.tsx/Account-Page-should-show-Security-section-with-Two-Factor-Authentication-1.png +0 -0
  222. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-API-documentation-section-should-display-API-documentation-link-section-1.png +0 -0
  223. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-Create-Webhook-Dialog-should-have-Add-Webhook-trigger-button-1.png +0 -0
  224. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-category-filters-should-display-all-category-buttons-1.png +0 -0
  225. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-integration-cards-should-display-all-integration-cards-with-names-1.png +0 -0
  226. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-integration-cards-should-display-category-badges-on-cards-1.png +0 -0
  227. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-integration-cards-should-show-Configure-button-for-connected-integrations-1.png +0 -0
  228. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-integration-cards-should-show-Connect-button-for-not-connected-integrations-1.png +0 -0
  229. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-integration-cards-should-show-Connected-badge-for-connected-integrations-1.png +0 -0
  230. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-display-Available-Integrations-section-1.png +0 -0
  231. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-display-Webhooks-section-1.png +0 -0
  232. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-display-connected-count-1.png +0 -0
  233. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-display-page-description-1.png +0 -0
  234. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-display-search-input-1.png +0 -0
  235. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-page-rendering-should-render-with-correct-title--Integrations--1.png +0 -0
  236. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-search-functionality-should-filter-integrations-based-on-search-query-1.png +0 -0
  237. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-search-functionality-should-search-by-description-1.png +0 -0
  238. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-search-functionality-should-show-no-results-message-when-search-has-no-matches-1.png +0 -0
  239. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-webhooks-section-should-display-existing-webhook-1.png +0 -0
  240. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-webhooks-section-should-display-webhook-events-1.png +0 -0
  241. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-webhooks-section-should-display-webhook-last-delivery-info-1.png +0 -0
  242. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-webhooks-section-should-display-webhook-success-status-1.png +0 -0
  243. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/integrations.test.tsx/Integrations-Page-webhooks-section-should-have-Add-Webhook-button-1.png +0 -0
  244. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Account-tab-should-display-connected-accounts-section-with-Google-provider-1.png +0 -0
  245. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Account-tab-should-display-sessions-and-danger-zone-sections-1.png +0 -0
  246. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Notifications-tab-should-display-all-notification-toggle-options-1.png +0 -0
  247. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Notifications-tab-should-display-email-notifications-section-1.png +0 -0
  248. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Notifications-tab-should-display-toggle-switches-for-notification-options-1.png +0 -0
  249. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Notifications-tab-should-have-toggles-checked-by-default-1.png +0 -0
  250. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display--Save-Changes--button-1.png +0 -0
  251. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display-personal-information-form-1.png +0 -0
  252. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display-profile-picture-section-1.png +0 -0
  253. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display-user-email-in-disabled-email-input-1.png +0 -0
  254. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display-user-initials-in-avatar-1.png +0 -0
  255. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-Profile-tab-should-display-user-name-in-the-name-input-1.png +0 -0
  256. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-page-rendering-should-display-all-three-tabs-1.png +0 -0
  257. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-page-rendering-should-display-page-description-1.png +0 -0
  258. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-page-rendering-should-render-with-correct-title--Settings--1.png +0 -0
  259. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-tab-navigation-should-show-Profile-tab-as-default-active-tab-1.png +0 -0
  260. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-tab-navigation-should-switch-to-Account-tab-when-clicked-1.png +0 -0
  261. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/settings.test.tsx/Settings-Page-tab-navigation-should-switch-to-Notifications-tab-when-clicked-1.png +0 -0
  262. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/team.test.tsx/Team-Page-should-display-Active-Members-section-with-member-count-1.png +0 -0
  263. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/team.test.tsx/Team-Page-should-display-Pending-Invitations-section-with-invitation-details-1.png +0 -0
  264. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/team.test.tsx/Team-Page-should-have-invite-member-button-that-can-be-clicked-1.png +0 -0
  265. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/team.test.tsx/Team-Page-should-render-page-with-correct-title-and-description-1.png +0 -0
  266. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/team.test.tsx/Team-Page-should-render-search-input-that-filters-team-members-1.png +0 -0
  267. /package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/__screenshots__/team.test.tsx/Team-Page-should-show-current-user-with---you---indicator-and-role-badge-1.png +0 -0
  268. /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/error-components.test.tsx +0 -0
  269. /package/templates/base/{src/shared/schemas/__tests__ → tests/unit/shared}/schemas.test.ts +0 -0
@@ -13,28 +13,10 @@
13
13
 
14
14
  import { describe, it, expect, beforeAll } from 'vitest'
15
15
  import { Hono } from 'hono'
16
- import { getEnv, getDb, type TestEnv } from '../setup'
16
+ import { getEnv, type TestEnv } from '../setup'
17
17
  import type { HonoEnv } from '../../../src/server/types'
18
18
  import { health } from '../../../src/server/routes/health'
19
19
 
20
- /**
21
- * Creates a database wrapper that adds the `execute` method
22
- * The better-sqlite3 drizzle doesn't have execute, but D1 does
23
- * We add it as an alias to `run` for test compatibility
24
- */
25
- function createTestDb() {
26
- const db = getDb()
27
- // Add execute method that delegates to run (both execute statements)
28
- return new Proxy(db, {
29
- get(target, prop) {
30
- if (prop === 'execute') {
31
- return target.run.bind(target)
32
- }
33
- return (target as any)[prop]
34
- },
35
- })
36
- }
37
-
38
20
  describe('Health Check Integration', () => {
39
21
  let app: Hono<HonoEnv>
40
22
  let env: TestEnv
@@ -47,11 +29,6 @@ describe('Health Check Integration', () => {
47
29
  app.use('*', async (c, next) => {
48
30
  // Inject environment bindings (cast to any to allow assignment)
49
31
  ;(c as any).env = env
50
-
51
- // Use a wrapped drizzle instance that has execute method for D1 compatibility
52
- const db = createTestDb()
53
- c.set('db', db)
54
-
55
32
  await next()
56
33
  })
57
34
 
@@ -225,8 +202,10 @@ describe('Health Check Integration', () => {
225
202
  // Create an app without db set
226
203
  const appWithoutDb = new Hono<HonoEnv>()
227
204
  appWithoutDb.use('*', async (c, next) => {
228
- ;(c as any).env = env
229
- // Note: NOT setting db to test line 9
205
+ const modifiedEnv = { ...env }
206
+ // @ts-expect-error - Removing DB to test database down
207
+ delete modifiedEnv.DB
208
+ ;(c as any).env = modifiedEnv
230
209
  await next()
231
210
  })
232
211
  appWithoutDb.route('/health', health)
@@ -247,7 +226,6 @@ describe('Health Check Integration', () => {
247
226
  // @ts-expect-error - Removing R2_BUCKET to test line 24
248
227
  delete modifiedEnv.R2_BUCKET
249
228
  ;(c as any).env = modifiedEnv
250
- c.set('db', createTestDb())
251
229
  await next()
252
230
  })
253
231
  appWithoutR2.route('/health', health)
@@ -264,14 +242,15 @@ describe('Health Check Integration', () => {
264
242
  // Create an app with a broken database
265
243
  const appWithBrokenDb = new Hono<HonoEnv>()
266
244
  appWithBrokenDb.use('*', async (c, next) => {
267
- ;(c as any).env = env
268
- // Create a mock db that throws on run()
269
- const brokenDb = {
270
- run: () => {
271
- throw new Error('Database connection failed')
272
- },
245
+ const modifiedEnv = {
246
+ ...env,
247
+ DB: {
248
+ prepare: () => {
249
+ throw new Error('Database connection failed')
250
+ },
251
+ } as D1Database,
273
252
  }
274
- c.set('db', brokenDb as any)
253
+ ;(c as any).env = modifiedEnv
275
254
  await next()
276
255
  })
277
256
  appWithBrokenDb.route('/health', health)
@@ -297,7 +276,6 @@ describe('Health Check Integration', () => {
297
276
  },
298
277
  }
299
278
  ;(c as any).env = modifiedEnv
300
- c.set('db', createTestDb())
301
279
  await next()
302
280
  })
303
281
  appWithBrokenR2.route('/health', health)
@@ -313,8 +291,10 @@ describe('Health Check Integration', () => {
313
291
  it('should return 503 when readiness check fails due to db being down', async () => {
314
292
  const appWithoutDb = new Hono<HonoEnv>()
315
293
  appWithoutDb.use('*', async (c, next) => {
316
- ;(c as any).env = env
317
- // Note: NOT setting db
294
+ const modifiedEnv = { ...env }
295
+ // @ts-expect-error - Removing DB to test database down
296
+ delete modifiedEnv.DB
297
+ ;(c as any).env = modifiedEnv
318
298
  await next()
319
299
  })
320
300
  appWithoutDb.route('/health', health)
@@ -329,14 +309,15 @@ describe('Health Check Integration', () => {
329
309
  it('should return 503 when readiness check throws an error', async () => {
330
310
  const appWithBrokenDb = new Hono<HonoEnv>()
331
311
  appWithBrokenDb.use('*', async (c, next) => {
332
- ;(c as any).env = env
333
- // Create a mock db that throws on run()
334
- const brokenDb = {
335
- run: () => {
336
- throw new Error('Database connection failed')
337
- },
312
+ const modifiedEnv = {
313
+ ...env,
314
+ DB: {
315
+ prepare: () => {
316
+ throw new Error('Database connection failed')
317
+ },
318
+ } as D1Database,
338
319
  }
339
- c.set('db', brokenDb as any)
320
+ ;(c as any).env = modifiedEnv
340
321
  await next()
341
322
  })
342
323
  appWithBrokenDb.route('/health', health)
@@ -28,19 +28,10 @@ import { errorHandler } from '../../../src/server/middleware/error-handler'
28
28
  import { sessionMiddleware } from '../../../src/server/lib/session'
29
29
 
30
30
  /**
31
- * Creates a database wrapper that adds the `execute` method
32
- * The better-sqlite3 drizzle doesn't have execute, but D1 does
31
+ * Creates a D1-compatible database instance for tests
33
32
  */
34
33
  function createTestDb() {
35
- const db = getDb()
36
- return new Proxy(db, {
37
- get(target, prop) {
38
- if (prop === 'execute') {
39
- return target.run.bind(target)
40
- }
41
- return (target as any)[prop]
42
- },
43
- })
34
+ return getDb()
44
35
  }
45
36
 
46
37
  describe('Invitations CRUD Integration', () => {
@@ -28,15 +28,7 @@ import { sendInvitationEmail } from '../../../src/server/lib/email'
28
28
  // ============================================================================
29
29
 
30
30
  function createTestDb() {
31
- const db = getDb()
32
- return new Proxy(db, {
33
- get(target, prop) {
34
- if (prop === 'execute') {
35
- return target.run.bind(target)
36
- }
37
- return (target as any)[prop]
38
- },
39
- })
31
+ return getDb()
40
32
  }
41
33
 
42
34
  describe('Invitation Email Integration Tests', () => {
@@ -20,19 +20,10 @@ import {
20
20
  } from '../setup'
21
21
 
22
22
  /**
23
- * Creates a database wrapper that adds the `execute` method
24
- * The better-sqlite3 drizzle doesn't have execute, but D1 does
23
+ * Creates a D1-compatible database instance for tests
25
24
  */
26
25
  function createTestDb() {
27
- const db = getDb()
28
- return new Proxy(db, {
29
- get(target, prop) {
30
- if (prop === 'execute') {
31
- return (target as any).run.bind(target)
32
- }
33
- return (target as any)[prop]
34
- },
35
- })
26
+ return getDb()
36
27
  }
37
28
 
38
29
  describe('Auth Middleware', () => {
@@ -57,7 +48,7 @@ describe('Auth Middleware', () => {
57
48
  const env = getEnv()
58
49
  ;(c as any).env = env
59
50
 
60
- // Set up the db for middleware (use the test drizzle instance with proxy)
51
+ // Set up the db for middleware
61
52
  const db = createTestDb()
62
53
  c.set('db', db)
63
54
 
@@ -21,15 +21,7 @@ import { errorHandler } from '../../../src/server/middleware/error-handler'
21
21
  * Creates a database wrapper
22
22
  */
23
23
  function createTestDb() {
24
- const db = getDb()
25
- return new Proxy(db, {
26
- get(target, prop) {
27
- if (prop === 'execute') {
28
- return target.run.bind(target)
29
- }
30
- return (target as any)[prop]
31
- },
32
- })
24
+ return getDb()
33
25
  }
34
26
 
35
27
  describe('Request Logger Middleware Integration', () => {
@@ -36,15 +36,7 @@ const THRESHOLDS = {
36
36
  * Creates a database wrapper that adds the `execute` method
37
37
  */
38
38
  function createTestDb() {
39
- const db = getDb()
40
- return new Proxy(db, {
41
- get(target, prop) {
42
- if (prop === 'execute') {
43
- return target.run.bind(target)
44
- }
45
- return (target as unknown as Record<string | symbol, unknown>)[prop]
46
- },
47
- })
39
+ return getDb()
48
40
  }
49
41
 
50
42
  /**
@@ -27,19 +27,10 @@ import { errorHandler } from '../../../src/server/middleware/error-handler'
27
27
  import { sessionMiddleware } from '../../../src/server/lib/session'
28
28
 
29
29
  /**
30
- * Creates a database wrapper that adds the `execute` method
31
- * The better-sqlite3 drizzle doesn't have execute, but D1 does
30
+ * Creates a D1-compatible database instance for tests
32
31
  */
33
32
  function createTestDb() {
34
- const db = getDb()
35
- return new Proxy(db, {
36
- get(target, prop) {
37
- if (prop === 'execute') {
38
- return target.run.bind(target)
39
- }
40
- return (target as any)[prop]
41
- },
42
- })
33
+ return getDb()
43
34
  }
44
35
 
45
36
  describe('Session Cookie Security', () => {
@@ -24,19 +24,10 @@ import { configurableCors } from '../../../src/server/middleware/cors'
24
24
  import { sessionMiddleware } from '../../../src/server/lib/session'
25
25
 
26
26
  /**
27
- * Creates a database wrapper that adds the `execute` method
28
- * The better-sqlite3 drizzle doesn't have execute, but D1 does
27
+ * Creates a D1-compatible database instance for tests
29
28
  */
30
29
  function createTestDb() {
31
- const db = getDb()
32
- return new Proxy(db, {
33
- get(target, prop) {
34
- if (prop === 'execute') {
35
- return target.run.bind(target)
36
- }
37
- return (target as any)[prop]
38
- },
39
- })
30
+ return getDb()
40
31
  }
41
32
 
42
33
  describe('CSRF Protection', () => {
@@ -30,15 +30,7 @@ import { sessionMiddleware } from '../../../src/server/lib/session'
30
30
  * Creates a database wrapper that adds the `execute` method
31
31
  */
32
32
  function createTestDb() {
33
- const db = getDb()
34
- return new Proxy(db, {
35
- get(target, prop) {
36
- if (prop === 'execute') {
37
- return target.run.bind(target)
38
- }
39
- return (target as any)[prop]
40
- },
41
- })
33
+ return getDb()
42
34
  }
43
35
 
44
36
  describe('Log Sanitization', () => {
@@ -31,15 +31,7 @@ import {
31
31
  * Creates a database wrapper that adds the `execute` method
32
32
  */
33
33
  function createTestDb() {
34
- const db = getDb()
35
- return new Proxy(db, {
36
- get(target, prop) {
37
- if (prop === 'execute') {
38
- return target.run.bind(target)
39
- }
40
- return (target as any)[prop]
41
- },
42
- })
34
+ return getDb()
43
35
  }
44
36
 
45
37
  describe('Rate Limiting', () => {
@@ -2,18 +2,18 @@
2
2
  * SQL Injection Prevention Integration Tests
3
3
  *
4
4
  * Tests that the API properly prevents SQL injection attacks through:
5
- * - Parameterized queries via Drizzle ORM
5
+ * - Parameterized queries via SQL helpers
6
6
  * - Zod UUID validation for ID parameters
7
7
  * - Safe handling of user input in search queries
8
8
  *
9
- * Since the codebase uses Drizzle ORM with parameterized queries,
10
- * these tests should PASS - demonstrating that SQL injection protection
11
- * is already in place by default.
9
+ * Since the codebase uses parameterized SQL queries,
10
+ * these tests should PASS - demonstrating SQL injection protection
11
+ * is in place by default.
12
12
  */
13
13
 
14
14
  import { describe, it, expect, beforeAll } from 'vitest'
15
15
  import { Hono } from 'hono'
16
- import { getEnv, getSqlite, type TestEnv } from '../setup'
16
+ import { getEnv, getDb, getSqlite, type TestEnv } from '../setup'
17
17
  import { createTestScenario } from '../fixtures'
18
18
  import type { HonoEnv } from '../../../src/server/types'
19
19
  import { api } from '../../../src/server/routes'
@@ -21,21 +21,10 @@ import { errorHandler } from '../../../src/server/middleware/error-handler'
21
21
  import { sessionMiddleware } from '../../../src/server/lib/session'
22
22
 
23
23
  /**
24
- * Creates a database wrapper that adds the `execute` method
25
- * The better-sqlite3 drizzle doesn't have execute, but D1 does
24
+ * Creates a D1-compatible database instance for tests
26
25
  */
27
26
  function createTestDb() {
28
- const sqlite = getSqlite()
29
- const { drizzle } = require('drizzle-orm/better-sqlite3')
30
- const db = drizzle(sqlite)
31
- return new Proxy(db, {
32
- get(target, prop) {
33
- if (prop === 'execute') {
34
- return target.run.bind(target)
35
- }
36
- return (target as any)[prop]
37
- },
38
- })
27
+ return getDb()
39
28
  }
40
29
 
41
30
  describe('SQL Injection Prevention', () => {
@@ -23,19 +23,10 @@ import { errorHandler } from '../../../src/server/middleware/error-handler'
23
23
  import { sessionMiddleware } from '../../../src/server/lib/session'
24
24
 
25
25
  /**
26
- * Creates a database wrapper that adds the `execute` method
27
- * The better-sqlite3 drizzle doesn't have execute, but D1 does
26
+ * Creates a D1-compatible database instance for tests
28
27
  */
29
28
  function createTestDb() {
30
- const db = getDb()
31
- return new Proxy(db, {
32
- get(target, prop) {
33
- if (prop === 'execute') {
34
- return target.run.bind(target)
35
- }
36
- return (target as any)[prop]
37
- },
38
- })
29
+ return getDb()
39
30
  }
40
31
 
41
32
  describe('XSS Prevention', () => {
@@ -10,12 +10,13 @@
10
10
  */
11
11
 
12
12
  import Database from 'better-sqlite3'
13
- import { drizzle } from 'drizzle-orm/better-sqlite3'
13
+ import { readFileSync } from 'node:fs'
14
+ import { dirname, resolve } from 'node:path'
15
+ import { fileURLToPath } from 'node:url'
14
16
  import { vi, beforeAll, afterAll, beforeEach, afterEach } from 'vitest'
15
17
  import { Hono } from 'hono'
16
18
  import type { Env } from '../../src/server/env'
17
19
  import type { SessionData, HonoEnv } from '../../src/server/types'
18
- import * as schema from '../../src/server/db/schema'
19
20
 
20
21
  // ============================================================================
21
22
  // TYPES
@@ -50,90 +51,15 @@ export interface MockR2Store {
50
51
  // DATABASE SCHEMA SQL
51
52
  // ============================================================================
52
53
 
53
- const SCHEMA_SQL = `
54
- -- Users table
55
- CREATE TABLE IF NOT EXISTS users (
56
- id TEXT PRIMARY KEY,
57
- google_id TEXT NOT NULL UNIQUE,
58
- email TEXT NOT NULL,
59
- name TEXT NOT NULL,
60
- avatar_url TEXT,
61
- status TEXT DEFAULT 'active' NOT NULL CHECK (status IN ('active', 'inactive')),
62
- provider_ids TEXT DEFAULT '[]',
63
- is_super_admin INTEGER DEFAULT 0 NOT NULL,
64
- created_at TEXT DEFAULT (datetime('now')) NOT NULL,
65
- updated_at TEXT DEFAULT (datetime('now')) NOT NULL,
66
- deleted_at TEXT,
67
- created_by_id TEXT REFERENCES users(id),
68
- updated_by_id TEXT REFERENCES users(id),
69
- deleted_by_id TEXT REFERENCES users(id)
70
- );
71
-
72
- -- Accounts table
73
- CREATE TABLE IF NOT EXISTS accounts (
74
- id TEXT PRIMARY KEY,
75
- name TEXT NOT NULL,
76
- description TEXT,
77
- domain TEXT UNIQUE,
78
- created_at TEXT DEFAULT (datetime('now')) NOT NULL,
79
- updated_at TEXT DEFAULT (datetime('now')) NOT NULL,
80
- deleted_at TEXT
81
- );
82
-
83
- -- User-Accounts junction table
84
- CREATE TABLE IF NOT EXISTS user_accounts (
85
- user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
86
- account_id TEXT NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
87
- role TEXT NOT NULL CHECK (role IN ('ADMIN', 'MANAGER', 'EDITOR', 'AUTHOR', 'VIEWER', 'BILLING', 'ANALYTICS')),
88
- PRIMARY KEY (user_id, account_id)
89
- );
90
-
91
- -- Refresh tokens table
92
- CREATE TABLE IF NOT EXISTS refresh_tokens (
93
- id TEXT PRIMARY KEY,
94
- user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
95
- token_hash TEXT NOT NULL,
96
- expires_at INTEGER NOT NULL,
97
- created_at INTEGER DEFAULT (unixepoch()) NOT NULL,
98
- revoked_at INTEGER
99
- );
100
-
101
- -- Invitations table
102
- CREATE TABLE IF NOT EXISTS invitations (
103
- id TEXT PRIMARY KEY,
104
- account_id TEXT NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
105
- email TEXT NOT NULL,
106
- role TEXT NOT NULL CHECK (role IN ('ADMIN', 'MANAGER', 'EDITOR', 'AUTHOR', 'VIEWER', 'BILLING', 'ANALYTICS')),
107
- token TEXT NOT NULL UNIQUE,
108
- invited_by_id TEXT NOT NULL REFERENCES users(id),
109
- expires_at TEXT NOT NULL,
110
- accepted_at TEXT,
111
- created_at TEXT DEFAULT (datetime('now')) NOT NULL
112
- );
113
- CREATE UNIQUE INDEX IF NOT EXISTS account_email_idx ON invitations(account_id, email);
114
-
115
- -- Audit logs table
116
- CREATE TABLE IF NOT EXISTS audit_logs (
117
- id TEXT PRIMARY KEY,
118
- transaction_id TEXT NOT NULL,
119
- account_id TEXT REFERENCES accounts(id),
120
- user_id TEXT REFERENCES users(id),
121
- entity TEXT NOT NULL,
122
- entity_id TEXT NOT NULL,
123
- action TEXT NOT NULL CHECK (action IN ('INSERT', 'UPDATE', 'DELETE', 'LOGIN', 'LOGOUT', 'SIGNUP', 'TOKEN_REFRESH', 'LOGIN_FAILED')),
124
- changes TEXT,
125
- ip_address TEXT,
126
- user_agent TEXT,
127
- timestamp TEXT DEFAULT (datetime('now')) NOT NULL
128
- );
129
- `
54
+ const __filename = fileURLToPath(import.meta.url)
55
+ const __dirname = dirname(__filename)
56
+ const SCHEMA_SQL = readFileSync(resolve(__dirname, '..', '..', 'schema.sql'), 'utf8')
130
57
 
131
58
  // ============================================================================
132
59
  // GLOBAL STATE
133
60
  // ============================================================================
134
61
 
135
62
  let sqliteDb: Database.Database | null = null
136
- let drizzleDb: ReturnType<typeof drizzle> | null = null
137
63
  let mockKV: MockKVStore | null = null
138
64
  let mockR2: MockR2Store | null = null
139
65
  let testEnv: TestEnv | null = null
@@ -144,8 +70,8 @@ let testEnv: TestEnv | null = null
144
70
 
145
71
  /**
146
72
  * Creates a D1-compatible wrapper around better-sqlite3
147
- * This allows Drizzle ORM to work with our in-memory SQLite database
148
- * as if it were a Cloudflare D1 database.
73
+ * This allows our test helpers to use a Cloudflare D1-like API
74
+ * against an in-memory SQLite database.
149
75
  */
150
76
  function createD1CompatibleWrapper(db: Database.Database): D1Database {
151
77
  return {
@@ -582,13 +508,14 @@ export function getEnv(): TestEnv {
582
508
  }
583
509
 
584
510
  /**
585
- * Get the Drizzle database instance
511
+ * Get the D1-compatible database instance
586
512
  */
587
- export function getDb(): ReturnType<typeof drizzle> {
588
- if (!drizzleDb) {
513
+ export function getDb(): D1Database {
514
+ const env = getEnv()
515
+ if (!env.DB) {
589
516
  throw new Error('Database not initialized. Make sure beforeAll has run.')
590
517
  }
591
- return drizzleDb
518
+ return env.DB
592
519
  }
593
520
 
594
521
  /**
@@ -764,9 +691,6 @@ beforeAll(() => {
764
691
  // Create D1-compatible wrapper
765
692
  const d1Wrapper = createD1CompatibleWrapper(sqliteDb)
766
693
 
767
- // Create Drizzle instance
768
- drizzleDb = drizzle(sqliteDb, { schema })
769
-
770
694
  // Create mock stores
771
695
  mockKV = createMockKV()
772
696
  mockR2 = createMockR2()
@@ -797,7 +721,6 @@ afterAll(() => {
797
721
  sqliteDb = null
798
722
  }
799
723
 
800
- drizzleDb = null
801
724
  mockKV = null
802
725
  mockR2 = null
803
726
  testEnv = null
@@ -55,10 +55,11 @@ describe('Integration Test Infrastructure', () => {
55
55
  })
56
56
  })
57
57
 
58
- describe('Drizzle ORM', () => {
59
- it('should have initialized Drizzle database instance', () => {
58
+ describe('D1 Database', () => {
59
+ it('should have initialized D1 database instance', () => {
60
60
  const db = getDb()
61
61
  expect(db).toBeDefined()
62
+ expect(typeof db.prepare).toBe('function')
62
63
  })
63
64
  })
64
65
 
@@ -34,19 +34,10 @@ import { sessionMiddleware } from '../../../src/server/lib/session'
34
34
  // ============================================================================
35
35
 
36
36
  /**
37
- * Creates a database wrapper that adds the `execute` method
38
- * The better-sqlite3 drizzle doesn't have execute, but D1 does
37
+ * Creates a D1-compatible database instance for tests
39
38
  */
40
39
  function createTestDb() {
41
- const db = getDb()
42
- return new Proxy(db, {
43
- get(target, prop) {
44
- if (prop === 'execute') {
45
- return target.run.bind(target)
46
- }
47
- return (target as any)[prop]
48
- },
49
- })
40
+ return getDb()
50
41
  }
51
42
 
52
43
  /**
@@ -31,19 +31,10 @@ import { sessionMiddleware } from '../../../src/server/lib/session'
31
31
  // ============================================================================
32
32
 
33
33
  /**
34
- * Creates a database wrapper that adds the `execute` method
35
- * The better-sqlite3 drizzle doesn't have execute, but D1 does
34
+ * Creates a D1-compatible database instance for tests
36
35
  */
37
36
  function createTestDb() {
38
- const db = getDb()
39
- return new Proxy(db, {
40
- get(target, prop) {
41
- if (prop === 'execute') {
42
- return target.run.bind(target)
43
- }
44
- return (target as any)[prop]
45
- },
46
- })
37
+ return getDb()
47
38
  }
48
39
 
49
40
  /**
@@ -26,19 +26,10 @@ import { errorHandler } from '../../../src/server/middleware/error-handler'
26
26
  import { sessionMiddleware } from '../../../src/server/lib/session'
27
27
 
28
28
  /**
29
- * Creates a database wrapper that adds the `execute` method
30
- * The better-sqlite3 drizzle doesn't have execute, but D1 does
29
+ * Creates a D1-compatible database instance for tests
31
30
  */
32
31
  function createTestDb() {
33
- const db = getDb()
34
- return new Proxy(db, {
35
- get(target, prop) {
36
- if (prop === 'execute') {
37
- return target.run.bind(target)
38
- }
39
- return (target as any)[prop]
40
- },
41
- })
32
+ return getDb()
42
33
  }
43
34
 
44
35
  describe('Users CRUD Integration', () => {
@@ -29,19 +29,10 @@ import { errorHandler } from '../../../src/server/middleware/error-handler'
29
29
  import { sessionMiddleware } from '../../../src/server/lib/session'
30
30
 
31
31
  /**
32
- * Creates a database wrapper that adds the `execute` method
33
- * The better-sqlite3 drizzle doesn't have execute, but D1 does
32
+ * Creates a D1-compatible database instance for tests
34
33
  */
35
34
  function createTestDb() {
36
- const db = getDb()
37
- return new Proxy(db, {
38
- get(target, prop) {
39
- if (prop === 'execute') {
40
- return target.run.bind(target)
41
- }
42
- return (target as any)[prop]
43
- },
44
- })
35
+ return getDb()
45
36
  }
46
37
 
47
38
  describe('Users List Integration', () => {