@shadow-library/fastify 0.0.13 → 1.0.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/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
- export const AppModule = FastifyModule.forRoot({
86
- controllers: [UserController],
87
- port: 3000,
88
- host: '0.0.0.0',
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
- const AppModule = FastifyModule.forRoot({
223
- // Basic server configuration
224
- host: 'localhost',
225
- port: 8080,
237
+ @Module({
238
+ imports: [
239
+ FastifyModule.forRoot({
240
+ // Basic server configuration
241
+ host: 'localhost',
242
+ port: 8080,
226
243
 
227
- // Controllers to register
228
- controllers: [UserController, AuthController],
244
+ // Controllers to register
245
+ controllers: [UserController, AuthController],
229
246
 
230
- // Additional providers
231
- providers: [UserService, AuthService],
247
+ // Additional providers
248
+ providers: [UserService, AuthService],
232
249
 
233
- // Error handling
234
- errorHandler: new CustomErrorHandler(),
250
+ // Error handling
251
+ errorHandler: new CustomErrorHandler(),
235
252
 
236
- // Security
237
- maskSensitiveData: true,
253
+ // Security
254
+ maskSensitiveData: true,
238
255
 
239
- // Request ID generation
240
- requestIdLogLabel: 'rid',
241
- genReqId: () => uuid(),
256
+ // Request ID generation
257
+ requestIdLogLabel: 'rid',
258
+ genReqId: () => uuid(),
242
259
 
243
- // Router options
244
- routerOptions: {
245
- ignoreTrailingSlash: true,
246
- ignoreDuplicateSlashes: true,
247
- },
260
+ // Router options
261
+ routerOptions: {
262
+ ignoreTrailingSlash: true,
263
+ ignoreDuplicateSlashes: true,
264
+ },
248
265
 
249
- // Response schemas for error handling
250
- responseSchema: {
251
- '4xx': ErrorResponseSchema,
252
- '5xx': ErrorResponseSchema,
253
- },
266
+ // Response schemas for error handling
267
+ responseSchema: {
268
+ '4xx': ErrorResponseSchema,
269
+ '5xx': ErrorResponseSchema,
270
+ },
254
271
 
255
- // Extend Fastify instance before registering controllers
256
- fastifyFactory: async fastify => {
257
- // Register plugins, add hooks, or configure Fastify
258
- await fastify.register(require('@fastify/cors'), {
259
- origin: true,
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
- fastify.addHook('onRequest', async (request, reply) => {
263
- console.log(`Incoming request: ${request.method} ${request.url}`);
264
- });
279
+ fastify.addHook('onRequest', async (request, reply) => {
280
+ console.log(`Incoming request: ${request.method} ${request.url}`);
281
+ });
265
282
 
266
- return fastify;
267
- },
268
- });
283
+ return fastify;
284
+ },
285
+ }),
286
+ ],
287
+ })
288
+ export class AppModule {}
269
289
  ```
270
290
 
271
- ### Async Configuration
291
+ #### Asynchronous Configuration (forRootAsync)
292
+
293
+ Use `forRootAsync` when you need to inject dependencies or load configuration dynamically:
272
294
 
273
295
  ```typescript
274
- const AppModule = FastifyModule.forRootAsync({
275
- useFactory: async (configService: ConfigService) => ({
276
- host: configService.get('HOST'),
277
- port: configService.get('PORT'),
278
- controllers: [UserController],
279
- }),
280
- inject: [ConfigService],
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
- const AppModule = FastifyModule.forRoot({
294
- controllers: [UserController],
295
- fastifyFactory: async fastify => {
296
- // Register security plugins
297
- await fastify.register(helmet, {
298
- contentSecurityPolicy: {
299
- directives: {
300
- defaultSrc: ["'self'"],
301
- styleSrc: ["'self'", "'unsafe-inline'"],
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
- // Add CORS support
307
- await fastify.register(cors, {
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
- import { Class } from 'type-fest';
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): Class<FastifyModule>;
12
- static forRootAsync(options: FastifyModuleAsyncOptions): Class<FastifyModule>;
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 imports = options.imports ?? [];
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
- const Class = class extends FastifyModule {
65
- };
66
- Object.defineProperty(Class, 'name', { value: FastifyModule.name });
67
- (0, app_1.Module)({ imports, controllers, providers, exports: [app_1.Router, services_1.ContextService, ...exports] })(Class);
68
- return Class;
66
+ if (options.providers)
67
+ providers.push(...options.providers);
68
+ const exports = [app_1.Router, services_1.ContextService];
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
- import { Class } from 'type-fest';
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): Class<FastifyModule>;
12
- static forRootAsync(options: FastifyModuleAsyncOptions): Class<FastifyModule>;
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
- export class FastifyModule {
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 imports = options.imports ?? [];
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
- const Class = class extends FastifyModule {
62
- };
63
- Object.defineProperty(Class, 'name', { value: FastifyModule.name });
64
- Module({ imports, controllers, providers, exports: [Router, ContextService, ...exports] })(Class);
65
- return Class;
63
+ if (options.providers)
64
+ providers.push(...options.providers);
65
+ const exports = [Router, ContextService];
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": "0.0.13",
4
+ "version": "1.0.0",
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.7",
30
+ "@shadow-library/app": "^1.0.11",
31
31
  "@shadow-library/class-schema": "^0.0.12",
32
- "@shadow-library/common": "^1.0.18",
32
+ "@shadow-library/common": "^1.0.22",
33
33
  "reflect-metadata": "^0.2.2"
34
34
  },
35
35
  "peerDependenciesMeta": {