@cqrs-ddd/nestjs 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 ADDED
@@ -0,0 +1,46 @@
1
+ # @cqrs-ddd/nestjs
2
+
3
+ The NestJS adapter of the [`@cqrs-ddd`](https://github.com/aristoteliss/ddd-cqrs) packages.
4
+ Your application keeps NestJS and official `@nestjs/cqrs`; this package adds what NestJS
5
+ lacks:
6
+
7
+ - `PipelineModule.forRoot({ globalBehaviors, sources, diagnostics })` runs every
8
+ `@nestjs/cqrs` handler through the behaviors of its `@UsePipeline`. Each module provides
9
+ the behaviors it configures under their class; startup fails on a missing or doubly
10
+ provided behavior and on a request-scoped handler that runs behaviors.
11
+ - `ErrorFilter` (global, `APP_FILTER`) answers every `@cqrs-ddd` error as a NestJS
12
+ `HttpException` with NestJS's body (`statusCode`, `message`, `error`); `toHttpException`
13
+ and `httpAnswer` do the conversion alone.
14
+ - `@cqrs-ddd/nestjs/correlation`: `CorrelationMiddleware`.
15
+ - `@cqrs-ddd/nestjs/job-context`: `JobContextModule.forRoot({ principal, tenants, sources })`.
16
+
17
+ ```ts
18
+ @Module({
19
+ imports: [
20
+ CqrsModule.forRoot(),
21
+ PipelineModule.forRoot({
22
+ sources: { tenantId: tenantSource, correlationId: correlationSource },
23
+ globalBehaviors: [{ scope: 'all', before: [logging()] }],
24
+ }),
25
+ ],
26
+ providers: [
27
+ { provide: LoggingBehavior, useFactory: () => new LoggingBehavior(new Logger('Pipeline')) },
28
+ { provide: APP_FILTER, useClass: ErrorFilter },
29
+ ],
30
+ })
31
+ export class AppModule {}
32
+ ```
33
+
34
+ ## Install
35
+
36
+ ```bash
37
+ pnpm add @cqrs-ddd/nestjs @cqrs-ddd/pipeline @cqrs-ddd/core
38
+ ```
39
+
40
+ Peers: `@nestjs/common`, `@nestjs/core` and `@nestjs/cqrs` 12, `@cqrs-ddd/pipeline` and
41
+ `@cqrs-ddd/core` 0.5. The behavior packages (`-zod`, `-casl`, `-feature-flags`,
42
+ `-rate-limit`, `-idempotency`, `-correlation`, `-job-context`) are optional peers: their
43
+ errors are converted when they are installed. Node.js 22.12 or newer.
44
+
45
+ Guide: https://aristoteliss.github.io/ddd-cqrs/packages/nestjs/. A complete NestJS
46
+ application: [nestjs-pipeline `api/`](https://github.com/aristoteliss/nestjs-pipeline/tree/master/api).
@@ -0,0 +1,22 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ import { type NestMiddleware } from '@nestjs/common';
3
+ /**
4
+ * Takes the correlation id of every request from its header, or creates one,
5
+ * runs the request with it so the pipelines it starts take it, and echoes it
6
+ * on the response: `httpCorrelation()` of `@cqrs-ddd/pipeline-correlation` as
7
+ * a NestJS middleware.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * export class AppModule implements NestModule {
12
+ * configure(consumer: MiddlewareConsumer) {
13
+ * consumer.apply(CorrelationMiddleware).forRoutes('*');
14
+ * }
15
+ * }
16
+ * ```
17
+ */
18
+ export declare class CorrelationMiddleware implements NestMiddleware {
19
+ private readonly correlate;
20
+ use(request: IncomingMessage, response: ServerResponse, next: () => void): void;
21
+ }
22
+ //# sourceMappingURL=correlation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlation.d.ts","sourceRoot":"","sources":["../src/correlation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEjE,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEjE;;;;;;;;;;;;;;GAcG;AACH,qBACa,qBAAsB,YAAW,cAAc;IAC1D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;IAE/C,GAAG,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,IAAI,QAEvE;CACF"}
@@ -0,0 +1,35 @@
1
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
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
+ import { httpCorrelation } from '@cqrs-ddd/pipeline-correlation';
9
+ import { Injectable } from '@nestjs/common';
10
+ /**
11
+ * Takes the correlation id of every request from its header, or creates one,
12
+ * runs the request with it so the pipelines it starts take it, and echoes it
13
+ * on the response: `httpCorrelation()` of `@cqrs-ddd/pipeline-correlation` as
14
+ * a NestJS middleware.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * export class AppModule implements NestModule {
19
+ * configure(consumer: MiddlewareConsumer) {
20
+ * consumer.apply(CorrelationMiddleware).forRoutes('*');
21
+ * }
22
+ * }
23
+ * ```
24
+ */
25
+ let CorrelationMiddleware = class CorrelationMiddleware {
26
+ correlate = httpCorrelation();
27
+ use(request, response, next) {
28
+ this.correlate(request, response, next);
29
+ }
30
+ };
31
+ CorrelationMiddleware = __decorate([
32
+ Injectable()
33
+ ], CorrelationMiddleware);
34
+ export { CorrelationMiddleware };
35
+ //# sourceMappingURL=correlation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlation.js","sourceRoot":"","sources":["../src/correlation.ts"],"names":[],"mappings":"AAAA,sEAAsE;;;;;;;AAGtE,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,UAAU,EAAuB,MAAM,gBAAgB,CAAC;AAEjE;;;;;;;;;;;;;;GAcG;AAEI,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;IACf,SAAS,GAAG,eAAe,EAAE,CAAC;IAE/C,GAAG,CAAC,OAAwB,EAAE,QAAwB,EAAE,IAAgB;QACtE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC1C,CAAC;CACF,CAAA;AANY,qBAAqB;IADjC,UAAU,EAAE;GACA,qBAAqB,CAMjC"}
@@ -0,0 +1,19 @@
1
+ import { type ArgumentsHost } from '@nestjs/common';
2
+ import { BaseExceptionFilter } from '@nestjs/core';
3
+ /**
4
+ * Answers every error through NestJS's own exception handling: an error of a
5
+ * `@cqrs-ddd` package is first converted to its NestJS `HttpException` (see
6
+ * `httpAnswer`), with its headers such as `Retry-After`; anything else is
7
+ * handled exactly as Nest handles it by default. It works on Express and
8
+ * Fastify, also for errors thrown in middleware.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * @Module({ providers: [{ provide: APP_FILTER, useClass: ErrorFilter }] })
13
+ * export class AppModule {}
14
+ * ```
15
+ */
16
+ export declare class ErrorFilter extends BaseExceptionFilter {
17
+ catch(exception: unknown, host: ArgumentsHost): void;
18
+ }
19
+ //# sourceMappingURL=error.filter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.filter.d.ts","sourceRoot":"","sources":["../../src/filters/error.filter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAA0B,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAGnD;;;;;;;;;;;;GAYG;AACH,qBACa,WAAY,SAAQ,mBAAmB;IAClD,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI,CAWnD;CACF"}
@@ -0,0 +1,42 @@
1
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
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
+ import { Catch } from '@nestjs/common';
9
+ import { BaseExceptionFilter } from '@nestjs/core';
10
+ import { httpAnswer } from './http-exception.js';
11
+ /**
12
+ * Answers every error through NestJS's own exception handling: an error of a
13
+ * `@cqrs-ddd` package is first converted to its NestJS `HttpException` (see
14
+ * `httpAnswer`), with its headers such as `Retry-After`; anything else is
15
+ * handled exactly as Nest handles it by default. It works on Express and
16
+ * Fastify, also for errors thrown in middleware.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * @Module({ providers: [{ provide: APP_FILTER, useClass: ErrorFilter }] })
21
+ * export class AppModule {}
22
+ * ```
23
+ */
24
+ let ErrorFilter = class ErrorFilter extends BaseExceptionFilter {
25
+ catch(exception, host) {
26
+ const answer = httpAnswer(exception);
27
+ if (answer) {
28
+ const adapter = (this.httpAdapterHost?.httpAdapter ??
29
+ this.applicationRef);
30
+ const response = host.getArgByIndex(1);
31
+ for (const [name, value] of Object.entries(answer.headers)) {
32
+ adapter.setHeader(response, name, value);
33
+ }
34
+ }
35
+ super.catch(answer?.exception ?? exception, host);
36
+ }
37
+ };
38
+ ErrorFilter = __decorate([
39
+ Catch()
40
+ ], ErrorFilter);
41
+ export { ErrorFilter };
42
+ //# sourceMappingURL=error.filter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.filter.js","sourceRoot":"","sources":["../../src/filters/error.filter.ts"],"names":[],"mappings":"AAAA,sEAAsE;;;;;;;AAEtE,OAAO,EAAsB,KAAK,EAAmB,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD;;;;;;;;;;;;GAYG;AAEI,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,mBAAmB;IAClD,KAAK,CAAC,SAAkB,EAAE,IAAmB;QAC3C,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;QACrC,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,eAAe,EAAE,WAAW;gBAChD,IAAI,CAAC,cAAc,CAAe,CAAC;YACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;YACvC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC3D,OAAO,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC;QACD,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI,SAAS,EAAE,IAAI,CAAC,CAAC;IACpD,CAAC;CACF,CAAA;AAbY,WAAW;IADvB,KAAK,EAAE;GACK,WAAW,CAavB"}
@@ -0,0 +1,53 @@
1
+ import { HttpException } from '@nestjs/common';
2
+ /** A NestJS exception for a package error, and the headers its answer carries. */
3
+ export interface HttpAnswer {
4
+ readonly exception: HttpException;
5
+ readonly headers: Readonly<Record<string, string>>;
6
+ }
7
+ /** The flattened issues a `ZodValidationError` carries in `details`. */
8
+ export interface ValidationDetails {
9
+ readonly formErrors: readonly string[];
10
+ readonly fieldErrors: Readonly<Record<string, readonly string[] | undefined>>;
11
+ }
12
+ /**
13
+ * The validation messages of NestJS's `StandardSchemaValidationPipe` for
14
+ * flattened Zod issues: a form error as it is, a field error as
15
+ * `field: message`.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * validationMessages({ formErrors: [], fieldErrors: { email: ['Invalid email'] } });
20
+ * // ['email: Invalid email']
21
+ * ```
22
+ */
23
+ export declare function validationMessages(details: ValidationDetails): string[];
24
+ /**
25
+ * The NestJS exception and headers for an error of a `@cqrs-ddd` package, or
26
+ * `undefined` for any other error. A `ZodValidationError` becomes the
27
+ * `BadRequestException` NestJS's validation pipe throws (`message` lists the
28
+ * issues); a denied action, a disabled feature, an exceeded rate limit and an
29
+ * idempotency conflict take the status, body and headers their package's
30
+ * `toHttpResponse` defines; a `@cqrs-ddd/core` domain error takes
31
+ * `domainErrorHttpStatus`. Every body has NestJS's `statusCode`, `message` and
32
+ * `error`.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * const answer = httpAnswer(new RateLimitExceededError(details));
37
+ * answer?.exception.getStatus(); // 429
38
+ * answer?.headers; // { 'Retry-After': '3' }
39
+ * ```
40
+ */
41
+ export declare function httpAnswer(error: unknown): HttpAnswer | undefined;
42
+ /**
43
+ * The NestJS `HttpException` for an error of a `@cqrs-ddd` package, or
44
+ * `undefined` for any other error; see {@link httpAnswer}, which also gives the
45
+ * headers.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * throw toHttpException(error) ?? error;
50
+ * ```
51
+ */
52
+ export declare function toHttpException(error: unknown): HttpException | undefined;
53
+ //# sourceMappingURL=http-exception.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-exception.d.ts","sourceRoot":"","sources":["../../src/filters/http-exception.ts"],"names":[],"mappings":"AAIA,OAAO,EAAuB,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpE,kFAAkF;AAClF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACpD;AAED,wEAAwE;AACxE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC;CAC/E;AAUD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,EAAE,CAOvE;AAmFD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAMjE;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,GAAG,SAAS,CAEzE"}
@@ -0,0 +1,118 @@
1
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
2
+ import { createRequire } from 'node:module';
3
+ import { domainErrorHttpStatus } from '@cqrs-ddd/core/http';
4
+ import { BadRequestException, HttpException } from '@nestjs/common';
5
+ /**
6
+ * The validation messages of NestJS's `StandardSchemaValidationPipe` for
7
+ * flattened Zod issues: a form error as it is, a field error as
8
+ * `field: message`.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * validationMessages({ formErrors: [], fieldErrors: { email: ['Invalid email'] } });
13
+ * // ['email: Invalid email']
14
+ * ```
15
+ */
16
+ export function validationMessages(details) {
17
+ return [
18
+ ...details.formErrors,
19
+ ...Object.entries(details.fieldErrors).flatMap(([field, messages]) => (messages ?? []).map((message) => `${field}: ${message}`)),
20
+ ];
21
+ }
22
+ const require = createRequire(import.meta.url);
23
+ function installed(name) {
24
+ try {
25
+ require.resolve(name);
26
+ return true;
27
+ }
28
+ catch {
29
+ return false;
30
+ }
31
+ }
32
+ function optional(name) {
33
+ return installed(name)
34
+ ? require(name)
35
+ : undefined;
36
+ }
37
+ // Errors are matched by name, not by class, so an error from a second copy of its
38
+ // package (a bundled one) converts too; every package error sets its `name`.
39
+ function named(error, name) {
40
+ return error instanceof Error && error.name === name;
41
+ }
42
+ function packageConverter(name, errorName) {
43
+ const toHttpResponse = optional(`${name}/http`)?.toHttpResponse;
44
+ if (!toHttpResponse)
45
+ return undefined;
46
+ return (error) => {
47
+ if (!named(error, errorName))
48
+ return undefined;
49
+ const { status, body, headers } = toHttpResponse(error);
50
+ return { exception: new HttpException(body, status), headers };
51
+ };
52
+ }
53
+ const validationConverter = (error) => named(error, 'ZodValidationError')
54
+ ? {
55
+ exception: new BadRequestException(validationMessages(error.details)),
56
+ headers: {},
57
+ }
58
+ : undefined;
59
+ const domainConverter = (error) => {
60
+ const status = domainErrorHttpStatus(error);
61
+ if (!status)
62
+ return undefined;
63
+ const { statusCode, error: reason, message } = status;
64
+ return {
65
+ exception: new HttpException({ statusCode, message, error: reason }, statusCode),
66
+ headers: {},
67
+ };
68
+ };
69
+ // Behavior packages are optional peers: each converts only when installed.
70
+ const converters = [
71
+ validationConverter,
72
+ ...[
73
+ packageConverter('@cqrs-ddd/pipeline-casl', 'UnauthorizedActionException'),
74
+ packageConverter('@cqrs-ddd/pipeline-feature-flags', 'FeatureDisabledError'),
75
+ packageConverter('@cqrs-ddd/pipeline-rate-limit', 'RateLimitExceededError'),
76
+ packageConverter('@cqrs-ddd/pipeline-idempotency', 'IdempotencyConflictError'),
77
+ ].filter((convert) => convert !== undefined),
78
+ domainConverter,
79
+ ];
80
+ /**
81
+ * The NestJS exception and headers for an error of a `@cqrs-ddd` package, or
82
+ * `undefined` for any other error. A `ZodValidationError` becomes the
83
+ * `BadRequestException` NestJS's validation pipe throws (`message` lists the
84
+ * issues); a denied action, a disabled feature, an exceeded rate limit and an
85
+ * idempotency conflict take the status, body and headers their package's
86
+ * `toHttpResponse` defines; a `@cqrs-ddd/core` domain error takes
87
+ * `domainErrorHttpStatus`. Every body has NestJS's `statusCode`, `message` and
88
+ * `error`.
89
+ *
90
+ * @example
91
+ * ```ts
92
+ * const answer = httpAnswer(new RateLimitExceededError(details));
93
+ * answer?.exception.getStatus(); // 429
94
+ * answer?.headers; // { 'Retry-After': '3' }
95
+ * ```
96
+ */
97
+ export function httpAnswer(error) {
98
+ for (const convert of converters) {
99
+ const answer = convert(error);
100
+ if (answer)
101
+ return answer;
102
+ }
103
+ return undefined;
104
+ }
105
+ /**
106
+ * The NestJS `HttpException` for an error of a `@cqrs-ddd` package, or
107
+ * `undefined` for any other error; see {@link httpAnswer}, which also gives the
108
+ * headers.
109
+ *
110
+ * @example
111
+ * ```ts
112
+ * throw toHttpException(error) ?? error;
113
+ * ```
114
+ */
115
+ export function toHttpException(error) {
116
+ return httpAnswer(error)?.exception;
117
+ }
118
+ //# sourceMappingURL=http-exception.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-exception.js","sourceRoot":"","sources":["../../src/filters/http-exception.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The NestJS adapter: `PipelineModule` runs official `@nestjs/cqrs` handlers through
3
+ * their pipelines, and `ErrorFilter` answers every package error as a NestJS
4
+ * `HttpException`. Correlation and job context are the `@cqrs-ddd/nestjs/correlation`
5
+ * and `@cqrs-ddd/nestjs/job-context` entry points.
6
+ *
7
+ * @module main
8
+ */
9
+ export { ErrorFilter } from './filters/error.filter.js';
10
+ export { type HttpAnswer, httpAnswer, toHttpException, type ValidationDetails, validationMessages, } from './filters/http-exception.js';
11
+ export { PIPELINE_OPTIONS, PipelineBootstrap, type PipelineOptions, } from './pipeline/pipeline.bootstrap.js';
12
+ export { PipelineModule } from './pipeline/pipeline.module.js';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EACL,KAAK,UAAU,EACf,UAAU,EACV,eAAe,EACf,KAAK,iBAAiB,EACtB,kBAAkB,GACnB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,eAAe,GACrB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
2
+ /**
3
+ * The NestJS adapter: `PipelineModule` runs official `@nestjs/cqrs` handlers through
4
+ * their pipelines, and `ErrorFilter` answers every package error as a NestJS
5
+ * `HttpException`. Correlation and job context are the `@cqrs-ddd/nestjs/correlation`
6
+ * and `@cqrs-ddd/nestjs/job-context` entry points.
7
+ *
8
+ * @module main
9
+ */
10
+ export { ErrorFilter } from './filters/error.filter.js';
11
+ export { httpAnswer, toHttpException, validationMessages, } from './filters/http-exception.js';
12
+ export { PIPELINE_OPTIONS, PipelineBootstrap, } from './pipeline/pipeline.bootstrap.js';
13
+ export { PipelineModule } from './pipeline/pipeline.module.js';
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAEL,UAAU,EACV,eAAe,EAEf,kBAAkB,GACnB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,gBAAgB,EAChB,iBAAiB,GAElB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { type IJobPrincipal, type JobContextSources } from '@cqrs-ddd/pipeline-job-context';
2
+ import { type DynamicModule, type ModuleMetadata, type Type } from '@nestjs/common';
3
+ /** How `JobContextModule` registers the job context. */
4
+ export interface JobContextModuleOptions {
5
+ /** Modules that provide the principal's dependencies. */
6
+ readonly imports?: ModuleMetadata['imports'];
7
+ /** The provider that loads a job's principal again. */
8
+ readonly principal: Type<IJobPrincipal>;
9
+ /** The tenants a job may name, or a function read when the module starts. */
10
+ readonly tenants: readonly string[] | (() => readonly string[]);
11
+ /** Where the tenant and correlation id are read and restored. */
12
+ readonly sources: JobContextSources;
13
+ }
14
+ /**
15
+ * Lets the jobs a request enqueues carry its tenant, correlation id and
16
+ * principal (`withJobContext`), and restores them in processors
17
+ * (`@InJobContext()`): registers the application's job principal, tenants and
18
+ * context sources with `@cqrs-ddd/pipeline-job-context` when the module starts,
19
+ * and unregisters them on shutdown.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * @Module({
24
+ * imports: [
25
+ * JobContextModule.forRoot({
26
+ * imports: [AuthsModule],
27
+ * principal: SessionJobPrincipal,
28
+ * tenants: () => persistenceConfig().tenants,
29
+ * sources: { tenantId: tenantSource, correlationId: correlationSource },
30
+ * }),
31
+ * ],
32
+ * })
33
+ * export class AppModule {}
34
+ * ```
35
+ */
36
+ export declare class JobContextModule {
37
+ static forRoot(options: JobContextModuleOptions): DynamicModule;
38
+ }
39
+ //# sourceMappingURL=job-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-context.d.ts","sourceRoot":"","sources":["../src/job-context.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,aAAa,EAElB,KAAK,iBAAiB,EAEvB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,KAAK,aAAa,EAIlB,KAAK,cAAc,EAEnB,KAAK,IAAI,EACV,MAAM,gBAAgB,CAAC;AAExB,wDAAwD;AACxD,MAAM,WAAW,uBAAuB;IACtC,yDAAyD;IACzD,QAAQ,CAAC,OAAO,CAAC,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;IAC7C,uDAAuD;IACvD,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IACxC,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,CAAC,MAAM,SAAS,MAAM,EAAE,CAAC,CAAC;IAChE,iEAAiE;IACjE,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;CACrC;AAkBD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBACa,gBAAgB;IAC3B,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,uBAAuB,GAAG,aAAa,CAmB9D;CACF"}
@@ -0,0 +1,81 @@
1
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
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 __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var JobContextModule_1;
15
+ import { registerJobContext, } from '@cqrs-ddd/pipeline-job-context';
16
+ import { Inject, Injectable, Module, } from '@nestjs/common';
17
+ const JOB_PRINCIPAL = Symbol('JOB_PRINCIPAL');
18
+ const JOB_CONTEXT = Symbol('JOB_CONTEXT');
19
+ let JobContextRegistration = class JobContextRegistration {
20
+ unregister;
21
+ constructor(options) {
22
+ this.unregister = registerJobContext(options);
23
+ }
24
+ onApplicationShutdown() {
25
+ this.unregister();
26
+ }
27
+ };
28
+ JobContextRegistration = __decorate([
29
+ Injectable(),
30
+ __param(0, Inject(JOB_CONTEXT)),
31
+ __metadata("design:paramtypes", [Object])
32
+ ], JobContextRegistration);
33
+ /**
34
+ * Lets the jobs a request enqueues carry its tenant, correlation id and
35
+ * principal (`withJobContext`), and restores them in processors
36
+ * (`@InJobContext()`): registers the application's job principal, tenants and
37
+ * context sources with `@cqrs-ddd/pipeline-job-context` when the module starts,
38
+ * and unregisters them on shutdown.
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * @Module({
43
+ * imports: [
44
+ * JobContextModule.forRoot({
45
+ * imports: [AuthsModule],
46
+ * principal: SessionJobPrincipal,
47
+ * tenants: () => persistenceConfig().tenants,
48
+ * sources: { tenantId: tenantSource, correlationId: correlationSource },
49
+ * }),
50
+ * ],
51
+ * })
52
+ * export class AppModule {}
53
+ * ```
54
+ */
55
+ let JobContextModule = JobContextModule_1 = class JobContextModule {
56
+ static forRoot(options) {
57
+ const { tenants, sources } = options;
58
+ return {
59
+ module: JobContextModule_1,
60
+ imports: options.imports ?? [],
61
+ providers: [
62
+ { provide: JOB_PRINCIPAL, useClass: options.principal },
63
+ {
64
+ provide: JOB_CONTEXT,
65
+ inject: [JOB_PRINCIPAL],
66
+ useFactory: (principal) => ({
67
+ principal,
68
+ tenants: typeof tenants === 'function' ? tenants() : tenants,
69
+ sources,
70
+ }),
71
+ },
72
+ JobContextRegistration,
73
+ ],
74
+ };
75
+ }
76
+ };
77
+ JobContextModule = JobContextModule_1 = __decorate([
78
+ Module({})
79
+ ], JobContextModule);
80
+ export { JobContextModule };
81
+ //# sourceMappingURL=job-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-context.js","sourceRoot":"","sources":["../src/job-context.ts"],"names":[],"mappings":"AAAA,sEAAsE;;;;;;;;;;;;;;AAEtE,OAAO,EAIL,kBAAkB,GACnB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAEL,MAAM,EACN,UAAU,EACV,MAAM,GAIP,MAAM,gBAAgB,CAAC;AAcxB,MAAM,aAAa,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;AAC9C,MAAM,WAAW,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;AAE1C,IACM,sBAAsB,GAD5B,MACM,sBAAsB;IACT,UAAU,CAAa;IAExC,YAAiC,OAA0B;QACzD,IAAI,CAAC,UAAU,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAChD,CAAC;IAED,qBAAqB;QACnB,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;CACF,CAAA;AAVK,sBAAsB;IAD3B,UAAU,EAAE;IAIE,WAAA,MAAM,CAAC,WAAW,CAAC,CAAA;;GAH5B,sBAAsB,CAU3B;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEI,IAAM,gBAAgB,wBAAtB,MAAM,gBAAgB;IACpB,AAAP,MAAM,CAAC,OAAO,CAAC,OAAgC;QAC7C,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QACrC,OAAO;YACL,MAAM,oBAAkB;YACxB,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE;YAC9B,SAAS,EAAE;gBACT,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,CAAC,SAAS,EAAE;gBACvD;oBACE,OAAO,EAAE,WAAW;oBACpB,MAAM,EAAE,CAAC,aAAa,CAAC;oBACvB,UAAU,EAAE,CAAC,SAAwB,EAAqB,EAAE,CAAC,CAAC;wBAC5D,SAAS;wBACT,OAAO,EAAE,OAAO,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO;wBAC5D,OAAO;qBACR,CAAC;iBACH;gBACD,sBAAsB;aACvB;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AArBY,gBAAgB;IAD5B,MAAM,CAAC,EAAE,CAAC;GACE,gBAAgB,CAqB5B"}
@@ -0,0 +1,38 @@
1
+ import { type ContextSources, type GlobalBehaviorsOptions } from '@cqrs-ddd/pipeline';
2
+ import { type OnApplicationBootstrap, type OnModuleDestroy } from '@nestjs/common';
3
+ import { DiscoveryService } from '@nestjs/core';
4
+ /** What every handler's pipeline shares. */
5
+ export interface PipelineOptions {
6
+ readonly globalBehaviors?: GlobalBehaviorsOptions | GlobalBehaviorsOptions[];
7
+ readonly sources?: ContextSources;
8
+ /** `'strict'` (default) fails startup on a contract violation, `'warn'` logs it. */
9
+ readonly diagnostics?: 'strict' | 'warn' | 'off';
10
+ }
11
+ export declare const PIPELINE_OPTIONS: unique symbol;
12
+ /**
13
+ * Wraps every `@nestjs/cqrs` handler that runs behaviors with its pipeline, at
14
+ * application bootstrap: `execute` of command and query handlers, `handle` of
15
+ * event handlers. The buses read the method at call time, so they dispatch
16
+ * through the pipeline unchanged.
17
+ *
18
+ * A handler's pipeline comes from its `@UsePipeline`/`@SkipPipeline` and the
19
+ * global behaviors, compiled once. Each behavior instance is the one provider a
20
+ * module registers under the behavior class; this provider never builds one.
21
+ * Startup fails when a behavior has no provider or several, when a handler that
22
+ * runs behaviors is request-scoped (Nest builds such a handler per request, so a
23
+ * wrapped instance would never run), and, in `'strict'` mode, when a behavior's
24
+ * contract is broken. Only this application's own handler instances are wrapped,
25
+ * never their class, and they are restored when the application closes.
26
+ */
27
+ export declare class PipelineBootstrap implements OnApplicationBootstrap, OnModuleDestroy {
28
+ private readonly discovery;
29
+ private readonly options;
30
+ private readonly logger;
31
+ private readonly restores;
32
+ constructor(discovery: DiscoveryService, options: PipelineOptions);
33
+ onApplicationBootstrap(): void;
34
+ onModuleDestroy(): void;
35
+ private wrapHandlers;
36
+ private wrap;
37
+ }
38
+ //# sourceMappingURL=pipeline.bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.bootstrap.d.ts","sourceRoot":"","sources":["../../src/pipeline/pipeline.bootstrap.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,cAAc,EAInB,KAAK,sBAAsB,EAM5B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAIL,KAAK,sBAAsB,EAC3B,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGhD,4CAA4C;AAC5C,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,eAAe,CAAC,EAAE,sBAAsB,GAAG,sBAAsB,EAAE,CAAC;IAC7E,QAAQ,CAAC,OAAO,CAAC,EAAE,cAAc,CAAC;IAClC,oFAAoF;IACpF,QAAQ,CAAC,WAAW,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,KAAK,CAAC;CAClD;AAED,eAAO,MAAM,gBAAgB,eAA6B,CAAC;AAwB3D;;;;;;;;;;;;;;GAcG;AACH,qBACa,iBACX,YAAW,sBAAsB,EAAE,eAAe;IAMhD,OAAO,CAAC,QAAQ,CAAC,SAAS;IACA,OAAO,CAAC,QAAQ,CAAC,OAAO;IALpD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsC;IAC7D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyB;IAElD,YACmB,SAAS,EAAE,gBAAgB,EACD,OAAO,EAAE,eAAe,EACjE;IAEJ,sBAAsB,IAAI,IAAI,CAO7B;IAED,eAAe,IAAI,IAAI,CAEtB;IAED,OAAO,CAAC,YAAY;IA0CpB,OAAO,CAAC,IAAI;CA2Eb"}