servcraft 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.
- package/.claude/settings.local.json +29 -0
- package/.github/CODEOWNERS +18 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +46 -0
- package/.github/dependabot.yml +59 -0
- package/.github/workflows/ci.yml +188 -0
- package/.github/workflows/release.yml +195 -0
- package/AUDIT.md +602 -0
- package/README.md +1070 -1
- package/dist/cli/index.cjs +2026 -2168
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +2026 -2168
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +595 -616
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +114 -52
- package/dist/index.d.ts +114 -52
- package/dist/index.js +595 -616
- package/dist/index.js.map +1 -1
- package/docs/CLI-001_MULTI_DB_PLAN.md +546 -0
- package/docs/DATABASE_MULTI_ORM.md +399 -0
- package/docs/PHASE1_BREAKDOWN.md +346 -0
- package/docs/PROGRESS.md +550 -0
- package/docs/modules/ANALYTICS.md +226 -0
- package/docs/modules/API-VERSIONING.md +252 -0
- package/docs/modules/AUDIT.md +192 -0
- package/docs/modules/AUTH.md +431 -0
- package/docs/modules/CACHE.md +346 -0
- package/docs/modules/EMAIL.md +254 -0
- package/docs/modules/FEATURE-FLAG.md +291 -0
- package/docs/modules/I18N.md +294 -0
- package/docs/modules/MEDIA-PROCESSING.md +281 -0
- package/docs/modules/MFA.md +266 -0
- package/docs/modules/NOTIFICATION.md +311 -0
- package/docs/modules/OAUTH.md +237 -0
- package/docs/modules/PAYMENT.md +804 -0
- package/docs/modules/QUEUE.md +540 -0
- package/docs/modules/RATE-LIMIT.md +339 -0
- package/docs/modules/SEARCH.md +288 -0
- package/docs/modules/SECURITY.md +327 -0
- package/docs/modules/SESSION.md +382 -0
- package/docs/modules/SWAGGER.md +305 -0
- package/docs/modules/UPLOAD.md +296 -0
- package/docs/modules/USER.md +505 -0
- package/docs/modules/VALIDATION.md +294 -0
- package/docs/modules/WEBHOOK.md +270 -0
- package/docs/modules/WEBSOCKET.md +691 -0
- package/package.json +53 -38
- package/prisma/schema.prisma +395 -1
- package/src/cli/commands/add-module.ts +520 -87
- package/src/cli/commands/db.ts +3 -4
- package/src/cli/commands/docs.ts +256 -6
- package/src/cli/commands/generate.ts +12 -19
- package/src/cli/commands/init.ts +384 -214
- package/src/cli/index.ts +0 -4
- package/src/cli/templates/repository.ts +6 -1
- package/src/cli/templates/routes.ts +6 -21
- package/src/cli/utils/docs-generator.ts +6 -7
- package/src/cli/utils/env-manager.ts +717 -0
- package/src/cli/utils/field-parser.ts +16 -7
- package/src/cli/utils/interactive-prompt.ts +223 -0
- package/src/cli/utils/template-manager.ts +346 -0
- package/src/config/database.config.ts +183 -0
- package/src/config/env.ts +0 -10
- package/src/config/index.ts +0 -14
- package/src/core/server.ts +1 -1
- package/src/database/adapters/mongoose.adapter.ts +132 -0
- package/src/database/adapters/prisma.adapter.ts +118 -0
- package/src/database/connection.ts +190 -0
- package/src/database/interfaces/database.interface.ts +85 -0
- package/src/database/interfaces/index.ts +7 -0
- package/src/database/interfaces/repository.interface.ts +129 -0
- package/src/database/models/mongoose/index.ts +7 -0
- package/src/database/models/mongoose/payment.schema.ts +347 -0
- package/src/database/models/mongoose/user.schema.ts +154 -0
- package/src/database/prisma.ts +1 -4
- package/src/database/redis.ts +101 -0
- package/src/database/repositories/mongoose/index.ts +7 -0
- package/src/database/repositories/mongoose/payment.repository.ts +380 -0
- package/src/database/repositories/mongoose/user.repository.ts +255 -0
- package/src/database/seed.ts +6 -1
- package/src/index.ts +9 -20
- package/src/middleware/security.ts +2 -6
- package/src/modules/analytics/analytics.routes.ts +80 -0
- package/src/modules/analytics/analytics.service.ts +364 -0
- package/src/modules/analytics/index.ts +18 -0
- package/src/modules/analytics/types.ts +180 -0
- package/src/modules/api-versioning/index.ts +15 -0
- package/src/modules/api-versioning/types.ts +86 -0
- package/src/modules/api-versioning/versioning.middleware.ts +120 -0
- package/src/modules/api-versioning/versioning.routes.ts +54 -0
- package/src/modules/api-versioning/versioning.service.ts +189 -0
- package/src/modules/audit/audit.repository.ts +206 -0
- package/src/modules/audit/audit.service.ts +27 -59
- package/src/modules/auth/auth.controller.ts +2 -2
- package/src/modules/auth/auth.middleware.ts +3 -9
- package/src/modules/auth/auth.routes.ts +10 -107
- package/src/modules/auth/auth.service.ts +126 -23
- package/src/modules/auth/index.ts +3 -4
- package/src/modules/cache/cache.service.ts +367 -0
- package/src/modules/cache/index.ts +10 -0
- package/src/modules/cache/types.ts +44 -0
- package/src/modules/email/email.service.ts +3 -10
- package/src/modules/email/templates.ts +2 -8
- package/src/modules/feature-flag/feature-flag.repository.ts +303 -0
- package/src/modules/feature-flag/feature-flag.routes.ts +247 -0
- package/src/modules/feature-flag/feature-flag.service.ts +566 -0
- package/src/modules/feature-flag/index.ts +20 -0
- package/src/modules/feature-flag/types.ts +192 -0
- package/src/modules/i18n/i18n.middleware.ts +186 -0
- package/src/modules/i18n/i18n.routes.ts +191 -0
- package/src/modules/i18n/i18n.service.ts +456 -0
- package/src/modules/i18n/index.ts +18 -0
- package/src/modules/i18n/types.ts +118 -0
- package/src/modules/media-processing/index.ts +17 -0
- package/src/modules/media-processing/media-processing.routes.ts +111 -0
- package/src/modules/media-processing/media-processing.service.ts +245 -0
- package/src/modules/media-processing/types.ts +156 -0
- package/src/modules/mfa/index.ts +20 -0
- package/src/modules/mfa/mfa.repository.ts +206 -0
- package/src/modules/mfa/mfa.routes.ts +595 -0
- package/src/modules/mfa/mfa.service.ts +572 -0
- package/src/modules/mfa/totp.ts +150 -0
- package/src/modules/mfa/types.ts +57 -0
- package/src/modules/notification/index.ts +20 -0
- package/src/modules/notification/notification.repository.ts +356 -0
- package/src/modules/notification/notification.service.ts +483 -0
- package/src/modules/notification/types.ts +119 -0
- package/src/modules/oauth/index.ts +20 -0
- package/src/modules/oauth/oauth.repository.ts +219 -0
- package/src/modules/oauth/oauth.routes.ts +446 -0
- package/src/modules/oauth/oauth.service.ts +293 -0
- package/src/modules/oauth/providers/apple.provider.ts +250 -0
- package/src/modules/oauth/providers/facebook.provider.ts +181 -0
- package/src/modules/oauth/providers/github.provider.ts +248 -0
- package/src/modules/oauth/providers/google.provider.ts +189 -0
- package/src/modules/oauth/providers/twitter.provider.ts +214 -0
- package/src/modules/oauth/types.ts +94 -0
- package/src/modules/payment/index.ts +19 -0
- package/src/modules/payment/payment.repository.ts +733 -0
- package/src/modules/payment/payment.routes.ts +390 -0
- package/src/modules/payment/payment.service.ts +354 -0
- package/src/modules/payment/providers/mobile-money.provider.ts +274 -0
- package/src/modules/payment/providers/paypal.provider.ts +190 -0
- package/src/modules/payment/providers/stripe.provider.ts +215 -0
- package/src/modules/payment/types.ts +140 -0
- package/src/modules/queue/cron.ts +438 -0
- package/src/modules/queue/index.ts +87 -0
- package/src/modules/queue/queue.routes.ts +600 -0
- package/src/modules/queue/queue.service.ts +842 -0
- package/src/modules/queue/types.ts +222 -0
- package/src/modules/queue/workers.ts +366 -0
- package/src/modules/rate-limit/index.ts +59 -0
- package/src/modules/rate-limit/rate-limit.middleware.ts +134 -0
- package/src/modules/rate-limit/rate-limit.routes.ts +269 -0
- package/src/modules/rate-limit/rate-limit.service.ts +348 -0
- package/src/modules/rate-limit/stores/memory.store.ts +165 -0
- package/src/modules/rate-limit/stores/redis.store.ts +322 -0
- package/src/modules/rate-limit/types.ts +153 -0
- package/src/modules/search/adapters/elasticsearch.adapter.ts +326 -0
- package/src/modules/search/adapters/meilisearch.adapter.ts +261 -0
- package/src/modules/search/adapters/memory.adapter.ts +278 -0
- package/src/modules/search/index.ts +21 -0
- package/src/modules/search/search.service.ts +234 -0
- package/src/modules/search/types.ts +214 -0
- package/src/modules/security/index.ts +40 -0
- package/src/modules/security/sanitize.ts +223 -0
- package/src/modules/security/security-audit.service.ts +388 -0
- package/src/modules/security/security.middleware.ts +398 -0
- package/src/modules/session/index.ts +3 -0
- package/src/modules/session/session.repository.ts +159 -0
- package/src/modules/session/session.service.ts +340 -0
- package/src/modules/session/types.ts +38 -0
- package/src/modules/swagger/index.ts +7 -1
- package/src/modules/swagger/schema-builder.ts +16 -4
- package/src/modules/swagger/swagger.service.ts +9 -10
- package/src/modules/swagger/types.ts +0 -2
- package/src/modules/upload/index.ts +14 -0
- package/src/modules/upload/types.ts +83 -0
- package/src/modules/upload/upload.repository.ts +199 -0
- package/src/modules/upload/upload.routes.ts +311 -0
- package/src/modules/upload/upload.service.ts +448 -0
- package/src/modules/user/index.ts +3 -3
- package/src/modules/user/user.controller.ts +15 -9
- package/src/modules/user/user.repository.ts +237 -113
- package/src/modules/user/user.routes.ts +39 -164
- package/src/modules/user/user.service.ts +4 -3
- package/src/modules/validation/validator.ts +12 -17
- package/src/modules/webhook/index.ts +91 -0
- package/src/modules/webhook/retry.ts +196 -0
- package/src/modules/webhook/signature.ts +135 -0
- package/src/modules/webhook/types.ts +181 -0
- package/src/modules/webhook/webhook.repository.ts +358 -0
- package/src/modules/webhook/webhook.routes.ts +442 -0
- package/src/modules/webhook/webhook.service.ts +457 -0
- package/src/modules/websocket/features.ts +504 -0
- package/src/modules/websocket/index.ts +106 -0
- package/src/modules/websocket/middlewares.ts +298 -0
- package/src/modules/websocket/types.ts +181 -0
- package/src/modules/websocket/websocket.service.ts +692 -0
- package/src/utils/errors.ts +7 -0
- package/src/utils/pagination.ts +4 -1
- package/tests/helpers/db-check.ts +79 -0
- package/tests/integration/auth-redis.test.ts +94 -0
- package/tests/integration/cache-redis.test.ts +387 -0
- package/tests/integration/mongoose-repositories.test.ts +410 -0
- package/tests/integration/payment-prisma.test.ts +637 -0
- package/tests/integration/queue-bullmq.test.ts +417 -0
- package/tests/integration/user-prisma.test.ts +441 -0
- package/tests/integration/websocket-socketio.test.ts +552 -0
- package/tests/setup.ts +11 -9
- package/vitest.config.ts +3 -8
- package/npm-cache/_cacache/content-v2/sha512/1c/d0/03440d500a0487621aad1d6402978340698976602046db8e24fa03c01ee6c022c69b0582f969042d9442ee876ac35c038e960dd427d1e622fa24b8eb7dba +0 -0
- package/npm-cache/_cacache/content-v2/sha512/42/55/28b493ca491833e5aab0e9c3108d29ab3f36c248ca88f45d4630674fce9130959e56ae308797ac2b6328fa7f09a610b9550ed09cb971d039876d293fc69d +0 -0
- package/npm-cache/_cacache/content-v2/sha512/e0/12/f360dc9315ee5f17844a0c8c233ee6bf7c30837c4a02ea0d56c61c7f7ab21c0e958e50ed2c57c59f983c762b93056778c9009b2398ffc26def0183999b13 +0 -0
- package/npm-cache/_cacache/content-v2/sha512/ed/b0/fae1161902898f4c913c67d7f6cdf6be0665aec3b389b9c4f4f0a101ca1da59badf1b59c4e0030f5223023b8d63cfe501c46a32c20c895d4fb3f11ca2232 +0 -0
- package/npm-cache/_cacache/index-v5/58/94/c2cba79e0f16b4c10e95a87e32255741149e8222cc314a476aab67c39cc0 +0 -5
package/README.md
CHANGED
|
@@ -10,11 +10,174 @@ A modular, production-ready Node.js backend framework built with TypeScript, Fas
|
|
|
10
10
|
- **Validation**: Zod/Joi/Yup support
|
|
11
11
|
- **Database**: Prisma ORM (PostgreSQL, MySQL, SQLite)
|
|
12
12
|
- **Email**: SMTP with Handlebars templates
|
|
13
|
-
- **Security**: Helmet, CORS,
|
|
13
|
+
- **Security**: Helmet, CORS, Advanced rate limiting (fixed/sliding window, token bucket)
|
|
14
14
|
- **Logging**: Pino structured logs + Audit trail
|
|
15
15
|
- **Docker**: Ready for containerization
|
|
16
16
|
- **CLI**: Generate modules, controllers, services
|
|
17
17
|
|
|
18
|
+
## How to Use the Services
|
|
19
|
+
|
|
20
|
+
The modules (Rate Limiting, Webhooks, Queue, Websockets, etc.) are **reusable services** that you integrate into your own routes and controllers. They are NOT standalone user-facing endpoints.
|
|
21
|
+
|
|
22
|
+
### Quick Integration Example
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// YOUR controller (e.g., src/modules/post/post.controller.ts)
|
|
26
|
+
import { webhookService } from '../webhook';
|
|
27
|
+
import { queueService, emailWorker } from '../queue';
|
|
28
|
+
import { wsService } from '../websocket';
|
|
29
|
+
import { strictRateLimit } from '../rate-limit';
|
|
30
|
+
|
|
31
|
+
class PostController {
|
|
32
|
+
async createPost(req, res) {
|
|
33
|
+
// 1. Create the post
|
|
34
|
+
const post = await db.post.create(req.body);
|
|
35
|
+
|
|
36
|
+
// 2. Use webhook service - notify external systems
|
|
37
|
+
await webhookService.publishEvent('post.created', {
|
|
38
|
+
postId: post.id,
|
|
39
|
+
title: post.title,
|
|
40
|
+
author: req.user.id
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// 3. Use queue service - send emails asynchronously
|
|
44
|
+
await queueService.addJob('emails', 'send-email', {
|
|
45
|
+
to: 'admin@example.com',
|
|
46
|
+
subject: 'New Post Created',
|
|
47
|
+
html: `<p>${post.title} was published</p>`
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// 4. Use websocket service - real-time notification
|
|
51
|
+
await wsService.broadcastToAll('post:new', post);
|
|
52
|
+
|
|
53
|
+
// 5. Use cache service - invalidate cache
|
|
54
|
+
await cacheService.delete('posts:latest');
|
|
55
|
+
|
|
56
|
+
res.json(post);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Apply rate limiting to YOUR routes
|
|
61
|
+
app.post('/api/posts', strictRateLimit, postController.createPost);
|
|
62
|
+
app.get('/api/posts', standardRateLimit, postController.list);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Available Services
|
|
66
|
+
|
|
67
|
+
All services are available as importable modules in your code:
|
|
68
|
+
|
|
69
|
+
| Service | Import | Usage |
|
|
70
|
+
|---------|--------|-------|
|
|
71
|
+
| **Rate Limiting** | `import { strictRateLimit, createRateLimiter } from './modules/rate-limit'` | Apply as middleware on routes |
|
|
72
|
+
| **Webhooks** | `import { WebhookService } from './modules/webhook'` | Publish events to external URLs |
|
|
73
|
+
| **Queue/Jobs** | `import { QueueService, emailWorker } from './modules/queue'` | Background tasks & cron jobs |
|
|
74
|
+
| **Websockets** | `import { WebSocketService, ChatFeature } from './modules/websocket'` | Real-time communication |
|
|
75
|
+
| **Cache** | `import { CacheService } from './modules/cache'` | Redis caching |
|
|
76
|
+
| **MFA** | `import { MFAService } from './modules/mfa'` | Two-factor authentication |
|
|
77
|
+
| **OAuth** | `import { OAuthService } from './modules/oauth'` | Social login |
|
|
78
|
+
| **Payments** | `import { PaymentService } from './modules/payment'` | Process payments |
|
|
79
|
+
| **Upload** | `import { UploadService } from './modules/upload'` | File uploads |
|
|
80
|
+
| **Notifications** | `import { NotificationService } from './modules/notification'` | Send notifications |
|
|
81
|
+
| **Search** | `import { SearchService, ElasticsearchAdapter } from './modules/search'` | Full-text search with Elasticsearch/Meilisearch |
|
|
82
|
+
| **i18n** | `import { I18nService, createI18nMiddleware } from './modules/i18n'` | Multi-language support & localization |
|
|
83
|
+
| **Feature Flags** | `import { FeatureFlagService, createFeatureFlagRoutes } from './modules/feature-flag'` | A/B testing & progressive rollout |
|
|
84
|
+
| **Analytics** | `import { AnalyticsService, createAnalyticsRoutes } from './modules/analytics'` | Prometheus metrics & event tracking |
|
|
85
|
+
| **Media Processing** | `import { MediaProcessingService } from './modules/media-processing'` | Image/video processing with FFmpeg |
|
|
86
|
+
| **API Versioning** | `import { VersioningService, createVersioningMiddleware } from './modules/api-versioning'` | Multiple API versions support |
|
|
87
|
+
|
|
88
|
+
### Common Integration Patterns
|
|
89
|
+
|
|
90
|
+
**Pattern 1: E-commerce Order Flow**
|
|
91
|
+
```typescript
|
|
92
|
+
async createOrder(req, res) {
|
|
93
|
+
const order = await db.order.create(req.body);
|
|
94
|
+
|
|
95
|
+
// Send webhook to inventory system
|
|
96
|
+
await webhookService.publishEvent('order.created', order);
|
|
97
|
+
|
|
98
|
+
// Queue payment processing
|
|
99
|
+
await queueService.addJob('payments', 'process-payment', {
|
|
100
|
+
orderId: order.id,
|
|
101
|
+
amount: order.total
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Real-time update to user
|
|
105
|
+
await wsService.broadcastToUsers([order.userId], 'order:created', order);
|
|
106
|
+
|
|
107
|
+
// Queue confirmation email (delayed 5 minutes)
|
|
108
|
+
await queueService.addJob('emails', 'send-email', {
|
|
109
|
+
to: order.email,
|
|
110
|
+
template: 'order-confirmation',
|
|
111
|
+
data: order
|
|
112
|
+
}, { delay: 5 * 60 * 1000 });
|
|
113
|
+
|
|
114
|
+
res.json(order);
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Pattern 2: User Registration**
|
|
119
|
+
```typescript
|
|
120
|
+
async register(req, res) {
|
|
121
|
+
const user = await db.user.create(req.body);
|
|
122
|
+
|
|
123
|
+
// Generate MFA secret
|
|
124
|
+
const mfaSetup = await mfaService.setupTOTP(user.id, 'MyApp');
|
|
125
|
+
|
|
126
|
+
// Queue welcome email
|
|
127
|
+
await queueService.addJob('emails', 'send-email', {
|
|
128
|
+
to: user.email,
|
|
129
|
+
subject: 'Welcome!',
|
|
130
|
+
template: 'welcome',
|
|
131
|
+
data: { user, mfaQR: mfaSetup.qrCode }
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Webhook to CRM
|
|
135
|
+
await webhookService.publishEvent('user.registered', user);
|
|
136
|
+
|
|
137
|
+
res.json({ user, mfaSetup });
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Pattern 3: Content Moderation**
|
|
142
|
+
```typescript
|
|
143
|
+
async uploadImage(req, res) {
|
|
144
|
+
// Upload file
|
|
145
|
+
const file = await uploadService.upload(req.file, {
|
|
146
|
+
allowedTypes: ['image/jpeg', 'image/png'],
|
|
147
|
+
maxSize: 5 * 1024 * 1024
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Queue image processing
|
|
151
|
+
await queueService.addJob('images', 'process-image', {
|
|
152
|
+
source: file.path,
|
|
153
|
+
operations: [
|
|
154
|
+
{ type: 'resize', options: { width: 800 } },
|
|
155
|
+
{ type: 'watermark', options: { text: '© MyApp' } },
|
|
156
|
+
{ type: 'compress', options: { quality: 80 } }
|
|
157
|
+
],
|
|
158
|
+
output: `/processed/${file.id}.jpg`
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
res.json(file);
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Auto-Generated Documentation
|
|
166
|
+
|
|
167
|
+
Yes! Use the built-in docs generator:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# Generate API documentation automatically
|
|
171
|
+
servcraft docs generate
|
|
172
|
+
|
|
173
|
+
# This will scan all your routes and generate:
|
|
174
|
+
# - OpenAPI/Swagger spec
|
|
175
|
+
# - Endpoint list
|
|
176
|
+
# - Request/response examples
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The `src/cli/commands/docs.ts` file I created does this automatically!
|
|
180
|
+
|
|
18
181
|
## Quick Start
|
|
19
182
|
|
|
20
183
|
### Create a new project
|
|
@@ -79,9 +242,79 @@ servcraft add email # Email service
|
|
|
79
242
|
servcraft add audit # Audit logging
|
|
80
243
|
servcraft add cache # Redis cache
|
|
81
244
|
servcraft add upload # File uploads
|
|
245
|
+
servcraft add rate-limit # Advanced rate limiting
|
|
246
|
+
servcraft add webhook # Outgoing webhooks
|
|
247
|
+
servcraft add queue # Background jobs & queues
|
|
248
|
+
servcraft add websocket # Real-time with Socket.io
|
|
249
|
+
servcraft add search # Elasticsearch/Meilisearch search
|
|
250
|
+
servcraft add i18n # Multi-language support
|
|
251
|
+
servcraft add feature-flag # Feature flags & A/B testing
|
|
252
|
+
servcraft add analytics # Prometheus metrics & tracking
|
|
253
|
+
servcraft add media-processing # Image/video processing
|
|
254
|
+
servcraft add api-versioning # API version management
|
|
82
255
|
servcraft add --list # Show all modules
|
|
83
256
|
```
|
|
84
257
|
|
|
258
|
+
**Automatic Environment Configuration:**
|
|
259
|
+
|
|
260
|
+
When you add a module, ServCraft automatically:
|
|
261
|
+
- ✅ Adds required environment variables to your `.env` file
|
|
262
|
+
- ✅ Preserves existing variables (no overwrites)
|
|
263
|
+
- ✅ Updates `.env.example` with placeholder values
|
|
264
|
+
- ✅ Shows which variables need configuration
|
|
265
|
+
- ✅ Provides helpful comments for each variable
|
|
266
|
+
|
|
267
|
+
**Example:**
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
$ servcraft add search
|
|
271
|
+
|
|
272
|
+
✓ Module 'Search' added successfully!
|
|
273
|
+
|
|
274
|
+
📁 Files created:
|
|
275
|
+
✓ src/modules/search/types.ts
|
|
276
|
+
✓ src/modules/search/search.service.ts
|
|
277
|
+
✓ src/modules/search/index.ts
|
|
278
|
+
|
|
279
|
+
✓ Environment variables updated!
|
|
280
|
+
|
|
281
|
+
✅ Added to .env:
|
|
282
|
+
✓ SEARCH_ENGINE
|
|
283
|
+
✓ ELASTICSEARCH_NODE
|
|
284
|
+
✓ MEILISEARCH_HOST
|
|
285
|
+
|
|
286
|
+
⏭️ Already in .env (skipped):
|
|
287
|
+
ℹ REDIS_HOST
|
|
288
|
+
|
|
289
|
+
⚠️ Required configuration:
|
|
290
|
+
⚠ ELASTICSEARCH_USERNAME - Please configure this variable
|
|
291
|
+
⚠ ELASTICSEARCH_PASSWORD - Please configure this variable
|
|
292
|
+
|
|
293
|
+
📌 Next steps:
|
|
294
|
+
1. Configure environment variables in .env (if needed)
|
|
295
|
+
2. Register the module in your main app file
|
|
296
|
+
3. Run database migrations if needed
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Your `.env` file will be updated with:
|
|
300
|
+
|
|
301
|
+
```env
|
|
302
|
+
# Search Configuration (Elasticsearch)
|
|
303
|
+
SEARCH_ENGINE=memory
|
|
304
|
+
# Elasticsearch node URL
|
|
305
|
+
# ELASTICSEARCH_NODE=http://localhost:9200
|
|
306
|
+
# Elasticsearch username (optional)
|
|
307
|
+
# ELASTICSEARCH_USERNAME=
|
|
308
|
+
# Elasticsearch password (optional)
|
|
309
|
+
# ELASTICSEARCH_PASSWORD=
|
|
310
|
+
|
|
311
|
+
# Search Configuration (Meilisearch)
|
|
312
|
+
# Meilisearch host URL
|
|
313
|
+
# MEILISEARCH_HOST=http://localhost:7700
|
|
314
|
+
# Meilisearch API key (optional)
|
|
315
|
+
# MEILISEARCH_API_KEY=
|
|
316
|
+
```
|
|
317
|
+
|
|
85
318
|
### Database commands
|
|
86
319
|
|
|
87
320
|
```bash
|
|
@@ -164,6 +397,842 @@ SMTP_PASS=pass
|
|
|
164
397
|
LOG_LEVEL=info
|
|
165
398
|
```
|
|
166
399
|
|
|
400
|
+
## Modules
|
|
401
|
+
|
|
402
|
+
### Rate Limiting
|
|
403
|
+
|
|
404
|
+
Advanced rate limiting with multiple algorithms and strategies:
|
|
405
|
+
|
|
406
|
+
**Features:**
|
|
407
|
+
- Multiple algorithms: Fixed Window, Sliding Window, Token Bucket
|
|
408
|
+
- Storage options: In-memory or Redis (for distributed systems)
|
|
409
|
+
- Flexible key generation: IP, User ID, API Key, or custom
|
|
410
|
+
- Whitelist/Blacklist support
|
|
411
|
+
- Custom limits per endpoint or user role
|
|
412
|
+
- Standard rate limit headers (X-RateLimit-*)
|
|
413
|
+
- Admin API for management
|
|
414
|
+
|
|
415
|
+
**Usage:**
|
|
416
|
+
|
|
417
|
+
```typescript
|
|
418
|
+
import {
|
|
419
|
+
createRateLimiter,
|
|
420
|
+
strictRateLimit,
|
|
421
|
+
authRateLimit,
|
|
422
|
+
userRateLimit
|
|
423
|
+
} from './modules/rate-limit';
|
|
424
|
+
|
|
425
|
+
// Global rate limiter
|
|
426
|
+
app.use(createRateLimiter({
|
|
427
|
+
max: 100, // 100 requests
|
|
428
|
+
windowMs: 60 * 1000, // per minute
|
|
429
|
+
algorithm: 'sliding-window' // or 'fixed-window', 'token-bucket'
|
|
430
|
+
}));
|
|
431
|
+
|
|
432
|
+
// Pre-configured limiters
|
|
433
|
+
app.post('/login', authRateLimit, loginHandler); // 5 req/15min
|
|
434
|
+
app.post('/sensitive', strictRateLimit, sensitiveHandler); // 5 req/min
|
|
435
|
+
|
|
436
|
+
// Custom limiters
|
|
437
|
+
app.get('/api/data',
|
|
438
|
+
userRateLimit(1000, 60 * 60 * 1000), // 1000 req/hour per user
|
|
439
|
+
dataHandler
|
|
440
|
+
);
|
|
441
|
+
|
|
442
|
+
// Per-endpoint limits
|
|
443
|
+
app.use(createRateLimiter({
|
|
444
|
+
max: 100,
|
|
445
|
+
windowMs: 60 * 1000,
|
|
446
|
+
customLimits: {
|
|
447
|
+
'POST:/api/expensive': { max: 10, windowMs: 60 * 1000 },
|
|
448
|
+
'role:admin': { max: 10000, windowMs: 60 * 1000 }
|
|
449
|
+
}
|
|
450
|
+
}));
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
**Admin Routes:**
|
|
454
|
+
|
|
455
|
+
```
|
|
456
|
+
GET /rate-limit/info/:key Get rate limit info
|
|
457
|
+
POST /rate-limit/reset/:key Reset rate limit
|
|
458
|
+
GET /rate-limit/config Get configuration
|
|
459
|
+
POST /rate-limit/whitelist Add IP to whitelist
|
|
460
|
+
DELETE /rate-limit/whitelist/:ip Remove from whitelist
|
|
461
|
+
POST /rate-limit/blacklist Add IP to blacklist
|
|
462
|
+
DELETE /rate-limit/blacklist/:ip Remove from blacklist
|
|
463
|
+
POST /rate-limit/clear Clear all data
|
|
464
|
+
POST /rate-limit/cleanup Cleanup expired entries
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
**Redis Storage (for multi-instance):**
|
|
468
|
+
|
|
469
|
+
```typescript
|
|
470
|
+
import { RateLimitService, RedisStore } from './modules/rate-limit';
|
|
471
|
+
import Redis from 'ioredis';
|
|
472
|
+
|
|
473
|
+
const redis = new Redis();
|
|
474
|
+
const store = new RedisStore(redis);
|
|
475
|
+
const service = new RateLimitService({ max: 100, windowMs: 60000 }, store);
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
### Webhooks Sortants
|
|
479
|
+
|
|
480
|
+
Send events to external URLs with automatic retry, HMAC signatures, and monitoring:
|
|
481
|
+
|
|
482
|
+
**Features:**
|
|
483
|
+
- Automatic retry with exponential backoff
|
|
484
|
+
- HMAC-SHA256 signature verification
|
|
485
|
+
- Delivery tracking and monitoring
|
|
486
|
+
- Multiple retry strategies
|
|
487
|
+
- Event filtering by type
|
|
488
|
+
- Webhook endpoint management
|
|
489
|
+
|
|
490
|
+
**Usage:**
|
|
491
|
+
|
|
492
|
+
```typescript
|
|
493
|
+
import { WebhookService, createWebhookRoutes } from './modules/webhook';
|
|
494
|
+
|
|
495
|
+
// Create service
|
|
496
|
+
const webhookService = new WebhookService({
|
|
497
|
+
maxRetries: 5,
|
|
498
|
+
timeout: 10000,
|
|
499
|
+
enableSignature: true
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
// Create endpoint
|
|
503
|
+
const endpoint = await webhookService.createEndpoint({
|
|
504
|
+
url: 'https://example.com/webhook',
|
|
505
|
+
events: ['user.created', 'order.completed'],
|
|
506
|
+
description: 'Production webhook'
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
// Publish event
|
|
510
|
+
await webhookService.publishEvent('user.created', {
|
|
511
|
+
userId: '123',
|
|
512
|
+
email: 'user@example.com',
|
|
513
|
+
name: 'John Doe'
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
// Add routes
|
|
517
|
+
app.use('/api/webhooks', authMiddleware, createWebhookRoutes(webhookService));
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
**Signature Verification (Recipient Side):**
|
|
521
|
+
|
|
522
|
+
```typescript
|
|
523
|
+
import { verifyWebhookSignature } from './modules/webhook';
|
|
524
|
+
|
|
525
|
+
app.post('/webhook', (req, res) => {
|
|
526
|
+
const signature = req.headers['x-webhook-signature'];
|
|
527
|
+
const secret = 'your-webhook-secret';
|
|
528
|
+
|
|
529
|
+
if (!verifyWebhookSignature(req.body, signature, secret)) {
|
|
530
|
+
return res.status(401).json({ error: 'Invalid signature' });
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// Process webhook
|
|
534
|
+
res.json({ received: true });
|
|
535
|
+
});
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
**Admin Routes:**
|
|
539
|
+
|
|
540
|
+
```
|
|
541
|
+
POST /webhooks/endpoints Create endpoint
|
|
542
|
+
GET /webhooks/endpoints List endpoints
|
|
543
|
+
GET /webhooks/endpoints/:id Get endpoint
|
|
544
|
+
PATCH /webhooks/endpoints/:id Update endpoint
|
|
545
|
+
DELETE /webhooks/endpoints/:id Delete endpoint
|
|
546
|
+
POST /webhooks/endpoints/:id/rotate-secret Rotate secret
|
|
547
|
+
POST /webhooks/events Publish event
|
|
548
|
+
GET /webhooks/deliveries List deliveries
|
|
549
|
+
GET /webhooks/deliveries/:id Get delivery
|
|
550
|
+
GET /webhooks/deliveries/:id/attempts Get attempts
|
|
551
|
+
POST /webhooks/deliveries/:id/retry Retry delivery
|
|
552
|
+
GET /webhooks/stats Get statistics
|
|
553
|
+
POST /webhooks/cleanup Cleanup old data
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
**Retry Strategies:**
|
|
557
|
+
|
|
558
|
+
```typescript
|
|
559
|
+
import {
|
|
560
|
+
ExponentialBackoffStrategy,
|
|
561
|
+
LinearBackoffStrategy,
|
|
562
|
+
FixedDelayStrategy
|
|
563
|
+
} from './modules/webhook';
|
|
564
|
+
|
|
565
|
+
// Exponential: 1s, 2s, 4s, 8s, 16s
|
|
566
|
+
const exponential = new ExponentialBackoffStrategy(1000, 60000, 2, 5);
|
|
567
|
+
|
|
568
|
+
// Linear: 5s, 10s, 15s
|
|
569
|
+
const linear = new LinearBackoffStrategy(5000, 3);
|
|
570
|
+
|
|
571
|
+
// Fixed: 10s, 10s, 10s
|
|
572
|
+
const fixed = new FixedDelayStrategy(10000, 3);
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
### Queue/Jobs (Background Tasks)
|
|
576
|
+
|
|
577
|
+
Background job processing with Bull/BullMQ, cron scheduling, and pre-built workers:
|
|
578
|
+
|
|
579
|
+
**Features:**
|
|
580
|
+
- Background job processing
|
|
581
|
+
- Priority queues
|
|
582
|
+
- Automatic retry with backoff
|
|
583
|
+
- Cron-based scheduling
|
|
584
|
+
- Job progress tracking
|
|
585
|
+
- Real-time monitoring & metrics
|
|
586
|
+
- 10+ pre-built workers
|
|
587
|
+
|
|
588
|
+
**Usage:**
|
|
589
|
+
|
|
590
|
+
```typescript
|
|
591
|
+
import {
|
|
592
|
+
QueueService,
|
|
593
|
+
CronJobManager,
|
|
594
|
+
emailWorker,
|
|
595
|
+
imageProcessingWorker,
|
|
596
|
+
CronSchedules
|
|
597
|
+
} from './modules/queue';
|
|
598
|
+
|
|
599
|
+
// Create queue service
|
|
600
|
+
const queueService = new QueueService({
|
|
601
|
+
redis: { host: 'localhost', port: 6379 },
|
|
602
|
+
metrics: true
|
|
603
|
+
});
|
|
604
|
+
|
|
605
|
+
// Register workers
|
|
606
|
+
queueService.registerWorker('emails', emailWorker);
|
|
607
|
+
queueService.registerWorker('images', imageProcessingWorker);
|
|
608
|
+
|
|
609
|
+
// Add job
|
|
610
|
+
await queueService.addJob('emails', 'send-email', {
|
|
611
|
+
to: 'user@example.com',
|
|
612
|
+
subject: 'Welcome!',
|
|
613
|
+
html: '<h1>Welcome to our service</h1>'
|
|
614
|
+
}, {
|
|
615
|
+
priority: 'high',
|
|
616
|
+
attempts: 3,
|
|
617
|
+
backoff: { type: 'exponential', delay: 1000 }
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
// Bulk jobs
|
|
621
|
+
await queueService.addBulkJobs('notifications', {
|
|
622
|
+
jobs: [
|
|
623
|
+
{ name: 'send-notification', data: { userId: '1', message: 'Hello' } },
|
|
624
|
+
{ name: 'send-notification', data: { userId: '2', message: 'Hi' } }
|
|
625
|
+
]
|
|
626
|
+
});
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
**Cron Jobs:**
|
|
630
|
+
|
|
631
|
+
```typescript
|
|
632
|
+
const cronManager = new CronJobManager(queueService);
|
|
633
|
+
|
|
634
|
+
// Daily backup at midnight
|
|
635
|
+
await cronManager.createCronJob(
|
|
636
|
+
'Daily Backup',
|
|
637
|
+
CronSchedules.DAILY,
|
|
638
|
+
'maintenance',
|
|
639
|
+
'database-backup',
|
|
640
|
+
{ databases: ['main', 'analytics'] }
|
|
641
|
+
);
|
|
642
|
+
|
|
643
|
+
// Custom cron expression: Every 15 minutes
|
|
644
|
+
await cronManager.createCronJob(
|
|
645
|
+
'Cache Warming',
|
|
646
|
+
'*/15 * * * *',
|
|
647
|
+
'cache',
|
|
648
|
+
'warm-cache',
|
|
649
|
+
{ keys: ['popular-posts', 'trending-users'] }
|
|
650
|
+
);
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
**Pre-built Workers:**
|
|
654
|
+
|
|
655
|
+
- `emailWorker` - Send emails (nodemailer, SendGrid, etc.)
|
|
656
|
+
- `imageProcessingWorker` - Resize, crop, watermark images
|
|
657
|
+
- `notificationWorker` - Push/SMS/email notifications
|
|
658
|
+
- `webhookWorker` - HTTP webhooks
|
|
659
|
+
- `dataExportWorker` - Export to CSV/Excel/PDF
|
|
660
|
+
- `reportGenerationWorker` - Generate reports
|
|
661
|
+
- `databaseBackupWorker` - Database backups
|
|
662
|
+
- `cacheWarmingWorker` - Cache warming
|
|
663
|
+
- `dataCleanupWorker` - Clean old data
|
|
664
|
+
- `batchProcessingWorker` - Batch processing
|
|
665
|
+
|
|
666
|
+
**Admin Routes:**
|
|
667
|
+
|
|
668
|
+
```
|
|
669
|
+
GET /queue/queues List all queues
|
|
670
|
+
GET /queue/queues/:name/stats Get queue stats
|
|
671
|
+
GET /queue/queues/:name/metrics Get queue metrics
|
|
672
|
+
POST /queue/queues/:name/pause Pause queue
|
|
673
|
+
POST /queue/queues/:name/resume Resume queue
|
|
674
|
+
POST /queue/queues/:name/jobs Add job
|
|
675
|
+
POST /queue/queues/:name/jobs/bulk Add bulk jobs
|
|
676
|
+
GET /queue/queues/:name/jobs List jobs
|
|
677
|
+
GET /queue/queues/:name/jobs/:id Get job
|
|
678
|
+
DELETE /queue/queues/:name/jobs/:id Remove job
|
|
679
|
+
POST /queue/queues/:name/jobs/:id/retry Retry job
|
|
680
|
+
POST /queue/queues/:name/clean Clean old jobs
|
|
681
|
+
POST /queue/cron Create cron job
|
|
682
|
+
GET /queue/cron List cron jobs
|
|
683
|
+
GET /queue/cron/:id Get cron job
|
|
684
|
+
PATCH /queue/cron/:id Update cron job
|
|
685
|
+
DELETE /queue/cron/:id Delete cron job
|
|
686
|
+
POST /queue/cron/:id/trigger Trigger cron job
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
**Cron Schedules:**
|
|
690
|
+
|
|
691
|
+
```typescript
|
|
692
|
+
CronSchedules.EVERY_MINUTE // * * * * *
|
|
693
|
+
CronSchedules.EVERY_15_MINUTES // */15 * * * *
|
|
694
|
+
CronSchedules.EVERY_HOUR // 0 * * * *
|
|
695
|
+
CronSchedules.DAILY // 0 0 * * *
|
|
696
|
+
CronSchedules.WEEKLY // 0 0 * * 0
|
|
697
|
+
CronSchedules.MONTHLY // 0 0 1 * *
|
|
698
|
+
CronSchedules.WEEKDAYS_9AM // 0 9 * * 1-5
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
### Websockets/Real-time
|
|
702
|
+
|
|
703
|
+
Real-time communication with Socket.io for chat, presence, notifications, and live events:
|
|
704
|
+
|
|
705
|
+
**Features:**
|
|
706
|
+
- Real-time chat with typing indicators
|
|
707
|
+
- User presence tracking (online/offline/away)
|
|
708
|
+
- Live notifications
|
|
709
|
+
- Room/namespace management
|
|
710
|
+
- Event broadcasting
|
|
711
|
+
- Authentication & role-based access
|
|
712
|
+
- Rate limiting & throttling
|
|
713
|
+
|
|
714
|
+
**Usage:**
|
|
715
|
+
|
|
716
|
+
```typescript
|
|
717
|
+
import {
|
|
718
|
+
WebSocketService,
|
|
719
|
+
ChatFeature,
|
|
720
|
+
PresenceFeature,
|
|
721
|
+
NotificationFeature,
|
|
722
|
+
authMiddleware
|
|
723
|
+
} from './modules/websocket';
|
|
724
|
+
|
|
725
|
+
// Create service
|
|
726
|
+
const wsService = new WebSocketService({
|
|
727
|
+
cors: { origin: 'http://localhost:3000' },
|
|
728
|
+
redis: { host: 'localhost', port: 6379 }
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
// Initialize with HTTP server
|
|
732
|
+
wsService.initialize(httpServer);
|
|
733
|
+
|
|
734
|
+
// Create features
|
|
735
|
+
const chat = new ChatFeature(wsService);
|
|
736
|
+
const presence = new PresenceFeature(wsService);
|
|
737
|
+
const notifications = new NotificationFeature(wsService);
|
|
738
|
+
|
|
739
|
+
// Send chat message
|
|
740
|
+
await chat.sendMessage('room-123', 'user-456', 'Hello everyone!', {
|
|
741
|
+
mentions: ['user-789']
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
// Typing indicator
|
|
745
|
+
await chat.startTyping('room-123', 'user-456', 'John');
|
|
746
|
+
|
|
747
|
+
// Send notification
|
|
748
|
+
await notifications.send(
|
|
749
|
+
'user-123',
|
|
750
|
+
'message',
|
|
751
|
+
'New Message',
|
|
752
|
+
'You have a new message from John'
|
|
753
|
+
);
|
|
754
|
+
|
|
755
|
+
// Broadcast live event
|
|
756
|
+
await wsService.broadcastToAll('analytics:update', {
|
|
757
|
+
metric: 'active_users',
|
|
758
|
+
value: 1250
|
|
759
|
+
});
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
**Client-side:**
|
|
763
|
+
|
|
764
|
+
```typescript
|
|
765
|
+
import { io } from 'socket.io-client';
|
|
766
|
+
|
|
767
|
+
const socket = io('http://localhost:3000', {
|
|
768
|
+
auth: { token: 'your-jwt-token' },
|
|
769
|
+
query: { username: 'john' }
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
// Listen for events
|
|
773
|
+
socket.on('chat:message', (msg) => console.log('New message:', msg));
|
|
774
|
+
socket.on('presence:status', (status) => console.log('Status:', status));
|
|
775
|
+
socket.on('notification:new', (notif) => console.log('Notification:', notif));
|
|
776
|
+
socket.on('live:event', (event) => console.log('Live event:', event));
|
|
777
|
+
|
|
778
|
+
// Send message
|
|
779
|
+
socket.emit('chat:send', { roomId: 'room-123', content: 'Hello!' });
|
|
780
|
+
|
|
781
|
+
// Start typing
|
|
782
|
+
socket.emit('chat:typing', { roomId: 'room-123' });
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
**Middlewares:**
|
|
786
|
+
|
|
787
|
+
```typescript
|
|
788
|
+
import {
|
|
789
|
+
authMiddleware,
|
|
790
|
+
rateLimitMiddleware,
|
|
791
|
+
roleMiddleware,
|
|
792
|
+
throttleMiddleware
|
|
793
|
+
} from './modules/websocket';
|
|
794
|
+
|
|
795
|
+
// Apply middlewares
|
|
796
|
+
io.use(authMiddleware());
|
|
797
|
+
io.use(rateLimitMiddleware(5, 60000)); // 5 connections per minute
|
|
798
|
+
io.use(roleMiddleware(['user', 'admin']));
|
|
799
|
+
io.use(throttleMiddleware(100, 1000)); // 100 events per second
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
**Features:**
|
|
803
|
+
|
|
804
|
+
- **Chat**: Messages, typing indicators, mentions, edit/delete
|
|
805
|
+
- **Presence**: Online/away/busy status, last seen
|
|
806
|
+
- **Notifications**: Real-time push, read/unread tracking
|
|
807
|
+
- **Live Events**: Analytics, system updates, custom events
|
|
808
|
+
- **Rooms**: Create, join, leave, member management
|
|
809
|
+
- **Broadcasting**: To all, to room, to specific users
|
|
810
|
+
|
|
811
|
+
### Search (Elasticsearch/Meilisearch)
|
|
812
|
+
|
|
813
|
+
Full-text search with support for Elasticsearch, Meilisearch, or in-memory adapter for development:
|
|
814
|
+
|
|
815
|
+
**Features:**
|
|
816
|
+
- Multiple search engines: Elasticsearch, Meilisearch, In-memory
|
|
817
|
+
- Unified interface for all engines
|
|
818
|
+
- Full-text search with fuzzy matching
|
|
819
|
+
- Filtering, sorting, pagination
|
|
820
|
+
- Faceted search
|
|
821
|
+
- Autocomplete suggestions
|
|
822
|
+
- Similar document search
|
|
823
|
+
- Bulk indexing
|
|
824
|
+
- Index management & statistics
|
|
825
|
+
|
|
826
|
+
**Usage:**
|
|
827
|
+
|
|
828
|
+
```typescript
|
|
829
|
+
import {
|
|
830
|
+
SearchService,
|
|
831
|
+
ElasticsearchAdapter,
|
|
832
|
+
MeilisearchAdapter,
|
|
833
|
+
MemorySearchAdapter
|
|
834
|
+
} from './modules/search';
|
|
835
|
+
|
|
836
|
+
// Using Elasticsearch
|
|
837
|
+
import { Client } from '@elastic/elasticsearch';
|
|
838
|
+
const esClient = new Client({ node: 'http://localhost:9200' });
|
|
839
|
+
const searchService = new SearchService(
|
|
840
|
+
{ engine: 'elasticsearch' },
|
|
841
|
+
new ElasticsearchAdapter(esClient)
|
|
842
|
+
);
|
|
843
|
+
|
|
844
|
+
// Or Meilisearch
|
|
845
|
+
import { MeiliSearch } from 'meilisearch';
|
|
846
|
+
const meiliClient = new MeiliSearch({ host: 'http://localhost:7700' });
|
|
847
|
+
const searchService = new SearchService(
|
|
848
|
+
{ engine: 'meilisearch' },
|
|
849
|
+
new MeilisearchAdapter(meiliClient)
|
|
850
|
+
);
|
|
851
|
+
|
|
852
|
+
// Or in-memory (for development)
|
|
853
|
+
const searchService = new SearchService(); // Uses MemorySearchAdapter by default
|
|
854
|
+
|
|
855
|
+
// Create an index
|
|
856
|
+
await searchService.createIndex('products', {
|
|
857
|
+
searchableAttributes: ['title', 'description', 'tags'],
|
|
858
|
+
filterableAttributes: ['category', 'price', 'inStock'],
|
|
859
|
+
sortableAttributes: ['price', 'createdAt']
|
|
860
|
+
});
|
|
861
|
+
|
|
862
|
+
// Index documents
|
|
863
|
+
await searchService.indexDocuments('products', [
|
|
864
|
+
{
|
|
865
|
+
id: '1',
|
|
866
|
+
title: 'Laptop',
|
|
867
|
+
description: 'High-performance laptop',
|
|
868
|
+
category: 'electronics',
|
|
869
|
+
price: 999,
|
|
870
|
+
inStock: true
|
|
871
|
+
},
|
|
872
|
+
{
|
|
873
|
+
id: '2',
|
|
874
|
+
title: 'Headphones',
|
|
875
|
+
description: 'Noise-canceling headphones',
|
|
876
|
+
category: 'electronics',
|
|
877
|
+
price: 299,
|
|
878
|
+
inStock: true
|
|
879
|
+
}
|
|
880
|
+
]);
|
|
881
|
+
|
|
882
|
+
// Search
|
|
883
|
+
const results = await searchService.search('products', {
|
|
884
|
+
query: 'laptop',
|
|
885
|
+
filters: [
|
|
886
|
+
{ field: 'category', operator: 'eq', value: 'electronics' },
|
|
887
|
+
{ field: 'price', operator: 'lte', value: 1000 }
|
|
888
|
+
],
|
|
889
|
+
sort: [{ field: 'price', direction: 'asc' }],
|
|
890
|
+
limit: 10
|
|
891
|
+
});
|
|
892
|
+
|
|
893
|
+
// Autocomplete
|
|
894
|
+
const suggestions = await searchService.autocomplete('products', 'lap', 5);
|
|
895
|
+
|
|
896
|
+
// Search with facets
|
|
897
|
+
const facetResults = await searchService.searchWithFacets('products', 'laptop', {
|
|
898
|
+
facets: ['category', 'inStock'],
|
|
899
|
+
filters: [{ field: 'price', operator: 'gte', value: 100 }]
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
// Similar documents
|
|
903
|
+
const similar = await searchService.searchSimilar('products', '1', 5);
|
|
904
|
+
|
|
905
|
+
// Reindex (with transformation)
|
|
906
|
+
await searchService.reindex('products', 'products_v2', (doc) => ({
|
|
907
|
+
...doc,
|
|
908
|
+
slug: doc.title.toLowerCase().replace(/\s+/g, '-')
|
|
909
|
+
}));
|
|
910
|
+
```
|
|
911
|
+
|
|
912
|
+
**Integration Example:**
|
|
913
|
+
|
|
914
|
+
```typescript
|
|
915
|
+
// Product search endpoint
|
|
916
|
+
app.get('/api/products/search', async (req, res) => {
|
|
917
|
+
const { q, category, minPrice, maxPrice, sort } = req.query;
|
|
918
|
+
|
|
919
|
+
const filters = [];
|
|
920
|
+
if (category) {
|
|
921
|
+
filters.push({ field: 'category', operator: 'eq', value: category });
|
|
922
|
+
}
|
|
923
|
+
if (minPrice) {
|
|
924
|
+
filters.push({ field: 'price', operator: 'gte', value: Number(minPrice) });
|
|
925
|
+
}
|
|
926
|
+
if (maxPrice) {
|
|
927
|
+
filters.push({ field: 'price', operator: 'lte', value: Number(maxPrice) });
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
const results = await searchService.search('products', {
|
|
931
|
+
query: q || '*',
|
|
932
|
+
filters,
|
|
933
|
+
sort: sort ? [{ field: sort, direction: 'asc' }] : undefined,
|
|
934
|
+
limit: 20
|
|
935
|
+
});
|
|
936
|
+
|
|
937
|
+
res.json(results);
|
|
938
|
+
});
|
|
939
|
+
|
|
940
|
+
// Autocomplete endpoint
|
|
941
|
+
app.get('/api/products/autocomplete', async (req, res) => {
|
|
942
|
+
const { q } = req.query;
|
|
943
|
+
const suggestions = await searchService.autocomplete('products', q, 10);
|
|
944
|
+
res.json(suggestions);
|
|
945
|
+
});
|
|
946
|
+
|
|
947
|
+
// Index product when created
|
|
948
|
+
app.post('/api/products', async (req, res) => {
|
|
949
|
+
const product = await db.product.create(req.body);
|
|
950
|
+
|
|
951
|
+
// Index in search engine
|
|
952
|
+
await searchService.indexDocument('products', product.id, product);
|
|
953
|
+
|
|
954
|
+
res.json(product);
|
|
955
|
+
});
|
|
956
|
+
```
|
|
957
|
+
|
|
958
|
+
**Filter Operators:**
|
|
959
|
+
|
|
960
|
+
- `eq` - Equal to
|
|
961
|
+
- `ne` - Not equal to
|
|
962
|
+
- `gt` - Greater than
|
|
963
|
+
- `gte` - Greater than or equal to
|
|
964
|
+
- `lt` - Less than
|
|
965
|
+
- `lte` - Less than or equal to
|
|
966
|
+
- `in` - In array
|
|
967
|
+
- `nin` - Not in array
|
|
968
|
+
- `contains` - Contains text
|
|
969
|
+
- `exists` - Field exists
|
|
970
|
+
|
|
971
|
+
**Index Statistics:**
|
|
972
|
+
|
|
973
|
+
```typescript
|
|
974
|
+
const stats = await searchService.getStats('products');
|
|
975
|
+
console.log({
|
|
976
|
+
documentCount: stats.documentCount,
|
|
977
|
+
size: stats.size,
|
|
978
|
+
isIndexing: stats.isIndexing,
|
|
979
|
+
health: stats.health
|
|
980
|
+
});
|
|
981
|
+
```
|
|
982
|
+
|
|
983
|
+
### i18n/Localization
|
|
984
|
+
|
|
985
|
+
Multi-language support with automatic locale detection and translation management:
|
|
986
|
+
|
|
987
|
+
**Features:**
|
|
988
|
+
- Multiple locale support
|
|
989
|
+
- Automatic locale detection (query, cookie, header)
|
|
990
|
+
- Translation loading from files or in-memory
|
|
991
|
+
- Variable interpolation
|
|
992
|
+
- Pluralization support
|
|
993
|
+
- Date, number, currency formatting
|
|
994
|
+
- Relative time formatting
|
|
995
|
+
- Translation metadata & missing keys tracking
|
|
996
|
+
- Nested translation keys
|
|
997
|
+
- Namespace organization
|
|
998
|
+
|
|
999
|
+
**Usage:**
|
|
1000
|
+
|
|
1001
|
+
```typescript
|
|
1002
|
+
import {
|
|
1003
|
+
I18nService,
|
|
1004
|
+
createI18nMiddleware,
|
|
1005
|
+
createI18nRoutes
|
|
1006
|
+
} from './modules/i18n';
|
|
1007
|
+
|
|
1008
|
+
// Create service
|
|
1009
|
+
const i18nService = new I18nService({
|
|
1010
|
+
defaultLocale: 'en',
|
|
1011
|
+
supportedLocales: ['en', 'fr', 'es', 'de', 'ar', 'zh', 'ja'],
|
|
1012
|
+
fallbackLocale: 'en',
|
|
1013
|
+
translationsDir: './locales',
|
|
1014
|
+
cache: true
|
|
1015
|
+
});
|
|
1016
|
+
|
|
1017
|
+
// Load translations from files
|
|
1018
|
+
await i18nService.loadTranslations('en', 'common');
|
|
1019
|
+
await i18nService.loadTranslations('fr', 'common');
|
|
1020
|
+
|
|
1021
|
+
// Or add translations programmatically
|
|
1022
|
+
i18nService.addTranslations({
|
|
1023
|
+
locale: 'en',
|
|
1024
|
+
namespace: 'common',
|
|
1025
|
+
data: {
|
|
1026
|
+
welcome: 'Welcome',
|
|
1027
|
+
greeting: 'Hello, {{name}}!',
|
|
1028
|
+
items: 'You have {{count}} item{s}',
|
|
1029
|
+
user: {
|
|
1030
|
+
profile: {
|
|
1031
|
+
title: 'User Profile',
|
|
1032
|
+
edit: 'Edit Profile'
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
});
|
|
1037
|
+
|
|
1038
|
+
// Apply middleware
|
|
1039
|
+
app.use(createI18nMiddleware(i18nService, {
|
|
1040
|
+
queryParam: 'lang',
|
|
1041
|
+
cookieName: 'locale',
|
|
1042
|
+
detectFromHeader: true
|
|
1043
|
+
}));
|
|
1044
|
+
|
|
1045
|
+
// Add routes
|
|
1046
|
+
app.use('/api/i18n', createI18nRoutes(i18nService));
|
|
1047
|
+
|
|
1048
|
+
// Use in controllers
|
|
1049
|
+
app.get('/api/welcome', (req, res) => {
|
|
1050
|
+
const message = req.t('welcome');
|
|
1051
|
+
res.json({ message });
|
|
1052
|
+
});
|
|
1053
|
+
```
|
|
1054
|
+
|
|
1055
|
+
**Translation Features:**
|
|
1056
|
+
|
|
1057
|
+
```typescript
|
|
1058
|
+
// Simple translation
|
|
1059
|
+
i18nService.t('welcome', { locale: 'en' });
|
|
1060
|
+
// => 'Welcome'
|
|
1061
|
+
|
|
1062
|
+
// Variable interpolation
|
|
1063
|
+
i18nService.t('greeting', {
|
|
1064
|
+
locale: 'en',
|
|
1065
|
+
variables: { name: 'John' }
|
|
1066
|
+
});
|
|
1067
|
+
// => 'Hello, John!'
|
|
1068
|
+
|
|
1069
|
+
// Pluralization
|
|
1070
|
+
i18nService.t('items', {
|
|
1071
|
+
locale: 'en',
|
|
1072
|
+
count: 1,
|
|
1073
|
+
variables: { count: 1 }
|
|
1074
|
+
});
|
|
1075
|
+
// => 'You have 1 item'
|
|
1076
|
+
|
|
1077
|
+
i18nService.t('items', {
|
|
1078
|
+
locale: 'en',
|
|
1079
|
+
count: 5,
|
|
1080
|
+
variables: { count: 5 }
|
|
1081
|
+
});
|
|
1082
|
+
// => 'You have 5 items'
|
|
1083
|
+
|
|
1084
|
+
// Nested keys
|
|
1085
|
+
i18nService.t('user.profile.title', { locale: 'en' });
|
|
1086
|
+
// => 'User Profile'
|
|
1087
|
+
|
|
1088
|
+
// With default value
|
|
1089
|
+
i18nService.t('missing.key', {
|
|
1090
|
+
locale: 'en',
|
|
1091
|
+
defaultValue: 'Fallback text'
|
|
1092
|
+
});
|
|
1093
|
+
// => 'Fallback text'
|
|
1094
|
+
```
|
|
1095
|
+
|
|
1096
|
+
**Formatting:**
|
|
1097
|
+
|
|
1098
|
+
```typescript
|
|
1099
|
+
// Date formatting
|
|
1100
|
+
i18nService.formatDate(new Date(), 'en', {
|
|
1101
|
+
dateStyle: 'full',
|
|
1102
|
+
timeStyle: 'short'
|
|
1103
|
+
});
|
|
1104
|
+
// => 'Monday, January 1, 2024 at 10:30 AM'
|
|
1105
|
+
|
|
1106
|
+
// Number formatting
|
|
1107
|
+
i18nService.formatNumber(1234567.89, 'en', {
|
|
1108
|
+
minimumFractionDigits: 2
|
|
1109
|
+
});
|
|
1110
|
+
// => '1,234,567.89'
|
|
1111
|
+
|
|
1112
|
+
// Currency formatting
|
|
1113
|
+
i18nService.formatCurrency(99.99, 'en', 'USD');
|
|
1114
|
+
// => '$99.99'
|
|
1115
|
+
|
|
1116
|
+
i18nService.formatCurrency(99.99, 'fr', 'EUR');
|
|
1117
|
+
// => '99,99 €'
|
|
1118
|
+
|
|
1119
|
+
// Relative time
|
|
1120
|
+
i18nService.formatRelativeTime(new Date(Date.now() - 3600000), 'en');
|
|
1121
|
+
// => '1 hour ago'
|
|
1122
|
+
```
|
|
1123
|
+
|
|
1124
|
+
**Locale Detection:**
|
|
1125
|
+
|
|
1126
|
+
The middleware automatically detects locale from:
|
|
1127
|
+
1. Query parameter (?lang=fr)
|
|
1128
|
+
2. Cookie (locale=fr)
|
|
1129
|
+
3. Accept-Language header
|
|
1130
|
+
4. Default locale (fallback)
|
|
1131
|
+
|
|
1132
|
+
```typescript
|
|
1133
|
+
// Detection result available in request
|
|
1134
|
+
app.get('/api/info', (req, res) => {
|
|
1135
|
+
res.json({
|
|
1136
|
+
locale: req.locale,
|
|
1137
|
+
detection: req.localeDetection // { locale, source, confidence }
|
|
1138
|
+
});
|
|
1139
|
+
});
|
|
1140
|
+
```
|
|
1141
|
+
|
|
1142
|
+
**API Routes:**
|
|
1143
|
+
|
|
1144
|
+
```
|
|
1145
|
+
GET /i18n/locales List supported locales
|
|
1146
|
+
GET /i18n/locale Get current locale
|
|
1147
|
+
POST /i18n/locale Switch locale
|
|
1148
|
+
GET /i18n/translations/:namespace Get translations
|
|
1149
|
+
GET /i18n/translations/:namespace/metadata Get metadata
|
|
1150
|
+
GET /i18n/translations/:namespace/missing Get missing keys
|
|
1151
|
+
POST /i18n/translate Translate a key
|
|
1152
|
+
POST /i18n/cache/clear Clear cache
|
|
1153
|
+
```
|
|
1154
|
+
|
|
1155
|
+
**Translation File Structure:**
|
|
1156
|
+
|
|
1157
|
+
```
|
|
1158
|
+
locales/
|
|
1159
|
+
├── en/
|
|
1160
|
+
│ ├── common.json
|
|
1161
|
+
│ ├── errors.json
|
|
1162
|
+
│ └── emails.json
|
|
1163
|
+
├── fr/
|
|
1164
|
+
│ ├── common.json
|
|
1165
|
+
│ ├── errors.json
|
|
1166
|
+
│ └── emails.json
|
|
1167
|
+
└── es/
|
|
1168
|
+
├── common.json
|
|
1169
|
+
├── errors.json
|
|
1170
|
+
└── emails.json
|
|
1171
|
+
```
|
|
1172
|
+
|
|
1173
|
+
**common.json example:**
|
|
1174
|
+
|
|
1175
|
+
```json
|
|
1176
|
+
{
|
|
1177
|
+
"welcome": "Welcome",
|
|
1178
|
+
"greeting": "Hello, {{name}}!",
|
|
1179
|
+
"farewell": "Goodbye",
|
|
1180
|
+
"nav": {
|
|
1181
|
+
"home": "Home",
|
|
1182
|
+
"about": "About",
|
|
1183
|
+
"contact": "Contact"
|
|
1184
|
+
},
|
|
1185
|
+
"errors": {
|
|
1186
|
+
"notFound": "Not found",
|
|
1187
|
+
"serverError": "Server error"
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
```
|
|
1191
|
+
|
|
1192
|
+
**Tracking Translation Progress:**
|
|
1193
|
+
|
|
1194
|
+
```typescript
|
|
1195
|
+
// Get metadata
|
|
1196
|
+
const metadata = await i18nService.getTranslationMetadata('fr', 'common');
|
|
1197
|
+
console.log({
|
|
1198
|
+
totalKeys: metadata.totalKeys,
|
|
1199
|
+
translatedKeys: metadata.translatedKeys,
|
|
1200
|
+
completionPercentage: metadata.completionPercentage
|
|
1201
|
+
});
|
|
1202
|
+
|
|
1203
|
+
// Get missing translations
|
|
1204
|
+
const missing = i18nService.getMissingTranslations('en', 'fr', 'common');
|
|
1205
|
+
console.log('Missing keys:', missing);
|
|
1206
|
+
```
|
|
1207
|
+
|
|
1208
|
+
## Modules & Resources
|
|
1209
|
+
|
|
1210
|
+
ServCraft includes these pre-built modules:
|
|
1211
|
+
|
|
1212
|
+
### Core Modules
|
|
1213
|
+
- ✅ **Authentication** - JWT access/refresh tokens, RBAC
|
|
1214
|
+
- ✅ **User Management** - Full CRUD with roles & permissions
|
|
1215
|
+
- ✅ **Email Service** - SMTP with Handlebars templates
|
|
1216
|
+
- ✅ **Audit Logging** - Activity tracking & audit trail
|
|
1217
|
+
|
|
1218
|
+
### Advanced Features
|
|
1219
|
+
- ✅ **Cache Module** - Redis caching with TTL & invalidation
|
|
1220
|
+
- ✅ **Rate Limiting** - Fixed/sliding window, token bucket algorithms
|
|
1221
|
+
- ✅ **Webhooks (Outgoing)** - HMAC signatures, auto-retry, delivery tracking
|
|
1222
|
+
- ✅ **Queue/Jobs** - Background tasks, cron scheduling, 10+ workers
|
|
1223
|
+
- ✅ **Websockets/Real-time** - Chat, presence, notifications, live events
|
|
1224
|
+
- ✅ **Search** - Elasticsearch/Meilisearch full-text search
|
|
1225
|
+
- ✅ **i18n/Localization** - Multi-language support with 7+ locales
|
|
1226
|
+
- ✅ **Feature Flags** - A/B testing, progressive rollout, user targeting
|
|
1227
|
+
- ✅ **Analytics/Metrics** - Prometheus metrics, counters, gauges, histograms
|
|
1228
|
+
- ✅ **Media Processing** - Image/video processing with FFmpeg, thumbnails
|
|
1229
|
+
- ✅ **API Versioning** - Multiple API versions with migrations
|
|
1230
|
+
- ✅ **File Upload** - Multi-provider support (local, S3, etc.)
|
|
1231
|
+
- ✅ **MFA/TOTP** - Two-factor authentication with QR codes
|
|
1232
|
+
- ✅ **OAuth** - Google, GitHub, Facebook, Twitter, Apple
|
|
1233
|
+
- ✅ **Payments** - Stripe, PayPal, Mobile Money integration
|
|
1234
|
+
- ✅ **Notifications** - Email, SMS, Push notifications
|
|
1235
|
+
|
|
167
1236
|
## API Endpoints
|
|
168
1237
|
|
|
169
1238
|
### Authentication
|