@etus/bhono-app 0.1.5 → 0.1.7
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.
- package/dist/index.js +0 -0
- package/package.json +7 -2
- package/templates/base/.claude/commands/check-skill-rules.md +112 -29
- package/templates/base/.claude/commands/linear/implement-issue.md +383 -55
- package/templates/base/.claude/commands/ship.md +77 -13
- package/templates/base/.claude/hooks/package-lock.json +0 -419
- package/templates/base/.claude/hooks/skill-activation-prompt.ts +185 -113
- package/templates/base/.claude/hooks/skill-tool-guard.sh +6 -0
- package/templates/base/.claude/hooks/skill-tool-guard.ts +198 -0
- package/templates/base/.claude/scripts/validate-skill-rules.sh +55 -32
- package/templates/base/.claude/settings.json +18 -11
- package/templates/base/.claude/skills/skill-rules.json +326 -173
- package/templates/base/.env.example +3 -0
- package/templates/base/CLAUDE.md +5 -5
- package/templates/base/README.md +40 -27
- package/templates/base/config/eslint.config.js +1 -0
- package/templates/base/config/wrangler.json +16 -17
- package/templates/base/docs/SETUP-GUIDE.md +566 -0
- package/templates/base/docs/app_spec.txt +13 -10
- package/templates/base/docs/architecture/README.md +162 -5
- package/templates/base/docs/architecture/api-catalog.md +575 -0
- package/templates/base/docs/architecture/c4-component.md +309 -0
- package/templates/base/docs/architecture/c4-container.md +183 -0
- package/templates/base/docs/architecture/c4-context.md +106 -0
- package/templates/base/docs/architecture/data-requirements.md +4 -3
- package/templates/base/docs/architecture/db-bootstrap.md +39 -0
- package/templates/base/docs/architecture/dependencies.md +327 -0
- package/templates/base/docs/architecture/drizzle-migration-plan.md +125 -0
- package/templates/base/docs/architecture/erd.md +1 -1
- package/templates/base/docs/architecture/sql-standards.md +100 -0
- package/templates/base/docs/architecture/tech-debt.md +184 -0
- package/templates/base/docs/testing.md +36 -29
- package/templates/base/package.json +26 -20
- package/templates/base/schema.sql +84 -0
- package/templates/base/scripts/capture-prod-session.ts +2 -2
- package/templates/base/scripts/init.sh +244 -59
- package/templates/base/scripts/sync-template.sh +104 -0
- package/templates/base/src/client/hooks/use-auth.ts +5 -0
- package/templates/base/src/client/routes/_authenticated/dashboard.tsx +1 -1
- package/templates/base/src/client/routes/index.tsx +1 -1
- package/templates/base/src/server/db/client.ts +3 -5
- package/templates/base/src/server/db/records.ts +81 -0
- package/templates/base/src/server/db/seed.ts +3 -2
- package/templates/base/src/server/db/sql.ts +116 -0
- package/templates/base/src/server/index.ts +17 -2
- package/templates/base/src/server/lib/audit.ts +74 -26
- package/templates/base/src/server/lib/audited-db.ts +219 -109
- package/templates/base/src/server/lib/transaction.ts +10 -16
- package/templates/base/src/server/middleware/account.ts +9 -16
- package/templates/base/src/server/middleware/auth.ts +102 -38
- package/templates/base/src/server/middleware/rate-limit.ts +8 -6
- package/templates/base/src/server/routes/accounts/handlers.ts +18 -6
- package/templates/base/src/server/routes/audits/handlers.ts +3 -1
- package/templates/base/src/server/routes/auth/handlers.ts +15 -10
- package/templates/base/src/server/routes/auth/test-login.ts +99 -45
- package/templates/base/src/server/routes/health/handlers.ts +4 -4
- package/templates/base/src/server/routes/index.ts +9 -0
- package/templates/base/src/server/routes/invitations/handlers.ts +9 -6
- package/templates/base/src/server/routes/openapi.ts +1 -1
- package/templates/base/src/server/routes/users/handlers.ts +21 -14
- package/templates/base/src/server/services/accounts.ts +242 -217
- package/templates/base/src/server/services/audits.ts +114 -61
- package/templates/base/src/server/services/auth.ts +310 -180
- package/templates/base/src/server/services/invitations.ts +282 -222
- package/templates/base/src/server/services/users.ts +383 -293
- package/templates/base/src/server/types/index.ts +1 -2
- package/templates/base/src/shared/types/api.ts +66 -198
- package/templates/base/tests/e2e/auth.setup.ts +1 -1
- package/templates/base/{src/server/__tests__/fixtures.ts → tests/fixtures/server.ts} +3 -3
- package/templates/base/{src/client/__tests__/setup-browser.ts → tests/helpers/client-setup-browser.ts} +2 -2
- package/templates/base/{src/client/__tests__/setup.ts → tests/helpers/client-setup.ts} +1 -1
- package/templates/base/{src/client/__tests__/test-utils.tsx → tests/helpers/client-test-utils.tsx} +2 -2
- package/templates/base/{src/server/__tests__/setup.ts → tests/helpers/server.ts} +9 -9
- package/templates/base/tests/integration/accounts/crud.test.ts +2 -11
- package/templates/base/tests/integration/audits/list.test.ts +2 -11
- package/templates/base/tests/integration/auth/auth-service.test.ts +1 -10
- package/templates/base/tests/integration/auth/invitation-token.test.ts +2 -11
- package/templates/base/tests/integration/auth/logout.test.ts +2 -11
- package/templates/base/tests/integration/auth/oauth.test.ts +23 -42
- package/templates/base/tests/integration/auth/refresh-token.test.ts +1 -9
- package/templates/base/tests/integration/auth/session-expiry.test.ts +1 -9
- package/templates/base/tests/integration/auth/session.test.ts +2 -11
- package/templates/base/tests/integration/auth/super-admin.test.ts +1 -9
- package/templates/base/tests/integration/authorization/analytics-role.test.ts +2 -11
- package/templates/base/tests/integration/authorization/billing-role.test.ts +2 -11
- package/templates/base/tests/integration/authorization/guards-roles.test.ts +1 -9
- package/templates/base/tests/integration/authorization/multi-tenancy.test.ts +2 -11
- package/templates/base/tests/integration/authorization/roles.test.ts +2 -11
- package/templates/base/tests/integration/config/production-behavior.test.ts +2 -11
- package/templates/base/tests/integration/health/health.test.ts +25 -44
- package/templates/base/tests/integration/invitations/crud.test.ts +2 -11
- package/templates/base/tests/integration/invitations/email.test.ts +1 -9
- package/templates/base/tests/integration/middleware/auth.test.ts +3 -12
- package/templates/base/tests/integration/middleware/request-logger.test.ts +1 -9
- package/templates/base/tests/integration/performance/response-times.test.ts +1 -9
- package/templates/base/tests/integration/security/cookie-security.test.ts +2 -11
- package/templates/base/tests/integration/security/csrf-protection.test.ts +2 -11
- package/templates/base/tests/integration/security/log-sanitization.test.ts +1 -9
- package/templates/base/tests/integration/security/rate-limiting.test.ts +1 -9
- package/templates/base/tests/integration/security/sql-injection.test.ts +7 -18
- package/templates/base/tests/integration/security/xss-prevention.test.ts +2 -11
- package/templates/base/tests/integration/setup.ts +13 -90
- package/templates/base/tests/integration/smoke.test.ts +3 -2
- package/templates/base/tests/integration/storage/upload.test.ts +2 -11
- package/templates/base/tests/integration/storage/validation.test.ts +2 -11
- package/templates/base/tests/integration/users/crud.test.ts +2 -11
- package/templates/base/tests/integration/users/list.test.ts +2 -11
- package/templates/base/tests/integration/vitest.config.ts +2 -9
- package/templates/base/{src/server/__tests__ → tests}/mocks/db.ts +1 -1
- package/templates/base/{src/server/__tests__ → tests}/mocks/index.ts +1 -1
- package/templates/base/{src/server/__tests__ → tests}/mocks/kv.ts +1 -1
- package/templates/base/{src/server/__tests__ → tests}/mocks/r2.ts +1 -1
- package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/sidebar.test.tsx +1 -1
- package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/avatar.test.tsx +1 -1
- package/templates/base/{src/client/__tests__ → tests/unit/client/components/ui}/button.test.tsx +1 -1
- package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/card.test.tsx +1 -1
- package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/dialog.test.tsx +1 -1
- package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/input.test.tsx +1 -1
- package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/loading-skeleton.test.tsx +1 -1
- package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/skeleton.test.tsx +1 -1
- package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/sonner.test.tsx +1 -1
- package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/tabs.test.tsx +1 -1
- package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/account.test.tsx +1 -1
- package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/integrations.test.tsx +1 -1
- package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/settings.test.tsx +1 -1
- package/templates/base/{src/client/routes/_authenticated/__tests__ → tests/unit/client/routes/_authenticated}/team.test.tsx +1 -1
- package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/authenticated-layout.test.tsx +1 -1
- package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/dashboard.test.tsx +1 -1
- package/templates/base/{src/client/routes/__tests__ → tests/unit/client/routes}/invite.test.tsx +1 -1
- package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/login.test.tsx +1 -1
- package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/navigation.test.tsx +1 -1
- package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/root-layout.test.tsx +1 -1
- package/templates/base/{src/server/auth/__tests__ → tests/unit/server/auth}/guards.test.ts +2 -2
- package/templates/base/{src → tests/unit}/server/auth/permissions.test.ts +1 -1
- package/templates/base/{src → tests/unit}/server/auth/roles.test.ts +1 -1
- package/templates/base/tests/unit/server/db/sql.test.ts +68 -0
- package/templates/base/{src → tests/unit}/server/env.test.ts +1 -1
- package/templates/base/tests/unit/server/lib/audited-db.test.ts +78 -0
- package/templates/base/{src → tests/unit}/server/lib/email.test.ts +1 -1
- package/templates/base/{src → tests/unit}/server/lib/errors.test.ts +1 -1
- package/templates/base/{src → tests/unit}/server/lib/oauth.test.ts +1 -1
- package/templates/base/{src → tests/unit}/server/lib/pagination.test.ts +1 -1
- package/templates/base/{src → tests/unit}/server/lib/password.test.ts +1 -1
- package/templates/base/{src → tests/unit}/server/lib/providers.test.ts +1 -1
- package/templates/base/{src → tests/unit}/server/lib/r2-storage.test.ts +2 -2
- package/templates/base/{src → tests/unit}/server/lib/session.test.ts +2 -2
- package/templates/base/{src → tests/unit}/server/lib/tokens.test.ts +1 -1
- package/templates/base/{src → tests/unit}/server/lib/transaction.test.ts +5 -14
- package/templates/base/{src → tests/unit}/server/middleware/account.test.ts +16 -24
- package/templates/base/tests/unit/server/middleware/auth.test.ts +647 -0
- package/templates/base/{src → tests/unit}/server/middleware/cors.test.ts +1 -1
- package/templates/base/{src → tests/unit}/server/middleware/error-handler.test.ts +2 -2
- package/templates/base/{src → tests/unit}/server/middleware/rate-limit.test.ts +3 -2
- package/templates/base/{src → tests/unit}/server/middleware/request-context.test.ts +1 -1
- package/templates/base/{src → tests/unit}/server/middleware/request-logger.test.ts +1 -1
- package/templates/base/{src/server/__tests__/mocks/__tests__ → tests/unit/server/mocks}/db.test.ts +1 -1
- package/templates/base/{src/server/__tests__/mocks/__tests__ → tests/unit/server/mocks}/kv.test.ts +1 -1
- package/templates/base/{src/server/__tests__/mocks/__tests__ → tests/unit/server/mocks}/r2.test.ts +1 -1
- package/templates/base/{src/server/routes/accounts/__tests__ → tests/unit/server/routes/accounts}/handlers.test.ts +12 -12
- package/templates/base/{src/server/routes/audits/__tests__ → tests/unit/server/routes/audits}/handlers.test.ts +11 -11
- package/templates/base/{src/server/routes/auth/__tests__ → tests/unit/server/routes/auth}/handlers.test.ts +124 -13
- package/templates/base/{src/server/routes/health/__tests__ → tests/unit/server/routes/health}/handlers.test.ts +27 -23
- package/templates/base/{src/server/routes/invitations/__tests__ → tests/unit/server/routes/invitations}/handlers.test.ts +14 -17
- package/templates/base/{src/server/routes/storage/__tests__ → tests/unit/server/routes/storage}/handlers.test.ts +6 -6
- package/templates/base/{src/server/routes/users/__tests__ → tests/unit/server/routes/users}/handlers.test.ts +81 -17
- package/templates/base/tests/unit/server/services/accounts.test.ts +406 -0
- package/templates/base/tests/unit/server/services/audits.test.ts +360 -0
- package/templates/base/tests/unit/server/services/auth.test.ts +656 -0
- package/templates/base/tests/unit/server/services/invitations.test.ts +343 -0
- package/templates/base/tests/unit/server/services/users.test.ts +706 -0
- package/templates/base/{src/shared/schemas/__tests__ → tests/unit/shared}/schemas.test.ts +1 -1
- package/templates/base/tsconfig.json +2 -1
- package/templates/base/vite.config.ts +3 -1
- package/templates/base/vitest.config.browser.ts +3 -2
- package/templates/base/vitest.config.frontend.ts +3 -2
- package/templates/base/vitest.config.ts +7 -14
- package/templates/base/.claude/settings.local.json +0 -11
- package/templates/base/.github/workflows/test.yml +0 -127
- package/templates/base/auth-setup-error.png +0 -0
- package/templates/base/config/drizzle.config.ts +0 -10
- package/templates/base/pnpm-lock.yaml +0 -8175
- package/templates/base/src/server/db/schema/accounts.ts +0 -20
- package/templates/base/src/server/db/schema/audit-logs.ts +0 -26
- package/templates/base/src/server/db/schema/index.ts +0 -7
- package/templates/base/src/server/db/schema/invitations.ts +0 -30
- package/templates/base/src/server/db/schema/refresh-tokens.ts +0 -22
- package/templates/base/src/server/db/schema/user-accounts.ts +0 -25
- package/templates/base/src/server/db/schema/users.ts +0 -33
- package/templates/base/src/server/lib/audited-db.test.ts +0 -107
- package/templates/base/src/server/lib/schema-helpers.ts +0 -16
- package/templates/base/src/server/middleware/auth.test.ts +0 -345
- package/templates/base/src/server/services/__tests__/accounts.test.ts +0 -764
- package/templates/base/src/server/services/__tests__/audits.test.ts +0 -235
- package/templates/base/src/server/services/__tests__/auth.test.ts +0 -765
- package/templates/base/src/server/services/__tests__/invitations.test.ts +0 -704
- package/templates/base/src/server/services/__tests__/users.test.ts +0 -755
- package/templates/base/tests/e2e/_auth/.gitkeep +0 -0
- package/templates/base/tests/integration/lib/schema-helpers.test.ts +0 -129
- package/templates/base/tsconfig.tsbuildinfo +0 -1
- /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
- /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
- /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-handles-logout-button-click-1.png +0 -0
- /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-handles-navigation-clicks-1.png +0 -0
- /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
- /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-highlights-active-route-1.png +0 -0
- /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/__screenshots__/sidebar.test.tsx/Sidebar-renders-sidebar-navigation-items-1.png +0 -0
- /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
- /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
- /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
- /package/templates/base/{src/client/components/__tests__ → tests/unit/client/components}/error-boundary.test.tsx +0 -0
- /package/templates/base/{src/client/components/ui/__tests__ → tests/unit/client/components/ui}/error-fallback.test.tsx +0 -0
- /package/templates/base/{src/client/hooks/__tests__ → tests/unit/client/hooks}/use-auth.test.tsx +0 -0
- /package/templates/base/{src/client/hooks/__tests__ → tests/unit/client/hooks}/use-theme.test.tsx +0 -0
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /package/templates/base/{src/client/__tests__ → tests/unit/client}/routes/error-components.test.tsx +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
import type { User, Account, SessionData } from '
|
|
3
|
-
import type { Role } from '
|
|
1
|
+
// tests/fixtures/server.ts
|
|
2
|
+
import type { User, Account, SessionData } from '@server/types'
|
|
3
|
+
import type { Role } from '@server/auth/roles'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Counter for generating unique IDs
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
//
|
|
1
|
+
// tests/helpers/client-setup-browser.ts
|
|
2
2
|
// Setup file for Vitest Browser Mode (real browser, no mocks needed)
|
|
3
3
|
import "@testing-library/jest-dom/vitest"
|
|
4
|
-
import "../../test/vitest-zod-matcher"
|
|
4
|
+
import "../../src/test/vitest-zod-matcher"
|
|
5
5
|
import { cleanup } from "@testing-library/react"
|
|
6
6
|
import { afterEach, vi } from "vitest"
|
|
7
7
|
|
package/templates/base/{src/client/__tests__/test-utils.tsx → tests/helpers/client-test-utils.tsx}
RENAMED
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
createMemoryHistory,
|
|
7
7
|
createRouter,
|
|
8
8
|
} from "@tanstack/react-router"
|
|
9
|
-
import { routeTree } from "
|
|
10
|
-
import { ThemeProvider } from "
|
|
9
|
+
import { routeTree } from "@/routeTree.gen"
|
|
10
|
+
import { ThemeProvider } from "@/hooks/use-theme"
|
|
11
11
|
import type { ReactElement, ReactNode } from "react"
|
|
12
12
|
|
|
13
13
|
// Create a fresh QueryClient for each test
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
//
|
|
1
|
+
// tests/helpers/server.ts
|
|
2
2
|
import { vi, beforeEach, afterEach } from 'vitest'
|
|
3
|
-
import type { Env } from '
|
|
4
|
-
import type { SessionData } from '
|
|
5
|
-
import { createMockD1, createMockD1AsD1Database, type MockD1Database } from '
|
|
3
|
+
import type { Env } from '@server/env'
|
|
4
|
+
import type { SessionData } from '@server/types'
|
|
5
|
+
import { createMockD1, createMockD1AsD1Database, type MockD1Database } from '@tests/mocks/db'
|
|
6
6
|
import {
|
|
7
7
|
createMockKV,
|
|
8
8
|
createMockKVAsKVNamespace,
|
|
9
9
|
seedMockKV,
|
|
10
10
|
type MockKVNamespace,
|
|
11
|
-
} from '
|
|
12
|
-
import { createMockR2, createMockR2AsR2Bucket, type MockR2Bucket } from '
|
|
11
|
+
} from '@tests/mocks/kv'
|
|
12
|
+
import { createMockR2, createMockR2AsR2Bucket, type MockR2Bucket } from '@tests/mocks/r2'
|
|
13
13
|
|
|
14
14
|
// Re-export mocks for convenience
|
|
15
|
-
export * from '
|
|
16
|
-
export * from '
|
|
17
|
-
export * from '
|
|
15
|
+
export * from '@tests/mocks/db'
|
|
16
|
+
export * from '@tests/mocks/kv'
|
|
17
|
+
export * from '@tests/mocks/r2'
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Default environment configuration for tests
|
|
@@ -30,19 +30,10 @@ import { errorHandler } from '../../../src/server/middleware/error-handler'
|
|
|
30
30
|
import { sessionMiddleware } from '../../../src/server/lib/session'
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
* Creates a database
|
|
34
|
-
* The better-sqlite3 drizzle doesn't have execute, but D1 does
|
|
33
|
+
* Creates a D1-compatible database instance for tests
|
|
35
34
|
*/
|
|
36
35
|
function createTestDb() {
|
|
37
|
-
|
|
38
|
-
return new Proxy(db, {
|
|
39
|
-
get(target, prop) {
|
|
40
|
-
if (prop === 'execute') {
|
|
41
|
-
return target.run.bind(target)
|
|
42
|
-
}
|
|
43
|
-
return (target as any)[prop]
|
|
44
|
-
},
|
|
45
|
-
})
|
|
36
|
+
return getDb()
|
|
46
37
|
}
|
|
47
38
|
|
|
48
39
|
describe('Accounts CRUD Integration', () => {
|
|
@@ -22,19 +22,10 @@ import { errorHandler } from '../../../src/server/middleware/error-handler'
|
|
|
22
22
|
import { sessionMiddleware } from '../../../src/server/lib/session'
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
* Creates a database
|
|
26
|
-
* The better-sqlite3 drizzle doesn't have execute, but D1 does
|
|
25
|
+
* Creates a D1-compatible database instance for tests
|
|
27
26
|
*/
|
|
28
27
|
function createTestDb() {
|
|
29
|
-
|
|
30
|
-
return new Proxy(db, {
|
|
31
|
-
get(target, prop) {
|
|
32
|
-
if (prop === 'execute') {
|
|
33
|
-
return target.run.bind(target)
|
|
34
|
-
}
|
|
35
|
-
return (target as any)[prop]
|
|
36
|
-
},
|
|
37
|
-
})
|
|
28
|
+
return getDb()
|
|
38
29
|
}
|
|
39
30
|
|
|
40
31
|
/**
|
|
@@ -15,21 +15,12 @@ import { createUser } from '../fixtures'
|
|
|
15
15
|
import { authService } from '../../../src/server/services/auth'
|
|
16
16
|
import { generateRefreshToken, hashToken } from '../../../src/server/lib/tokens'
|
|
17
17
|
import type { GoogleUserInfo, AuthEventContext } from '../../../src/server/types/auth'
|
|
18
|
-
import * as schema from '../../../src/server/db/schema'
|
|
19
18
|
|
|
20
19
|
/**
|
|
21
20
|
* Creates a database wrapper
|
|
22
21
|
*/
|
|
23
22
|
function createTestDb() {
|
|
24
|
-
|
|
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
|
-
}) as any
|
|
23
|
+
return getDb()
|
|
33
24
|
}
|
|
34
25
|
|
|
35
26
|
describe('Auth Service Integration', () => {
|
|
@@ -34,19 +34,10 @@ import { sessionMiddleware } from '../../../src/server/lib/session'
|
|
|
34
34
|
import { errorHandler } from '../../../src/server/middleware/error-handler'
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
* Creates a database
|
|
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
|
-
|
|
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
|
describe('Invitation Token Authentication Integration', () => {
|
|
@@ -24,19 +24,10 @@ import { sessionMiddleware } from '../../../src/server/lib/session'
|
|
|
24
24
|
import { errorHandler } from '../../../src/server/middleware/error-handler'
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
* Creates a database
|
|
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
|
-
|
|
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('Logout Integration', () => {
|
|
@@ -9,15 +9,13 @@
|
|
|
9
9
|
|
|
10
10
|
import { describe, it, expect, beforeAll, vi, beforeEach } from 'vitest'
|
|
11
11
|
import { Hono } from 'hono'
|
|
12
|
-
import {
|
|
13
|
-
import { getEnv, getDb, getKV, type TestEnv } from '../setup'
|
|
12
|
+
import { getEnv, getDb, getKV, getSqlite, type TestEnv } from '../setup'
|
|
14
13
|
import { createUser, createUserSession } from '../fixtures'
|
|
15
14
|
import type { HonoEnv } from '../../../src/server/types'
|
|
16
15
|
import { auth } from '../../../src/server/routes/auth'
|
|
17
16
|
import { sessionMiddleware } from '../../../src/server/lib/session'
|
|
18
17
|
import { errorHandler } from '../../../src/server/middleware/error-handler'
|
|
19
18
|
import { createAccount, addUserToAccount } from '../fixtures'
|
|
20
|
-
import { users } from '../../../src/server/db/schema'
|
|
21
19
|
|
|
22
20
|
// Mock ID token for testing (base64url encoded)
|
|
23
21
|
function createMockIdToken(payload: Record<string, unknown>): string {
|
|
@@ -32,15 +30,7 @@ function createMockIdToken(payload: Record<string, unknown>): string {
|
|
|
32
30
|
* Creates a database wrapper that adds the `execute` method
|
|
33
31
|
*/
|
|
34
32
|
function createTestDb() {
|
|
35
|
-
|
|
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
|
-
})
|
|
33
|
+
return getDb()
|
|
44
34
|
}
|
|
45
35
|
|
|
46
36
|
describe('OAuth Authentication Integration', () => {
|
|
@@ -353,16 +343,14 @@ describe('OAuth Authentication Integration', () => {
|
|
|
353
343
|
expect(res.status).toBe(302)
|
|
354
344
|
|
|
355
345
|
// Verify user was updated in database
|
|
356
|
-
const
|
|
357
|
-
const result =
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
.where(eq(users.id, existingUser.id))
|
|
361
|
-
.limit(1)
|
|
346
|
+
const sqlite = getSqlite()
|
|
347
|
+
const result = sqlite.prepare(
|
|
348
|
+
'SELECT name, email, avatar_url as avatarUrl FROM users WHERE id = ?'
|
|
349
|
+
).get(existingUser.id) as { name: string; email: string; avatarUrl: string } | undefined
|
|
362
350
|
|
|
363
|
-
expect(result
|
|
364
|
-
expect(result
|
|
365
|
-
expect(result
|
|
351
|
+
expect(result?.name).toBe('New Updated Name')
|
|
352
|
+
expect(result?.email).toBe('newemail@gmail.com')
|
|
353
|
+
expect(result?.avatarUrl).toBe('https://new-avatar.jpg')
|
|
366
354
|
|
|
367
355
|
globalThis.fetch = originalFetch
|
|
368
356
|
})
|
|
@@ -374,18 +362,16 @@ describe('OAuth Authentication Integration', () => {
|
|
|
374
362
|
await addUserToAccount(inviter.id, account.id, 'ADMIN')
|
|
375
363
|
|
|
376
364
|
// Create an invitation in the database
|
|
377
|
-
const
|
|
365
|
+
const sqlite = getSqlite()
|
|
378
366
|
const invitationId = crypto.randomUUID()
|
|
379
367
|
const invitationToken = crypto.randomUUID()
|
|
380
368
|
const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString()
|
|
381
369
|
const inviteeEmail = `pending-invitee-${crypto.randomUUID().slice(0, 8)}@gmail.com`
|
|
382
370
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
`
|
|
388
|
-
)
|
|
371
|
+
sqlite.prepare(
|
|
372
|
+
`INSERT INTO invitations (id, account_id, email, role, token, invited_by_id, expires_at)
|
|
373
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`
|
|
374
|
+
).run(invitationId, account.id, inviteeEmail, 'EDITOR', invitationToken, inviter.id, expiresAt)
|
|
389
375
|
|
|
390
376
|
// Mock Google OAuth response
|
|
391
377
|
const mockIdToken = createMockIdToken({
|
|
@@ -433,14 +419,11 @@ describe('OAuth Authentication Integration', () => {
|
|
|
433
419
|
expect(location).toContain('/dashboard')
|
|
434
420
|
|
|
435
421
|
// Verify the invitation was accepted (accepted_at should be set)
|
|
436
|
-
const
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
.from(invitations)
|
|
440
|
-
.where(eq(invitations.id, invitationId))
|
|
441
|
-
.limit(1)
|
|
422
|
+
const invitationResult = sqlite.prepare(
|
|
423
|
+
'SELECT accepted_at as acceptedAt FROM invitations WHERE id = ?'
|
|
424
|
+
).get(invitationId) as { acceptedAt: string | null } | undefined
|
|
442
425
|
|
|
443
|
-
expect(invitationResult
|
|
426
|
+
expect(invitationResult?.acceptedAt).not.toBeNull()
|
|
444
427
|
|
|
445
428
|
globalThis.fetch = originalFetch
|
|
446
429
|
})
|
|
@@ -567,17 +550,15 @@ describe('OAuth Authentication Integration', () => {
|
|
|
567
550
|
await addUserToAccount(inviter.id, account.id, 'ADMIN')
|
|
568
551
|
|
|
569
552
|
// Create invitation directly in the database
|
|
570
|
-
const
|
|
553
|
+
const sqlite = getSqlite()
|
|
571
554
|
const invitationId = crypto.randomUUID()
|
|
572
555
|
const token = crypto.randomUUID()
|
|
573
556
|
const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString()
|
|
574
557
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
`
|
|
580
|
-
)
|
|
558
|
+
sqlite.prepare(
|
|
559
|
+
`INSERT INTO invitations (id, account_id, email, role, token, invited_by_id, expires_at)
|
|
560
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`
|
|
561
|
+
).run(invitationId, account.id, 'invitee@example.com', 'EDITOR', token, inviter.id, expiresAt)
|
|
581
562
|
|
|
582
563
|
const res = await app.request(`/auth/invite/${token}`, {
|
|
583
564
|
method: 'GET',
|
|
@@ -22,15 +22,7 @@ import { hashToken, generateRefreshToken, getRefreshTokenExpiry } from '../../..
|
|
|
22
22
|
* Creates a database wrapper
|
|
23
23
|
*/
|
|
24
24
|
function createTestDb() {
|
|
25
|
-
|
|
26
|
-
return new Proxy(db, {
|
|
27
|
-
get(target, prop) {
|
|
28
|
-
if (prop === 'execute') {
|
|
29
|
-
return target.run.bind(target)
|
|
30
|
-
}
|
|
31
|
-
return (target as any)[prop]
|
|
32
|
-
},
|
|
33
|
-
})
|
|
25
|
+
return getDb()
|
|
34
26
|
}
|
|
35
27
|
|
|
36
28
|
describe('Refresh Token Integration', () => {
|
|
@@ -23,15 +23,7 @@ import { hashToken, generateRefreshToken } from '../../../src/server/lib/tokens'
|
|
|
23
23
|
// ============================================================================
|
|
24
24
|
|
|
25
25
|
function createTestDb() {
|
|
26
|
-
|
|
27
|
-
return new Proxy(db, {
|
|
28
|
-
get(target, prop) {
|
|
29
|
-
if (prop === 'execute') {
|
|
30
|
-
return target.run.bind(target)
|
|
31
|
-
}
|
|
32
|
-
return (target as any)[prop]
|
|
33
|
-
},
|
|
34
|
-
})
|
|
26
|
+
return getDb()
|
|
35
27
|
}
|
|
36
28
|
|
|
37
29
|
describe('Session Expiry Integration Tests', () => {
|
|
@@ -24,19 +24,10 @@ import { sessionMiddleware } from '../../../src/server/lib/session'
|
|
|
24
24
|
import { errorHandler } from '../../../src/server/middleware/error-handler'
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
* Creates a database
|
|
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
|
-
|
|
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('Session Authentication Integration', () => {
|
|
@@ -30,15 +30,7 @@ import { isSuperAdminEmail } from '../../../src/server/env'
|
|
|
30
30
|
// ============================================================================
|
|
31
31
|
|
|
32
32
|
function createTestDb() {
|
|
33
|
-
|
|
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('Super Admin Integration Tests', () => {
|
|
@@ -38,19 +38,10 @@ import { hasMinimumRole, isHierarchicalRole, ROLE_HIERARCHY } from '../../../src
|
|
|
38
38
|
// ============================================================================
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
|
-
* Creates a database
|
|
42
|
-
* The better-sqlite3 drizzle doesn't have execute, but D1 does
|
|
41
|
+
* Creates a D1-compatible database instance for tests
|
|
43
42
|
*/
|
|
44
43
|
function createTestDb() {
|
|
45
|
-
|
|
46
|
-
return new Proxy(db, {
|
|
47
|
-
get(target, prop) {
|
|
48
|
-
if (prop === 'execute') {
|
|
49
|
-
return target.run.bind(target)
|
|
50
|
-
}
|
|
51
|
-
return (target as any)[prop]
|
|
52
|
-
},
|
|
53
|
-
})
|
|
44
|
+
return getDb()
|
|
54
45
|
}
|
|
55
46
|
|
|
56
47
|
/**
|
|
@@ -38,19 +38,10 @@ import { hasMinimumRole, isHierarchicalRole, ROLE_HIERARCHY } from '../../../src
|
|
|
38
38
|
// ============================================================================
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
|
-
* Creates a database
|
|
42
|
-
* The better-sqlite3 drizzle doesn't have execute, but D1 does
|
|
41
|
+
* Creates a D1-compatible database instance for tests
|
|
43
42
|
*/
|
|
44
43
|
function createTestDb() {
|
|
45
|
-
|
|
46
|
-
return new Proxy(db, {
|
|
47
|
-
get(target, prop) {
|
|
48
|
-
if (prop === 'execute') {
|
|
49
|
-
return target.run.bind(target)
|
|
50
|
-
}
|
|
51
|
-
return (target as any)[prop]
|
|
52
|
-
},
|
|
53
|
-
})
|
|
44
|
+
return getDb()
|
|
54
45
|
}
|
|
55
46
|
|
|
56
47
|
/**
|
|
@@ -40,15 +40,7 @@ import {
|
|
|
40
40
|
* Creates a database wrapper
|
|
41
41
|
*/
|
|
42
42
|
function createTestDb() {
|
|
43
|
-
|
|
44
|
-
return new Proxy(db, {
|
|
45
|
-
get(target, prop) {
|
|
46
|
-
if (prop === 'execute') {
|
|
47
|
-
return target.run.bind(target)
|
|
48
|
-
}
|
|
49
|
-
return (target as any)[prop]
|
|
50
|
-
},
|
|
51
|
-
})
|
|
43
|
+
return getDb()
|
|
52
44
|
}
|
|
53
45
|
|
|
54
46
|
describe('Role Utility Functions', () => {
|
|
@@ -35,19 +35,10 @@ import { sessionMiddleware } from '../../../src/server/lib/session'
|
|
|
35
35
|
// ============================================================================
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
* Creates a database
|
|
39
|
-
* The better-sqlite3 drizzle doesn't have execute, but D1 does
|
|
38
|
+
* Creates a D1-compatible database instance for tests
|
|
40
39
|
*/
|
|
41
40
|
function createTestDb() {
|
|
42
|
-
|
|
43
|
-
return new Proxy(db, {
|
|
44
|
-
get(target, prop) {
|
|
45
|
-
if (prop === 'execute') {
|
|
46
|
-
return target.run.bind(target)
|
|
47
|
-
}
|
|
48
|
-
return (target as any)[prop]
|
|
49
|
-
},
|
|
50
|
-
})
|
|
41
|
+
return getDb()
|
|
51
42
|
}
|
|
52
43
|
|
|
53
44
|
/**
|
|
@@ -49,19 +49,10 @@ import { sessionMiddleware } from '../../../src/server/lib/session'
|
|
|
49
49
|
// ============================================================================
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
|
-
* Creates a database
|
|
53
|
-
* The better-sqlite3 drizzle doesn't have execute, but D1 does
|
|
52
|
+
* Creates a D1-compatible database instance for tests
|
|
54
53
|
*/
|
|
55
54
|
function createTestDb() {
|
|
56
|
-
|
|
57
|
-
return new Proxy(db, {
|
|
58
|
-
get(target, prop) {
|
|
59
|
-
if (prop === 'execute') {
|
|
60
|
-
return target.run.bind(target)
|
|
61
|
-
}
|
|
62
|
-
return (target as any)[prop]
|
|
63
|
-
},
|
|
64
|
-
})
|
|
55
|
+
return getDb()
|
|
65
56
|
}
|
|
66
57
|
|
|
67
58
|
/**
|
|
@@ -22,19 +22,10 @@ import { secureHeaders } from 'hono/secure-headers'
|
|
|
22
22
|
import { uuidv7 } from 'uuidv7'
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
* Creates a database
|
|
26
|
-
* The better-sqlite3 drizzle doesn't have execute, but D1 does
|
|
25
|
+
* Creates a D1-compatible database instance for tests
|
|
27
26
|
*/
|
|
28
27
|
function createTestDb() {
|
|
29
|
-
|
|
30
|
-
return new Proxy(db, {
|
|
31
|
-
get(target, prop) {
|
|
32
|
-
if (prop === 'execute') {
|
|
33
|
-
return target.run.bind(target)
|
|
34
|
-
}
|
|
35
|
-
return (target as any)[prop]
|
|
36
|
-
},
|
|
37
|
-
})
|
|
28
|
+
return getDb()
|
|
38
29
|
}
|
|
39
30
|
|
|
40
31
|
/**
|
|
@@ -13,28 +13,10 @@
|
|
|
13
13
|
|
|
14
14
|
import { describe, it, expect, beforeAll } from 'vitest'
|
|
15
15
|
import { Hono } from 'hono'
|
|
16
|
-
import { getEnv,
|
|
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
|
-
|
|
229
|
-
//
|
|
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
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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
|
|
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
|
-
|
|
317
|
-
//
|
|
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
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
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
|
|
320
|
+
;(c as any).env = modifiedEnv
|
|
340
321
|
await next()
|
|
341
322
|
})
|
|
342
323
|
appWithBrokenDb.route('/health', health)
|