@nest-forge/core 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,6 @@
1
1
  export declare const FORGE_ROOT_MODULE: unique symbol;
2
2
  export declare const FORGE_FIELD_MODULE_REF: unique symbol;
3
3
  export declare const FORGE_TOKEN_ROOT_MODULE: unique symbol;
4
+ export declare const FORGE_PATCHED: unique symbol;
5
+ export declare const FORGE_PATCH_BOOT_CALLBACK: unique symbol;
6
+ export declare const FORGE_PATCH_ENABLE_INIT: unique symbol;
package/dist/constants.js CHANGED
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FORGE_TOKEN_ROOT_MODULE = exports.FORGE_FIELD_MODULE_REF = exports.FORGE_ROOT_MODULE = void 0;
3
+ exports.FORGE_PATCH_ENABLE_INIT = exports.FORGE_PATCH_BOOT_CALLBACK = exports.FORGE_PATCHED = exports.FORGE_TOKEN_ROOT_MODULE = exports.FORGE_FIELD_MODULE_REF = exports.FORGE_ROOT_MODULE = void 0;
4
4
  exports.FORGE_ROOT_MODULE = Symbol('FORGE_ROOT_MODULE');
5
5
  exports.FORGE_FIELD_MODULE_REF = Symbol('FORGE_FIELD_MODULE_REF');
6
6
  exports.FORGE_TOKEN_ROOT_MODULE = Symbol('FORGE_TOKEN_ROOT_MODULE');
