create-blitzpack 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (259) hide show
  1. package/dist/index.js +35 -77
  2. package/package.json +5 -6
  3. package/template/.dockerignore +0 -59
  4. package/template/.github/workflows/ci.yml +0 -157
  5. package/template/.husky/pre-commit +0 -1
  6. package/template/.husky/pre-push +0 -1
  7. package/template/.lintstagedrc.cjs +0 -4
  8. package/template/.nvmrc +0 -1
  9. package/template/.prettierrc +0 -9
  10. package/template/.vscode/settings.json +0 -13
  11. package/template/CLAUDE.md +0 -175
  12. package/template/CONTRIBUTING.md +0 -32
  13. package/template/Dockerfile +0 -90
  14. package/template/GETTING_STARTED.md +0 -35
  15. package/template/LICENSE +0 -21
  16. package/template/README.md +0 -116
  17. package/template/apps/api/.dockerignore +0 -51
  18. package/template/apps/api/.env.local.example +0 -62
  19. package/template/apps/api/emails/account-deleted-email.tsx +0 -69
  20. package/template/apps/api/emails/components/email-layout.tsx +0 -154
  21. package/template/apps/api/emails/config.ts +0 -22
  22. package/template/apps/api/emails/password-changed-email.tsx +0 -88
  23. package/template/apps/api/emails/password-reset-email.tsx +0 -86
  24. package/template/apps/api/emails/verification-email.tsx +0 -85
  25. package/template/apps/api/emails/welcome-email.tsx +0 -70
  26. package/template/apps/api/package.json +0 -84
  27. package/template/apps/api/prisma/migrations/20251012111439_init/migration.sql +0 -13
  28. package/template/apps/api/prisma/migrations/20251018162629_add_better_auth_fields/migration.sql +0 -67
  29. package/template/apps/api/prisma/migrations/20251019142208_add_user_role_enum/migration.sql +0 -5
  30. package/template/apps/api/prisma/migrations/20251019182151_user_auth/migration.sql +0 -7
  31. package/template/apps/api/prisma/migrations/20251019211416_faster_session_lookup/migration.sql +0 -2
  32. package/template/apps/api/prisma/migrations/20251119124337_add_upload_model/migration.sql +0 -26
  33. package/template/apps/api/prisma/migrations/20251120071241_add_scope_to_account/migration.sql +0 -2
  34. package/template/apps/api/prisma/migrations/20251120072608_add_oauth_token_expiration_fields/migration.sql +0 -10
  35. package/template/apps/api/prisma/migrations/20251120144705_add_audit_logs/migration.sql +0 -29
  36. package/template/apps/api/prisma/migrations/20251127123614_remove_impersonated_by/migration.sql +0 -8
  37. package/template/apps/api/prisma/migrations/20251127125630_remove_audit_logs/migration.sql +0 -11
  38. package/template/apps/api/prisma/migrations/migration_lock.toml +0 -3
  39. package/template/apps/api/prisma/schema.prisma +0 -116
  40. package/template/apps/api/prisma/seed.ts +0 -159
  41. package/template/apps/api/prisma.config.ts +0 -14
  42. package/template/apps/api/src/app.ts +0 -377
  43. package/template/apps/api/src/common/logger.service.ts +0 -227
  44. package/template/apps/api/src/config/env.ts +0 -60
  45. package/template/apps/api/src/config/rate-limit.ts +0 -29
  46. package/template/apps/api/src/hooks/auth.ts +0 -122
  47. package/template/apps/api/src/plugins/auth.ts +0 -198
  48. package/template/apps/api/src/plugins/database.ts +0 -45
  49. package/template/apps/api/src/plugins/logger.ts +0 -33
  50. package/template/apps/api/src/plugins/multipart.ts +0 -16
  51. package/template/apps/api/src/plugins/scalar.ts +0 -20
  52. package/template/apps/api/src/plugins/schedule.ts +0 -52
  53. package/template/apps/api/src/plugins/services.ts +0 -66
  54. package/template/apps/api/src/plugins/swagger.ts +0 -56
  55. package/template/apps/api/src/routes/accounts.ts +0 -91
  56. package/template/apps/api/src/routes/admin-sessions.ts +0 -92
  57. package/template/apps/api/src/routes/metrics.ts +0 -71
  58. package/template/apps/api/src/routes/password.ts +0 -46
  59. package/template/apps/api/src/routes/sessions.ts +0 -53
  60. package/template/apps/api/src/routes/stats.ts +0 -38
  61. package/template/apps/api/src/routes/uploads-serve.ts +0 -27
  62. package/template/apps/api/src/routes/uploads.ts +0 -154
  63. package/template/apps/api/src/routes/users.ts +0 -114
  64. package/template/apps/api/src/routes/verification.ts +0 -90
  65. package/template/apps/api/src/server.ts +0 -34
  66. package/template/apps/api/src/services/accounts.service.ts +0 -125
  67. package/template/apps/api/src/services/authorization.service.ts +0 -162
  68. package/template/apps/api/src/services/email.service.ts +0 -170
  69. package/template/apps/api/src/services/file-storage.service.ts +0 -267
  70. package/template/apps/api/src/services/metrics.service.ts +0 -175
  71. package/template/apps/api/src/services/password.service.ts +0 -56
  72. package/template/apps/api/src/services/sessions.service.spec.ts +0 -134
  73. package/template/apps/api/src/services/sessions.service.ts +0 -276
  74. package/template/apps/api/src/services/stats.service.ts +0 -273
  75. package/template/apps/api/src/services/uploads.service.ts +0 -163
  76. package/template/apps/api/src/services/users.service.spec.ts +0 -249
  77. package/template/apps/api/src/services/users.service.ts +0 -198
  78. package/template/apps/api/src/utils/file-validation.ts +0 -108
  79. package/template/apps/api/start.sh +0 -33
  80. package/template/apps/api/test/helpers/fastify-app.ts +0 -24
  81. package/template/apps/api/test/helpers/mock-authorization.ts +0 -16
  82. package/template/apps/api/test/helpers/mock-logger.ts +0 -28
  83. package/template/apps/api/test/helpers/mock-prisma.ts +0 -30
  84. package/template/apps/api/test/helpers/test-db.ts +0 -125
  85. package/template/apps/api/test/integration/auth-flow.integration.spec.ts +0 -449
  86. package/template/apps/api/test/integration/password.integration.spec.ts +0 -427
  87. package/template/apps/api/test/integration/rate-limit.integration.spec.ts +0 -51
  88. package/template/apps/api/test/integration/sessions.integration.spec.ts +0 -445
  89. package/template/apps/api/test/integration/users.integration.spec.ts +0 -211
  90. package/template/apps/api/test/setup.ts +0 -31
  91. package/template/apps/api/tsconfig.json +0 -26
  92. package/template/apps/api/vitest.config.ts +0 -35
  93. package/template/apps/web/.env.local.example +0 -11
  94. package/template/apps/web/components.json +0 -24
  95. package/template/apps/web/next.config.ts +0 -22
  96. package/template/apps/web/package.json +0 -56
  97. package/template/apps/web/postcss.config.js +0 -5
  98. package/template/apps/web/public/apple-icon.png +0 -0
  99. package/template/apps/web/public/icon.png +0 -0
  100. package/template/apps/web/public/robots.txt +0 -3
  101. package/template/apps/web/src/app/(admin)/admin/layout.tsx +0 -222
  102. package/template/apps/web/src/app/(admin)/admin/page.tsx +0 -157
  103. package/template/apps/web/src/app/(admin)/admin/sessions/page.tsx +0 -18
  104. package/template/apps/web/src/app/(admin)/admin/users/page.tsx +0 -20
  105. package/template/apps/web/src/app/(auth)/forgot-password/page.tsx +0 -177
  106. package/template/apps/web/src/app/(auth)/login/page.tsx +0 -159
  107. package/template/apps/web/src/app/(auth)/reset-password/page.tsx +0 -245
  108. package/template/apps/web/src/app/(auth)/signup/page.tsx +0 -153
  109. package/template/apps/web/src/app/dashboard/change-password/page.tsx +0 -255
  110. package/template/apps/web/src/app/dashboard/page.tsx +0 -296
  111. package/template/apps/web/src/app/error.tsx +0 -32
  112. package/template/apps/web/src/app/examples/file-upload/page.tsx +0 -200
  113. package/template/apps/web/src/app/favicon.ico +0 -0
  114. package/template/apps/web/src/app/global-error.tsx +0 -96
  115. package/template/apps/web/src/app/globals.css +0 -22
  116. package/template/apps/web/src/app/icon.png +0 -0
  117. package/template/apps/web/src/app/layout.tsx +0 -34
  118. package/template/apps/web/src/app/not-found.tsx +0 -28
  119. package/template/apps/web/src/app/page.tsx +0 -192
  120. package/template/apps/web/src/components/admin/activity-feed.tsx +0 -101
  121. package/template/apps/web/src/components/admin/charts/auth-breakdown-chart.tsx +0 -114
  122. package/template/apps/web/src/components/admin/charts/chart-tooltip.tsx +0 -124
  123. package/template/apps/web/src/components/admin/charts/realtime-metrics-chart.tsx +0 -511
  124. package/template/apps/web/src/components/admin/charts/role-distribution-chart.tsx +0 -102
  125. package/template/apps/web/src/components/admin/charts/session-activity-chart.tsx +0 -90
  126. package/template/apps/web/src/components/admin/charts/user-growth-chart.tsx +0 -108
  127. package/template/apps/web/src/components/admin/health-indicator.tsx +0 -175
  128. package/template/apps/web/src/components/admin/refresh-control.tsx +0 -90
  129. package/template/apps/web/src/components/admin/session-revoke-all-dialog.tsx +0 -79
  130. package/template/apps/web/src/components/admin/session-revoke-dialog.tsx +0 -74
  131. package/template/apps/web/src/components/admin/sessions-management-table.tsx +0 -372
  132. package/template/apps/web/src/components/admin/stat-card.tsx +0 -137
  133. package/template/apps/web/src/components/admin/user-create-dialog.tsx +0 -152
  134. package/template/apps/web/src/components/admin/user-delete-dialog.tsx +0 -73
  135. package/template/apps/web/src/components/admin/user-edit-dialog.tsx +0 -170
  136. package/template/apps/web/src/components/admin/users-management-table.tsx +0 -285
  137. package/template/apps/web/src/components/auth/email-verification-banner.tsx +0 -85
  138. package/template/apps/web/src/components/auth/github-button.tsx +0 -40
  139. package/template/apps/web/src/components/auth/google-button.tsx +0 -54
  140. package/template/apps/web/src/components/auth/protected-route.tsx +0 -66
  141. package/template/apps/web/src/components/auth/redirect-if-authenticated.tsx +0 -31
  142. package/template/apps/web/src/components/auth/with-auth.tsx +0 -30
  143. package/template/apps/web/src/components/error/error-card.tsx +0 -47
  144. package/template/apps/web/src/components/error/forbidden.tsx +0 -25
  145. package/template/apps/web/src/components/landing/command-block.tsx +0 -64
  146. package/template/apps/web/src/components/landing/feature-card.tsx +0 -60
  147. package/template/apps/web/src/components/landing/included-feature-card.tsx +0 -63
  148. package/template/apps/web/src/components/landing/logo.tsx +0 -41
  149. package/template/apps/web/src/components/landing/tech-badge.tsx +0 -11
  150. package/template/apps/web/src/components/layout/auth-nav.tsx +0 -58
  151. package/template/apps/web/src/components/layout/footer.tsx +0 -3
  152. package/template/apps/web/src/config/landing-data.ts +0 -152
  153. package/template/apps/web/src/config/site.ts +0 -5
  154. package/template/apps/web/src/hooks/api/__tests__/use-users.test.tsx +0 -181
  155. package/template/apps/web/src/hooks/api/use-admin-sessions.ts +0 -75
  156. package/template/apps/web/src/hooks/api/use-admin-stats.ts +0 -33
  157. package/template/apps/web/src/hooks/api/use-sessions.ts +0 -52
  158. package/template/apps/web/src/hooks/api/use-uploads.ts +0 -156
  159. package/template/apps/web/src/hooks/api/use-users.ts +0 -149
  160. package/template/apps/web/src/hooks/use-mobile.ts +0 -21
  161. package/template/apps/web/src/hooks/use-realtime-metrics.ts +0 -120
  162. package/template/apps/web/src/lib/__tests__/utils.test.ts +0 -29
  163. package/template/apps/web/src/lib/api.ts +0 -151
  164. package/template/apps/web/src/lib/auth.ts +0 -13
  165. package/template/apps/web/src/lib/env.ts +0 -52
  166. package/template/apps/web/src/lib/form-utils.ts +0 -11
  167. package/template/apps/web/src/lib/utils.ts +0 -1
  168. package/template/apps/web/src/providers.tsx +0 -34
  169. package/template/apps/web/src/store/atoms.ts +0 -15
  170. package/template/apps/web/src/test/helpers/test-utils.tsx +0 -44
  171. package/template/apps/web/src/test/setup.ts +0 -8
  172. package/template/apps/web/tailwind.config.ts +0 -5
  173. package/template/apps/web/tsconfig.json +0 -26
  174. package/template/apps/web/vitest.config.ts +0 -32
  175. package/template/assets/logo-512.png +0 -0
  176. package/template/assets/logo.svg +0 -4
  177. package/template/docker-compose.prod.yml +0 -66
  178. package/template/docker-compose.yml +0 -36
  179. package/template/eslint.config.ts +0 -119
  180. package/template/package.json +0 -77
  181. package/template/packages/tailwind-config/package.json +0 -9
  182. package/template/packages/tailwind-config/theme.css +0 -179
  183. package/template/packages/types/package.json +0 -29
  184. package/template/packages/types/src/__tests__/schemas.test.ts +0 -255
  185. package/template/packages/types/src/api-response.ts +0 -53
  186. package/template/packages/types/src/health-check.ts +0 -11
  187. package/template/packages/types/src/pagination.ts +0 -41
  188. package/template/packages/types/src/role.ts +0 -5
  189. package/template/packages/types/src/session.ts +0 -48
  190. package/template/packages/types/src/stats.ts +0 -113
  191. package/template/packages/types/src/upload.ts +0 -51
  192. package/template/packages/types/src/user.ts +0 -36
  193. package/template/packages/types/tsconfig.json +0 -5
  194. package/template/packages/types/vitest.config.ts +0 -21
  195. package/template/packages/ui/components.json +0 -21
  196. package/template/packages/ui/package.json +0 -108
  197. package/template/packages/ui/src/__tests__/button.test.tsx +0 -70
  198. package/template/packages/ui/src/alert-dialog.tsx +0 -141
  199. package/template/packages/ui/src/alert.tsx +0 -66
  200. package/template/packages/ui/src/animated-theme-toggler.tsx +0 -167
  201. package/template/packages/ui/src/avatar.tsx +0 -53
  202. package/template/packages/ui/src/badge.tsx +0 -36
  203. package/template/packages/ui/src/button.tsx +0 -84
  204. package/template/packages/ui/src/card.tsx +0 -92
  205. package/template/packages/ui/src/checkbox.tsx +0 -32
  206. package/template/packages/ui/src/data-table/data-table-column-header.tsx +0 -68
  207. package/template/packages/ui/src/data-table/data-table-pagination.tsx +0 -99
  208. package/template/packages/ui/src/data-table/data-table-toolbar.tsx +0 -55
  209. package/template/packages/ui/src/data-table/data-table-view-options.tsx +0 -63
  210. package/template/packages/ui/src/data-table/data-table.tsx +0 -167
  211. package/template/packages/ui/src/dialog.tsx +0 -143
  212. package/template/packages/ui/src/dropdown-menu.tsx +0 -257
  213. package/template/packages/ui/src/empty-state.tsx +0 -52
  214. package/template/packages/ui/src/file-upload-input.tsx +0 -202
  215. package/template/packages/ui/src/form.tsx +0 -168
  216. package/template/packages/ui/src/hooks/use-mobile.ts +0 -19
  217. package/template/packages/ui/src/icons/brand-icons.tsx +0 -16
  218. package/template/packages/ui/src/input.tsx +0 -21
  219. package/template/packages/ui/src/label.tsx +0 -24
  220. package/template/packages/ui/src/lib/utils.ts +0 -6
  221. package/template/packages/ui/src/password-input.tsx +0 -102
  222. package/template/packages/ui/src/popover.tsx +0 -48
  223. package/template/packages/ui/src/radio-group.tsx +0 -45
  224. package/template/packages/ui/src/scroll-area.tsx +0 -58
  225. package/template/packages/ui/src/select.tsx +0 -187
  226. package/template/packages/ui/src/separator.tsx +0 -28
  227. package/template/packages/ui/src/sheet.tsx +0 -139
  228. package/template/packages/ui/src/sidebar.tsx +0 -726
  229. package/template/packages/ui/src/skeleton-variants.tsx +0 -87
  230. package/template/packages/ui/src/skeleton.tsx +0 -13
  231. package/template/packages/ui/src/slider.tsx +0 -63
  232. package/template/packages/ui/src/sonner.tsx +0 -25
  233. package/template/packages/ui/src/spinner.tsx +0 -16
  234. package/template/packages/ui/src/switch.tsx +0 -31
  235. package/template/packages/ui/src/table.tsx +0 -116
  236. package/template/packages/ui/src/tabs.tsx +0 -66
  237. package/template/packages/ui/src/textarea.tsx +0 -18
  238. package/template/packages/ui/src/tooltip.tsx +0 -61
  239. package/template/packages/ui/src/user-avatar.tsx +0 -97
  240. package/template/packages/ui/test-config.js +0 -3
  241. package/template/packages/ui/tsconfig.json +0 -12
  242. package/template/packages/ui/turbo.json +0 -18
  243. package/template/packages/ui/vitest.config.ts +0 -17
  244. package/template/packages/ui/vitest.setup.ts +0 -1
  245. package/template/packages/utils/package.json +0 -23
  246. package/template/packages/utils/src/__tests__/utils.test.ts +0 -223
  247. package/template/packages/utils/src/array.ts +0 -18
  248. package/template/packages/utils/src/async.ts +0 -3
  249. package/template/packages/utils/src/date.ts +0 -77
  250. package/template/packages/utils/src/errors.ts +0 -73
  251. package/template/packages/utils/src/number.ts +0 -11
  252. package/template/packages/utils/src/string.ts +0 -13
  253. package/template/packages/utils/tsconfig.json +0 -5
  254. package/template/packages/utils/vitest.config.ts +0 -21
  255. package/template/pnpm-workspace.yaml +0 -4
  256. package/template/tsconfig.base.json +0 -32
  257. package/template/turbo.json +0 -133
  258. package/template/vitest.shared.ts +0 -26
  259. package/template/vitest.workspace.ts +0 -9
