servcraft 0.1.0 → 0.1.3

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 (217) hide show
  1. package/.claude/settings.local.json +30 -0
  2. package/.github/CODEOWNERS +18 -0
  3. package/.github/PULL_REQUEST_TEMPLATE.md +46 -0
  4. package/.github/dependabot.yml +59 -0
  5. package/.github/workflows/ci.yml +188 -0
  6. package/.github/workflows/release.yml +195 -0
  7. package/AUDIT.md +602 -0
  8. package/LICENSE +21 -0
  9. package/README.md +1102 -1
  10. package/dist/cli/index.cjs +2026 -2168
  11. package/dist/cli/index.cjs.map +1 -1
  12. package/dist/cli/index.js +2026 -2168
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/index.cjs +595 -616
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +114 -52
  17. package/dist/index.d.ts +114 -52
  18. package/dist/index.js +595 -616
  19. package/dist/index.js.map +1 -1
  20. package/docs/CLI-001_MULTI_DB_PLAN.md +546 -0
  21. package/docs/DATABASE_MULTI_ORM.md +399 -0
  22. package/docs/PHASE1_BREAKDOWN.md +346 -0
  23. package/docs/PROGRESS.md +550 -0
  24. package/docs/modules/ANALYTICS.md +226 -0
  25. package/docs/modules/API-VERSIONING.md +252 -0
  26. package/docs/modules/AUDIT.md +192 -0
  27. package/docs/modules/AUTH.md +431 -0
  28. package/docs/modules/CACHE.md +346 -0
  29. package/docs/modules/EMAIL.md +254 -0
  30. package/docs/modules/FEATURE-FLAG.md +291 -0
  31. package/docs/modules/I18N.md +294 -0
  32. package/docs/modules/MEDIA-PROCESSING.md +281 -0
  33. package/docs/modules/MFA.md +266 -0
  34. package/docs/modules/NOTIFICATION.md +311 -0
  35. package/docs/modules/OAUTH.md +237 -0
  36. package/docs/modules/PAYMENT.md +804 -0
  37. package/docs/modules/QUEUE.md +540 -0
  38. package/docs/modules/RATE-LIMIT.md +339 -0
  39. package/docs/modules/SEARCH.md +288 -0
  40. package/docs/modules/SECURITY.md +327 -0
  41. package/docs/modules/SESSION.md +382 -0
  42. package/docs/modules/SWAGGER.md +305 -0
  43. package/docs/modules/UPLOAD.md +296 -0
  44. package/docs/modules/USER.md +505 -0
  45. package/docs/modules/VALIDATION.md +294 -0
  46. package/docs/modules/WEBHOOK.md +270 -0
  47. package/docs/modules/WEBSOCKET.md +691 -0
  48. package/package.json +53 -38
  49. package/prisma/schema.prisma +395 -1
  50. package/src/cli/commands/add-module.ts +520 -87
  51. package/src/cli/commands/db.ts +3 -4
  52. package/src/cli/commands/docs.ts +256 -6
  53. package/src/cli/commands/generate.ts +12 -19
  54. package/src/cli/commands/init.ts +384 -214
  55. package/src/cli/index.ts +0 -4
  56. package/src/cli/templates/repository.ts +6 -1
  57. package/src/cli/templates/routes.ts +6 -21
  58. package/src/cli/utils/docs-generator.ts +6 -7
  59. package/src/cli/utils/env-manager.ts +717 -0
  60. package/src/cli/utils/field-parser.ts +16 -7
  61. package/src/cli/utils/interactive-prompt.ts +223 -0
  62. package/src/cli/utils/template-manager.ts +346 -0
  63. package/src/config/database.config.ts +183 -0
  64. package/src/config/env.ts +0 -10
  65. package/src/config/index.ts +0 -14
  66. package/src/core/server.ts +1 -1
  67. package/src/database/adapters/mongoose.adapter.ts +132 -0
  68. package/src/database/adapters/prisma.adapter.ts +118 -0
  69. package/src/database/connection.ts +190 -0
  70. package/src/database/interfaces/database.interface.ts +85 -0
  71. package/src/database/interfaces/index.ts +7 -0
  72. package/src/database/interfaces/repository.interface.ts +129 -0
  73. package/src/database/models/mongoose/index.ts +7 -0
  74. package/src/database/models/mongoose/payment.schema.ts +347 -0
  75. package/src/database/models/mongoose/user.schema.ts +154 -0
  76. package/src/database/prisma.ts +1 -4
  77. package/src/database/redis.ts +101 -0
  78. package/src/database/repositories/mongoose/index.ts +7 -0
  79. package/src/database/repositories/mongoose/payment.repository.ts +380 -0
  80. package/src/database/repositories/mongoose/user.repository.ts +255 -0
  81. package/src/database/seed.ts +6 -1
  82. package/src/index.ts +9 -20
  83. package/src/middleware/security.ts +2 -6
  84. package/src/modules/analytics/analytics.routes.ts +80 -0
  85. package/src/modules/analytics/analytics.service.ts +364 -0
  86. package/src/modules/analytics/index.ts +18 -0
  87. package/src/modules/analytics/types.ts +180 -0
  88. package/src/modules/api-versioning/index.ts +15 -0
  89. package/src/modules/api-versioning/types.ts +86 -0
  90. package/src/modules/api-versioning/versioning.middleware.ts +120 -0
  91. package/src/modules/api-versioning/versioning.routes.ts +54 -0
  92. package/src/modules/api-versioning/versioning.service.ts +189 -0
  93. package/src/modules/audit/audit.repository.ts +206 -0
  94. package/src/modules/audit/audit.service.ts +27 -59
  95. package/src/modules/auth/auth.controller.ts +2 -2
  96. package/src/modules/auth/auth.middleware.ts +3 -9
  97. package/src/modules/auth/auth.routes.ts +10 -107
  98. package/src/modules/auth/auth.service.ts +126 -23
  99. package/src/modules/auth/index.ts +3 -4
  100. package/src/modules/cache/cache.service.ts +367 -0
  101. package/src/modules/cache/index.ts +10 -0
  102. package/src/modules/cache/types.ts +44 -0
  103. package/src/modules/email/email.service.ts +3 -10
  104. package/src/modules/email/templates.ts +2 -8
  105. package/src/modules/feature-flag/feature-flag.repository.ts +303 -0
  106. package/src/modules/feature-flag/feature-flag.routes.ts +247 -0
  107. package/src/modules/feature-flag/feature-flag.service.ts +566 -0
  108. package/src/modules/feature-flag/index.ts +20 -0
  109. package/src/modules/feature-flag/types.ts +192 -0
  110. package/src/modules/i18n/i18n.middleware.ts +186 -0
  111. package/src/modules/i18n/i18n.routes.ts +191 -0
  112. package/src/modules/i18n/i18n.service.ts +456 -0
  113. package/src/modules/i18n/index.ts +18 -0
  114. package/src/modules/i18n/types.ts +118 -0
  115. package/src/modules/media-processing/index.ts +17 -0
  116. package/src/modules/media-processing/media-processing.routes.ts +111 -0
  117. package/src/modules/media-processing/media-processing.service.ts +245 -0
  118. package/src/modules/media-processing/types.ts +156 -0
  119. package/src/modules/mfa/index.ts +20 -0
  120. package/src/modules/mfa/mfa.repository.ts +206 -0
  121. package/src/modules/mfa/mfa.routes.ts +595 -0
  122. package/src/modules/mfa/mfa.service.ts +572 -0
  123. package/src/modules/mfa/totp.ts +150 -0
  124. package/src/modules/mfa/types.ts +57 -0
  125. package/src/modules/notification/index.ts +20 -0
  126. package/src/modules/notification/notification.repository.ts +356 -0
  127. package/src/modules/notification/notification.service.ts +483 -0
  128. package/src/modules/notification/types.ts +119 -0
  129. package/src/modules/oauth/index.ts +20 -0
  130. package/src/modules/oauth/oauth.repository.ts +219 -0
  131. package/src/modules/oauth/oauth.routes.ts +446 -0
  132. package/src/modules/oauth/oauth.service.ts +293 -0
  133. package/src/modules/oauth/providers/apple.provider.ts +250 -0
  134. package/src/modules/oauth/providers/facebook.provider.ts +181 -0
  135. package/src/modules/oauth/providers/github.provider.ts +248 -0
  136. package/src/modules/oauth/providers/google.provider.ts +189 -0
  137. package/src/modules/oauth/providers/twitter.provider.ts +214 -0
  138. package/src/modules/oauth/types.ts +94 -0
  139. package/src/modules/payment/index.ts +19 -0
  140. package/src/modules/payment/payment.repository.ts +733 -0
  141. package/src/modules/payment/payment.routes.ts +390 -0
  142. package/src/modules/payment/payment.service.ts +354 -0
  143. package/src/modules/payment/providers/mobile-money.provider.ts +274 -0
  144. package/src/modules/payment/providers/paypal.provider.ts +190 -0
  145. package/src/modules/payment/providers/stripe.provider.ts +215 -0
  146. package/src/modules/payment/types.ts +140 -0
  147. package/src/modules/queue/cron.ts +438 -0
  148. package/src/modules/queue/index.ts +87 -0
  149. package/src/modules/queue/queue.routes.ts +600 -0
  150. package/src/modules/queue/queue.service.ts +842 -0
  151. package/src/modules/queue/types.ts +222 -0
  152. package/src/modules/queue/workers.ts +366 -0
  153. package/src/modules/rate-limit/index.ts +59 -0
  154. package/src/modules/rate-limit/rate-limit.middleware.ts +134 -0
  155. package/src/modules/rate-limit/rate-limit.routes.ts +269 -0
  156. package/src/modules/rate-limit/rate-limit.service.ts +348 -0
  157. package/src/modules/rate-limit/stores/memory.store.ts +165 -0
  158. package/src/modules/rate-limit/stores/redis.store.ts +322 -0
  159. package/src/modules/rate-limit/types.ts +153 -0
  160. package/src/modules/search/adapters/elasticsearch.adapter.ts +326 -0
  161. package/src/modules/search/adapters/meilisearch.adapter.ts +261 -0
  162. package/src/modules/search/adapters/memory.adapter.ts +278 -0
  163. package/src/modules/search/index.ts +21 -0
  164. package/src/modules/search/search.service.ts +234 -0
  165. package/src/modules/search/types.ts +214 -0
  166. package/src/modules/security/index.ts +40 -0
  167. package/src/modules/security/sanitize.ts +223 -0
  168. package/src/modules/security/security-audit.service.ts +388 -0
  169. package/src/modules/security/security.middleware.ts +398 -0
  170. package/src/modules/session/index.ts +3 -0
  171. package/src/modules/session/session.repository.ts +159 -0
  172. package/src/modules/session/session.service.ts +340 -0
  173. package/src/modules/session/types.ts +38 -0
  174. package/src/modules/swagger/index.ts +7 -1
  175. package/src/modules/swagger/schema-builder.ts +16 -4
  176. package/src/modules/swagger/swagger.service.ts +9 -10
  177. package/src/modules/swagger/types.ts +0 -2
  178. package/src/modules/upload/index.ts +14 -0
  179. package/src/modules/upload/types.ts +83 -0
  180. package/src/modules/upload/upload.repository.ts +199 -0
  181. package/src/modules/upload/upload.routes.ts +311 -0
  182. package/src/modules/upload/upload.service.ts +448 -0
  183. package/src/modules/user/index.ts +3 -3
  184. package/src/modules/user/user.controller.ts +15 -9
  185. package/src/modules/user/user.repository.ts +237 -113
  186. package/src/modules/user/user.routes.ts +39 -164
  187. package/src/modules/user/user.service.ts +4 -3
  188. package/src/modules/validation/validator.ts +12 -17
  189. package/src/modules/webhook/index.ts +91 -0
  190. package/src/modules/webhook/retry.ts +196 -0
  191. package/src/modules/webhook/signature.ts +135 -0
  192. package/src/modules/webhook/types.ts +181 -0
  193. package/src/modules/webhook/webhook.repository.ts +358 -0
  194. package/src/modules/webhook/webhook.routes.ts +442 -0
  195. package/src/modules/webhook/webhook.service.ts +457 -0
  196. package/src/modules/websocket/features.ts +504 -0
  197. package/src/modules/websocket/index.ts +106 -0
  198. package/src/modules/websocket/middlewares.ts +298 -0
  199. package/src/modules/websocket/types.ts +181 -0
  200. package/src/modules/websocket/websocket.service.ts +692 -0
  201. package/src/utils/errors.ts +7 -0
  202. package/src/utils/pagination.ts +4 -1
  203. package/tests/helpers/db-check.ts +79 -0
  204. package/tests/integration/auth-redis.test.ts +94 -0
  205. package/tests/integration/cache-redis.test.ts +387 -0
  206. package/tests/integration/mongoose-repositories.test.ts +410 -0
  207. package/tests/integration/payment-prisma.test.ts +637 -0
  208. package/tests/integration/queue-bullmq.test.ts +417 -0
  209. package/tests/integration/user-prisma.test.ts +441 -0
  210. package/tests/integration/websocket-socketio.test.ts +552 -0
  211. package/tests/setup.ts +11 -9
  212. package/vitest.config.ts +3 -8
  213. package/npm-cache/_cacache/content-v2/sha512/1c/d0/03440d500a0487621aad1d6402978340698976602046db8e24fa03c01ee6c022c69b0582f969042d9442ee876ac35c038e960dd427d1e622fa24b8eb7dba +0 -0
  214. package/npm-cache/_cacache/content-v2/sha512/42/55/28b493ca491833e5aab0e9c3108d29ab3f36c248ca88f45d4630674fce9130959e56ae308797ac2b6328fa7f09a610b9550ed09cb971d039876d293fc69d +0 -0
  215. package/npm-cache/_cacache/content-v2/sha512/e0/12/f360dc9315ee5f17844a0c8c233ee6bf7c30837c4a02ea0d56c61c7f7ab21c0e958e50ed2c57c59f983c762b93056778c9009b2398ffc26def0183999b13 +0 -0
  216. package/npm-cache/_cacache/content-v2/sha512/ed/b0/fae1161902898f4c913c67d7f6cdf6be0665aec3b389b9c4f4f0a101ca1da59badf1b59c4e0030f5223023b8d63cfe501c46a32c20c895d4fb3f11ca2232 +0 -0
  217. package/npm-cache/_cacache/index-v5/58/94/c2cba79e0f16b4c10e95a87e32255741149e8222cc314a476aab67c39cc0 +0 -5
