@singhak/nodeui-nestjs 0.3.0 → 0.5.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
@@ -76,3 +76,7 @@ app.useLogger(app.get(NodeUILogger));
76
76
 
77
77
  The module also shuts the console down (stopping samplers and restoring
78
78
  `console.*`) when the Nest app closes.
79
+
80
+ ## Request bodies
81
+
82
+ Nest parses request bodies before module middleware runs, so with `captureRequestDetail: { bodies: true }` response bodies are captured but request bodies are not (query and headers are). Capturing request bodies needs the middleware registered ahead of the parser, which Nest does not expose for module middleware.
package/dist/index.cjs CHANGED
@@ -31,6 +31,7 @@ var __decorateParam = (index, decorator) => (target, key) => decorator(target, k
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  NODEUI_SERVER: () => NODEUI_SERVER,
34
+ NodeUIErrorInterceptor: () => NodeUIErrorInterceptor,
34
35
  NodeUILogger: () => NodeUILogger,
35
36
  NodeUIModule: () => NodeUIModule,
36
37
  NodeUIService: () => NodeUIService
@@ -38,16 +39,43 @@ __export(index_exports, {
38
39
  module.exports = __toCommonJS(index_exports);
39
40
 
40
41
  // src/nodeui.module.ts
41
- var import_common3 = require("@nestjs/common");
42
+ var import_common4 = require("@nestjs/common");
43
+ var import_core = require("@nestjs/core");
42
44
  var import_nodeui_core = require("@singhak/nodeui-core");
43
45
 
44
- // src/nodeui.logger.ts
46
+ // src/nodeui.interceptor.ts
45
47
  var import_common = require("@nestjs/common");
48
+ var import_rxjs = require("rxjs");
49
+ var import_operators = require("rxjs/operators");
46
50
 
47
51
  // src/tokens.ts
48
52
  var NODEUI_SERVER = /* @__PURE__ */ Symbol("NODEUI_SERVER");
49
53
 
54
+ // src/nodeui.interceptor.ts
55
+ var NodeUIErrorInterceptor = class {
56
+ constructor(server) {
57
+ this.server = server;
58
+ }
59
+ server;
60
+ intercept(_context, next) {
61
+ return next.handle().pipe(
62
+ (0, import_operators.catchError)((error) => {
63
+ const status = error instanceof import_common.HttpException ? error.getStatus() : void 0;
64
+ if (status === void 0 || status >= 500) {
65
+ this.server.recordError(error, status === void 0 ? {} : { status });
66
+ }
67
+ return (0, import_rxjs.throwError)(() => error);
68
+ })
69
+ );
70
+ }
71
+ };
72
+ NodeUIErrorInterceptor = __decorateClass([
73
+ (0, import_common.Injectable)(),
74
+ __decorateParam(0, (0, import_common.Inject)(NODEUI_SERVER))
75
+ ], NodeUIErrorInterceptor);
76
+
50
77
  // src/nodeui.logger.ts
78
+ var import_common2 = require("@nestjs/common");
51
79
  function format(message, optionalParams) {
52
80
  const parts = [
53
81
  message,
@@ -57,7 +85,7 @@ function format(message, optionalParams) {
57
85
  (p) => typeof p === "string" ? p : p instanceof Error ? p.stack ?? p.message : JSON.stringify(p)
58
86
  ).join(" ");
59
87
  }
60
- var NodeUILogger = class extends import_common.ConsoleLogger {
88
+ var NodeUILogger = class extends import_common2.ConsoleLogger {
61
89
  constructor(server) {
62
90
  super();
63
91
  this.server = server;
@@ -88,12 +116,12 @@ var NodeUILogger = class extends import_common.ConsoleLogger {
88
116
  }
89
117
  };
90
118
  NodeUILogger = __decorateClass([
91
- (0, import_common.Injectable)(),
92
- __decorateParam(0, (0, import_common.Inject)(NODEUI_SERVER))
119
+ (0, import_common2.Injectable)(),
120
+ __decorateParam(0, (0, import_common2.Inject)(NODEUI_SERVER))
93
121
  ], NodeUILogger);
94
122
 
95
123
  // src/nodeui.service.ts
96
- var import_common2 = require("@nestjs/common");
124
+ var import_common3 = require("@nestjs/common");
97
125
  var NodeUIService = class {
98
126
  constructor(server) {
99
127
  this.server = server;
@@ -105,6 +133,14 @@ var NodeUIService = class {
105
133
  get config() {
106
134
  return this.server.config;
107
135
  }
136
+ /** Records an error in the Errors panel (also done automatically for uncaught request errors). */
137
+ recordError(error, context) {
138
+ this.server.recordError(error, context);
139
+ }
140
+ /** Records a database query (pg and mysql2 are captured automatically). */
141
+ recordQuery(query) {
142
+ this.server.recordQuery(query);
143
+ }
108
144
  shutdown() {
109
145
  this.server.shutdown();
110
146
  }
@@ -113,8 +149,8 @@ var NodeUIService = class {
113
149
  }
114
150
  };
115
151
  NodeUIService = __decorateClass([
116
- (0, import_common2.Injectable)(),
117
- __decorateParam(0, (0, import_common2.Inject)(NODEUI_SERVER))
152
+ (0, import_common3.Injectable)(),
153
+ __decorateParam(0, (0, import_common3.Inject)(NODEUI_SERVER))
118
154
  ], NodeUIService);
119
155
 
120
156
  // src/nodeui.module.ts
@@ -127,7 +163,12 @@ var NodeUIModule = class {
127
163
  const server = (0, import_nodeui_core.createNodeUI)(options);
128
164
  return {
129
165
  module: NodeUIModule,
130
- providers: [{ provide: NODEUI_SERVER, useValue: server }, NodeUIService, NodeUILogger],
166
+ providers: [
167
+ { provide: NODEUI_SERVER, useValue: server },
168
+ { provide: import_core.APP_INTERCEPTOR, useClass: NodeUIErrorInterceptor },
169
+ NodeUIService,
170
+ NodeUILogger
171
+ ],
131
172
  exports: [NodeUIService, NodeUILogger, NODEUI_SERVER]
132
173
  };
133
174
  }
@@ -140,8 +181,8 @@ var NodeUIModule = class {
140
181
  }
141
182
  };
142
183
  NodeUIModule = __decorateClass([
143
- (0, import_common3.Module)({}),
144
- __decorateParam(0, (0, import_common3.Inject)(NODEUI_SERVER))
184
+ (0, import_common4.Module)({}),
185
+ __decorateParam(0, (0, import_common4.Inject)(NODEUI_SERVER))
145
186
  ], NodeUIModule);
146
187
 
147
188
  // src/index.ts
@@ -149,6 +190,7 @@ __reExport(index_exports, require("@singhak/nodeui-core"), module.exports);
149
190
  // Annotate the CommonJS export names for ESM import in node:
150
191
  0 && (module.exports = {
151
192
  NODEUI_SERVER,
193
+ NodeUIErrorInterceptor,
152
194
  NodeUILogger,
153
195
  NodeUIModule,
154
196
  NodeUIService,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/nodeui.module.ts","../src/nodeui.logger.ts","../src/tokens.ts","../src/nodeui.service.ts"],"sourcesContent":["/**\r\n * @singhak/nodeui-nestjs — NestJS adapter for the NodeUI developer console.\r\n */\r\n\r\nexport { NodeUIModule } from './nodeui.module';\r\nexport { NodeUILogger } from './nodeui.logger';\r\nexport { NodeUIService } from './nodeui.service';\r\nexport { NODEUI_SERVER } from './tokens';\r\nexport * from '@singhak/nodeui-core';\r\n","import {\r\n DynamicModule,\r\n Inject,\r\n MiddlewareConsumer,\r\n Module,\r\n NestModule,\r\n OnModuleDestroy,\r\n} from '@nestjs/common';\r\nimport { createNodeUI, type NodeUIOptions, type NodeUIServer } from '@singhak/nodeui-core';\r\nimport { NodeUILogger } from './nodeui.logger';\r\nimport { NodeUIService } from './nodeui.service';\r\nimport { NODEUI_SERVER } from './tokens';\r\n\r\n/**\r\n * NestJS adapter for the NodeUI developer console. Mounts the core middleware\r\n * for every route; the console and its API live under `NODEUI_PATH` (default\r\n * `/nodeui`) and app requests are recorded in the request log.\r\n *\r\n * @example\r\n * @Module({ imports: [NodeUIModule.register()] })\r\n * export class AppModule {}\r\n */\r\n@Module({})\r\nexport class NodeUIModule implements NestModule, OnModuleDestroy {\r\n static register(options?: NodeUIOptions): DynamicModule {\r\n const server = createNodeUI(options);\r\n return {\r\n module: NodeUIModule,\r\n providers: [{ provide: NODEUI_SERVER, useValue: server }, NodeUIService, NodeUILogger],\r\n exports: [NodeUIService, NodeUILogger, NODEUI_SERVER],\r\n };\r\n }\r\n\r\n constructor(@Inject(NODEUI_SERVER) private readonly server: NodeUIServer) {}\r\n\r\n configure(consumer: MiddlewareConsumer): void {\r\n consumer.apply(this.server.middleware()).forRoutes('*');\r\n }\r\n\r\n /** Stops samplers and restores `console.*` when the Nest app closes. */\r\n onModuleDestroy(): void {\r\n this.server.shutdown();\r\n }\r\n}\r\n","import { ConsoleLogger, Inject, Injectable } from '@nestjs/common';\r\nimport type { NodeUIServer } from '@singhak/nodeui-core';\r\nimport { NODEUI_SERVER } from './tokens';\r\n\r\ntype Level = 'debug' | 'info' | 'warn' | 'error';\r\n\r\nfunction format(message: unknown, optionalParams: unknown[]): string {\r\n const parts = [\r\n message,\r\n ...optionalParams.filter((p) => typeof p === 'string' || p instanceof Error),\r\n ];\r\n return parts\r\n .map((p) =>\r\n typeof p === 'string' ? p : p instanceof Error ? (p.stack ?? p.message) : JSON.stringify(p),\r\n )\r\n .join(' ');\r\n}\r\n\r\n/**\r\n * Nest's default logger writes straight to `process.stdout`, bypassing\r\n * `console.*`, so the Logs panel would stay empty. Use this logger to mirror\r\n * every Nest log line into the panel while keeping the normal console output.\r\n *\r\n * @example\r\n * const app = await NestFactory.create(AppModule, { bufferLogs: true });\r\n * app.useLogger(app.get(NodeUILogger));\r\n */\r\n@Injectable()\r\nexport class NodeUILogger extends ConsoleLogger {\r\n constructor(@Inject(NODEUI_SERVER) private readonly server: NodeUIServer) {\r\n super();\r\n }\r\n\r\n private tee(level: Level, message: unknown, params: unknown[]): void {\r\n this.server.addLogSource({ level, message: format(message, params) });\r\n }\r\n\r\n override log(message: unknown, ...optionalParams: unknown[]): void {\r\n this.tee('info', message, optionalParams);\r\n super.log(message, ...optionalParams);\r\n }\r\n\r\n override warn(message: unknown, ...optionalParams: unknown[]): void {\r\n this.tee('warn', message, optionalParams);\r\n super.warn(message, ...optionalParams);\r\n }\r\n\r\n override error(message: unknown, ...optionalParams: unknown[]): void {\r\n this.tee('error', message, optionalParams);\r\n super.error(message, ...optionalParams);\r\n }\r\n\r\n override debug(message: unknown, ...optionalParams: unknown[]): void {\r\n this.tee('debug', message, optionalParams);\r\n super.debug(message, ...optionalParams);\r\n }\r\n\r\n override verbose(message: unknown, ...optionalParams: unknown[]): void {\r\n this.tee('debug', message, optionalParams);\r\n super.verbose(message, ...optionalParams);\r\n }\r\n}\r\n","/** Injection token for the underlying NodeUIServer instance. */\nexport const NODEUI_SERVER = Symbol('NODEUI_SERVER');\n","import { Inject, Injectable } from '@nestjs/common';\nimport type { NodeUIServer } from '@singhak/nodeui-core';\nimport { NODEUI_SERVER } from './tokens';\n\n/** Injectable handle to the NodeUI server: record startup marks, read config. */\n@Injectable()\nexport class NodeUIService {\n constructor(@Inject(NODEUI_SERVER) private readonly server: NodeUIServer) {}\n\n mark(name: string): void {\n this.server.mark(name);\n }\n\n get config() {\n return this.server.config;\n }\n\n shutdown(): void {\n this.server.shutdown();\n }\n\n addLogSource(entry: { level: 'debug' | 'info' | 'warn' | 'error'; message: string }): void {\n this.server.addLogSource(entry);\n }\n}\n"],"mappings":"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","names":["import_common","import_common"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/nodeui.module.ts","../src/nodeui.interceptor.ts","../src/tokens.ts","../src/nodeui.logger.ts","../src/nodeui.service.ts"],"sourcesContent":["/**\r\n * @singhak/nodeui-nestjs — NestJS adapter for the NodeUI developer console.\r\n */\r\n\r\nexport { NodeUIModule } from './nodeui.module';\r\nexport { NodeUIErrorInterceptor } from './nodeui.interceptor';\r\nexport { NodeUILogger } from './nodeui.logger';\r\nexport { NodeUIService } from './nodeui.service';\r\nexport { NODEUI_SERVER } from './tokens';\r\nexport * from '@singhak/nodeui-core';\r\n","import {\r\n DynamicModule,\r\n Inject,\r\n MiddlewareConsumer,\r\n Module,\r\n NestModule,\r\n OnModuleDestroy,\r\n} from '@nestjs/common';\r\nimport { APP_INTERCEPTOR } from '@nestjs/core';\r\nimport { createNodeUI, type NodeUIOptions, type NodeUIServer } from '@singhak/nodeui-core';\r\nimport { NodeUIErrorInterceptor } from './nodeui.interceptor';\r\nimport { NodeUILogger } from './nodeui.logger';\r\nimport { NodeUIService } from './nodeui.service';\r\nimport { NODEUI_SERVER } from './tokens';\r\n\r\n/**\r\n * NestJS adapter for the NodeUI developer console. Mounts the core middleware\r\n * for every route; the console and its API live under `NODEUI_PATH` (default\r\n * `/nodeui`) and app requests are recorded in the request log.\r\n *\r\n * @example\r\n * @Module({ imports: [NodeUIModule.register()] })\r\n * export class AppModule {}\r\n */\r\n@Module({})\r\nexport class NodeUIModule implements NestModule, OnModuleDestroy {\r\n static register(options?: NodeUIOptions): DynamicModule {\r\n const server = createNodeUI(options);\r\n return {\r\n module: NodeUIModule,\r\n providers: [\r\n { provide: NODEUI_SERVER, useValue: server },\r\n { provide: APP_INTERCEPTOR, useClass: NodeUIErrorInterceptor },\r\n NodeUIService,\r\n NodeUILogger,\r\n ],\r\n exports: [NodeUIService, NodeUILogger, NODEUI_SERVER],\r\n };\r\n }\r\n\r\n constructor(@Inject(NODEUI_SERVER) private readonly server: NodeUIServer) {}\r\n\r\n configure(consumer: MiddlewareConsumer): void {\r\n consumer.apply(this.server.middleware()).forRoutes('*');\r\n }\r\n\r\n /** Stops samplers and restores `console.*` when the Nest app closes. */\r\n onModuleDestroy(): void {\r\n this.server.shutdown();\r\n }\r\n}\r\n","import {\r\n CallHandler,\r\n ExecutionContext,\r\n HttpException,\r\n Inject,\r\n Injectable,\r\n NestInterceptor,\r\n} from '@nestjs/common';\r\nimport type { NodeUIServer } from '@singhak/nodeui-core';\r\nimport { Observable, throwError } from 'rxjs';\r\nimport { catchError } from 'rxjs/operators';\r\nimport { NODEUI_SERVER } from './tokens';\r\n\r\n/**\r\n * Records errors thrown by route handlers in the Errors panel and rethrows them\r\n * untouched. Client errors (`HttpException` < 500) are expected and skipped.\r\n * Errors raised earlier, in guards or pipes, bypass interceptors.\r\n */\r\n@Injectable()\r\nexport class NodeUIErrorInterceptor implements NestInterceptor {\r\n constructor(@Inject(NODEUI_SERVER) private readonly server: NodeUIServer) {}\r\n\r\n intercept(_context: ExecutionContext, next: CallHandler): Observable<unknown> {\r\n return next.handle().pipe(\r\n catchError((error: unknown) => {\r\n const status = error instanceof HttpException ? error.getStatus() : undefined;\r\n if (status === undefined || status >= 500) {\r\n this.server.recordError(error, status === undefined ? {} : { status });\r\n }\r\n return throwError(() => error);\r\n }),\r\n );\r\n }\r\n}\r\n","/** Injection token for the underlying NodeUIServer instance. */\nexport const NODEUI_SERVER = Symbol('NODEUI_SERVER');\n","import { ConsoleLogger, Inject, Injectable } from '@nestjs/common';\nimport type { NodeUIServer } from '@singhak/nodeui-core';\nimport { NODEUI_SERVER } from './tokens';\n\ntype Level = 'debug' | 'info' | 'warn' | 'error';\n\nfunction format(message: unknown, optionalParams: unknown[]): string {\n const parts = [\n message,\n ...optionalParams.filter((p) => typeof p === 'string' || p instanceof Error),\n ];\n return parts\n .map((p) =>\n typeof p === 'string' ? p : p instanceof Error ? (p.stack ?? p.message) : JSON.stringify(p),\n )\n .join(' ');\n}\n\n/**\n * Nest's default logger writes straight to `process.stdout`, bypassing\n * `console.*`, so the Logs panel would stay empty. Use this logger to mirror\n * every Nest log line into the panel while keeping the normal console output.\n *\n * @example\n * const app = await NestFactory.create(AppModule, { bufferLogs: true });\n * app.useLogger(app.get(NodeUILogger));\n */\n@Injectable()\nexport class NodeUILogger extends ConsoleLogger {\n constructor(@Inject(NODEUI_SERVER) private readonly server: NodeUIServer) {\n super();\n }\n\n private tee(level: Level, message: unknown, params: unknown[]): void {\n this.server.addLogSource({ level, message: format(message, params) });\n }\n\n override log(message: unknown, ...optionalParams: unknown[]): void {\n this.tee('info', message, optionalParams);\n super.log(message, ...optionalParams);\n }\n\n override warn(message: unknown, ...optionalParams: unknown[]): void {\n this.tee('warn', message, optionalParams);\n super.warn(message, ...optionalParams);\n }\n\n override error(message: unknown, ...optionalParams: unknown[]): void {\n this.tee('error', message, optionalParams);\n super.error(message, ...optionalParams);\n }\n\n override debug(message: unknown, ...optionalParams: unknown[]): void {\n this.tee('debug', message, optionalParams);\n super.debug(message, ...optionalParams);\n }\n\n override verbose(message: unknown, ...optionalParams: unknown[]): void {\n this.tee('debug', message, optionalParams);\n super.verbose(message, ...optionalParams);\n }\n}\n","import { Inject, Injectable } from '@nestjs/common';\r\nimport type { NodeUIServer } from '@singhak/nodeui-core';\r\nimport { NODEUI_SERVER } from './tokens';\r\n\r\n/** Injectable handle to the NodeUI server: record startup marks, read config. */\r\n@Injectable()\r\nexport class NodeUIService {\r\n constructor(@Inject(NODEUI_SERVER) private readonly server: NodeUIServer) {}\r\n\r\n mark(name: string): void {\r\n this.server.mark(name);\r\n }\r\n\r\n get config() {\r\n return this.server.config;\r\n }\r\n\r\n /** Records an error in the Errors panel (also done automatically for uncaught request errors). */\r\n recordError(error: unknown, context?: Parameters<NodeUIServer['recordError']>[1]): void {\r\n this.server.recordError(error, context);\r\n }\r\n\r\n /** Records a database query (pg and mysql2 are captured automatically). */\r\n recordQuery(query: Parameters<NodeUIServer['recordQuery']>[0]): void {\r\n this.server.recordQuery(query);\r\n }\r\n\r\n shutdown(): void {\r\n this.server.shutdown();\r\n }\r\n\r\n addLogSource(entry: { level: 'debug' | 'info' | 'warn' | 'error'; message: string }): void {\r\n this.server.addLogSource(entry);\r\n }\r\n}\r\n"],"mappings":"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","names":["import_common","import_common","import_common"]}
package/dist/index.d.mts CHANGED
@@ -1,7 +1,8 @@
1
- import { NestModule, OnModuleDestroy, DynamicModule, MiddlewareConsumer, ConsoleLogger } from '@nestjs/common';
1
+ import { NestModule, OnModuleDestroy, DynamicModule, MiddlewareConsumer, NestInterceptor, ExecutionContext, CallHandler, ConsoleLogger } from '@nestjs/common';
2
2
  import * as _singhak_nodeui_core from '@singhak/nodeui-core';
3
3
  import { NodeUIOptions, NodeUIServer } from '@singhak/nodeui-core';
4
4
  export * from '@singhak/nodeui-core';
5
+ import { Observable } from 'rxjs';
5
6
 
6
7
  /**
7
8
  * NestJS adapter for the NodeUI developer console. Mounts the core middleware
@@ -21,6 +22,17 @@ declare class NodeUIModule implements NestModule, OnModuleDestroy {
21
22
  onModuleDestroy(): void;
22
23
  }
23
24
 
25
+ /**
26
+ * Records errors thrown by route handlers in the Errors panel and rethrows them
27
+ * untouched. Client errors (`HttpException` < 500) are expected and skipped.
28
+ * Errors raised earlier, in guards or pipes, bypass interceptors.
29
+ */
30
+ declare class NodeUIErrorInterceptor implements NestInterceptor {
31
+ private readonly server;
32
+ constructor(server: NodeUIServer);
33
+ intercept(_context: ExecutionContext, next: CallHandler): Observable<unknown>;
34
+ }
35
+
24
36
  /**
25
37
  * Nest's default logger writes straight to `process.stdout`, bypassing
26
38
  * `console.*`, so the Logs panel would stay empty. Use this logger to mirror
@@ -47,6 +59,10 @@ declare class NodeUIService {
47
59
  constructor(server: NodeUIServer);
48
60
  mark(name: string): void;
49
61
  get config(): _singhak_nodeui_core.NodeUIConfig;
62
+ /** Records an error in the Errors panel (also done automatically for uncaught request errors). */
63
+ recordError(error: unknown, context?: Parameters<NodeUIServer['recordError']>[1]): void;
64
+ /** Records a database query (pg and mysql2 are captured automatically). */
65
+ recordQuery(query: Parameters<NodeUIServer['recordQuery']>[0]): void;
50
66
  shutdown(): void;
51
67
  addLogSource(entry: {
52
68
  level: 'debug' | 'info' | 'warn' | 'error';
@@ -57,4 +73,4 @@ declare class NodeUIService {
57
73
  /** Injection token for the underlying NodeUIServer instance. */
58
74
  declare const NODEUI_SERVER: unique symbol;
59
75
 
60
- export { NODEUI_SERVER, NodeUILogger, NodeUIModule, NodeUIService };
76
+ export { NODEUI_SERVER, NodeUIErrorInterceptor, NodeUILogger, NodeUIModule, NodeUIService };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- import { NestModule, OnModuleDestroy, DynamicModule, MiddlewareConsumer, ConsoleLogger } from '@nestjs/common';
1
+ import { NestModule, OnModuleDestroy, DynamicModule, MiddlewareConsumer, NestInterceptor, ExecutionContext, CallHandler, ConsoleLogger } from '@nestjs/common';
2
2
  import * as _singhak_nodeui_core from '@singhak/nodeui-core';
3
3
  import { NodeUIOptions, NodeUIServer } from '@singhak/nodeui-core';
4
4
  export * from '@singhak/nodeui-core';
5
+ import { Observable } from 'rxjs';
5
6
 
6
7
  /**
7
8
  * NestJS adapter for the NodeUI developer console. Mounts the core middleware
@@ -21,6 +22,17 @@ declare class NodeUIModule implements NestModule, OnModuleDestroy {
21
22
  onModuleDestroy(): void;
22
23
  }
23
24
 
25
+ /**
26
+ * Records errors thrown by route handlers in the Errors panel and rethrows them
27
+ * untouched. Client errors (`HttpException` < 500) are expected and skipped.
28
+ * Errors raised earlier, in guards or pipes, bypass interceptors.
29
+ */
30
+ declare class NodeUIErrorInterceptor implements NestInterceptor {
31
+ private readonly server;
32
+ constructor(server: NodeUIServer);
33
+ intercept(_context: ExecutionContext, next: CallHandler): Observable<unknown>;
34
+ }
35
+
24
36
  /**
25
37
  * Nest's default logger writes straight to `process.stdout`, bypassing
26
38
  * `console.*`, so the Logs panel would stay empty. Use this logger to mirror
@@ -47,6 +59,10 @@ declare class NodeUIService {
47
59
  constructor(server: NodeUIServer);
48
60
  mark(name: string): void;
49
61
  get config(): _singhak_nodeui_core.NodeUIConfig;
62
+ /** Records an error in the Errors panel (also done automatically for uncaught request errors). */
63
+ recordError(error: unknown, context?: Parameters<NodeUIServer['recordError']>[1]): void;
64
+ /** Records a database query (pg and mysql2 are captured automatically). */
65
+ recordQuery(query: Parameters<NodeUIServer['recordQuery']>[0]): void;
50
66
  shutdown(): void;
51
67
  addLogSource(entry: {
52
68
  level: 'debug' | 'info' | 'warn' | 'error';
@@ -57,4 +73,4 @@ declare class NodeUIService {
57
73
  /** Injection token for the underlying NodeUIServer instance. */
58
74
  declare const NODEUI_SERVER: unique symbol;
59
75
 
60
- export { NODEUI_SERVER, NodeUILogger, NodeUIModule, NodeUIService };
76
+ export { NODEUI_SERVER, NodeUIErrorInterceptor, NodeUILogger, NodeUIModule, NodeUIService };
package/dist/index.mjs CHANGED
@@ -12,18 +12,49 @@ var __decorateParam = (index, decorator) => (target, key) => decorator(target, k
12
12
 
13
13
  // src/nodeui.module.ts
14
14
  import {
15
- Inject as Inject3,
15
+ Inject as Inject4,
16
16
  Module
17
17
  } from "@nestjs/common";
18
+ import { APP_INTERCEPTOR } from "@nestjs/core";
18
19
  import { createNodeUI } from "@singhak/nodeui-core";
19
20
 
20
- // src/nodeui.logger.ts
21
- import { ConsoleLogger, Inject, Injectable } from "@nestjs/common";
21
+ // src/nodeui.interceptor.ts
22
+ import {
23
+ HttpException,
24
+ Inject,
25
+ Injectable
26
+ } from "@nestjs/common";
27
+ import { throwError } from "rxjs";
28
+ import { catchError } from "rxjs/operators";
22
29
 
23
30
  // src/tokens.ts
24
31
  var NODEUI_SERVER = /* @__PURE__ */ Symbol("NODEUI_SERVER");
25
32
 
33
+ // src/nodeui.interceptor.ts
34
+ var NodeUIErrorInterceptor = class {
35
+ constructor(server) {
36
+ this.server = server;
37
+ }
38
+ server;
39
+ intercept(_context, next) {
40
+ return next.handle().pipe(
41
+ catchError((error) => {
42
+ const status = error instanceof HttpException ? error.getStatus() : void 0;
43
+ if (status === void 0 || status >= 500) {
44
+ this.server.recordError(error, status === void 0 ? {} : { status });
45
+ }
46
+ return throwError(() => error);
47
+ })
48
+ );
49
+ }
50
+ };
51
+ NodeUIErrorInterceptor = __decorateClass([
52
+ Injectable(),
53
+ __decorateParam(0, Inject(NODEUI_SERVER))
54
+ ], NodeUIErrorInterceptor);
55
+
26
56
  // src/nodeui.logger.ts
57
+ import { ConsoleLogger, Inject as Inject2, Injectable as Injectable2 } from "@nestjs/common";
27
58
  function format(message, optionalParams) {
28
59
  const parts = [
29
60
  message,
@@ -64,12 +95,12 @@ var NodeUILogger = class extends ConsoleLogger {
64
95
  }
65
96
  };
66
97
  NodeUILogger = __decorateClass([
67
- Injectable(),
68
- __decorateParam(0, Inject(NODEUI_SERVER))
98
+ Injectable2(),
99
+ __decorateParam(0, Inject2(NODEUI_SERVER))
69
100
  ], NodeUILogger);
70
101
 
71
102
  // src/nodeui.service.ts
72
- import { Inject as Inject2, Injectable as Injectable2 } from "@nestjs/common";
103
+ import { Inject as Inject3, Injectable as Injectable3 } from "@nestjs/common";
73
104
  var NodeUIService = class {
74
105
  constructor(server) {
75
106
  this.server = server;
@@ -81,6 +112,14 @@ var NodeUIService = class {
81
112
  get config() {
82
113
  return this.server.config;
83
114
  }
115
+ /** Records an error in the Errors panel (also done automatically for uncaught request errors). */
116
+ recordError(error, context) {
117
+ this.server.recordError(error, context);
118
+ }
119
+ /** Records a database query (pg and mysql2 are captured automatically). */
120
+ recordQuery(query) {
121
+ this.server.recordQuery(query);
122
+ }
84
123
  shutdown() {
85
124
  this.server.shutdown();
86
125
  }
@@ -89,8 +128,8 @@ var NodeUIService = class {
89
128
  }
90
129
  };
91
130
  NodeUIService = __decorateClass([
92
- Injectable2(),
93
- __decorateParam(0, Inject2(NODEUI_SERVER))
131
+ Injectable3(),
132
+ __decorateParam(0, Inject3(NODEUI_SERVER))
94
133
  ], NodeUIService);
95
134
 
96
135
  // src/nodeui.module.ts
@@ -103,7 +142,12 @@ var NodeUIModule = class {
103
142
  const server = createNodeUI(options);
104
143
  return {
105
144
  module: NodeUIModule,
106
- providers: [{ provide: NODEUI_SERVER, useValue: server }, NodeUIService, NodeUILogger],
145
+ providers: [
146
+ { provide: NODEUI_SERVER, useValue: server },
147
+ { provide: APP_INTERCEPTOR, useClass: NodeUIErrorInterceptor },
148
+ NodeUIService,
149
+ NodeUILogger
150
+ ],
107
151
  exports: [NodeUIService, NodeUILogger, NODEUI_SERVER]
108
152
  };
109
153
  }
@@ -117,13 +161,14 @@ var NodeUIModule = class {
117
161
  };
118
162
  NodeUIModule = __decorateClass([
119
163
  Module({}),
120
- __decorateParam(0, Inject3(NODEUI_SERVER))
164
+ __decorateParam(0, Inject4(NODEUI_SERVER))
121
165
  ], NodeUIModule);
122
166
 
123
167
  // src/index.ts
124
168
  export * from "@singhak/nodeui-core";
125
169
  export {
126
170
  NODEUI_SERVER,
171
+ NodeUIErrorInterceptor,
127
172
  NodeUILogger,
128
173
  NodeUIModule,
129
174
  NodeUIService
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/nodeui.module.ts","../src/nodeui.logger.ts","../src/tokens.ts","../src/nodeui.service.ts","../src/index.ts"],"sourcesContent":["import {\r\n DynamicModule,\r\n Inject,\r\n MiddlewareConsumer,\r\n Module,\r\n NestModule,\r\n OnModuleDestroy,\r\n} from '@nestjs/common';\r\nimport { createNodeUI, type NodeUIOptions, type NodeUIServer } from '@singhak/nodeui-core';\r\nimport { NodeUILogger } from './nodeui.logger';\r\nimport { NodeUIService } from './nodeui.service';\r\nimport { NODEUI_SERVER } from './tokens';\r\n\r\n/**\r\n * NestJS adapter for the NodeUI developer console. Mounts the core middleware\r\n * for every route; the console and its API live under `NODEUI_PATH` (default\r\n * `/nodeui`) and app requests are recorded in the request log.\r\n *\r\n * @example\r\n * @Module({ imports: [NodeUIModule.register()] })\r\n * export class AppModule {}\r\n */\r\n@Module({})\r\nexport class NodeUIModule implements NestModule, OnModuleDestroy {\r\n static register(options?: NodeUIOptions): DynamicModule {\r\n const server = createNodeUI(options);\r\n return {\r\n module: NodeUIModule,\r\n providers: [{ provide: NODEUI_SERVER, useValue: server }, NodeUIService, NodeUILogger],\r\n exports: [NodeUIService, NodeUILogger, NODEUI_SERVER],\r\n };\r\n }\r\n\r\n constructor(@Inject(NODEUI_SERVER) private readonly server: NodeUIServer) {}\r\n\r\n configure(consumer: MiddlewareConsumer): void {\r\n consumer.apply(this.server.middleware()).forRoutes('*');\r\n }\r\n\r\n /** Stops samplers and restores `console.*` when the Nest app closes. */\r\n onModuleDestroy(): void {\r\n this.server.shutdown();\r\n }\r\n}\r\n","import { ConsoleLogger, Inject, Injectable } from '@nestjs/common';\r\nimport type { NodeUIServer } from '@singhak/nodeui-core';\r\nimport { NODEUI_SERVER } from './tokens';\r\n\r\ntype Level = 'debug' | 'info' | 'warn' | 'error';\r\n\r\nfunction format(message: unknown, optionalParams: unknown[]): string {\r\n const parts = [\r\n message,\r\n ...optionalParams.filter((p) => typeof p === 'string' || p instanceof Error),\r\n ];\r\n return parts\r\n .map((p) =>\r\n typeof p === 'string' ? p : p instanceof Error ? (p.stack ?? p.message) : JSON.stringify(p),\r\n )\r\n .join(' ');\r\n}\r\n\r\n/**\r\n * Nest's default logger writes straight to `process.stdout`, bypassing\r\n * `console.*`, so the Logs panel would stay empty. Use this logger to mirror\r\n * every Nest log line into the panel while keeping the normal console output.\r\n *\r\n * @example\r\n * const app = await NestFactory.create(AppModule, { bufferLogs: true });\r\n * app.useLogger(app.get(NodeUILogger));\r\n */\r\n@Injectable()\r\nexport class NodeUILogger extends ConsoleLogger {\r\n constructor(@Inject(NODEUI_SERVER) private readonly server: NodeUIServer) {\r\n super();\r\n }\r\n\r\n private tee(level: Level, message: unknown, params: unknown[]): void {\r\n this.server.addLogSource({ level, message: format(message, params) });\r\n }\r\n\r\n override log(message: unknown, ...optionalParams: unknown[]): void {\r\n this.tee('info', message, optionalParams);\r\n super.log(message, ...optionalParams);\r\n }\r\n\r\n override warn(message: unknown, ...optionalParams: unknown[]): void {\r\n this.tee('warn', message, optionalParams);\r\n super.warn(message, ...optionalParams);\r\n }\r\n\r\n override error(message: unknown, ...optionalParams: unknown[]): void {\r\n this.tee('error', message, optionalParams);\r\n super.error(message, ...optionalParams);\r\n }\r\n\r\n override debug(message: unknown, ...optionalParams: unknown[]): void {\r\n this.tee('debug', message, optionalParams);\r\n super.debug(message, ...optionalParams);\r\n }\r\n\r\n override verbose(message: unknown, ...optionalParams: unknown[]): void {\r\n this.tee('debug', message, optionalParams);\r\n super.verbose(message, ...optionalParams);\r\n }\r\n}\r\n","/** Injection token for the underlying NodeUIServer instance. */\nexport const NODEUI_SERVER = Symbol('NODEUI_SERVER');\n","import { Inject, Injectable } from '@nestjs/common';\nimport type { NodeUIServer } from '@singhak/nodeui-core';\nimport { NODEUI_SERVER } from './tokens';\n\n/** Injectable handle to the NodeUI server: record startup marks, read config. */\n@Injectable()\nexport class NodeUIService {\n constructor(@Inject(NODEUI_SERVER) private readonly server: NodeUIServer) {}\n\n mark(name: string): void {\n this.server.mark(name);\n }\n\n get config() {\n return this.server.config;\n }\n\n shutdown(): void {\n this.server.shutdown();\n }\n\n addLogSource(entry: { level: 'debug' | 'info' | 'warn' | 'error'; message: string }): void {\n this.server.addLogSource(entry);\n }\n}\n","/**\r\n * @singhak/nodeui-nestjs — NestJS adapter for the NodeUI developer console.\r\n */\r\n\r\nexport { NodeUIModule } from './nodeui.module';\r\nexport { NodeUILogger } from './nodeui.logger';\r\nexport { NodeUIService } from './nodeui.service';\r\nexport { NODEUI_SERVER } from './tokens';\r\nexport * from '@singhak/nodeui-core';\r\n"],"mappings":"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","names":["Inject","Inject","Injectable","Injectable","Inject","Inject"]}
1
+ {"version":3,"sources":["../src/nodeui.module.ts","../src/nodeui.interceptor.ts","../src/tokens.ts","../src/nodeui.logger.ts","../src/nodeui.service.ts","../src/index.ts"],"sourcesContent":["import {\r\n DynamicModule,\r\n Inject,\r\n MiddlewareConsumer,\r\n Module,\r\n NestModule,\r\n OnModuleDestroy,\r\n} from '@nestjs/common';\r\nimport { APP_INTERCEPTOR } from '@nestjs/core';\r\nimport { createNodeUI, type NodeUIOptions, type NodeUIServer } from '@singhak/nodeui-core';\r\nimport { NodeUIErrorInterceptor } from './nodeui.interceptor';\r\nimport { NodeUILogger } from './nodeui.logger';\r\nimport { NodeUIService } from './nodeui.service';\r\nimport { NODEUI_SERVER } from './tokens';\r\n\r\n/**\r\n * NestJS adapter for the NodeUI developer console. Mounts the core middleware\r\n * for every route; the console and its API live under `NODEUI_PATH` (default\r\n * `/nodeui`) and app requests are recorded in the request log.\r\n *\r\n * @example\r\n * @Module({ imports: [NodeUIModule.register()] })\r\n * export class AppModule {}\r\n */\r\n@Module({})\r\nexport class NodeUIModule implements NestModule, OnModuleDestroy {\r\n static register(options?: NodeUIOptions): DynamicModule {\r\n const server = createNodeUI(options);\r\n return {\r\n module: NodeUIModule,\r\n providers: [\r\n { provide: NODEUI_SERVER, useValue: server },\r\n { provide: APP_INTERCEPTOR, useClass: NodeUIErrorInterceptor },\r\n NodeUIService,\r\n NodeUILogger,\r\n ],\r\n exports: [NodeUIService, NodeUILogger, NODEUI_SERVER],\r\n };\r\n }\r\n\r\n constructor(@Inject(NODEUI_SERVER) private readonly server: NodeUIServer) {}\r\n\r\n configure(consumer: MiddlewareConsumer): void {\r\n consumer.apply(this.server.middleware()).forRoutes('*');\r\n }\r\n\r\n /** Stops samplers and restores `console.*` when the Nest app closes. */\r\n onModuleDestroy(): void {\r\n this.server.shutdown();\r\n }\r\n}\r\n","import {\r\n CallHandler,\r\n ExecutionContext,\r\n HttpException,\r\n Inject,\r\n Injectable,\r\n NestInterceptor,\r\n} from '@nestjs/common';\r\nimport type { NodeUIServer } from '@singhak/nodeui-core';\r\nimport { Observable, throwError } from 'rxjs';\r\nimport { catchError } from 'rxjs/operators';\r\nimport { NODEUI_SERVER } from './tokens';\r\n\r\n/**\r\n * Records errors thrown by route handlers in the Errors panel and rethrows them\r\n * untouched. Client errors (`HttpException` < 500) are expected and skipped.\r\n * Errors raised earlier, in guards or pipes, bypass interceptors.\r\n */\r\n@Injectable()\r\nexport class NodeUIErrorInterceptor implements NestInterceptor {\r\n constructor(@Inject(NODEUI_SERVER) private readonly server: NodeUIServer) {}\r\n\r\n intercept(_context: ExecutionContext, next: CallHandler): Observable<unknown> {\r\n return next.handle().pipe(\r\n catchError((error: unknown) => {\r\n const status = error instanceof HttpException ? error.getStatus() : undefined;\r\n if (status === undefined || status >= 500) {\r\n this.server.recordError(error, status === undefined ? {} : { status });\r\n }\r\n return throwError(() => error);\r\n }),\r\n );\r\n }\r\n}\r\n","/** Injection token for the underlying NodeUIServer instance. */\nexport const NODEUI_SERVER = Symbol('NODEUI_SERVER');\n","import { ConsoleLogger, Inject, Injectable } from '@nestjs/common';\nimport type { NodeUIServer } from '@singhak/nodeui-core';\nimport { NODEUI_SERVER } from './tokens';\n\ntype Level = 'debug' | 'info' | 'warn' | 'error';\n\nfunction format(message: unknown, optionalParams: unknown[]): string {\n const parts = [\n message,\n ...optionalParams.filter((p) => typeof p === 'string' || p instanceof Error),\n ];\n return parts\n .map((p) =>\n typeof p === 'string' ? p : p instanceof Error ? (p.stack ?? p.message) : JSON.stringify(p),\n )\n .join(' ');\n}\n\n/**\n * Nest's default logger writes straight to `process.stdout`, bypassing\n * `console.*`, so the Logs panel would stay empty. Use this logger to mirror\n * every Nest log line into the panel while keeping the normal console output.\n *\n * @example\n * const app = await NestFactory.create(AppModule, { bufferLogs: true });\n * app.useLogger(app.get(NodeUILogger));\n */\n@Injectable()\nexport class NodeUILogger extends ConsoleLogger {\n constructor(@Inject(NODEUI_SERVER) private readonly server: NodeUIServer) {\n super();\n }\n\n private tee(level: Level, message: unknown, params: unknown[]): void {\n this.server.addLogSource({ level, message: format(message, params) });\n }\n\n override log(message: unknown, ...optionalParams: unknown[]): void {\n this.tee('info', message, optionalParams);\n super.log(message, ...optionalParams);\n }\n\n override warn(message: unknown, ...optionalParams: unknown[]): void {\n this.tee('warn', message, optionalParams);\n super.warn(message, ...optionalParams);\n }\n\n override error(message: unknown, ...optionalParams: unknown[]): void {\n this.tee('error', message, optionalParams);\n super.error(message, ...optionalParams);\n }\n\n override debug(message: unknown, ...optionalParams: unknown[]): void {\n this.tee('debug', message, optionalParams);\n super.debug(message, ...optionalParams);\n }\n\n override verbose(message: unknown, ...optionalParams: unknown[]): void {\n this.tee('debug', message, optionalParams);\n super.verbose(message, ...optionalParams);\n }\n}\n","import { Inject, Injectable } from '@nestjs/common';\r\nimport type { NodeUIServer } from '@singhak/nodeui-core';\r\nimport { NODEUI_SERVER } from './tokens';\r\n\r\n/** Injectable handle to the NodeUI server: record startup marks, read config. */\r\n@Injectable()\r\nexport class NodeUIService {\r\n constructor(@Inject(NODEUI_SERVER) private readonly server: NodeUIServer) {}\r\n\r\n mark(name: string): void {\r\n this.server.mark(name);\r\n }\r\n\r\n get config() {\r\n return this.server.config;\r\n }\r\n\r\n /** Records an error in the Errors panel (also done automatically for uncaught request errors). */\r\n recordError(error: unknown, context?: Parameters<NodeUIServer['recordError']>[1]): void {\r\n this.server.recordError(error, context);\r\n }\r\n\r\n /** Records a database query (pg and mysql2 are captured automatically). */\r\n recordQuery(query: Parameters<NodeUIServer['recordQuery']>[0]): void {\r\n this.server.recordQuery(query);\r\n }\r\n\r\n shutdown(): void {\r\n this.server.shutdown();\r\n }\r\n\r\n addLogSource(entry: { level: 'debug' | 'info' | 'warn' | 'error'; message: string }): void {\r\n this.server.addLogSource(entry);\r\n }\r\n}\r\n","/**\r\n * @singhak/nodeui-nestjs — NestJS adapter for the NodeUI developer console.\r\n */\r\n\r\nexport { NodeUIModule } from './nodeui.module';\r\nexport { NodeUIErrorInterceptor } from './nodeui.interceptor';\r\nexport { NodeUILogger } from './nodeui.logger';\r\nexport { NodeUIService } from './nodeui.service';\r\nexport { NODEUI_SERVER } from './tokens';\r\nexport * from '@singhak/nodeui-core';\r\n"],"mappings":";;;;;;;;;;;;;AAAA;AAAA,EAEE,UAAAA;AAAA,EAEA;AAAA,OAGK;AACP,SAAS,uBAAuB;AAChC,SAAS,oBAA2D;;;ACTpE;AAAA,EAGE;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAEP,SAAqB,kBAAkB;AACvC,SAAS,kBAAkB;;;ACTpB,IAAM,gBAAgB,uBAAO,eAAe;;;ADkB5C,IAAM,yBAAN,MAAwD;AAAA,EAC7D,YAAoD,QAAsB;AAAtB;AAAA,EAAuB;AAAA,EAAvB;AAAA,EAEpD,UAAU,UAA4B,MAAwC;AAC5E,WAAO,KAAK,OAAO,EAAE;AAAA,MACnB,WAAW,CAAC,UAAmB;AAC7B,cAAM,SAAS,iBAAiB,gBAAgB,MAAM,UAAU,IAAI;AACpE,YAAI,WAAW,UAAa,UAAU,KAAK;AACzC,eAAK,OAAO,YAAY,OAAO,WAAW,SAAY,CAAC,IAAI,EAAE,OAAO,CAAC;AAAA,QACvE;AACA,eAAO,WAAW,MAAM,KAAK;AAAA,MAC/B,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAda,yBAAN;AAAA,EADN,WAAW;AAAA,EAEG,0BAAO,aAAa;AAAA,GADtB;;;AEnBb,SAAS,eAAe,UAAAC,SAAQ,cAAAC,mBAAkB;AAMlD,SAAS,OAAO,SAAkB,gBAAmC;AACnE,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA,GAAG,eAAe,OAAO,CAAC,MAAM,OAAO,MAAM,YAAY,aAAa,KAAK;AAAA,EAC7E;AACA,SAAO,MACJ;AAAA,IAAI,CAAC,MACJ,OAAO,MAAM,WAAW,IAAI,aAAa,QAAS,EAAE,SAAS,EAAE,UAAW,KAAK,UAAU,CAAC;AAAA,EAC5F,EACC,KAAK,GAAG;AACb;AAYO,IAAM,eAAN,cAA2B,cAAc;AAAA,EAC9C,YAAoD,QAAsB;AACxE,UAAM;AAD4C;AAAA,EAEpD;AAAA,EAFoD;AAAA,EAI5C,IAAI,OAAc,SAAkB,QAAyB;AACnE,SAAK,OAAO,aAAa,EAAE,OAAO,SAAS,OAAO,SAAS,MAAM,EAAE,CAAC;AAAA,EACtE;AAAA,EAES,IAAI,YAAqB,gBAAiC;AACjE,SAAK,IAAI,QAAQ,SAAS,cAAc;AACxC,UAAM,IAAI,SAAS,GAAG,cAAc;AAAA,EACtC;AAAA,EAES,KAAK,YAAqB,gBAAiC;AAClE,SAAK,IAAI,QAAQ,SAAS,cAAc;AACxC,UAAM,KAAK,SAAS,GAAG,cAAc;AAAA,EACvC;AAAA,EAES,MAAM,YAAqB,gBAAiC;AACnE,SAAK,IAAI,SAAS,SAAS,cAAc;AACzC,UAAM,MAAM,SAAS,GAAG,cAAc;AAAA,EACxC;AAAA,EAES,MAAM,YAAqB,gBAAiC;AACnE,SAAK,IAAI,SAAS,SAAS,cAAc;AACzC,UAAM,MAAM,SAAS,GAAG,cAAc;AAAA,EACxC;AAAA,EAES,QAAQ,YAAqB,gBAAiC;AACrE,SAAK,IAAI,SAAS,SAAS,cAAc;AACzC,UAAM,QAAQ,SAAS,GAAG,cAAc;AAAA,EAC1C;AACF;AAjCa,eAAN;AAAA,EADNC,YAAW;AAAA,EAEG,mBAAAC,QAAO,aAAa;AAAA,GADtB;;;AC5Bb,SAAS,UAAAC,SAAQ,cAAAC,mBAAkB;AAM5B,IAAM,gBAAN,MAAoB;AAAA,EACzB,YAAoD,QAAsB;AAAtB;AAAA,EAAuB;AAAA,EAAvB;AAAA,EAEpD,KAAK,MAAoB;AACvB,SAAK,OAAO,KAAK,IAAI;AAAA,EACvB;AAAA,EAEA,IAAI,SAAS;AACX,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA;AAAA,EAGA,YAAY,OAAgB,SAA4D;AACtF,SAAK,OAAO,YAAY,OAAO,OAAO;AAAA,EACxC;AAAA;AAAA,EAGA,YAAY,OAAyD;AACnE,SAAK,OAAO,YAAY,KAAK;AAAA,EAC/B;AAAA,EAEA,WAAiB;AACf,SAAK,OAAO,SAAS;AAAA,EACvB;AAAA,EAEA,aAAa,OAA8E;AACzF,SAAK,OAAO,aAAa,KAAK;AAAA,EAChC;AACF;AA5Ba,gBAAN;AAAA,EADNC,YAAW;AAAA,EAEG,mBAAAC,QAAO,aAAa;AAAA,GADtB;;;AJmBN,IAAM,eAAN,MAA0D;AAAA,EAe/D,YAAoD,QAAsB;AAAtB;AAAA,EAAuB;AAAA,EAAvB;AAAA,EAdpD,OAAO,SAAS,SAAwC;AACtD,UAAM,SAAS,aAAa,OAAO;AACnC,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,WAAW;AAAA,QACT,EAAE,SAAS,eAAe,UAAU,OAAO;AAAA,QAC3C,EAAE,SAAS,iBAAiB,UAAU,uBAAuB;AAAA,QAC7D;AAAA,QACA;AAAA,MACF;AAAA,MACA,SAAS,CAAC,eAAe,cAAc,aAAa;AAAA,IACtD;AAAA,EACF;AAAA,EAIA,UAAU,UAAoC;AAC5C,aAAS,MAAM,KAAK,OAAO,WAAW,CAAC,EAAE,UAAU,GAAG;AAAA,EACxD;AAAA;AAAA,EAGA,kBAAwB;AACtB,SAAK,OAAO,SAAS;AAAA,EACvB;AACF;AAzBa,eAAN;AAAA,EADN,OAAO,CAAC,CAAC;AAAA,EAgBK,mBAAAC,QAAO,aAAa;AAAA,GAftB;;;AKhBb,cAAc;","names":["Inject","Inject","Injectable","Injectable","Inject","Inject","Injectable","Injectable","Inject","Inject"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@singhak/nodeui-nestjs",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "NestJS module adapter for the NodeUI developer console.",
5
5
  "license": "Apache-2.0",
6
6
  "main": "./dist/index.cjs",
@@ -47,7 +47,7 @@
47
47
  "test": "vitest run"
48
48
  },
49
49
  "dependencies": {
50
- "@singhak/nodeui-core": "^0.3.0"
50
+ "@singhak/nodeui-core": "^0.5.0"
51
51
  },
52
52
  "peerDependencies": {
53
53
  "@nestjs/common": "^11.0.0",
@@ -59,11 +59,13 @@
59
59
  "@nestjs/common": "^11.2.1",
60
60
  "@nestjs/core": "^11.2.1",
61
61
  "@nestjs/platform-express": "^11.2.1",
62
+ "@nestjs/platform-fastify": "^11.2.7",
62
63
  "@nestjs/testing": "^11.2.1",
63
64
  "@types/express": "^5.0.0",
64
65
  "@types/node": "^22.19.0",
65
66
  "@types/supertest": "^6.0.2",
66
67
  "express": "^5.2.1",
68
+ "fastify": "^5.12.5",
67
69
  "reflect-metadata": "^0.2.2",
68
70
  "rxjs": "^7.8.2",
69
71
  "supertest": "^7.1.0",