@noony-serverless/core 0.1.1 → 0.2.0
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/build/core/core.d.ts +16 -48
- package/build/core/core.js +2 -61
- package/build/core/handler.d.ts +37 -16
- package/build/core/handler.js +131 -42
- package/build/core/index.d.ts +0 -1
- package/build/core/index.js +0 -1
- package/build/middlewares/ConsolidatedValidationMiddleware.d.ts +126 -0
- package/build/middlewares/ConsolidatedValidationMiddleware.js +330 -0
- package/build/middlewares/ProcessingMiddleware.d.ts +138 -0
- package/build/middlewares/ProcessingMiddleware.js +425 -0
- package/build/middlewares/SecurityMiddleware.d.ts +157 -0
- package/build/middlewares/SecurityMiddleware.js +307 -0
- package/build/middlewares/authenticationMiddleware.d.ts +379 -0
- package/build/middlewares/authenticationMiddleware.js +216 -0
- package/build/middlewares/bodyParserMiddleware.d.ts +99 -0
- package/build/middlewares/bodyParserMiddleware.js +99 -0
- package/build/middlewares/bodyValidationMiddleware.d.ts +69 -3
- package/build/middlewares/bodyValidationMiddleware.js +68 -2
- package/build/middlewares/dependencyInjectionMiddleware.d.ts +238 -0
- package/build/middlewares/dependencyInjectionMiddleware.js +238 -0
- package/build/middlewares/errorHandlerMiddleware.d.ts +94 -0
- package/build/middlewares/errorHandlerMiddleware.js +105 -0
- package/build/middlewares/guards/RouteGuards.d.ts +476 -21
- package/build/middlewares/guards/RouteGuards.js +418 -21
- package/build/middlewares/guards/adapters/CustomTokenVerificationPortAdapter.d.ts +271 -0
- package/build/middlewares/guards/adapters/CustomTokenVerificationPortAdapter.js +301 -0
- package/build/middlewares/guards/cache/CacheAdapter.d.ts +369 -28
- package/build/middlewares/guards/cache/CacheAdapter.js +124 -5
- package/build/middlewares/guards/cache/MemoryCacheAdapter.d.ts +113 -4
- package/build/middlewares/guards/cache/MemoryCacheAdapter.js +113 -4
- package/build/middlewares/guards/config/GuardConfiguration.d.ts +568 -18
- package/build/middlewares/guards/config/GuardConfiguration.js +266 -10
- package/build/middlewares/guards/guards/FastAuthGuard.d.ts +5 -5
- package/build/middlewares/guards/guards/PermissionGuardFactory.d.ts +5 -13
- package/build/middlewares/guards/guards/PermissionGuardFactory.js +4 -4
- package/build/middlewares/guards/index.d.ts +43 -1
- package/build/middlewares/guards/index.js +46 -1
- package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.js +1 -1
- package/build/middlewares/guards/resolvers/PermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/resolvers/PlainPermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/resolvers/WildcardPermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/services/FastUserContextService.d.ts +20 -33
- package/build/middlewares/guards/services/FastUserContextService.js +19 -5
- package/build/middlewares/headerVariablesMiddleware.d.ts +118 -0
- package/build/middlewares/headerVariablesMiddleware.js +118 -0
- package/build/middlewares/httpAttributesMiddleware.d.ts +235 -0
- package/build/middlewares/httpAttributesMiddleware.js +236 -1
- package/build/middlewares/index.d.ts +3 -1
- package/build/middlewares/index.js +6 -1
- package/build/middlewares/queryParametersMiddleware.d.ts +105 -0
- package/build/middlewares/queryParametersMiddleware.js +105 -0
- package/build/middlewares/rateLimitingMiddleware.d.ts +601 -9
- package/build/middlewares/rateLimitingMiddleware.js +623 -11
- package/build/middlewares/responseWrapperMiddleware.d.ts +170 -1
- package/build/middlewares/responseWrapperMiddleware.js +170 -1
- package/build/middlewares/securityAuditMiddleware.js +5 -5
- package/package.json +11 -9
- package/build/core/containerPool.d.ts +0 -44
- package/build/core/containerPool.js +0 -103
- package/build/middlewares/validationMiddleware.d.ts +0 -9
- package/build/middlewares/validationMiddleware.js +0 -40
|
@@ -1,4 +1,150 @@
|
|
|
1
1
|
import { BaseMiddleware, Context } from '../core';
|
|
2
|
+
/**
|
|
3
|
+
* Middleware to inject dependencies into the request context using typedi.
|
|
4
|
+
* This allows handlers to access shared services or data via context.container.
|
|
5
|
+
*
|
|
6
|
+
* @implements {BaseMiddleware}
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* Basic service injection:
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { Container } from 'typedi';
|
|
12
|
+
* import { Handler, DependencyInjectionMiddleware } from '@noony-serverless/core';
|
|
13
|
+
*
|
|
14
|
+
* // Define services
|
|
15
|
+
* class UserService {
|
|
16
|
+
* constructor(private userRepo: Map<string, any>) {}
|
|
17
|
+
*
|
|
18
|
+
* async findById(id: string) {
|
|
19
|
+
* return this.userRepo.get(id);
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* async create(userData: any) {
|
|
23
|
+
* const id = generateId();
|
|
24
|
+
* this.userRepo.set(id, { id, ...userData });
|
|
25
|
+
* return { id, ...userData };
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
*
|
|
29
|
+
* class EmailService {
|
|
30
|
+
* async sendWelcomeEmail(email: string) {
|
|
31
|
+
* console.log(`Sending welcome email to ${email}`);
|
|
32
|
+
* return { sent: true, email };
|
|
33
|
+
* }
|
|
34
|
+
* }
|
|
35
|
+
*
|
|
36
|
+
* // Initialize services
|
|
37
|
+
* const services = [
|
|
38
|
+
* { id: UserService, value: new UserService(new Map()) },
|
|
39
|
+
* { id: EmailService, value: new EmailService() },
|
|
40
|
+
* { id: 'config', value: { apiUrl: 'https://api.example.com' } }
|
|
41
|
+
* ];
|
|
42
|
+
*
|
|
43
|
+
* const userHandler = new Handler()
|
|
44
|
+
* .use(new DependencyInjectionMiddleware(services))
|
|
45
|
+
* .handle(async (context) => {
|
|
46
|
+
* const userService = context.container?.get(UserService);
|
|
47
|
+
* const emailService = context.container?.get(EmailService);
|
|
48
|
+
* const config = context.container?.get('config');
|
|
49
|
+
*
|
|
50
|
+
* const user = await userService.create({ name: 'John', email: 'john@example.com' });
|
|
51
|
+
* await emailService.sendWelcomeEmail(user.email);
|
|
52
|
+
*
|
|
53
|
+
* return { success: true, user, apiUrl: config.apiUrl };
|
|
54
|
+
* });
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* Database and caching services:
|
|
59
|
+
* ```typescript
|
|
60
|
+
* class DatabaseService {
|
|
61
|
+
* async query(sql: string, params: any[]) {
|
|
62
|
+
* // Mock database query
|
|
63
|
+
* return { rows: [{ id: 1, name: 'Test' }] };
|
|
64
|
+
* }
|
|
65
|
+
* }
|
|
66
|
+
*
|
|
67
|
+
* class CacheService {
|
|
68
|
+
* private cache = new Map();
|
|
69
|
+
*
|
|
70
|
+
* get(key: string) {
|
|
71
|
+
* return this.cache.get(key);
|
|
72
|
+
* }
|
|
73
|
+
*
|
|
74
|
+
* set(key: string, value: any, ttl: number = 3600) {
|
|
75
|
+
* this.cache.set(key, value);
|
|
76
|
+
* setTimeout(() => this.cache.delete(key), ttl * 1000);
|
|
77
|
+
* }
|
|
78
|
+
* }
|
|
79
|
+
*
|
|
80
|
+
* const services = [
|
|
81
|
+
* { id: 'db', value: new DatabaseService() },
|
|
82
|
+
* { id: 'cache', value: new CacheService() }
|
|
83
|
+
* ];
|
|
84
|
+
*
|
|
85
|
+
* const dataHandler = new Handler()
|
|
86
|
+
* .use(new DependencyInjectionMiddleware(services))
|
|
87
|
+
* .handle(async (context) => {
|
|
88
|
+
* const db = context.container?.get('db');
|
|
89
|
+
* const cache = context.container?.get('cache');
|
|
90
|
+
*
|
|
91
|
+
* const cacheKey = `users:${context.params.id}`;
|
|
92
|
+
* let user = cache.get(cacheKey);
|
|
93
|
+
*
|
|
94
|
+
* if (!user) {
|
|
95
|
+
* const result = await db.query('SELECT * FROM users WHERE id = ?', [context.params.id]);
|
|
96
|
+
* user = result.rows[0];
|
|
97
|
+
* cache.set(cacheKey, user);
|
|
98
|
+
* }
|
|
99
|
+
*
|
|
100
|
+
* return { success: true, user, fromCache: !!cache.get(cacheKey) };
|
|
101
|
+
* });
|
|
102
|
+
* ```
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* Business logic services with complex dependencies:
|
|
106
|
+
* ```typescript
|
|
107
|
+
* class PaymentService {
|
|
108
|
+
* async processPayment(amount: number, method: string) {
|
|
109
|
+
* return { transactionId: 'txn_123', status: 'completed', amount };
|
|
110
|
+
* }
|
|
111
|
+
* }
|
|
112
|
+
*
|
|
113
|
+
* class OrderService {
|
|
114
|
+
* constructor(
|
|
115
|
+
* private paymentService: PaymentService,
|
|
116
|
+
* private emailService: EmailService,
|
|
117
|
+
* private inventoryService: any
|
|
118
|
+
* ) {}
|
|
119
|
+
*
|
|
120
|
+
* async createOrder(orderData: any) {
|
|
121
|
+
* // Complex business logic
|
|
122
|
+
* const payment = await this.paymentService.processPayment(orderData.total, orderData.paymentMethod);
|
|
123
|
+
* await this.emailService.sendWelcomeEmail(orderData.customerEmail);
|
|
124
|
+
* return { orderId: 'order_123', payment };
|
|
125
|
+
* }
|
|
126
|
+
* }
|
|
127
|
+
*
|
|
128
|
+
* const paymentService = new PaymentService();
|
|
129
|
+
* const emailService = new EmailService();
|
|
130
|
+
* const inventoryService = { checkStock: () => true };
|
|
131
|
+
*
|
|
132
|
+
* const services = [
|
|
133
|
+
* { id: PaymentService, value: paymentService },
|
|
134
|
+
* { id: EmailService, value: emailService },
|
|
135
|
+
* { id: 'inventory', value: inventoryService },
|
|
136
|
+
* { id: OrderService, value: new OrderService(paymentService, emailService, inventoryService) }
|
|
137
|
+
* ];
|
|
138
|
+
*
|
|
139
|
+
* const checkoutHandler = new Handler()
|
|
140
|
+
* .use(new DependencyInjectionMiddleware(services))
|
|
141
|
+
* .handle(async (context) => {
|
|
142
|
+
* const orderService = context.container?.get(OrderService);
|
|
143
|
+
* const order = await orderService.createOrder(context.req.parsedBody);
|
|
144
|
+
* return { success: true, order };
|
|
145
|
+
* });
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
2
148
|
export declare class DependencyInjectionMiddleware implements BaseMiddleware {
|
|
3
149
|
private services;
|
|
4
150
|
constructor(services: {
|
|
@@ -7,6 +153,98 @@ export declare class DependencyInjectionMiddleware implements BaseMiddleware {
|
|
|
7
153
|
}[]);
|
|
8
154
|
before(context: Context): Promise<void>;
|
|
9
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Factory function that creates a dependency injection middleware.
|
|
158
|
+
* Creates a new container instance for each request to avoid shared state issues.
|
|
159
|
+
*
|
|
160
|
+
* @param services - Array of service definitions with id and value
|
|
161
|
+
* @returns BaseMiddleware object with dependency injection logic
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* Simple services injection:
|
|
165
|
+
* ```typescript
|
|
166
|
+
* import { Handler, dependencyInjection } from '@noony-serverless/core';
|
|
167
|
+
*
|
|
168
|
+
* const logger = {
|
|
169
|
+
* info: (msg: string) => console.log(`[INFO] ${msg}`),
|
|
170
|
+
* error: (msg: string) => console.error(`[ERROR] ${msg}`)
|
|
171
|
+
* };
|
|
172
|
+
*
|
|
173
|
+
* const config = {
|
|
174
|
+
* apiKey: process.env.API_KEY,
|
|
175
|
+
* environment: process.env.NODE_ENV
|
|
176
|
+
* };
|
|
177
|
+
*
|
|
178
|
+
* const services = [
|
|
179
|
+
* { id: 'logger', value: logger },
|
|
180
|
+
* { id: 'config', value: config }
|
|
181
|
+
* ];
|
|
182
|
+
*
|
|
183
|
+
* const apiHandler = new Handler()
|
|
184
|
+
* .use(dependencyInjection(services))
|
|
185
|
+
* .handle(async (context) => {
|
|
186
|
+
* const logger = context.container?.get('logger');
|
|
187
|
+
* const config = context.container?.get('config');
|
|
188
|
+
*
|
|
189
|
+
* logger.info(`Processing request in ${config.environment}`);
|
|
190
|
+
* return { success: true, environment: config.environment };
|
|
191
|
+
* });
|
|
192
|
+
* ```
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* Repository pattern with database:
|
|
196
|
+
* ```typescript
|
|
197
|
+
* class UserRepository {
|
|
198
|
+
* constructor(private db: any) {}
|
|
199
|
+
*
|
|
200
|
+
* async findAll() {
|
|
201
|
+
* return await this.db.users.findMany();
|
|
202
|
+
* }
|
|
203
|
+
*
|
|
204
|
+
* async findById(id: string) {
|
|
205
|
+
* return await this.db.users.findUnique({ where: { id } });
|
|
206
|
+
* }
|
|
207
|
+
* }
|
|
208
|
+
*
|
|
209
|
+
* const mockDb = {
|
|
210
|
+
* users: {
|
|
211
|
+
* findMany: () => Promise.resolve([{ id: '1', name: 'John' }]),
|
|
212
|
+
* findUnique: ({ where }: any) => Promise.resolve({ id: where.id, name: 'John' })
|
|
213
|
+
* }
|
|
214
|
+
* };
|
|
215
|
+
*
|
|
216
|
+
* const userRepo = new UserRepository(mockDb);
|
|
217
|
+
*
|
|
218
|
+
* const userHandler = new Handler()
|
|
219
|
+
* .use(dependencyInjection([
|
|
220
|
+
* { id: UserRepository, value: userRepo },
|
|
221
|
+
* { id: 'database', value: mockDb }
|
|
222
|
+
* ]))
|
|
223
|
+
* .handle(async (context) => {
|
|
224
|
+
* const repo = context.container?.get(UserRepository);
|
|
225
|
+
* const users = await repo.findAll();
|
|
226
|
+
* return { success: true, users };
|
|
227
|
+
* });
|
|
228
|
+
* ```
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* Empty services for middleware registration:
|
|
232
|
+
* ```typescript
|
|
233
|
+
* // Sometimes you just want to enable DI without initial services
|
|
234
|
+
* const baseHandler = new Handler()
|
|
235
|
+
* .use(dependencyInjection()) // Empty services array
|
|
236
|
+
* .use(async (context, next) => {
|
|
237
|
+
* // Add services dynamically based on request
|
|
238
|
+
* const requestService = new RequestSpecificService(context.req.headers);
|
|
239
|
+
* context.container?.set('requestService', requestService);
|
|
240
|
+
* return next();
|
|
241
|
+
* })
|
|
242
|
+
* .handle(async (context) => {
|
|
243
|
+
* const service = context.container?.get('requestService');
|
|
244
|
+
* return { success: true, data: service.process() };
|
|
245
|
+
* });
|
|
246
|
+
* ```
|
|
247
|
+
*/
|
|
10
248
|
export declare const dependencyInjection: (services?: {
|
|
11
249
|
id: any;
|
|
12
250
|
value: any;
|
|
@@ -3,6 +3,152 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.dependencyInjection = exports.DependencyInjectionMiddleware = void 0;
|
|
5
5
|
const typedi_1 = require("typedi");
|
|
6
|
+
/**
|
|
7
|
+
* Middleware to inject dependencies into the request context using typedi.
|
|
8
|
+
* This allows handlers to access shared services or data via context.container.
|
|
9
|
+
*
|
|
10
|
+
* @implements {BaseMiddleware}
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* Basic service injection:
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { Container } from 'typedi';
|
|
16
|
+
* import { Handler, DependencyInjectionMiddleware } from '@noony-serverless/core';
|
|
17
|
+
*
|
|
18
|
+
* // Define services
|
|
19
|
+
* class UserService {
|
|
20
|
+
* constructor(private userRepo: Map<string, any>) {}
|
|
21
|
+
*
|
|
22
|
+
* async findById(id: string) {
|
|
23
|
+
* return this.userRepo.get(id);
|
|
24
|
+
* }
|
|
25
|
+
*
|
|
26
|
+
* async create(userData: any) {
|
|
27
|
+
* const id = generateId();
|
|
28
|
+
* this.userRepo.set(id, { id, ...userData });
|
|
29
|
+
* return { id, ...userData };
|
|
30
|
+
* }
|
|
31
|
+
* }
|
|
32
|
+
*
|
|
33
|
+
* class EmailService {
|
|
34
|
+
* async sendWelcomeEmail(email: string) {
|
|
35
|
+
* console.log(`Sending welcome email to ${email}`);
|
|
36
|
+
* return { sent: true, email };
|
|
37
|
+
* }
|
|
38
|
+
* }
|
|
39
|
+
*
|
|
40
|
+
* // Initialize services
|
|
41
|
+
* const services = [
|
|
42
|
+
* { id: UserService, value: new UserService(new Map()) },
|
|
43
|
+
* { id: EmailService, value: new EmailService() },
|
|
44
|
+
* { id: 'config', value: { apiUrl: 'https://api.example.com' } }
|
|
45
|
+
* ];
|
|
46
|
+
*
|
|
47
|
+
* const userHandler = new Handler()
|
|
48
|
+
* .use(new DependencyInjectionMiddleware(services))
|
|
49
|
+
* .handle(async (context) => {
|
|
50
|
+
* const userService = context.container?.get(UserService);
|
|
51
|
+
* const emailService = context.container?.get(EmailService);
|
|
52
|
+
* const config = context.container?.get('config');
|
|
53
|
+
*
|
|
54
|
+
* const user = await userService.create({ name: 'John', email: 'john@example.com' });
|
|
55
|
+
* await emailService.sendWelcomeEmail(user.email);
|
|
56
|
+
*
|
|
57
|
+
* return { success: true, user, apiUrl: config.apiUrl };
|
|
58
|
+
* });
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* Database and caching services:
|
|
63
|
+
* ```typescript
|
|
64
|
+
* class DatabaseService {
|
|
65
|
+
* async query(sql: string, params: any[]) {
|
|
66
|
+
* // Mock database query
|
|
67
|
+
* return { rows: [{ id: 1, name: 'Test' }] };
|
|
68
|
+
* }
|
|
69
|
+
* }
|
|
70
|
+
*
|
|
71
|
+
* class CacheService {
|
|
72
|
+
* private cache = new Map();
|
|
73
|
+
*
|
|
74
|
+
* get(key: string) {
|
|
75
|
+
* return this.cache.get(key);
|
|
76
|
+
* }
|
|
77
|
+
*
|
|
78
|
+
* set(key: string, value: any, ttl: number = 3600) {
|
|
79
|
+
* this.cache.set(key, value);
|
|
80
|
+
* setTimeout(() => this.cache.delete(key), ttl * 1000);
|
|
81
|
+
* }
|
|
82
|
+
* }
|
|
83
|
+
*
|
|
84
|
+
* const services = [
|
|
85
|
+
* { id: 'db', value: new DatabaseService() },
|
|
86
|
+
* { id: 'cache', value: new CacheService() }
|
|
87
|
+
* ];
|
|
88
|
+
*
|
|
89
|
+
* const dataHandler = new Handler()
|
|
90
|
+
* .use(new DependencyInjectionMiddleware(services))
|
|
91
|
+
* .handle(async (context) => {
|
|
92
|
+
* const db = context.container?.get('db');
|
|
93
|
+
* const cache = context.container?.get('cache');
|
|
94
|
+
*
|
|
95
|
+
* const cacheKey = `users:${context.params.id}`;
|
|
96
|
+
* let user = cache.get(cacheKey);
|
|
97
|
+
*
|
|
98
|
+
* if (!user) {
|
|
99
|
+
* const result = await db.query('SELECT * FROM users WHERE id = ?', [context.params.id]);
|
|
100
|
+
* user = result.rows[0];
|
|
101
|
+
* cache.set(cacheKey, user);
|
|
102
|
+
* }
|
|
103
|
+
*
|
|
104
|
+
* return { success: true, user, fromCache: !!cache.get(cacheKey) };
|
|
105
|
+
* });
|
|
106
|
+
* ```
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* Business logic services with complex dependencies:
|
|
110
|
+
* ```typescript
|
|
111
|
+
* class PaymentService {
|
|
112
|
+
* async processPayment(amount: number, method: string) {
|
|
113
|
+
* return { transactionId: 'txn_123', status: 'completed', amount };
|
|
114
|
+
* }
|
|
115
|
+
* }
|
|
116
|
+
*
|
|
117
|
+
* class OrderService {
|
|
118
|
+
* constructor(
|
|
119
|
+
* private paymentService: PaymentService,
|
|
120
|
+
* private emailService: EmailService,
|
|
121
|
+
* private inventoryService: any
|
|
122
|
+
* ) {}
|
|
123
|
+
*
|
|
124
|
+
* async createOrder(orderData: any) {
|
|
125
|
+
* // Complex business logic
|
|
126
|
+
* const payment = await this.paymentService.processPayment(orderData.total, orderData.paymentMethod);
|
|
127
|
+
* await this.emailService.sendWelcomeEmail(orderData.customerEmail);
|
|
128
|
+
* return { orderId: 'order_123', payment };
|
|
129
|
+
* }
|
|
130
|
+
* }
|
|
131
|
+
*
|
|
132
|
+
* const paymentService = new PaymentService();
|
|
133
|
+
* const emailService = new EmailService();
|
|
134
|
+
* const inventoryService = { checkStock: () => true };
|
|
135
|
+
*
|
|
136
|
+
* const services = [
|
|
137
|
+
* { id: PaymentService, value: paymentService },
|
|
138
|
+
* { id: EmailService, value: emailService },
|
|
139
|
+
* { id: 'inventory', value: inventoryService },
|
|
140
|
+
* { id: OrderService, value: new OrderService(paymentService, emailService, inventoryService) }
|
|
141
|
+
* ];
|
|
142
|
+
*
|
|
143
|
+
* const checkoutHandler = new Handler()
|
|
144
|
+
* .use(new DependencyInjectionMiddleware(services))
|
|
145
|
+
* .handle(async (context) => {
|
|
146
|
+
* const orderService = context.container?.get(OrderService);
|
|
147
|
+
* const order = await orderService.createOrder(context.req.parsedBody);
|
|
148
|
+
* return { success: true, order };
|
|
149
|
+
* });
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
6
152
|
class DependencyInjectionMiddleware {
|
|
7
153
|
services;
|
|
8
154
|
constructor(services) {
|
|
@@ -16,6 +162,98 @@ class DependencyInjectionMiddleware {
|
|
|
16
162
|
}
|
|
17
163
|
}
|
|
18
164
|
exports.DependencyInjectionMiddleware = DependencyInjectionMiddleware;
|
|
165
|
+
/**
|
|
166
|
+
* Factory function that creates a dependency injection middleware.
|
|
167
|
+
* Creates a new container instance for each request to avoid shared state issues.
|
|
168
|
+
*
|
|
169
|
+
* @param services - Array of service definitions with id and value
|
|
170
|
+
* @returns BaseMiddleware object with dependency injection logic
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* Simple services injection:
|
|
174
|
+
* ```typescript
|
|
175
|
+
* import { Handler, dependencyInjection } from '@noony-serverless/core';
|
|
176
|
+
*
|
|
177
|
+
* const logger = {
|
|
178
|
+
* info: (msg: string) => console.log(`[INFO] ${msg}`),
|
|
179
|
+
* error: (msg: string) => console.error(`[ERROR] ${msg}`)
|
|
180
|
+
* };
|
|
181
|
+
*
|
|
182
|
+
* const config = {
|
|
183
|
+
* apiKey: process.env.API_KEY,
|
|
184
|
+
* environment: process.env.NODE_ENV
|
|
185
|
+
* };
|
|
186
|
+
*
|
|
187
|
+
* const services = [
|
|
188
|
+
* { id: 'logger', value: logger },
|
|
189
|
+
* { id: 'config', value: config }
|
|
190
|
+
* ];
|
|
191
|
+
*
|
|
192
|
+
* const apiHandler = new Handler()
|
|
193
|
+
* .use(dependencyInjection(services))
|
|
194
|
+
* .handle(async (context) => {
|
|
195
|
+
* const logger = context.container?.get('logger');
|
|
196
|
+
* const config = context.container?.get('config');
|
|
197
|
+
*
|
|
198
|
+
* logger.info(`Processing request in ${config.environment}`);
|
|
199
|
+
* return { success: true, environment: config.environment };
|
|
200
|
+
* });
|
|
201
|
+
* ```
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* Repository pattern with database:
|
|
205
|
+
* ```typescript
|
|
206
|
+
* class UserRepository {
|
|
207
|
+
* constructor(private db: any) {}
|
|
208
|
+
*
|
|
209
|
+
* async findAll() {
|
|
210
|
+
* return await this.db.users.findMany();
|
|
211
|
+
* }
|
|
212
|
+
*
|
|
213
|
+
* async findById(id: string) {
|
|
214
|
+
* return await this.db.users.findUnique({ where: { id } });
|
|
215
|
+
* }
|
|
216
|
+
* }
|
|
217
|
+
*
|
|
218
|
+
* const mockDb = {
|
|
219
|
+
* users: {
|
|
220
|
+
* findMany: () => Promise.resolve([{ id: '1', name: 'John' }]),
|
|
221
|
+
* findUnique: ({ where }: any) => Promise.resolve({ id: where.id, name: 'John' })
|
|
222
|
+
* }
|
|
223
|
+
* };
|
|
224
|
+
*
|
|
225
|
+
* const userRepo = new UserRepository(mockDb);
|
|
226
|
+
*
|
|
227
|
+
* const userHandler = new Handler()
|
|
228
|
+
* .use(dependencyInjection([
|
|
229
|
+
* { id: UserRepository, value: userRepo },
|
|
230
|
+
* { id: 'database', value: mockDb }
|
|
231
|
+
* ]))
|
|
232
|
+
* .handle(async (context) => {
|
|
233
|
+
* const repo = context.container?.get(UserRepository);
|
|
234
|
+
* const users = await repo.findAll();
|
|
235
|
+
* return { success: true, users };
|
|
236
|
+
* });
|
|
237
|
+
* ```
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* Empty services for middleware registration:
|
|
241
|
+
* ```typescript
|
|
242
|
+
* // Sometimes you just want to enable DI without initial services
|
|
243
|
+
* const baseHandler = new Handler()
|
|
244
|
+
* .use(dependencyInjection()) // Empty services array
|
|
245
|
+
* .use(async (context, next) => {
|
|
246
|
+
* // Add services dynamically based on request
|
|
247
|
+
* const requestService = new RequestSpecificService(context.req.headers);
|
|
248
|
+
* context.container?.set('requestService', requestService);
|
|
249
|
+
* return next();
|
|
250
|
+
* })
|
|
251
|
+
* .handle(async (context) => {
|
|
252
|
+
* const service = context.container?.get('requestService');
|
|
253
|
+
* return { success: true, data: service.process() };
|
|
254
|
+
* });
|
|
255
|
+
* ```
|
|
256
|
+
*/
|
|
19
257
|
const dependencyInjection = (services = []) => ({
|
|
20
258
|
before: async (context) => {
|
|
21
259
|
services.forEach((service) => {
|
|
@@ -1,6 +1,100 @@
|
|
|
1
1
|
import { BaseMiddleware, Context } from '../core';
|
|
2
|
+
/**
|
|
3
|
+
* Middleware class for handling errors in the application.
|
|
4
|
+
* Implements the `BaseMiddleware` interface and provides an asynchronous
|
|
5
|
+
* `onError` method that delegates error handling to the `handleError` function.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* This middleware should be registered to catch and process errors that occur
|
|
9
|
+
* during request handling.
|
|
10
|
+
*
|
|
11
|
+
* @method onError
|
|
12
|
+
* @param error - The error object that was thrown.
|
|
13
|
+
* @param context - The context in which the error occurred.
|
|
14
|
+
* @returns A promise that resolves when error handling is complete.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* Basic handler with error handling:
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { Handler, ErrorHandlerMiddleware, HttpError } from '@noony-serverless/core';
|
|
20
|
+
*
|
|
21
|
+
* const createUserHandler = new Handler()
|
|
22
|
+
* .use(new ErrorHandlerMiddleware())
|
|
23
|
+
* .handle(async (request, context) => {
|
|
24
|
+
* if (!request.body?.email) {
|
|
25
|
+
* throw new HttpError(400, 'Email is required', 'MISSING_EMAIL');
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* return {
|
|
29
|
+
* success: true,
|
|
30
|
+
* data: { id: 'user-123', email: request.body.email }
|
|
31
|
+
* };
|
|
32
|
+
* });
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* Google Cloud Functions integration:
|
|
37
|
+
* ```typescript
|
|
38
|
+
* import { http } from '@google-cloud/functions-framework';
|
|
39
|
+
* import { Handler, ErrorHandlerMiddleware } from '@noony-serverless/core';
|
|
40
|
+
*
|
|
41
|
+
* const orderHandler = new Handler()
|
|
42
|
+
* .use(new ErrorHandlerMiddleware())
|
|
43
|
+
* .handle(async (request, context) => {
|
|
44
|
+
* // Handler logic that might throw errors
|
|
45
|
+
* return { success: true, data: processedOrder };
|
|
46
|
+
* });
|
|
47
|
+
*
|
|
48
|
+
* export const processOrder = http('processOrder', (req, res) => {
|
|
49
|
+
* return orderHandler.execute(req, res);
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
2
53
|
export declare class ErrorHandlerMiddleware implements BaseMiddleware {
|
|
3
54
|
onError(error: Error, context: Context): Promise<void>;
|
|
4
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Creates an error handling middleware for processing errors in the application.
|
|
58
|
+
*
|
|
59
|
+
* @returns {BaseMiddleware} An object implementing the `onError` method to handle errors.
|
|
60
|
+
*
|
|
61
|
+
* @remarks
|
|
62
|
+
* The middleware's `onError` method asynchronously delegates error handling to the `handleError` function,
|
|
63
|
+
* passing the error and context objects.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* Basic usage with factory function:
|
|
67
|
+
* ```typescript
|
|
68
|
+
* import { Handler, errorHandler, HttpError } from '@noony-serverless/core';
|
|
69
|
+
*
|
|
70
|
+
* const loginHandler = new Handler()
|
|
71
|
+
* .use(errorHandler())
|
|
72
|
+
* .handle(async (request, context) => {
|
|
73
|
+
* const { username, password } = request.body || {};
|
|
74
|
+
*
|
|
75
|
+
* if (!username || !password) {
|
|
76
|
+
* throw new HttpError(400, 'Credentials required', 'MISSING_CREDENTIALS');
|
|
77
|
+
* }
|
|
78
|
+
*
|
|
79
|
+
* const user = await authenticateUser(username, password);
|
|
80
|
+
* return { success: true, data: { token: generateToken(user) } };
|
|
81
|
+
* });
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* Multiple middleware chain:
|
|
86
|
+
* ```typescript
|
|
87
|
+
* import { Handler, errorHandler, BodyParserMiddleware } from '@noony-serverless/core';
|
|
88
|
+
*
|
|
89
|
+
* const secureHandler = new Handler()
|
|
90
|
+
* .use(new BodyParserMiddleware())
|
|
91
|
+
* .use(new AuthenticationMiddleware())
|
|
92
|
+
* .use(errorHandler()) // Should be last to catch all errors
|
|
93
|
+
* .handle(async (request, context) => {
|
|
94
|
+
* // Handler logic
|
|
95
|
+
* return { success: true, data: result };
|
|
96
|
+
* });
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
5
99
|
export declare const errorHandler: () => BaseMiddleware;
|
|
6
100
|
//# sourceMappingURL=errorHandlerMiddleware.d.ts.map
|