7
+ exports.FORGE_PATCHED = Symbol('FORGE_PATCHED');
8
+ exports.FORGE_PATCH_BOOT_CALLBACK = Symbol('FORGE_PATCH_BOOT_CALLBACK');
9
+ exports.FORGE_PATCH_ENABLE_INIT = Symbol('FORGE_PATCH_ENABLE_INIT');
@@ -1,5 +1,8 @@
1
- import { INestApplication, INestApplicationContext, INestMicroservice, MiddlewareConsumer, ModuleMetadata } from '@nestjs/common';
2
- import { ForgeController, ForgeModule, ForgeService } from '../architecture';
1
+ import { INestApplication, INestApplicationContext, INestMicroservice, MiddlewareConsumer, ModuleMetadata, NestApplicationOptions } from '@nestjs/common';
2
+ import { ForgeBaseComponent, ForgeController, ForgeModule, ForgeService } from '../architecture';
3
+ import { NestApplicationContextOptions } from '@nestjs/common/interfaces/nest-application-context-options.interface';
4
+ import { NestMicroserviceOptions } from '@nestjs/common/interfaces/microservices/nest-microservice-options.interface';
5
+ import { AbstractHttpAdapter } from '@nestjs/core';
3
6
  export declare abstract class ForgeExtension {
4
7
  /**
5
8
  * The metdata for this extension.
@@ -9,27 +12,53 @@ export declare abstract class ForgeExtension {
9
12
  * Constructs a new forge extension instance.
10
13
  */
11
14
  constructor(options?: ForgeExtensionMetadata);
15
+ /**
16
+ * Configures the HTTP adapter to use for the Nest application instance.
17
+ *
18
+ * @param current The current adapter instance, or `undefined` if not set (default will be used).
19
+ */
20
+ configureHttpAdapter(current?: AbstractHttpAdapter): ForgeHttpAdapterLike;
12
21
  /**
13
22
  * Configures a Nest application instance.
14
23
  */
15
24
  configureHttpApplication(application: INestApplication): any;
25
+ /**
26
+ * Configures the options object for a Nest application instance.
27
+ */
28
+ configureHttpApplicationOptions(options: NestApplicationOptions): NestApplicationOptions | Promise<NestApplicationOptions>;
16
29
  /**
17
30
  * Configures a Nest application context. This is for a standalone application that has no web server.
18
31
  */
19
32
  configureStandaloneApplication(context: INestApplicationContext): any;
33
+ /**
34
+ * Configures the options object for a standalone Nest application instance.
35
+ */
36
+ configureStandaloneApplicationOptions(options: NestApplicationContextOptions): NestApplicationContextOptions | Promise<NestApplicationContextOptions>;
20
37
  /**
21
38
  * Configures a Nest microservice context.
22
39
  */
23
40
  configureMicroserviceApplication(context: INestMicroservice): any;
41
+ /**
42
+ * Configures the options object for a Nest microservice instance.
43
+ */
44
+ configureMicroserviceApplicationOptions(options: NestMicroserviceOptions): NestMicroserviceOptions | Promise<NestMicroserviceOptions>;
24
45
  /**
25
46
  * Configures the root module of the application.
26
47
  */
27
48
  configureRootModule(consumer: MiddlewareConsumer): any;
49
+ /**
50
+ * Runs after all services in the application have booted.
51
+ */
52
+ afterBoot(app: INestApplicationContext): any;
28
53
  /**
29
54
  * Instruments the application context. If a value is returned, the instance is replaced with that value, and no further extensions are
30
55
  * queried.
31
56
  */
32
57
  instrument(instance: unknown): any;
58
+ /**
59
+ * Augments a `ForgeBaseComponent` instance.
60
+ */
61
+ augmentComponent(instance: ForgeBaseComponent, moduleRef: any): any;
33
62
  /**
34
63
  * Augments a `ForgeModule` instance.
35
64
  */
@@ -54,3 +83,4 @@ export interface ForgeExtensionMetadata extends ModuleMetadata {
54
83
  extensions?: ForgeExtensionResolvable[];
55
84
  }
56
85
  export type ForgeExtensionResolvable = ForgeExtension | (new () => ForgeExtension) | null | undefined | false;
86
+ export type ForgeHttpAdapterLike = AbstractHttpAdapter | null | undefined | Promise<AbstractHttpAdapter | null | undefined>;
@@ -12,27 +12,61 @@ class ForgeExtension {
12
12
  constructor(options) {
13
13
  this._metadata = options || {};
14
14
  }
15
+ /**
16
+ * Configures the HTTP adapter to use for the Nest application instance.
17
+ *
18
+ * @param current The current adapter instance, or `undefined` if not set (default will be used).
19
+ */
20
+ configureHttpAdapter(current) {
21
+ return;
22
+ }
15
23
  /**
16
24
  * Configures a Nest application instance.
17
25
  */
18
26
  configureHttpApplication(application) { }
27
+ /**
28
+ * Configures the options object for a Nest application instance.
29
+ */
30
+ configureHttpApplicationOptions(options) {
31
+ return options;
32
+ }
19
33
  /**
20
34
  * Configures a Nest application context. This is for a standalone application that has no web server.
21
35
  */
22
36
  configureStandaloneApplication(context) { }
37
+ /**
38
+ * Configures the options object for a standalone Nest application instance.
39
+ */
40
+ configureStandaloneApplicationOptions(options) {
41
+ return options;
42
+ }
23
43
  /**
24
44
  * Configures a Nest microservice context.
25
45
  */
26
46
  configureMicroserviceApplication(context) { }
47
+ /**
48
+ * Configures the options object for a Nest microservice instance.
49
+ */
50
+ configureMicroserviceApplicationOptions(options) {
51
+ return options;
52
+ }
27
53
  /**
28
54
  * Configures the root module of the application.
29
55
  */
30
56
  configureRootModule(consumer) { }
57
+ /**
58
+ * Runs after all services in the application have booted.
59
+ */
60
+ afterBoot(app) { }
31
61
  /**
32
62
  * Instruments the application context. If a value is returned, the instance is replaced with that value, and no further extensions are
33
63
  * queried.
34
64
  */
35
65
  instrument(instance) { }
66
+ /**
67
+ * Augments a `ForgeBaseComponent` instance.
68
+ */
69
+ augmentComponent(instance, moduleRef) { }
36
70
  /**
37
71
  * Augments a `ForgeModule` instance.
38
72
  */
@@ -1,29 +1,34 @@
1
- import { DynamicModule, ForwardReference, MiddlewareConsumer, Type } from '@nestjs/common';
1
+ import { DynamicModule, ForwardReference, INestApplication, INestApplicationContext, MiddlewareConsumer, Type } from '@nestjs/common';
2
2
  import { ForgeApplicationContextOptions, ForgeApplicationOptions, ForgeMicroserviceOptions } from './forge-options.interface';
3
3
  import { ForgeExtension, ForgeExtensionResolvable } from './extensions';
4
- import { ModuleRef } from '@nestjs/core';
4
+ import { AbstractHttpAdapter, ModuleRef } from '@nestjs/core';
5
5
  import { FORGE_ROOT_MODULE } from './constants';
6
6
  import { ForgeBaseComponent, ForgeController, ForgeModule, ForgeService } from './architecture';
7
7
  declare class Forge {
8
8
  private _augmented;
9
- create(appModule: IEntryNestModule, options?: ForgeApplicationOptions): Promise<import("@nestjs/common").INestApplication<any>>;
10
- createApplicationContext(appModule: IEntryNestModule, options: ForgeApplicationContextOptions): Promise<import("@nestjs/common").INestApplicationContext>;
9
+ create<T extends INestApplication = INestApplication>(appModule: IEntryNestModule, options?: ForgeApplicationOptions): Promise<T>;
10
+ create<T extends INestApplication = INestApplication>(appModule: IEntryNestModule, httpAdapter: AbstractHttpAdapter, options?: ForgeApplicationOptions): Promise<T>;
11
+ createApplicationContext(appModule: IEntryNestModule, options: ForgeApplicationContextOptions): Promise<INestApplicationContext>;
11
12
  createMicroservice<T extends object>(appModule: IEntryNestModule, options: ForgeMicroserviceOptions & T): Promise<import("@nestjs/common").INestMicroservice>;
12
13
  protected discoverExtensions(resolvables: ForgeExtensionResolvable | ForgeExtensionResolvable[]): ForgeExtension[];
13
- protected resolveExtension(resolvable: ForgeExtensionResolvable): ForgeExtension;
14
+ protected resolveExtension(resolvable: ForgeExtensionResolvable): ForgeExtension | null;
14
15
  protected createRootModule(appModule: IEntryNestModule, extensions: ForgeExtension[]): {
15
16
  new (moduleRef: ModuleRef): {
16
17
  readonly moduleRef: ModuleRef;
17
- configure(consumer: MiddlewareConsumer): void;
18
+ configure(consumer: MiddlewareConsumer): Promise<void>;
18
19
  readonly [FORGE_ROOT_MODULE]: true;
19
20
  };
20
21
  };
21
22
  protected createInstrument(extensions: ForgeExtension[], originalInstrument?: Instrument): InstrumentResponse;
22
- protected augmentComponents(instances: ForgeBaseComponent[], extensions: ForgeExtension[]): void;
23
- protected augmentModule(instance: ForgeModule, extensions: ForgeExtension[]): void;
24
- protected augmentController(instance: ForgeController, extensions: ForgeExtension[]): void;
25
- protected augmentService(instance: ForgeService, extensions: ForgeExtension[]): void;
23
+ protected augmentComponents(instances: ForgeBaseComponent[], extensions: ForgeExtension[]): Promise<void>;
24
+ protected augmentComponent(instance: ForgeBaseComponent, extensions: ForgeExtension[]): Promise<void>;
25
+ protected augmentModule(instance: ForgeModule, extensions: ForgeExtension[]): Promise<void>;
26
+ protected augmentController(instance: ForgeController, extensions: ForgeExtension[]): Promise<void>;
27
+ protected augmentService(instance: ForgeService, extensions: ForgeExtension[]): Promise<void>;
26
28
  protected _isRootModule(instance: unknown): instance is IForgeRootModule;
29
+ protected _isHttpAdapter(instance: unknown): instance is AbstractHttpAdapter;
30
+ protected _augmentBootHooks(createOptions: object, extensions: ForgeExtension[]): void;
31
+ protected _augmentNestApplication(): void;
27
32
  }
28
33
  type IEntryNestModule = Type<any> | DynamicModule | ForwardReference | Promise<IEntryNestModule>;
29
34
  type Instrument = {
@@ -8,19 +8,39 @@ const constants_1 = require("./constants");
8
8
  const architecture_1 = require("./architecture");
9
9
  class Forge {
10
10
  _augmented = new Set();
11
- async create(appModule, options) {
11
+ async create(appModule, optionsOrHttpAdapter, optionsFallback) {
12
+ let adapter = this._isHttpAdapter(optionsOrHttpAdapter) ? optionsOrHttpAdapter : undefined;
13
+ const options = (typeof optionsFallback === 'object' ? optionsFallback : adapter ? {} : optionsOrHttpAdapter) ??
14
+ {};
12
15
  const extensions = this.discoverExtensions(options?.extensions ?? []);
13
16
  const root = this.createRootModule(appModule, extensions);
14
17
  const instrument = this.createInstrument(extensions, options.instrument);
15
- const app = await core_1.NestFactory.create(root, {
18
+ let createOptions = {
16
19
  ...options,
17
20
  instrument: {
18
21
  instanceDecorator: instrument.instanceDecorator,
19
22
  },
20
- });
21
- this.augmentComponents(instrument.instances, extensions);
23
+ };
22
24
  for (const extension of extensions) {
23
- extension.configureHttpApplication(app);
25
+ const newOptions = await extension.configureHttpApplicationOptions(createOptions);
26
+ const newAdapter = await extension.configureHttpAdapter(adapter);
27
+ if (typeof newOptions === 'object' && newOptions !== null) {
28
+ createOptions = newOptions;
29
+ }
30
+ if (typeof newAdapter === 'object' && newAdapter !== null) {
31
+ adapter = newAdapter;
32
+ }
33
+ }
34
+ const createArgs = [root, createOptions];
35
+ if (adapter) {
36
+ createArgs.splice(1, 0, adapter);
37
+ }
38
+ this._augmentBootHooks(createOptions, extensions);
39
+ this._augmentNestApplication();
40
+ const app = await core_1.NestFactory.create.apply(core_1.NestFactory, createArgs);
41
+ await this.augmentComponents(instrument.instances, extensions);
42
+ for (const extension of extensions) {
43
+ await extension.configureHttpApplication(app);
24
44
  }
25
45
  return app;
26
46
  }
@@ -28,31 +48,52 @@ class Forge {
28
48
  const extensions = this.discoverExtensions(options?.extensions ?? []);
29
49
  const root = this.createRootModule(appModule, extensions);
30
50
  const instrument = this.createInstrument(extensions, options.instrument);
31
- const app = await core_1.NestFactory.createApplicationContext(root, {
51
+ let createOptions = {
32
52
  ...options,
33
53
  instrument: {
34
54
  instanceDecorator: instrument.instanceDecorator,
35
55
  },
36
- });
37
- this.augmentComponents(instrument.instances, extensions);
56
+ };
38
57
  for (const extension of extensions) {
39
- extension.configureStandaloneApplication(app);
58
+ const newOptions = await extension.configureStandaloneApplicationOptions(createOptions);
59
+ if (typeof newOptions === 'object' && newOptions !== null) {
60
+ createOptions = newOptions;
61
+ }
62
+ }
63
+ createOptions[constants_1.FORGE_PATCH_ENABLE_INIT] = false;
64
+ this._augmentBootHooks(createOptions, extensions);
65
+ this._augmentNestApplication();
66
+ const app = await core_1.NestFactory.createApplicationContext(root, createOptions);
67
+ await this.augmentComponents(instrument.instances, extensions);
68
+ for (const extension of extensions) {
69
+ await extension.configureStandaloneApplication(app);
40
70
  }
71
+ createOptions[constants_1.FORGE_PATCH_ENABLE_INIT] = true;
72
+ await app.init();
41
73
  return app;
42
74
  }
43
75
  async createMicroservice(appModule, options) {
44
76
  const extensions = this.discoverExtensions(options?.extensions ?? []);
45
77
  const root = this.createRootModule(appModule, extensions);
46
78
  const instrument = this.createInstrument(extensions, options.instrument);
47
- const app = await core_1.NestFactory.createMicroservice(root, {
79
+ let createOptions = {
48
80
  ...options,
49
81
  instrument: {
50
82
  instanceDecorator: instrument.instanceDecorator,
51
83
  },
52
- });
53
- this.augmentComponents(instrument.instances, extensions);
84
+ };
85
+ for (const extension of extensions) {
86
+ const newOptions = await extension.configureMicroserviceApplicationOptions(createOptions);
87
+ if (typeof newOptions === 'object' && newOptions !== null) {
88
+ createOptions = newOptions;
89
+ }
90
+ }
91
+ this._augmentBootHooks(createOptions, extensions);
92
+ this._augmentNestApplication();
93
+ const app = await core_1.NestFactory.createMicroservice(root, createOptions);
94
+ await this.augmentComponents(instrument.instances, extensions);
54
95
  for (const extension of extensions) {
55
- extension.configureMicroserviceApplication(app);
96
+ await extension.configureMicroserviceApplication(app);
56
97
  }
57
98
  return app;
58
99
  }
@@ -108,9 +149,9 @@ class Forge {
108
149
  constructor(moduleRef) {
109
150
  this.moduleRef = moduleRef;
110
151
  }
111
- configure(consumer) {
152
+ async configure(consumer) {
112
153
  for (const extension of extensions) {
113
- extension.configureRootModule(consumer);
154
+ await extension.configureRootModule(consumer);
114
155
  }
115
156
  }
116
157
  };
@@ -161,40 +202,80 @@ class Forge {
161
202
  },
162
203
  };
163
204
  }
164
- augmentComponents(instances, extensions) {
205
+ async augmentComponents(instances, extensions) {
165
206
  for (const instance of instances) {
166
207
  if (!this._augmented.has(instance)) {
208
+ await this.augmentComponent(instance, extensions);
167
209
  if (instance instanceof architecture_1.ForgeModule) {
168
- this.augmentModule(instance, extensions);
210
+ await this.augmentModule(instance, extensions);
169
211
  }
170
212
  else if (instance instanceof architecture_1.ForgeController) {
171
- this.augmentController(instance, extensions);
213
+ await this.augmentController(instance, extensions);
172
214
  }
173
215
  else if (instance instanceof architecture_1.ForgeService) {
174
- this.augmentService(instance, extensions);
216
+ await this.augmentService(instance, extensions);
175
217
  }
176
218
  this._augmented.add(instance);
177
219
  }
178
220
  }
179
221
  }
180
- augmentModule(instance, extensions) {
222
+ async augmentComponent(instance, extensions) {
181
223
  for (const extension of extensions) {
182
- extension.augmentModule(instance, instance[constants_1.FORGE_FIELD_MODULE_REF]);
224
+ await extension.augmentComponent(instance, instance[constants_1.FORGE_FIELD_MODULE_REF]);
183
225
  }
184
226
  }
185
- augmentController(instance, extensions) {
227
+ async augmentModule(instance, extensions) {
186
228
  for (const extension of extensions) {
187
- extension.augmentController(instance, instance[constants_1.FORGE_FIELD_MODULE_REF]);
229
+ await extension.augmentModule(instance, instance[constants_1.FORGE_FIELD_MODULE_REF]);
188
230
  }
189
231
  }
190
- augmentService(instance, extensions) {
232
+ async augmentController(instance, extensions) {
191
233
  for (const extension of extensions) {
192
- extension.augmentService(instance, instance[constants_1.FORGE_FIELD_MODULE_REF]);
234
+ await extension.augmentController(instance, instance[constants_1.FORGE_FIELD_MODULE_REF]);
235
+ }
236
+ }
237
+ async augmentService(instance, extensions) {
238
+ for (const extension of extensions) {
239
+ await extension.augmentService(instance, instance[constants_1.FORGE_FIELD_MODULE_REF]);
193
240
  }
194
241
  }
195
242
  _isRootModule(instance) {
196
243
  return typeof instance === 'object' && instance !== null && instance[constants_1.FORGE_ROOT_MODULE] === true;
197
244
  }
245
+ _isHttpAdapter(instance) {
246
+ return typeof instance === 'object' && instance !== null && typeof instance['use'] === 'function';
247
+ }
248
+ _augmentBootHooks(createOptions, extensions) {
249
+ createOptions[constants_1.FORGE_PATCH_BOOT_CALLBACK] = async (app) => {
250
+ try {
251
+ await Promise.all(extensions.map((e) => e.afterBoot(app)));
252
+ }
253
+ catch (error) {
254
+ console.error(error);
255
+ }
256
+ };
257
+ }
258
+ _augmentNestApplication() {
259
+ const application = core_1.NestApplicationContext;
260
+ const originalBootstrapHook = application.prototype.callBootstrapHook;
261
+ const originalInit = application.prototype.init;
262
+ if (application.prototype[constants_1.FORGE_PATCHED]) {
263
+ return;
264
+ }
265
+ application.prototype[constants_1.FORGE_PATCHED] = true;
266
+ application.prototype.callBootstrapHook = async function () {
267
+ await originalBootstrapHook.call(this);
268
+ if (this.appOptions[constants_1.FORGE_PATCH_BOOT_CALLBACK]) {
269
+ await this.appOptions[constants_1.FORGE_PATCH_BOOT_CALLBACK](this);
270
+ }
271
+ };
272
+ application.prototype.init = async function () {
273
+ if (this.appOptions[constants_1.FORGE_PATCH_ENABLE_INIT] === false) {
274
+ return this;
275
+ }
276
+ return originalInit.call(this);
277
+ };
278
+ }
198
279
  }
199
280
  const forge = new Forge();
200
281
  exports.Forge = forge;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nest-forge/core",
3
3
  "description": "",
4
- "version": "0.0.2",
4
+ "version": "0.0.3",
5
5
  "scripts": {
6
6
  "build": "rimraf dist && tsc -p tsconfig.json",
7
7
  "watch": "rimraf dist && tsc -w -p tsconfig.json",
@@ -31,14 +31,12 @@
31
31
  "devDependencies": {
32
32
  "@eslint/eslintrc": "^3.3.3",
33
33
  "@eslint/js": "^9.39.2",
34
- "@types/node": "~25.0.0",
34
+ "@types/node": "~24.0.0",
35
35
  "eslint": "^9.18.0",
36
36
  "eslint-config-prettier": "^10.1.8",
37
- "eslint-plugin-import": "^2.32.0",
38
37
  "eslint-plugin-prettier": "^5.5.4",
39
38
  "globals": "^16.0.0",
40
39
  "prettier": "3.7.4",
41
- "reflect-metadata": "^0.2.2",
42
40
  "rimraf": "^6.1.2",
43
41
  "typescript": "^5.9.0",
44
42
  "typescript-eslint": "^8.51.0"
package/tsconfig.json CHANGED
@@ -17,7 +17,8 @@
17
17
  "outDir": "./dist",
18
18
  "forceConsistentCasingInFileNames": true,
19
19
  "strictPropertyInitialization": false,
20
- "stripInternal": true
20
+ "stripInternal": true,
21
+ "strict": true
21
22
  },
22
23
  "include": [
23
24
  "src/**/*"
package/.prettierignore DELETED
@@ -1,3 +0,0 @@
1
- pnpm-lock.yaml
2
- package-lock.json
3
- yarn.lock
package/.prettierrc DELETED
@@ -1,7 +0,0 @@
1
- {
2
- "parser": "typescript",
3
- "useTabs": true,
4
- "singleQuote": true,
5
- "trailingComma": "es5",
6
- "printWidth": 140
7
- }
package/eslint.config.mjs DELETED
@@ -1,31 +0,0 @@
1
- import eslint from '@eslint/js';
2
- import { defineConfig } from 'eslint/config';
3
- import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
4
- import tseslint from 'typescript-eslint';
5
- import globals from 'globals';
6
-
7
- export default defineConfig(
8
- {
9
- ignores: ['node_modules', '**/node_modules/**', '**/*.js', '**/*.d.ts']
10
- },
11
- eslint.configs.recommended,
12
- ...tseslint.configs.recommendedTypeChecked,
13
- eslintPluginPrettierRecommended,
14
- {
15
- languageOptions: {
16
- globals: {
17
- ...globals.node,
18
- ...globals.jest
19
- },
20
- ecmaVersion: 2024,
21
- sourceType: 'module',
22
- parserOptions: {
23
- projectService: true,
24
- tsconfigRootDir: import.meta.dirname
25
- }
26
- }
27
- },
28
- {
29
- rules: {}
30
- }
31
- );