@@ -1,152 +0,0 @@
1
- export const features = [
2
- {
3
- iconName: 'Rocket' as const,
4
- title: 'Production Ready',
5
- description:
6
- 'Helmet security, rate limiting, CORS, validated environment configs, and GitHub Actions CI/CD',
7
- },
8
- {
9
- iconName: 'Zap' as const,
10
- title: 'Fast Development',
11
- description:
12
- 'Turborepo for optimized builds and pnpm for efficient package management',
13
- },
14
- {
15
- iconName: 'Shield' as const,
16
- title: 'Type Safe',
17
- description:
18
- 'Zod schemas with TypeScript everywhere for runtime and compile-time safety',
19
- },
20
- {
21
- iconName: 'Code2' as const,
22
- title: 'Modern UI Components',
23
- description:
24
- 'shadcn/ui with Radix primitives, Tailwind v4, dark mode, and Framer Motion',
25
- },
26
- {
27
- iconName: 'Workflow' as const,
28
- title: 'Database Ready',
29
- description:
30
- 'Prisma ORM with PostgreSQL, migrations, better-auth and Docker setup',
31
- },
32
- {
33
- iconName: 'Lock' as const,
34
- title: 'Authentication',
35
- description:
36
- 'Better-auth with email/password, session management and OAuth support',
37
- },
38
- {
39
- iconName: 'TestTube' as const,
40
- title: 'Comprehensive Testing',
41
- description:
42
- 'Vitest for unit and integration tests with coverage reports across all packages',
43
- },
44
- {
45
- iconName: 'PackageOpen' as const,
46
- title: 'Shared Packages',
47
- description: 'Types and utilities shared across web and backend',
48
- },
49
- {
50
- iconName: 'Bot' as const,
51
- title: 'AI-Assisted Development',
52
- description:
53
- 'Comprehensive CLAUDE.md enables instant onboarding for AI coding assistants',
54
- },
55
- ] as const;
56
-
57
- export const techStack = {
58
- web: {
59
- title: 'Web',
60
- items: [
61
- 'Next.js 16',
62
- 'React 19',
63
- 'TypeScript',
64
- 'Tailwind CSS v4',
65
- 'shadcn/ui',
66
- 'TanStack Query',
67
- 'Zod',
68
- 'Jotai',
69
- 'React Hook Form',
70
- 'Framer Motion',
71
- 'Sonner',
72
- 'next-themes',
73
- ],
74
- },
75
- api: {
76
- title: 'API',
77
- items: [
78
- 'Fastify 5',
79
- 'TypeScript',
80
- 'Prisma 7',
81
- 'PostgreSQL',
82
- 'Better-auth',
83
- 'Zod',
84
- 'Scalar Docs',
85
- 'Helmet',
86
- 'Rate Limiting',
87
- 'CORS',
88
- ],
89
- },
90
- sharedPackages: {
91
- title: 'Shared Packages',
92
- items: ['Zod Schemas', 'Utility Functions', 'Type Definitions'],
93
- },
94
- devOps: {
95
- title: 'DevOps',
96
- items: [
97
- 'Turborepo',
98
- 'pnpm Workspaces',
99
- 'Vitest',
100
- 'GitHub Actions CI',
101
- 'ESLint',
102
- 'Prettier',
103
- 'Husky + lint-staged',
104
- ],
105
- },
106
- } as const;
107
-
108
- export const quickStartCommands: Array<{
109
- command: string;
110
- tooltip?: string;
111
- }> = [
112
- {
113
- command: 'pnpm install',
114
- },
115
- {
116
- command: 'pnpm init:project',
117
- tooltip:
118
- 'Automated setup: checks prerequisites, creates environment files, starts Docker containers, runs database migrations, and optionally seeds data',
119
- },
120
- {
121
- command: 'pnpm dev',
122
- },
123
- ];
124
-
125
- export const includedFeatures = [
126
- {
127
- iconName: 'Lock' as const,
128
- title: 'Authentication System',
129
- pages: [
130
- { name: 'Sign in', href: '/login' },
131
- { name: 'Sign up', href: '/signup' },
132
- { name: 'Forgot password', href: '/forgot-password' },
133
- ],
134
- },
135
- {
136
- iconName: 'LayoutDashboard' as const,
137
- title: 'User Dashboard',
138
- pages: [
139
- { name: 'Dashboard', href: '/dashboard' },
140
- { name: 'Change password', href: '/dashboard/change-password' },
141
- ],
142
- },
143
- {
144
- iconName: 'ShieldCheck' as const,
145
- title: 'Admin Dashboard',
146
- pages: [
147
- { name: 'System monitoring', href: '/admin' },
148
- { name: 'User management', href: '/admin/users' },
149
- { name: 'Sessions management', href: '/admin/sessions' },
150
- ],
151
- },
152
- ] as const;
@@ -1,5 +0,0 @@
1
- export const siteConfig = {
2
- name: 'Blitzpack',
3
- description: 'Production-ready TypeScript monorepo template',
4
- github: 'https://github.com/CarboxyDev/blitzpack',
5
- } as const;
@@ -1,181 +0,0 @@
1
- import type { PaginatedResponse } from '@repo/packages-types/pagination';
2
- import type { CreateUser, User } from '@repo/packages-types/user';
3
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
4
- import { renderHook, waitFor } from '@testing-library/react';
5
- import type { ReactNode } from 'react';
6
- import { beforeEach, describe, expect, it, vi } from 'vitest';
7
-
8
- import {
9
- useCreateUser,
10
- useFetchUser,
11
- useFetchUsers,
12
- userKeys,
13
- } from '@/hooks/api/use-users';
14
- import * as apiModule from '@/lib/api';
15
-
16
- vi.mock('@/lib/api', () => ({
17
- api: {
18
- get: vi.fn(),
19
- post: vi.fn(),
20
- },
21
- isApiError: vi.fn(),
22
- getErrorMessage: vi.fn(),
23
- ApiError: class ApiError extends Error {
24
- constructor(
25
- message: string,
26
- public status: number,
27
- public data?: unknown
28
- ) {
29
- super(message);
30
- this.name = 'ApiError';
31
- }
32
- },
33
- }));
34
-
35
- const createWrapper = () => {
36
- const queryClient = new QueryClient({
37
- defaultOptions: {
38
- queries: { retry: false },
39
- mutations: { retry: false },
40
- },
41
- });
42
-
43
- const Wrapper = ({ children }: { children: ReactNode }) => (
44
- <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
45
- );
46
- Wrapper.displayName = 'TestWrapper';
47
- return Wrapper;
48
- };
49
-
50
- describe('useUsers API Hooks', () => {
51
- beforeEach(() => {
52
- vi.clearAllMocks();
53
- });
54
-
55
- describe('useFetchUsers', () => {
56
- it('should fetch paginated users successfully', async () => {
57
- const mockResponse: PaginatedResponse<User> = {
58
- data: [
59
- {
60
- id: '123',
61
- email: 'test@example.com',
62
- name: 'Test User',
63
- createdAt: '2024-01-01T00:00:00Z',
64
- updatedAt: '2024-01-01T00:00:00Z',
65
- role: 'user',
66
- },
67
- ],
68
- pagination: {
69
- page: 1,
70
- limit: 10,
71
- total: 1,
72
- totalPages: 1,
73
- },
74
- };
75
-
76
- vi.spyOn(apiModule.api, 'get').mockResolvedValue(mockResponse);
77
-
78
- const { result } = renderHook(
79
- () =>
80
- useFetchUsers({
81
- page: 1,
82
- limit: 10,
83
- sortBy: 'createdAt',
84
- sortOrder: 'desc',
85
- }),
86
- { wrapper: createWrapper() }
87
- );
88
-
89
- await waitFor(() => expect(result.current.isSuccess).toBe(true));
90
-
91
- expect(result.current.data).toEqual(mockResponse);
92
- expect(apiModule.api.get).toHaveBeenCalledWith('/users', {
93
- params: { page: 1, limit: 10, sortBy: 'createdAt', sortOrder: 'desc' },
94
- });
95
- });
96
-
97
- it('should use correct query key for caching', () => {
98
- const params = {
99
- page: 1,
100
- limit: 10,
101
- sortBy: 'createdAt' as const,
102
- sortOrder: 'desc' as const,
103
- };
104
- const key = userKeys.list(params);
105
-
106
- expect(key).toEqual(['users', 'list', params]);
107
- });
108
- });
109
-
110
- describe('useFetchUser', () => {
111
- it('should fetch a single user by ID', async () => {
112
- const mockUser: User = {
113
- id: '123',
114
- email: 'test@example.com',
115
- name: 'Test User',
116
- createdAt: '2024-01-01T00:00:00Z',
117
- updatedAt: '2024-01-01T00:00:00Z',
118
- role: 'user',
119
- };
120
-
121
- vi.spyOn(apiModule.api, 'get').mockResolvedValue(mockUser);
122
-
123
- const { result } = renderHook(() => useFetchUser('123'), {
124
- wrapper: createWrapper(),
125
- });
126
-
127
- await waitFor(() => expect(result.current.isSuccess).toBe(true));
128
-
129
- expect(result.current.data).toEqual(mockUser);
130
- expect(apiModule.api.get).toHaveBeenCalledWith('/users/123');
131
- });
132
-
133
- it('should not fetch if ID is empty', () => {
134
- const { result } = renderHook(() => useFetchUser(''), {
135
- wrapper: createWrapper(),
136
- });
137
-
138
- expect(result.current.fetchStatus).toBe('idle');
139
- expect(apiModule.api.get).not.toHaveBeenCalled();
140
- });
141
- });
142
-
143
- describe('useCreateUser', () => {
144
- it('should create a new user', async () => {
145
- const newUser: CreateUser = {
146
- name: 'New User',
147
- email: 'new@example.com',
148
- role: 'user',
149
- };
150
-
151
- const mockResponse: User = {
152
- id: '456',
153
- ...newUser,
154
- createdAt: '2024-01-01T00:00:00Z',
155
- updatedAt: '2024-01-01T00:00:00Z',
156
- };
157
-
158
- vi.spyOn(apiModule.api, 'post').mockResolvedValue(mockResponse);
159
-
160
- const { result } = renderHook(() => useCreateUser(), {
161
- wrapper: createWrapper(),
162
- });
163
-
164
- result.current.mutate(newUser);
165
-
166
- await waitFor(() => expect(result.current.isSuccess).toBe(true));
167
-
168
- expect(result.current.data).toEqual(mockResponse);
169
- expect(apiModule.api.post).toHaveBeenCalledWith('/users', newUser);
170
- });
171
- });
172
-
173
- describe('userKeys', () => {
174
- it('should generate correct query keys', () => {
175
- expect(userKeys.all).toEqual(['users']);
176
- expect(userKeys.lists()).toEqual(['users', 'list']);
177
- expect(userKeys.details()).toEqual(['users', 'detail']);
178
- expect(userKeys.detail('123')).toEqual(['users', 'detail', '123']);
179
- });
180
- });
181
- });
@@ -1,75 +0,0 @@
1
- import type { PaginatedResponse } from '@repo/packages-types/pagination';
2
- import type {
3
- AdminSession,
4
- QuerySessions,
5
- SessionStats,
6
- } from '@repo/packages-types/session';
7
- import {
8
- useMutation,
9
- useQuery,
10
- useQueryClient,
11
- type UseQueryOptions,
12
- } from '@tanstack/react-query';
13
-
14
- import { api } from '@/lib/api';
15
-
16
- export const adminSessionKeys = {
17
- all: ['adminSessions'] as const,
18
- lists: () => [...adminSessionKeys.all, 'list'] as const,
19
- list: (params: QuerySessions) =>
20
- [...adminSessionKeys.lists(), params] as const,
21
- stats: () => [...adminSessionKeys.all, 'stats'] as const,
22
- };
23
-
24
- export function useFetchAdminSessions(
25
- params: QuerySessions,
26
- options?: Omit<
27
- UseQueryOptions<PaginatedResponse<AdminSession>>,
28
- 'queryKey' | 'queryFn'
29
- >
30
- ) {
31
- return useQuery({
32
- queryKey: adminSessionKeys.list(params),
33
- queryFn: () =>
34
- api.get<PaginatedResponse<AdminSession>>('/admin/sessions', {
35
- params: params as Record<string, string | number | boolean>,
36
- }),
37
- ...options,
38
- });
39
- }
40
-
41
- export function useFetchSessionStats(
42
- options?: Omit<UseQueryOptions<SessionStats>, 'queryKey' | 'queryFn'>
43
- ) {
44
- return useQuery({
45
- queryKey: adminSessionKeys.stats(),
46
- queryFn: () => api.get<SessionStats>('/admin/sessions/stats'),
47
- ...options,
48
- });
49
- }
50
-
51
- export function useRevokeSession() {
52
- const queryClient = useQueryClient();
53
-
54
- return useMutation({
55
- mutationFn: (sessionId: string) =>
56
- api.delete(`/admin/sessions/${sessionId}`),
57
- onSuccess: () => {
58
- queryClient.invalidateQueries({ queryKey: adminSessionKeys.lists() });
59
- queryClient.invalidateQueries({ queryKey: adminSessionKeys.stats() });
60
- },
61
- });
62
- }
63
-
64
- export function useRevokeUserSessions() {
65
- const queryClient = useQueryClient();
66
-
67
- return useMutation({
68
- mutationFn: (userId: string) =>
69
- api.delete(`/admin/sessions/user/${userId}`),
70
- onSuccess: () => {
71
- queryClient.invalidateQueries({ queryKey: adminSessionKeys.lists() });
72
- queryClient.invalidateQueries({ queryKey: adminSessionKeys.stats() });
73
- },
74
- });
75
- }
@@ -1,33 +0,0 @@
1
- import type {
2
- HealthCheckResponse,
3
- SystemStats,
4
- } from '@repo/packages-types/stats';
5
- import { useQuery, type UseQueryOptions } from '@tanstack/react-query';
6
-
7
- import { api } from '@/lib/api';
8
-
9
- export const adminStatsKeys = {
10
- all: ['adminStats'] as const,
11
- stats: () => [...adminStatsKeys.all, 'stats'] as const,
12
- health: () => [...adminStatsKeys.all, 'health'] as const,
13
- };
14
-
15
- export function useFetchSystemStats(
16
- options?: Omit<UseQueryOptions<SystemStats>, 'queryKey' | 'queryFn'>
17
- ) {
18
- return useQuery({
19
- queryKey: adminStatsKeys.stats(),
20
- queryFn: () => api.get<SystemStats>('/admin/stats'),
21
- ...options,
22
- });
23
- }
24
-
25
- export function useFetchHealthCheck(
26
- options?: Omit<UseQueryOptions<HealthCheckResponse>, 'queryKey' | 'queryFn'>
27
- ) {
28
- return useQuery({
29
- queryKey: adminStatsKeys.health(),
30
- queryFn: () => api.get<HealthCheckResponse>('/admin/stats/health'),
31
- ...options,
32
- });
33
- }
@@ -1,52 +0,0 @@
1
- import type {
2
- ListResponse,
3
- MessageResponse,
4
- } from '@repo/packages-types/api-response';
5
- import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
6
-
7
- import { fetcher } from '@/lib/api';
8
-
9
- export interface SessionInfo {
10
- id: string;
11
- ipAddress: string | null;
12
- userAgent: string | null;
13
- createdAt: string;
14
- updatedAt: string;
15
- expiresAt: string;
16
- isCurrent?: boolean;
17
- }
18
-
19
- export function useGetSessions() {
20
- return useQuery<ListResponse<SessionInfo>>({
21
- queryKey: ['sessions'],
22
- queryFn: () => fetcher<ListResponse<SessionInfo>>('/sessions'),
23
- });
24
- }
25
-
26
- export function useDeleteSession() {
27
- const queryClient = useQueryClient();
28
-
29
- return useMutation({
30
- mutationFn: (sessionId: string) =>
31
- fetcher<MessageResponse>(`/sessions/${sessionId}`, {
32
- method: 'DELETE',
33
- }),
34
- onSuccess: () => {
35
- queryClient.invalidateQueries({ queryKey: ['sessions'] });
36
- },
37
- });
38
- }
39
-
40
- export function useRevokeAllSessions() {
41
- const queryClient = useQueryClient();
42
-
43
- return useMutation({
44
- mutationFn: () =>
45
- fetcher<MessageResponse>('/sessions', {
46
- method: 'DELETE',
47
- }),
48
- onSuccess: () => {
49
- queryClient.invalidateQueries({ queryKey: ['sessions'] });
50
- },
51
- });
52
- }
@@ -1,156 +0,0 @@
1
- import type {
2
- DeleteUploadParams,
3
- GetUploadsQuery,
4
- Upload,
5
- UploadResponse,
6
- UploadStats,
7
- } from '@repo/packages-types/upload';
8
- import {
9
- useMutation,
10
- type UseMutationOptions,
11
- useQuery,
12
- useQueryClient,
13
- type UseQueryOptions,
14
- } from '@tanstack/react-query';
15
-
16
- import { api } from '@/lib/api';
17
-
18
- /**
19
- * Query Keys
20
- * Centralized query keys for cache management and invalidation
21
- */
22
- export const uploadKeys = {
23
- all: ['uploads'] as const,
24
- lists: () => [...uploadKeys.all, 'list'] as const,
25
- list: (params: GetUploadsQuery) => [...uploadKeys.lists(), params] as const,
26
- stats: () => [...uploadKeys.all, 'stats'] as const,
27
- };
28
-
29
- /**
30
- * Fetch user's uploads
31
- *
32
- * @example
33
- * ```tsx
34
- * const { data, isLoading } = useFetchUploads({ limit: 50, offset: 0 });
35
- * ```
36
- */
37
- export function useFetchUploads(
38
- params: GetUploadsQuery = { limit: 50, offset: 0 },
39
- options?: Omit<UseQueryOptions<Upload[]>, 'queryKey' | 'queryFn'>
40
- ) {
41
- return useQuery({
42
- queryKey: uploadKeys.list(params),
43
- queryFn: async () => {
44
- const searchParams = new globalThis.URLSearchParams({
45
- limit: String(params.limit),
46
- offset: String(params.offset),
47
- });
48
-
49
- return api.get<Upload[]>(`/uploads?${searchParams.toString()}`);
50
- },
51
- ...options,
52
- });
53
- }
54
-
55
- /**
56
- * Fetch upload statistics
57
- *
58
- * @example
59
- * ```tsx
60
- * const { data: stats } = useFetchUploadStats();
61
- * // stats: { totalFiles: 10, totalSize: 5242880 }
62
- * ```
63
- */
64
- export function useFetchUploadStats(
65
- options?: Omit<UseQueryOptions<UploadStats>, 'queryKey' | 'queryFn'>
66
- ) {
67
- return useQuery({
68
- queryKey: uploadKeys.stats(),
69
- queryFn: () => api.get<UploadStats>('/uploads/stats'),
70
- ...options,
71
- });
72
- }
73
-
74
- /**
75
- * Upload a file
76
- *
77
- * @example
78
- * ```tsx
79
- * const uploadMutation = useUploadFile();
80
- *
81
- * const handleUpload = (file: File) => {
82
- * uploadMutation.mutate(file, {
83
- * onSuccess: (data) => console.log('Uploaded:', data.url),
84
- * onError: (error) => console.error('Upload failed:', error)
85
- * });
86
- * };
87
- * ```
88
- */
89
- export function useUploadFile(
90
- options?: Omit<
91
- UseMutationOptions<UploadResponse, Error, globalThis.File>,
92
- 'mutationFn'
93
- >
94
- ) {
95
- const queryClient = useQueryClient();
96
-
97
- return useMutation({
98
- mutationFn: async (file: globalThis.File) => {
99
- const formData = new globalThis.FormData();
100
- formData.append('file', file);
101
-
102
- const response = await fetch(
103
- `${process.env.NEXT_PUBLIC_API_URL}/uploads`,
104
- {
105
- method: 'POST',
106
- body: formData,
107
- credentials: 'include',
108
- }
109
- );
110
-
111
- if (!response.ok) {
112
- const error = await response.json();
113
- throw new Error(error.error?.message || 'Upload failed');
114
- }
115
-
116
- return response.json();
117
- },
118
- onSuccess: () => {
119
- queryClient.invalidateQueries({ queryKey: uploadKeys.lists() });
120
- queryClient.invalidateQueries({ queryKey: uploadKeys.stats() });
121
- },
122
- ...options,
123
- });
124
- }
125
-
126
- /**
127
- * Delete an upload
128
- *
129
- * @example
130
- * ```tsx
131
- * const deleteMutation = useDeleteUpload();
132
- *
133
- * const handleDelete = (uploadId: string) => {
134
- * deleteMutation.mutate({ id: uploadId });
135
- * };
136
- * ```
137
- */
138
- export function useDeleteUpload(
139
- options?: Omit<
140
- UseMutationOptions<void, Error, DeleteUploadParams>,
141
- 'mutationFn'
142
- >
143
- ) {
144
- const queryClient = useQueryClient();
145
-
146
- return useMutation({
147
- mutationFn: async ({ id }: DeleteUploadParams) => {
148
- await api.delete(`/uploads/${id}`);
149
- },
150
- onSuccess: () => {
151
- queryClient.invalidateQueries({ queryKey: uploadKeys.lists() });
152
- queryClient.invalidateQueries({ queryKey: uploadKeys.stats() });
153
- },
154
- ...options,
155
- });
156
- }