@@ -0,0 +1,305 @@
1
+ # Swagger Module
2
+
3
+ OpenAPI 3.0 documentation with Swagger UI integration.
4
+
5
+ ## Features
6
+
7
+ - **OpenAPI 3.0** - Full OpenAPI specification support
8
+ - **Swagger UI** - Interactive API documentation at `/docs`
9
+ - **JWT Auth** - Bearer token authentication support
10
+ - **Common Schemas** - Pre-built response schemas
11
+ - **Zod Integration** - Convert Zod schemas to JSON Schema
12
+
13
+ ## Usage
14
+
15
+ ### Basic Setup
16
+
17
+ ```typescript
18
+ import Fastify from 'fastify';
19
+ import { registerSwagger } from 'servcraft/modules/swagger';
20
+
21
+ const app = Fastify();
22
+
23
+ await registerSwagger(app, {
24
+ title: 'My API',
25
+ description: 'API documentation',
26
+ version: '1.0.0',
27
+ tags: [
28
+ { name: 'Auth', description: 'Authentication endpoints' },
29
+ { name: 'Users', description: 'User management' },
30
+ { name: 'Products', description: 'Product catalog' },
31
+ ],
32
+ servers: [
33
+ { url: 'http://localhost:3000', description: 'Development' },
34
+ { url: 'https://api.example.com', description: 'Production' },
35
+ ],
36
+ contact: {
37
+ name: 'API Support',
38
+ email: 'support@example.com',
39
+ },
40
+ license: {
41
+ name: 'MIT',
42
+ url: 'https://opensource.org/licenses/MIT',
43
+ },
44
+ });
45
+
46
+ // Documentation available at http://localhost:3000/docs
47
+ ```
48
+
49
+ ### Route Documentation
50
+
51
+ ```typescript
52
+ fastify.post('/api/users', {
53
+ schema: {
54
+ description: 'Create a new user',
55
+ tags: ['Users'],
56
+ summary: 'Create user',
57
+ body: {
58
+ type: 'object',
59
+ required: ['email', 'password', 'name'],
60
+ properties: {
61
+ email: { type: 'string', format: 'email' },
62
+ password: { type: 'string', minLength: 8 },
63
+ name: { type: 'string' },
64
+ },
65
+ },
66
+ response: {
67
+ 201: {
68
+ description: 'User created successfully',
69
+ type: 'object',
70
+ properties: {
71
+ success: { type: 'boolean' },
72
+ data: {
73
+ type: 'object',
74
+ properties: {
75
+ id: { type: 'string', format: 'uuid' },
76
+ email: { type: 'string' },
77
+ name: { type: 'string' },
78
+ },
79
+ },
80
+ },
81
+ },
82
+ 400: commonResponses.error,
83
+ },
84
+ security: [{ bearerAuth: [] }],
85
+ },
86
+ }, async (request, reply) => {
87
+ // Handler
88
+ });
89
+ ```
90
+
91
+ ### Common Response Schemas
92
+
93
+ ```typescript
94
+ import { commonResponses, paginationQuery, idParam } from 'servcraft/modules/swagger';
95
+
96
+ // Success response
97
+ commonResponses.success
98
+ // { success: boolean, data: object }
99
+
100
+ // Error response
101
+ commonResponses.error
102
+ // { success: boolean, message: string, errors: object }
103
+
104
+ // Unauthorized
105
+ commonResponses.unauthorized
106
+ // { success: boolean, message: 'Unauthorized' }
107
+
108
+ // Not found
109
+ commonResponses.notFound
110
+ // { success: boolean, message: 'Resource not found' }
111
+
112
+ // Paginated response
113
+ commonResponses.paginated
114
+ // { success: boolean, data: { data: [], meta: { total, page, ... } } }
115
+ ```
116
+
117
+ ### Query Parameters
118
+
119
+ ```typescript
120
+ // Pagination query parameters
121
+ fastify.get('/api/users', {
122
+ schema: {
123
+ querystring: paginationQuery,
124
+ // Adds: page, limit, sortBy, sortOrder, search
125
+ },
126
+ });
127
+
128
+ // ID parameter
129
+ fastify.get('/api/users/:id', {
130
+ schema: {
131
+ params: idParam,
132
+ // Adds: id (uuid)
133
+ },
134
+ });
135
+ ```
136
+
137
+ ### Authentication
138
+
139
+ ```typescript
140
+ // Protected route
141
+ fastify.get('/api/profile', {
142
+ schema: {
143
+ tags: ['Users'],
144
+ security: [{ bearerAuth: [] }],
145
+ response: {
146
+ 200: userSchema,
147
+ 401: commonResponses.unauthorized,
148
+ },
149
+ },
150
+ });
151
+
152
+ // Public route (no security)
153
+ fastify.get('/api/public', {
154
+ schema: {
155
+ tags: ['Public'],
156
+ // No security property = public endpoint
157
+ },
158
+ });
159
+ ```
160
+
161
+ ## Configuration
162
+
163
+ ```typescript
164
+ interface SwaggerConfig {
165
+ title: string;
166
+ description?: string;
167
+ version: string;
168
+ tags?: Array<{
169
+ name: string;
170
+ description?: string;
171
+ }>;
172
+ servers?: Array<{
173
+ url: string;
174
+ description?: string;
175
+ }>;
176
+ contact?: {
177
+ name?: string;
178
+ email?: string;
179
+ url?: string;
180
+ };
181
+ license?: {
182
+ name: string;
183
+ url?: string;
184
+ };
185
+ }
186
+ ```
187
+
188
+ ## Schema Examples
189
+
190
+ ### User Schema
191
+
192
+ ```typescript
193
+ const userSchema = {
194
+ type: 'object',
195
+ properties: {
196
+ id: { type: 'string', format: 'uuid' },
197
+ email: { type: 'string', format: 'email' },
198
+ name: { type: 'string' },
199
+ role: { type: 'string', enum: ['user', 'admin'] },
200
+ createdAt: { type: 'string', format: 'date-time' },
201
+ },
202
+ };
203
+ ```
204
+
205
+ ### Request Body
206
+
207
+ ```typescript
208
+ const createUserBody = {
209
+ type: 'object',
210
+ required: ['email', 'password'],
211
+ properties: {
212
+ email: {
213
+ type: 'string',
214
+ format: 'email',
215
+ description: 'User email address',
216
+ },
217
+ password: {
218
+ type: 'string',
219
+ minLength: 8,
220
+ description: 'Password (min 8 characters)',
221
+ },
222
+ name: {
223
+ type: 'string',
224
+ maxLength: 100,
225
+ description: 'Display name',
226
+ },
227
+ },
228
+ };
229
+ ```
230
+
231
+ ### Array Response
232
+
233
+ ```typescript
234
+ const usersListResponse = {
235
+ type: 'object',
236
+ properties: {
237
+ success: { type: 'boolean' },
238
+ data: {
239
+ type: 'array',
240
+ items: userSchema,
241
+ },
242
+ meta: {
243
+ type: 'object',
244
+ properties: {
245
+ total: { type: 'integer' },
246
+ page: { type: 'integer' },
247
+ limit: { type: 'integer' },
248
+ totalPages: { type: 'integer' },
249
+ },
250
+ },
251
+ },
252
+ };
253
+ ```
254
+
255
+ ## Complete Route Example
256
+
257
+ ```typescript
258
+ fastify.route({
259
+ method: 'GET',
260
+ url: '/api/products',
261
+ schema: {
262
+ description: 'Get all products with pagination and filtering',
263
+ tags: ['Products'],
264
+ summary: 'List products',
265
+ querystring: {
266
+ type: 'object',
267
+ properties: {
268
+ page: { type: 'integer', default: 1 },
269
+ limit: { type: 'integer', default: 20 },
270
+ category: { type: 'string', description: 'Filter by category' },
271
+ minPrice: { type: 'number', description: 'Minimum price' },
272
+ maxPrice: { type: 'number', description: 'Maximum price' },
273
+ search: { type: 'string', description: 'Search term' },
274
+ },
275
+ },
276
+ response: {
277
+ 200: {
278
+ description: 'List of products',
279
+ ...commonResponses.paginated,
280
+ },
281
+ },
282
+ },
283
+ handler: async (request, reply) => {
284
+ // Implementation
285
+ },
286
+ });
287
+ ```
288
+
289
+ ## Swagger UI Features
290
+
291
+ The documentation UI at `/docs` includes:
292
+ - **Try It Out** - Execute API calls directly
293
+ - **Filter** - Search endpoints
294
+ - **Expand/Collapse** - Organize by tags
295
+ - **Request Duration** - Show response times
296
+ - **Authorization** - Set bearer token
297
+
298
+ ## Best Practices
299
+
300
+ 1. **Consistent Tags** - Group related endpoints
301
+ 2. **Detailed Descriptions** - Document parameters and responses
302
+ 3. **Examples** - Provide example values
303
+ 4. **Error Responses** - Document all error cases
304
+ 5. **Security** - Mark authenticated endpoints
305
+ 6. **Versioning** - Include version in title
@@ -0,0 +1,296 @@
1
+ # Upload Module
2
+
3
+ File upload service with multiple storage providers and image transformation support.
4
+
5
+ ## Features
6
+
7
+ - **Multiple Providers** - Local, AWS S3, Google Cloud Storage, Cloudinary
8
+ - **File Validation** - MIME type and size validation
9
+ - **Image Transformation** - Resize, crop, format conversion
10
+ - **Signed URLs** - Secure temporary URLs for private files
11
+ - **User Storage Tracking** - Track storage usage per user
12
+
13
+ ## Supported Providers
14
+
15
+ | Provider | Use Case |
16
+ |----------|----------|
17
+ | Local | Development, simple deployments |
18
+ | AWS S3 | Production, scalable storage |
19
+ | Google Cloud Storage | GCP infrastructure |
20
+ | Cloudinary | Image optimization, transformations |
21
+
22
+ ## Usage
23
+
24
+ ### Configuration
25
+
26
+ ```typescript
27
+ import { createUploadService } from 'servcraft/modules/upload';
28
+
29
+ // Local storage
30
+ const uploadService = createUploadService({
31
+ provider: 'local',
32
+ maxFileSize: 10 * 1024 * 1024, // 10MB
33
+ allowedMimeTypes: ['image/jpeg', 'image/png', 'application/pdf'],
34
+ local: {
35
+ uploadDir: './uploads',
36
+ publicPath: '/uploads',
37
+ },
38
+ });
39
+
40
+ // AWS S3
41
+ const s3Service = createUploadService({
42
+ provider: 's3',
43
+ maxFileSize: 50 * 1024 * 1024,
44
+ s3: {
45
+ bucket: 'my-bucket',
46
+ region: 'us-east-1',
47
+ accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
48
+ secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
49
+ },
50
+ });
51
+
52
+ // Cloudinary
53
+ const cloudinaryService = createUploadService({
54
+ provider: 'cloudinary',
55
+ cloudinary: {
56
+ cloudName: process.env.CLOUDINARY_CLOUD_NAME!,
57
+ apiKey: process.env.CLOUDINARY_API_KEY!,
58
+ apiSecret: process.env.CLOUDINARY_API_SECRET!,
59
+ folder: 'uploads',
60
+ },
61
+ });
62
+ ```
63
+
64
+ ### Single File Upload
65
+
66
+ ```typescript
67
+ // Fastify route example
68
+ fastify.post('/upload', async (request, reply) => {
69
+ const file = await request.file();
70
+
71
+ const uploaded = await uploadService.upload(file, {
72
+ folder: 'avatars',
73
+ filename: `user-${userId}-avatar`,
74
+ isPublic: true,
75
+ });
76
+
77
+ return { url: uploaded.url, id: uploaded.id };
78
+ });
79
+ ```
80
+
81
+ ### Multiple Files Upload
82
+
83
+ ```typescript
84
+ fastify.post('/upload-multiple', async (request, reply) => {
85
+ const files = await request.files();
86
+ const fileArray = [];
87
+
88
+ for await (const file of files) {
89
+ fileArray.push(file);
90
+ }
91
+
92
+ const uploaded = await uploadService.uploadMultiple(fileArray, {
93
+ folder: 'documents',
94
+ });
95
+
96
+ return uploaded.map(f => ({ id: f.id, url: f.url }));
97
+ });
98
+ ```
99
+
100
+ ### Image Transformation
101
+
102
+ ```typescript
103
+ const uploaded = await uploadService.upload(file, {
104
+ transform: {
105
+ width: 300,
106
+ height: 300,
107
+ fit: 'cover',
108
+ format: 'webp',
109
+ quality: 80,
110
+ },
111
+ });
112
+ ```
113
+
114
+ ### File Management
115
+
116
+ ```typescript
117
+ // Get file by ID
118
+ const file = await uploadService.getFile(fileId);
119
+
120
+ // Delete file
121
+ await uploadService.deleteFile(fileId);
122
+
123
+ // Get signed URL (for private files)
124
+ const signedUrl = await uploadService.getSignedUrl(fileId, 3600); // 1 hour
125
+ ```
126
+
127
+ ### User Storage Management
128
+
129
+ ```typescript
130
+ // Get user's files
131
+ const files = await uploadService.getFilesByUser(userId, {
132
+ limit: 20,
133
+ offset: 0,
134
+ });
135
+
136
+ // Get storage usage
137
+ const usage = await uploadService.getUserStorageUsage(userId);
138
+ // { totalSize: 15728640, fileCount: 12 }
139
+
140
+ // Delete all user files
141
+ await uploadService.deleteUserFiles(userId);
142
+ ```
143
+
144
+ ## Configuration Types
145
+
146
+ ```typescript
147
+ interface UploadConfig {
148
+ provider: 'local' | 's3' | 'cloudinary' | 'gcs';
149
+ maxFileSize: number; // in bytes
150
+ allowedMimeTypes: string[];
151
+
152
+ local?: {
153
+ uploadDir: string;
154
+ publicPath: string;
155
+ };
156
+
157
+ s3?: {
158
+ bucket: string;
159
+ region: string;
160
+ accessKeyId: string;
161
+ secretAccessKey: string;
162
+ };
163
+
164
+ cloudinary?: {
165
+ cloudName: string;
166
+ apiKey: string;
167
+ apiSecret: string;
168
+ folder?: string;
169
+ };
170
+
171
+ gcs?: {
172
+ projectId: string;
173
+ bucket: string;
174
+ keyFilename?: string;
175
+ };
176
+ }
177
+
178
+ interface UploadOptions {
179
+ folder?: string;
180
+ filename?: string;
181
+ isPublic?: boolean;
182
+ transform?: ImageTransformOptions;
183
+ }
184
+
185
+ interface ImageTransformOptions {
186
+ width?: number;
187
+ height?: number;
188
+ fit?: 'cover' | 'contain' | 'fill' | 'inside' | 'outside';
189
+ format?: 'jpeg' | 'png' | 'webp' | 'avif';
190
+ quality?: number;
191
+ grayscale?: boolean;
192
+ blur?: number;
193
+ }
194
+ ```
195
+
196
+ ## Response Types
197
+
198
+ ```typescript
199
+ interface UploadedFile {
200
+ id: string;
201
+ originalName: string;
202
+ filename: string;
203
+ mimetype: string;
204
+ size: number;
205
+ path: string;
206
+ url: string;
207
+ provider: string;
208
+ bucket?: string;
209
+ userId?: string;
210
+ createdAt: Date;
211
+ }
212
+ ```
213
+
214
+ ## Fastify Integration
215
+
216
+ ```typescript
217
+ import fastifyMultipart from '@fastify/multipart';
218
+
219
+ // Register multipart
220
+ fastify.register(fastifyMultipart, {
221
+ limits: {
222
+ fileSize: 10 * 1024 * 1024, // 10MB
223
+ },
224
+ });
225
+
226
+ // Upload route with validation
227
+ fastify.post('/api/files', async (request, reply) => {
228
+ const file = await request.file();
229
+
230
+ if (!file) {
231
+ return reply.status(400).send({ error: 'No file provided' });
232
+ }
233
+
234
+ try {
235
+ const uploaded = await uploadService.upload(file, {
236
+ folder: 'documents',
237
+ isPublic: false,
238
+ });
239
+
240
+ return {
241
+ id: uploaded.id,
242
+ url: uploaded.url,
243
+ size: uploaded.size,
244
+ mimetype: uploaded.mimetype,
245
+ };
246
+ } catch (error) {
247
+ if (error.message.includes('File type not allowed')) {
248
+ return reply.status(400).send({ error: error.message });
249
+ }
250
+ throw error;
251
+ }
252
+ });
253
+ ```
254
+
255
+ ## Database Schema
256
+
257
+ ```sql
258
+ CREATE TABLE uploaded_files (
259
+ id UUID PRIMARY KEY,
260
+ user_id TEXT,
261
+ original_name TEXT NOT NULL,
262
+ filename TEXT NOT NULL,
263
+ mimetype TEXT NOT NULL,
264
+ size INTEGER NOT NULL,
265
+ path TEXT NOT NULL,
266
+ url TEXT NOT NULL,
267
+ provider TEXT NOT NULL,
268
+ bucket TEXT,
269
+ created_at TIMESTAMP DEFAULT NOW()
270
+ );
271
+
272
+ CREATE INDEX idx_uploaded_files_user ON uploaded_files(user_id);
273
+ ```
274
+
275
+ ## Default Allowed MIME Types
276
+
277
+ ```typescript
278
+ [
279
+ 'image/jpeg',
280
+ 'image/png',
281
+ 'image/gif',
282
+ 'image/webp',
283
+ 'application/pdf',
284
+ 'text/plain',
285
+ 'application/json',
286
+ ]
287
+ ```
288
+
289
+ ## Best Practices
290
+
291
+ 1. **Validate on Server** - Always validate file types server-side
292
+ 2. **Use Signed URLs** - Use signed URLs for sensitive files
293
+ 3. **Set Size Limits** - Configure appropriate file size limits
294
+ 4. **Clean Up** - Implement cleanup for orphaned files
295
+ 5. **CDN** - Use CDN for public files in production
296
+ 6. **Virus Scanning** - Consider virus scanning for user uploads