@shadow-library/fastify 0.0.13 → 1.0.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/README.md +148 -107
- package/cjs/module/fastify.module.d.ts +6 -3
- package/cjs/module/fastify.module.js +24 -13
- package/esm/module/fastify.module.d.ts +6 -3
- package/esm/module/fastify.module.js +25 -13
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@ A powerful TypeScript-first Fastify wrapper featuring decorator-based routing, a
|
|
|
13
13
|
- 🔄 **Middleware Support**: Flexible middleware system with lifecycle hooks
|
|
14
14
|
- 📊 **Type Safety**: Full TypeScript support with schema generation
|
|
15
15
|
- 🎨 **Templating Ready**: Built-in support for templating engines
|
|
16
|
+
- ⚡ **Dynamic Module**: Configurable module with `forRoot()` and `forRootAsync()` methods
|
|
16
17
|
|
|
17
18
|
## Installation
|
|
18
19
|
|
|
@@ -78,15 +79,23 @@ export class UserController {
|
|
|
78
79
|
|
|
79
80
|
### 2. Create a Module
|
|
80
81
|
|
|
82
|
+
`FastifyModule` is a dynamic module that provides both synchronous and asynchronous configuration methods.
|
|
83
|
+
|
|
81
84
|
```typescript
|
|
85
|
+
import { Module } from '@shadow-library/app';
|
|
82
86
|
import { FastifyModule } from '@shadow-library/fastify';
|
|
83
87
|
import { UserController } from './user.controller';
|
|
84
88
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
@Module({
|
|
90
|
+
imports: [
|
|
91
|
+
FastifyModule.forRoot({
|
|
92
|
+
controllers: [UserController],
|
|
93
|
+
port: 3000,
|
|
94
|
+
host: '0.0.0.0',
|
|
95
|
+
}),
|
|
96
|
+
],
|
|
97
|
+
})
|
|
98
|
+
export class AppModule {}
|
|
90
99
|
```
|
|
91
100
|
|
|
92
101
|
### 3. Bootstrap Your Application
|
|
@@ -216,136 +225,168 @@ export class RoutesController {
|
|
|
216
225
|
|
|
217
226
|
## Configuration
|
|
218
227
|
|
|
219
|
-
### Module Configuration
|
|
228
|
+
### Dynamic Module Configuration
|
|
229
|
+
|
|
230
|
+
`FastifyModule` is a **dynamic module** that configures itself based on the options you provide. Unlike static modules, dynamic modules return a module configuration object at runtime, allowing for flexible dependency injection and configuration.
|
|
231
|
+
|
|
232
|
+
The module provides two configuration methods:
|
|
233
|
+
|
|
234
|
+
#### Synchronous Configuration (forRoot)
|
|
220
235
|
|
|
221
236
|
```typescript
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
237
|
+
@Module({
|
|
238
|
+
imports: [
|
|
239
|
+
FastifyModule.forRoot({
|
|
240
|
+
// Basic server configuration
|
|
241
|
+
host: 'localhost',
|
|
242
|
+
port: 8080,
|
|
226
243
|
|
|
227
|
-
|
|
228
|
-
|
|
244
|
+
// Controllers to register
|
|
245
|
+
controllers: [UserController, AuthController],
|
|
229
246
|
|
|
230
|
-
|
|
231
|
-
|
|
247
|
+
// Additional providers
|
|
248
|
+
providers: [UserService, AuthService],
|
|
232
249
|
|
|
233
|
-
|
|
234
|
-
|
|
250
|
+
// Error handling
|
|
251
|
+
errorHandler: new CustomErrorHandler(),
|
|
235
252
|
|
|
236
|
-
|
|
237
|
-
|
|
253
|
+
// Security
|
|
254
|
+
maskSensitiveData: true,
|
|
238
255
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
256
|
+
// Request ID generation
|
|
257
|
+
requestIdLogLabel: 'rid',
|
|
258
|
+
genReqId: () => uuid(),
|
|
242
259
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
260
|
+
// Router options
|
|
261
|
+
routerOptions: {
|
|
262
|
+
ignoreTrailingSlash: true,
|
|
263
|
+
ignoreDuplicateSlashes: true,
|
|
264
|
+
},
|
|
248
265
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
266
|
+
// Response schemas for error handling
|
|
267
|
+
responseSchema: {
|
|
268
|
+
'4xx': ErrorResponseSchema,
|
|
269
|
+
'5xx': ErrorResponseSchema,
|
|
270
|
+
},
|
|
254
271
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
272
|
+
// Extend Fastify instance before registering controllers
|
|
273
|
+
fastifyFactory: async fastify => {
|
|
274
|
+
// Register plugins, add hooks, or configure Fastify
|
|
275
|
+
await fastify.register(require('@fastify/cors'), {
|
|
276
|
+
origin: true,
|
|
277
|
+
});
|
|
261
278
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
279
|
+
fastify.addHook('onRequest', async (request, reply) => {
|
|
280
|
+
console.log(`Incoming request: ${request.method} ${request.url}`);
|
|
281
|
+
});
|
|
265
282
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
})
|
|
283
|
+
return fastify;
|
|
284
|
+
},
|
|
285
|
+
}),
|
|
286
|
+
],
|
|
287
|
+
})
|
|
288
|
+
export class AppModule {}
|
|
269
289
|
```
|
|
270
290
|
|
|
271
|
-
|
|
291
|
+
#### Asynchronous Configuration (forRootAsync)
|
|
292
|
+
|
|
293
|
+
Use `forRootAsync` when you need to inject dependencies or load configuration dynamically:
|
|
272
294
|
|
|
273
295
|
```typescript
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
})
|
|
296
|
+
@Module({
|
|
297
|
+
imports: [
|
|
298
|
+
FastifyModule.forRootAsync({
|
|
299
|
+
useFactory: async (configService: ConfigService) => ({
|
|
300
|
+
host: configService.get('HOST'),
|
|
301
|
+
port: configService.get('PORT'),
|
|
302
|
+
controllers: [UserController],
|
|
303
|
+
}),
|
|
304
|
+
inject: [ConfigService],
|
|
305
|
+
}),
|
|
306
|
+
],
|
|
307
|
+
})
|
|
308
|
+
export class AppModule {}
|
|
282
309
|
```
|
|
283
310
|
|
|
311
|
+
#### Dynamic Module Benefits
|
|
312
|
+
|
|
313
|
+
- **Flexible Configuration**: Configure the module differently for different environments
|
|
314
|
+
- **Dependency Injection**: Inject services into the module configuration
|
|
315
|
+
- **Runtime Configuration**: Load configuration from external sources (databases, config files, etc.)
|
|
316
|
+
- **Type Safety**: Full TypeScript support for all configuration options
|
|
317
|
+
- **Modular Design**: Easy to compose with other modules in your application
|
|
318
|
+
|
|
284
319
|
### Extending Fastify Instance
|
|
285
320
|
|
|
286
321
|
Use the `fastifyFactory` option to customize the Fastify instance before controllers are registered. This is perfect for adding plugins, global hooks, or custom configurations:
|
|
287
322
|
|
|
288
323
|
```typescript
|
|
324
|
+
import { Module } from '@shadow-library/app';
|
|
289
325
|
import cors from '@fastify/cors';
|
|
290
326
|
import helmet from '@fastify/helmet';
|
|
291
327
|
import rateLimit from '@fastify/rate-limit';
|
|
292
328
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
329
|
+
@Module({
|
|
330
|
+
imports: [
|
|
331
|
+
FastifyModule.forRoot({
|
|
332
|
+
controllers: [UserController],
|
|
333
|
+
fastifyFactory: async fastify => {
|
|
334
|
+
// Register security plugins
|
|
335
|
+
await fastify.register(helmet, {
|
|
336
|
+
contentSecurityPolicy: {
|
|
337
|
+
directives: {
|
|
338
|
+
defaultSrc: ["'self'"],
|
|
339
|
+
styleSrc: ["'self'", "'unsafe-inline'"],
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
// Add CORS support
|
|
345
|
+
await fastify.register(cors, {
|
|
346
|
+
origin: (origin, callback) => {
|
|
347
|
+
const allowedOrigins = ['http://localhost:3000', 'https://myapp.com'];
|
|
348
|
+
if (!origin || allowedOrigins.includes(origin)) {
|
|
349
|
+
callback(null, true);
|
|
350
|
+
} else {
|
|
351
|
+
callback(new Error('Not allowed by CORS'), false);
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
credentials: true,
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
// Add rate limiting
|
|
358
|
+
await fastify.register(rateLimit, {
|
|
359
|
+
max: 100,
|
|
360
|
+
timeWindow: '1 minute',
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
// Add global hooks
|
|
364
|
+
fastify.addHook('onRequest', async (request, reply) => {
|
|
365
|
+
console.log(`[${new Date().toISOString()}] ${request.method} ${request.url}`);
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
fastify.addHook('onResponse', async (request, reply) => {
|
|
369
|
+
const responseTime = reply.elapsedTime;
|
|
370
|
+
console.log(`Response sent in ${responseTime}ms`);
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
// Add custom context or decorators
|
|
374
|
+
fastify.decorate('config', {
|
|
375
|
+
apiVersion: 'v1',
|
|
376
|
+
environment: process.env.NODE_ENV,
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
// Register custom content type parsers
|
|
380
|
+
fastify.addContentTypeParser('text/plain', { parseAs: 'string' }, (req, body, done) => {
|
|
381
|
+
done(null, body);
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
return fastify;
|
|
303
385
|
},
|
|
304
|
-
})
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
origin: (origin, callback) => {
|
|
309
|
-
const allowedOrigins = ['http://localhost:3000', 'https://myapp.com'];
|
|
310
|
-
if (!origin || allowedOrigins.includes(origin)) {
|
|
311
|
-
callback(null, true);
|
|
312
|
-
} else {
|
|
313
|
-
callback(new Error('Not allowed by CORS'), false);
|
|
314
|
-
}
|
|
315
|
-
},
|
|
316
|
-
credentials: true,
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
// Add rate limiting
|
|
320
|
-
await fastify.register(rateLimit, {
|
|
321
|
-
max: 100,
|
|
322
|
-
timeWindow: '1 minute',
|
|
323
|
-
});
|
|
324
|
-
|
|
325
|
-
// Add global hooks
|
|
326
|
-
fastify.addHook('onRequest', async (request, reply) => {
|
|
327
|
-
console.log(`[${new Date().toISOString()}] ${request.method} ${request.url}`);
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
fastify.addHook('onResponse', async (request, reply) => {
|
|
331
|
-
const responseTime = reply.elapsedTime;
|
|
332
|
-
console.log(`Response sent in ${responseTime}ms`);
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
// Add custom context or decorators
|
|
336
|
-
fastify.decorate('config', {
|
|
337
|
-
apiVersion: 'v1',
|
|
338
|
-
environment: process.env.NODE_ENV,
|
|
339
|
-
});
|
|
340
|
-
|
|
341
|
-
// Register custom content type parsers
|
|
342
|
-
fastify.addContentTypeParser('text/plain', { parseAs: 'string' }, (req, body, done) => {
|
|
343
|
-
done(null, body);
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
return fastify;
|
|
347
|
-
},
|
|
348
|
-
});
|
|
386
|
+
}),
|
|
387
|
+
],
|
|
388
|
+
})
|
|
389
|
+
export class AppModule {}
|
|
349
390
|
```
|
|
350
391
|
|
|
351
392
|
#### Common Use Cases for fastifyFactory:
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Importing npm packages
|
|
3
|
+
*/
|
|
4
|
+
import { DynamicModule } from '@shadow-library/app';
|
|
2
5
|
import { FastifyModuleAsyncOptions, FastifyModuleOptions } from './fastify-module.interface.js';
|
|
3
6
|
/**
|
|
4
7
|
* Defining types
|
|
@@ -8,6 +11,6 @@ import { FastifyModuleAsyncOptions, FastifyModuleOptions } from './fastify-modul
|
|
|
8
11
|
*/
|
|
9
12
|
export declare class FastifyModule {
|
|
10
13
|
private static getDefaultConfig;
|
|
11
|
-
static forRoot(options: FastifyModuleOptions):
|
|
12
|
-
static forRootAsync(options: FastifyModuleAsyncOptions):
|
|
14
|
+
static forRoot(options: FastifyModuleOptions): DynamicModule;
|
|
15
|
+
static forRootAsync(options: FastifyModuleAsyncOptions): DynamicModule;
|
|
13
16
|
}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var FastifyModule_1;
|
|
2
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
10
|
exports.FastifyModule = void 0;
|
|
4
11
|
/**
|
|
@@ -23,7 +30,7 @@ const fastify_utils_1 = require("./fastify.utils.js");
|
|
|
23
30
|
/**
|
|
24
31
|
* Declaring the constants
|
|
25
32
|
*/
|
|
26
|
-
class FastifyModule {
|
|
33
|
+
let FastifyModule = FastifyModule_1 = class FastifyModule {
|
|
27
34
|
static getDefaultConfig() {
|
|
28
35
|
const errorResponseSchema = class_schema_1.ClassSchema.generate(error_response_dto_1.ErrorResponseDto);
|
|
29
36
|
return {
|
|
@@ -52,20 +59,24 @@ class FastifyModule {
|
|
|
52
59
|
});
|
|
53
60
|
}
|
|
54
61
|
static forRootAsync(options) {
|
|
55
|
-
const
|
|
56
|
-
const controllers = options.controllers ?? [];
|
|
57
|
-
const exports = options.exports ?? [];
|
|
62
|
+
const fastifyFactory = (config) => (0, fastify_utils_1.createFastifyInstance)(config, options.fastifyFactory);
|
|
58
63
|
const providers = [{ token: app_1.Router, useClass: fastify_router_1.FastifyRouter }, services_1.ContextService];
|
|
59
|
-
if (options.providers)
|
|
60
|
-
providers.push(...options.providers);
|
|
61
64
|
providers.push({ token: constants_1.FASTIFY_CONFIG, useFactory: options.useFactory, inject: options.inject });
|
|
62
|
-
const fastifyFactory = (config) => (0, fastify_utils_1.createFastifyInstance)(config, options.fastifyFactory);
|
|
63
65
|
providers.push({ token: constants_1.FASTIFY_INSTANCE, useFactory: fastifyFactory, inject: [constants_1.FASTIFY_CONFIG] });
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
if (options.providers)
|
|
67
|
+
providers.push(...options.providers);
|
|
68
|
+
const exports = [app_1.Router, services_1.ContextService, constants_1.FASTIFY_INSTANCE];
|
|
69
|
+
if (options.exports)
|
|
70
|
+
exports.push(...options.exports);
|
|
71
|
+
const Module = { module: FastifyModule_1, providers, exports };
|
|
72
|
+
if (options.imports)
|
|
73
|
+
Module.imports = options.imports;
|
|
74
|
+
if (options.controllers)
|
|
75
|
+
Module.controllers = options.controllers;
|
|
76
|
+
return Module;
|
|
69
77
|
}
|
|
70
|
-
}
|
|
78
|
+
};
|
|
71
79
|
exports.FastifyModule = FastifyModule;
|
|
80
|
+
exports.FastifyModule = FastifyModule = FastifyModule_1 = __decorate([
|
|
81
|
+
(0, app_1.Module)({})
|
|
82
|
+
], FastifyModule);
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Importing npm packages
|
|
3
|
+
*/
|
|
4
|
+
import { DynamicModule } from '@shadow-library/app';
|
|
2
5
|
import { FastifyModuleAsyncOptions, FastifyModuleOptions } from './fastify-module.interface.js';
|
|
3
6
|
/**
|
|
4
7
|
* Defining types
|
|
@@ -8,6 +11,6 @@ import { FastifyModuleAsyncOptions, FastifyModuleOptions } from './fastify-modul
|
|
|
8
11
|
*/
|
|
9
12
|
export declare class FastifyModule {
|
|
10
13
|
private static getDefaultConfig;
|
|
11
|
-
static forRoot(options: FastifyModuleOptions):
|
|
12
|
-
static forRootAsync(options: FastifyModuleAsyncOptions):
|
|
14
|
+
static forRoot(options: FastifyModuleOptions): DynamicModule;
|
|
15
|
+
static forRootAsync(options: FastifyModuleAsyncOptions): DynamicModule;
|
|
13
16
|
}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var FastifyModule_1;
|
|
1
8
|
/**
|
|
2
9
|
* Importing npm packages
|
|
3
10
|
*/
|
|
@@ -20,7 +27,7 @@ import { createFastifyInstance } from './fastify.utils.js';
|
|
|
20
27
|
/**
|
|
21
28
|
* Declaring the constants
|
|
22
29
|
*/
|
|
23
|
-
|
|
30
|
+
let FastifyModule = FastifyModule_1 = class FastifyModule {
|
|
24
31
|
static getDefaultConfig() {
|
|
25
32
|
const errorResponseSchema = ClassSchema.generate(ErrorResponseDto);
|
|
26
33
|
return {
|
|
@@ -49,19 +56,24 @@ export class FastifyModule {
|
|
|
49
56
|
});
|
|
50
57
|
}
|
|
51
58
|
static forRootAsync(options) {
|
|
52
|
-
const
|
|
53
|
-
const controllers = options.controllers ?? [];
|
|
54
|
-
const exports = options.exports ?? [];
|
|
59
|
+
const fastifyFactory = (config) => createFastifyInstance(config, options.fastifyFactory);
|
|
55
60
|
const providers = [{ token: Router, useClass: FastifyRouter }, ContextService];
|
|
56
|
-
if (options.providers)
|
|
57
|
-
providers.push(...options.providers);
|
|
58
61
|
providers.push({ token: FASTIFY_CONFIG, useFactory: options.useFactory, inject: options.inject });
|
|
59
|
-
const fastifyFactory = (config) => createFastifyInstance(config, options.fastifyFactory);
|
|
60
62
|
providers.push({ token: FASTIFY_INSTANCE, useFactory: fastifyFactory, inject: [FASTIFY_CONFIG] });
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
if (options.providers)
|
|
64
|
+
providers.push(...options.providers);
|
|
65
|
+
const exports = [Router, ContextService, FASTIFY_INSTANCE];
|
|
66
|
+
if (options.exports)
|
|
67
|
+
exports.push(...options.exports);
|
|
68
|
+
const Module = { module: FastifyModule_1, providers, exports };
|
|
69
|
+
if (options.imports)
|
|
70
|
+
Module.imports = options.imports;
|
|
71
|
+
if (options.controllers)
|
|
72
|
+
Module.controllers = options.controllers;
|
|
73
|
+
return Module;
|
|
66
74
|
}
|
|
67
|
-
}
|
|
75
|
+
};
|
|
76
|
+
FastifyModule = FastifyModule_1 = __decorate([
|
|
77
|
+
Module({})
|
|
78
|
+
], FastifyModule);
|
|
79
|
+
export { FastifyModule };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shadow-library/fastify",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "1.0.1",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "A Fastify wrapper featuring decorator-based routing, middleware and error handling",
|
|
7
7
|
"repository": {
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
29
29
|
"@fastify/view": "^10.0.0",
|
|
30
|
-
"@shadow-library/app": "^1.0.
|
|
30
|
+
"@shadow-library/app": "^1.0.11",
|
|
31
31
|
"@shadow-library/class-schema": "^0.0.12",
|
|
32
|
-
"@shadow-library/common": "^1.0.
|
|
32
|
+
"@shadow-library/common": "^1.0.22",
|
|
33
33
|
"reflect-metadata": "^0.2.2"
|
|
34
34
|
},
|
|
35
35
|
"peerDependenciesMeta": {
|