@duraflows/nestjs 2.1.0 → 3.1.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.
Files changed (105) hide show
  1. package/README.md +7 -0
  2. package/dist/cjs/controllers/dto/history-query.dto.d.ts +2 -2
  3. package/dist/cjs/controllers/dto/history-query.dto.js +10 -4
  4. package/dist/cjs/controllers/dto/timeout-process.dto.d.ts +1 -1
  5. package/dist/cjs/controllers/dto/timeout-process.dto.js +6 -2
  6. package/dist/cjs/controllers/workflow-event.controller.js +3 -1
  7. package/dist/cjs/controllers/workflow-instance.controller.js +3 -1
  8. package/dist/cjs/controllers/workflow-query.controller.js +5 -3
  9. package/dist/cjs/controllers/workflow-timeout.controller.js +4 -2
  10. package/dist/cjs/filters/workflow-exception.filter.d.ts +13 -0
  11. package/dist/cjs/filters/workflow-exception.filter.js +58 -0
  12. package/dist/cjs/index.d.ts +2 -1
  13. package/dist/cjs/index.js +5 -1
  14. package/dist/cjs/providers/nest-command-registry.js +30 -1
  15. package/dist/cjs/workflow.module.d.ts +9 -2
  16. package/dist/cjs/workflow.module.js +11 -4
  17. package/dist/controllers/dto/history-query.dto.d.ts +2 -2
  18. package/dist/controllers/dto/history-query.dto.js +11 -5
  19. package/dist/controllers/dto/timeout-process.dto.d.ts +1 -1
  20. package/dist/controllers/dto/timeout-process.dto.js +7 -3
  21. package/dist/controllers/workflow-event.controller.js +4 -2
  22. package/dist/controllers/workflow-instance.controller.js +4 -2
  23. package/dist/controllers/workflow-query.controller.js +6 -4
  24. package/dist/controllers/workflow-timeout.controller.js +5 -3
  25. package/dist/filters/workflow-exception.filter.d.ts +13 -0
  26. package/dist/filters/workflow-exception.filter.js +55 -0
  27. package/dist/index.d.ts +2 -1
  28. package/dist/index.js +3 -1
  29. package/dist/providers/nest-command-registry.js +30 -1
  30. package/dist/workflow.module.d.ts +9 -2
  31. package/dist/workflow.module.js +12 -5
  32. package/package.json +12 -6
  33. package/dist/cjs/controllers/dto/available-events-query.dto.d.ts.map +0 -1
  34. package/dist/cjs/controllers/dto/available-events-query.dto.js.map +0 -1
  35. package/dist/cjs/controllers/dto/create-instance.dto.d.ts.map +0 -1
  36. package/dist/cjs/controllers/dto/create-instance.dto.js.map +0 -1
  37. package/dist/cjs/controllers/dto/history-query.dto.d.ts.map +0 -1
  38. package/dist/cjs/controllers/dto/history-query.dto.js.map +0 -1
  39. package/dist/cjs/controllers/dto/index.d.ts.map +0 -1
  40. package/dist/cjs/controllers/dto/index.js.map +0 -1
  41. package/dist/cjs/controllers/dto/timeout-process.dto.d.ts.map +0 -1
  42. package/dist/cjs/controllers/dto/timeout-process.dto.js.map +0 -1
  43. package/dist/cjs/controllers/dto/trigger-event.dto.d.ts.map +0 -1
  44. package/dist/cjs/controllers/dto/trigger-event.dto.js.map +0 -1
  45. package/dist/cjs/controllers/workflow-event.controller.d.ts.map +0 -1
  46. package/dist/cjs/controllers/workflow-event.controller.js.map +0 -1
  47. package/dist/cjs/controllers/workflow-instance.controller.d.ts.map +0 -1
  48. package/dist/cjs/controllers/workflow-instance.controller.js.map +0 -1
  49. package/dist/cjs/controllers/workflow-query.controller.d.ts.map +0 -1
  50. package/dist/cjs/controllers/workflow-query.controller.js.map +0 -1
  51. package/dist/cjs/controllers/workflow-timeout.controller.d.ts.map +0 -1
  52. package/dist/cjs/controllers/workflow-timeout.controller.js.map +0 -1
  53. package/dist/cjs/decorators/workflow-command.decorator.d.ts.map +0 -1
  54. package/dist/cjs/decorators/workflow-command.decorator.js.map +0 -1
  55. package/dist/cjs/index.d.ts.map +0 -1
  56. package/dist/cjs/index.js.map +0 -1
  57. package/dist/cjs/providers/command-discovery.d.ts.map +0 -1
  58. package/dist/cjs/providers/command-discovery.js.map +0 -1
  59. package/dist/cjs/providers/injection-tokens.d.ts.map +0 -1
  60. package/dist/cjs/providers/injection-tokens.js.map +0 -1
  61. package/dist/cjs/providers/nest-command-registry.d.ts.map +0 -1
  62. package/dist/cjs/providers/nest-command-registry.js.map +0 -1
  63. package/dist/cjs/services/workflow-timeout.service.d.ts.map +0 -1
  64. package/dist/cjs/services/workflow-timeout.service.js.map +0 -1
  65. package/dist/cjs/services/workflow.service.d.ts.map +0 -1
  66. package/dist/cjs/services/workflow.service.js.map +0 -1
  67. package/dist/cjs/workflow.module.d.ts.map +0 -1
  68. package/dist/cjs/workflow.module.js.map +0 -1
  69. package/dist/controllers/dto/available-events-query.dto.d.ts.map +0 -1
  70. package/dist/controllers/dto/available-events-query.dto.js.map +0 -1
  71. package/dist/controllers/dto/create-instance.dto.d.ts.map +0 -1
  72. package/dist/controllers/dto/create-instance.dto.js.map +0 -1
  73. package/dist/controllers/dto/history-query.dto.d.ts.map +0 -1
  74. package/dist/controllers/dto/history-query.dto.js.map +0 -1
  75. package/dist/controllers/dto/index.d.ts.map +0 -1
  76. package/dist/controllers/dto/index.js.map +0 -1
  77. package/dist/controllers/dto/timeout-process.dto.d.ts.map +0 -1
  78. package/dist/controllers/dto/timeout-process.dto.js.map +0 -1
  79. package/dist/controllers/dto/trigger-event.dto.d.ts.map +0 -1
  80. package/dist/controllers/dto/trigger-event.dto.js.map +0 -1
  81. package/dist/controllers/workflow-event.controller.d.ts.map +0 -1
  82. package/dist/controllers/workflow-event.controller.js.map +0 -1
  83. package/dist/controllers/workflow-instance.controller.d.ts.map +0 -1
  84. package/dist/controllers/workflow-instance.controller.js.map +0 -1
  85. package/dist/controllers/workflow-query.controller.d.ts.map +0 -1
  86. package/dist/controllers/workflow-query.controller.js.map +0 -1
  87. package/dist/controllers/workflow-timeout.controller.d.ts.map +0 -1
  88. package/dist/controllers/workflow-timeout.controller.js.map +0 -1
  89. package/dist/decorators/workflow-command.decorator.d.ts.map +0 -1
  90. package/dist/decorators/workflow-command.decorator.js.map +0 -1
  91. package/dist/index.d.ts.map +0 -1
  92. package/dist/index.js.map +0 -1
  93. package/dist/providers/command-discovery.d.ts.map +0 -1
  94. package/dist/providers/command-discovery.js.map +0 -1
  95. package/dist/providers/injection-tokens.d.ts.map +0 -1
  96. package/dist/providers/injection-tokens.js.map +0 -1
  97. package/dist/providers/nest-command-registry.d.ts.map +0 -1
  98. package/dist/providers/nest-command-registry.js.map +0 -1
  99. package/dist/services/workflow-timeout.service.d.ts.map +0 -1
  100. package/dist/services/workflow-timeout.service.js.map +0 -1
  101. package/dist/services/workflow.service.d.ts.map +0 -1
  102. package/dist/services/workflow.service.js.map +0 -1
  103. package/dist/tsconfig.cjs.tsbuildinfo +0 -1
  104. package/dist/workflow.module.d.ts.map +0 -1
  105. package/dist/workflow.module.js.map +0 -1
package/README.md CHANGED
@@ -22,6 +22,11 @@ Part of the [duraflows](https://github.com/camcima/duraflows) monorepo.
22
22
  pnpm add @duraflows/core @duraflows/nestjs
23
23
  ```
24
24
 
25
+ > **Note:** `@duraflows/core` is a peer dependency — you install it alongside this
26
+ > package so your app and the adapter share a single core instance. `@nestjs/common`,
27
+ > `@nestjs/core`, `reflect-metadata`, and `rxjs` are peers too, but any NestJS app
28
+ > already has them, so no extra install is normally needed.
29
+
25
30
  You will also need a persistence adapter such as [`@duraflows/pg`](https://www.npmjs.com/package/@duraflows/pg):
26
31
 
27
32
  ```bash
@@ -157,6 +162,8 @@ export class SendToWarehouseCommand implements IWorkflowCommand {
157
162
 
158
163
  When `enableControllers: true` is set, the following endpoints are registered:
159
164
 
165
+ > **Security:** the generated controllers ship **without authentication**. They expose instance creation, arbitrary event triggering, full history reads, and `POST /workflows/timeouts/process` (an administrative bulk operation). Apply your own auth guards and rate limiting before enabling them in production — e.g. a global `APP_GUARD`, or guards bound per controller. Note also that `triggerEvent` responses include each command's `CommandResult` verbatim, so command authors must not place sensitive data in `CommandResult.error` / `message` if the controllers are enabled.
166
+
160
167
  | Controller | Endpoints |
161
168
  | ---------------------------- | -------------------------------------- |
162
169
  | `WorkflowInstanceController` | Create and retrieve workflow instances |
@@ -1,6 +1,6 @@
1
1
  export declare class HistoryQueryDto {
2
- limit?: string;
3
- offset?: string;
2
+ limit?: number;
3
+ offset?: number;
4
4
  }
5
5
  export declare class HistoryParamsDto {
6
6
  workflowInstanceUuid: string;
@@ -10,6 +10,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.HistoryParamsDto = exports.HistoryQueryDto = void 0;
13
+ const class_transformer_1 = require("class-transformer");
13
14
  const class_validator_1 = require("class-validator");
14
15
  class HistoryQueryDto {
15
16
  limit;
@@ -18,13 +19,18 @@ class HistoryQueryDto {
18
19
  exports.HistoryQueryDto = HistoryQueryDto;
19
20
  __decorate([
20
21
  (0, class_validator_1.IsOptional)(),
21
- (0, class_validator_1.IsNumberString)(),
22
- __metadata("design:type", String)
22
+ (0, class_transformer_1.Type)(() => Number),
23
+ (0, class_validator_1.IsInt)(),
24
+ (0, class_validator_1.Min)(1),
25
+ (0, class_validator_1.Max)(500),
26
+ __metadata("design:type", Number)
23
27
  ], HistoryQueryDto.prototype, "limit", void 0);
24
28
  __decorate([
25
29
  (0, class_validator_1.IsOptional)(),
26
- (0, class_validator_1.IsNumberString)(),
27
- __metadata("design:type", String)
30
+ (0, class_transformer_1.Type)(() => Number),
31
+ (0, class_validator_1.IsInt)(),
32
+ (0, class_validator_1.Min)(0),
33
+ __metadata("design:type", Number)
28
34
  ], HistoryQueryDto.prototype, "offset", void 0);
29
35
  class HistoryParamsDto {
30
36
  workflowInstanceUuid;
@@ -1,4 +1,4 @@
1
1
  export declare class TimeoutProcessQueryDto {
2
- limit?: string;
2
+ limit?: number;
3
3
  }
4
4
  //# sourceMappingURL=timeout-process.dto.d.ts.map
@@ -10,6 +10,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.TimeoutProcessQueryDto = void 0;
13
+ const class_transformer_1 = require("class-transformer");
13
14
  const class_validator_1 = require("class-validator");
14
15
  class TimeoutProcessQueryDto {
15
16
  limit;
@@ -17,7 +18,10 @@ class TimeoutProcessQueryDto {
17
18
  exports.TimeoutProcessQueryDto = TimeoutProcessQueryDto;
18
19
  __decorate([
19
20
  (0, class_validator_1.IsOptional)(),
20
- (0, class_validator_1.IsNumberString)(),
21
- __metadata("design:type", String)
21
+ (0, class_transformer_1.Type)(() => Number),
22
+ (0, class_validator_1.IsInt)(),
23
+ (0, class_validator_1.Min)(1),
24
+ (0, class_validator_1.Max)(1000),
25
+ __metadata("design:type", Number)
22
26
  ], TimeoutProcessQueryDto.prototype, "limit", void 0);
23
27
  //# sourceMappingURL=timeout-process.dto.js.map
@@ -16,6 +16,7 @@ exports.WorkflowEventController = void 0;
16
16
  const common_1 = require("@nestjs/common");
17
17
  const workflow_service_js_1 = require("../services/workflow.service.js");
18
18
  const index_js_1 = require("./dto/index.js");
19
+ const workflow_exception_filter_js_1 = require("../filters/workflow-exception.filter.js");
19
20
  let WorkflowEventController = class WorkflowEventController {
20
21
  workflowService;
21
22
  constructor(workflowService) {
@@ -42,7 +43,8 @@ __decorate([
42
43
  ], WorkflowEventController.prototype, "triggerEvent", null);
43
44
  exports.WorkflowEventController = WorkflowEventController = __decorate([
44
45
  (0, common_1.Controller)("workflows"),
45
- (0, common_1.UsePipes)(new common_1.ValidationPipe({ transform: true, whitelist: true })),
46
+ (0, common_1.UseFilters)(workflow_exception_filter_js_1.WorkflowExceptionFilter),
47
+ (0, common_1.UsePipes)(new common_1.ValidationPipe({ transform: true, whitelist: true, forbidNonWhitelisted: true })),
46
48
  __metadata("design:paramtypes", [workflow_service_js_1.WorkflowService])
47
49
  ], WorkflowEventController);
48
50
  //# sourceMappingURL=workflow-event.controller.js.map
@@ -16,6 +16,7 @@ exports.WorkflowInstanceController = void 0;
16
16
  const common_1 = require("@nestjs/common");
17
17
  const workflow_service_js_1 = require("../services/workflow.service.js");
18
18
  const index_js_1 = require("./dto/index.js");
19
+ const workflow_exception_filter_js_1 = require("../filters/workflow-exception.filter.js");
19
20
  let WorkflowInstanceController = class WorkflowInstanceController {
20
21
  workflowService;
21
22
  constructor(workflowService) {
@@ -54,7 +55,8 @@ __decorate([
54
55
  ], WorkflowInstanceController.prototype, "getInstance", null);
55
56
  exports.WorkflowInstanceController = WorkflowInstanceController = __decorate([
56
57
  (0, common_1.Controller)("workflows"),
57
- (0, common_1.UsePipes)(new common_1.ValidationPipe({ transform: true, whitelist: true })),
58
+ (0, common_1.UseFilters)(workflow_exception_filter_js_1.WorkflowExceptionFilter),
59
+ (0, common_1.UsePipes)(new common_1.ValidationPipe({ transform: true, whitelist: true, forbidNonWhitelisted: true })),
58
60
  __metadata("design:paramtypes", [workflow_service_js_1.WorkflowService])
59
61
  ], WorkflowInstanceController);
60
62
  //# sourceMappingURL=workflow-instance.controller.js.map
@@ -16,6 +16,7 @@ exports.WorkflowQueryController = void 0;
16
16
  const common_1 = require("@nestjs/common");
17
17
  const workflow_service_js_1 = require("../services/workflow.service.js");
18
18
  const index_js_1 = require("./dto/index.js");
19
+ const workflow_exception_filter_js_1 = require("../filters/workflow-exception.filter.js");
19
20
  let WorkflowQueryController = class WorkflowQueryController {
20
21
  workflowService;
21
22
  constructor(workflowService) {
@@ -28,8 +29,8 @@ let WorkflowQueryController = class WorkflowQueryController {
28
29
  }
29
30
  async getHistory(params, query) {
30
31
  return this.workflowService.getHistory(params.workflowInstanceUuid, {
31
- limit: query.limit ? parseInt(query.limit, 10) : undefined,
32
- offset: query.offset ? parseInt(query.offset, 10) : undefined,
32
+ limit: query.limit,
33
+ offset: query.offset,
33
34
  });
34
35
  }
35
36
  };
@@ -52,7 +53,8 @@ __decorate([
52
53
  ], WorkflowQueryController.prototype, "getHistory", null);
53
54
  exports.WorkflowQueryController = WorkflowQueryController = __decorate([
54
55
  (0, common_1.Controller)("workflows"),
55
- (0, common_1.UsePipes)(new common_1.ValidationPipe({ transform: true, whitelist: true })),
56
+ (0, common_1.UseFilters)(workflow_exception_filter_js_1.WorkflowExceptionFilter),
57
+ (0, common_1.UsePipes)(new common_1.ValidationPipe({ transform: true, whitelist: true, forbidNonWhitelisted: true })),
56
58
  __metadata("design:paramtypes", [workflow_service_js_1.WorkflowService])
57
59
  ], WorkflowQueryController);
58
60
  //# sourceMappingURL=workflow-query.controller.js.map
@@ -16,13 +16,14 @@ exports.WorkflowTimeoutController = void 0;
16
16
  const common_1 = require("@nestjs/common");
17
17
  const workflow_timeout_service_js_1 = require("../services/workflow-timeout.service.js");
18
18
  const index_js_1 = require("./dto/index.js");
19
+ const workflow_exception_filter_js_1 = require("../filters/workflow-exception.filter.js");
19
20
  let WorkflowTimeoutController = class WorkflowTimeoutController {
20
21
  timeoutService;
21
22
  constructor(timeoutService) {
22
23
  this.timeoutService = timeoutService;
23
24
  }
24
25
  async processExpired(query) {
25
- return this.timeoutService.processExpiredWorkflows(query.limit ? parseInt(query.limit, 10) : undefined);
26
+ return this.timeoutService.processExpiredWorkflows(query.limit);
26
27
  }
27
28
  };
28
29
  exports.WorkflowTimeoutController = WorkflowTimeoutController;
@@ -35,7 +36,8 @@ __decorate([
35
36
  ], WorkflowTimeoutController.prototype, "processExpired", null);
36
37
  exports.WorkflowTimeoutController = WorkflowTimeoutController = __decorate([
37
38
  (0, common_1.Controller)("workflows/timeouts"),
38
- (0, common_1.UsePipes)(new common_1.ValidationPipe({ transform: true, whitelist: true })),
39
+ (0, common_1.UseFilters)(workflow_exception_filter_js_1.WorkflowExceptionFilter),
40
+ (0, common_1.UsePipes)(new common_1.ValidationPipe({ transform: true, whitelist: true, forbidNonWhitelisted: true })),
39
41
  __metadata("design:paramtypes", [workflow_timeout_service_js_1.WorkflowTimeoutService])
40
42
  ], WorkflowTimeoutController);
41
43
  //# sourceMappingURL=workflow-timeout.controller.js.map
@@ -0,0 +1,13 @@
1
+ import { type ArgumentsHost, type ExceptionFilter } from "@nestjs/common";
2
+ import { WorkflowError } from "@duraflows/core";
3
+ /**
4
+ * Maps duraflows domain errors to HTTP statuses for the optional REST
5
+ * controllers. Without this filter, a missing instance or an event invalid
6
+ * for the current state surfaces as a generic 500 and leaks internal
7
+ * messages.
8
+ */
9
+ export declare class WorkflowExceptionFilter implements ExceptionFilter {
10
+ private readonly logger;
11
+ catch(exception: WorkflowError, host: ArgumentsHost): void;
12
+ }
13
+ //# sourceMappingURL=workflow-exception.filter.d.ts.map
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var WorkflowExceptionFilter_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.WorkflowExceptionFilter = void 0;
11
+ const common_1 = require("@nestjs/common");
12
+ const core_1 = require("@duraflows/core");
13
+ /**
14
+ * Maps duraflows domain errors to HTTP statuses for the optional REST
15
+ * controllers. Without this filter, a missing instance or an event invalid
16
+ * for the current state surfaces as a generic 500 and leaks internal
17
+ * messages.
18
+ */
19
+ let WorkflowExceptionFilter = WorkflowExceptionFilter_1 = class WorkflowExceptionFilter {
20
+ logger = new common_1.Logger(WorkflowExceptionFilter_1.name);
21
+ catch(exception, host) {
22
+ const response = host.switchToHttp().getResponse();
23
+ if (exception instanceof core_1.WorkflowInstanceNotFoundError) {
24
+ response.status(common_1.HttpStatus.NOT_FOUND).send({
25
+ statusCode: common_1.HttpStatus.NOT_FOUND,
26
+ error: "Not Found",
27
+ message: exception.message,
28
+ });
29
+ return;
30
+ }
31
+ if (exception instanceof core_1.InvalidEventError) {
32
+ response.status(common_1.HttpStatus.CONFLICT).send({
33
+ statusCode: common_1.HttpStatus.CONFLICT,
34
+ error: "Conflict",
35
+ message: exception.message,
36
+ });
37
+ return;
38
+ }
39
+ // The response body is sanitized, so log the real cause here — otherwise
40
+ // unmapped domain errors (e.g. optimistic-locking conflicts under
41
+ // concurrency) become undiagnosable silent 500s. `WorkflowError` wraps the
42
+ // originating DI/persistence failure as `cause` (e.g. NestCommandRegistry
43
+ // attaches the container error), so prefer the cause's message and stack —
44
+ // the wrapper alone hides the underlying failure from operators.
45
+ const cause = exception.cause instanceof Error ? exception.cause : undefined;
46
+ this.logger.error(cause ? `${exception.message} (cause: ${cause.message})` : exception.message, (cause ?? exception).stack);
47
+ response.status(common_1.HttpStatus.INTERNAL_SERVER_ERROR).send({
48
+ statusCode: common_1.HttpStatus.INTERNAL_SERVER_ERROR,
49
+ error: "Internal Server Error",
50
+ message: "Internal server error",
51
+ });
52
+ }
53
+ };
54
+ exports.WorkflowExceptionFilter = WorkflowExceptionFilter;
55
+ exports.WorkflowExceptionFilter = WorkflowExceptionFilter = WorkflowExceptionFilter_1 = __decorate([
56
+ (0, common_1.Catch)(core_1.WorkflowError)
57
+ ], WorkflowExceptionFilter);
58
+ //# sourceMappingURL=workflow-exception.filter.js.map
@@ -10,9 +10,10 @@ export { WorkflowInstanceController } from "./controllers/workflow-instance.cont
10
10
  export { WorkflowEventController } from "./controllers/workflow-event.controller.js";
11
11
  export { WorkflowQueryController } from "./controllers/workflow-query.controller.js";
12
12
  export { WorkflowTimeoutController } from "./controllers/workflow-timeout.controller.js";
13
+ export { WorkflowExceptionFilter } from "./filters/workflow-exception.filter.js";
13
14
  export { TriggerEventDto, TriggerEventParamsDto, HistoryQueryDto, HistoryParamsDto, AvailableEventsParamsDto, TimeoutProcessQueryDto, CreateInstanceDto, } from "./controllers/dto/index.js";
14
15
  export type { WorkflowDefinition, WorkflowStateDefinition, WorkflowEventDefinition, WorkflowOnEnterDefinition, WorkflowCommandRef, WorkflowTimeoutDefinition, CommandResult, WorkflowExecutionContext, WorkflowInstance, WorkflowExecutionResult, AvailableWorkflowEvent, CreateWorkflowInstanceInput, TriggerWorkflowEventInput, ProcessExpiredWorkflowsInput, ProcessExpiredWorkflowsResult, GetAvailableEventsInput, WorkflowInstanceStore, WorkflowHistoryStore, WorkflowHistoryRecord, WorkflowTransactionRunner, WorkflowClock, WorkflowPersistenceProvider, WorkflowDefinitionRegistry, WorkflowCommandRegistry, ValidationResult, ValidationError, CompiledWorkflow, OnEnterChainResult, OnEnterHopResult, WorkflowRuntimeClient, } from "@duraflows/core";
15
- export { WorkflowError, WorkflowDefinitionError, InvalidEventError, CommandFailureError, OnEnterDepthExceededError, WorkflowValidator, WorkflowCompiler, CommandExecutor, EventExecutor, OnEnterExecutor, TimeoutResolver, WorkflowRuntime, WorkflowHandle, InMemoryDefinitionRegistry, InMemoryCommandRegistry, InMemoryGuardRegistry, } from "@duraflows/core";
16
+ export { WorkflowError, WorkflowDefinitionError, WorkflowInstanceNotFoundError, InvalidEventError, CommandFailureError, OnEnterDepthExceededError, WorkflowValidator, WorkflowCompiler, CommandExecutor, EventExecutor, OnEnterExecutor, TimeoutResolver, WorkflowRuntime, WorkflowHandle, InMemoryDefinitionRegistry, InMemoryCommandRegistry, InMemoryGuardRegistry, } from "@duraflows/core";
16
17
  export type { WorkflowObserver, StateEnterEvent, ObserverErrorHandler } from "@duraflows/core";
17
18
  export type { WorkflowGuard, WorkflowGuardRef, WorkflowGuardRegistry } from "@duraflows/core";
18
19
  //# sourceMappingURL=index.d.ts.map
package/dist/cjs/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.InMemoryGuardRegistry = exports.InMemoryCommandRegistry = exports.InMemoryDefinitionRegistry = exports.WorkflowHandle = exports.WorkflowRuntime = exports.TimeoutResolver = exports.OnEnterExecutor = exports.EventExecutor = exports.CommandExecutor = exports.WorkflowCompiler = exports.WorkflowValidator = exports.OnEnterDepthExceededError = exports.CommandFailureError = exports.InvalidEventError = exports.WorkflowDefinitionError = exports.WorkflowError = exports.CreateInstanceDto = exports.TimeoutProcessQueryDto = exports.AvailableEventsParamsDto = exports.HistoryParamsDto = exports.HistoryQueryDto = exports.TriggerEventParamsDto = exports.TriggerEventDto = exports.WorkflowTimeoutController = exports.WorkflowQueryController = exports.WorkflowEventController = exports.WorkflowInstanceController = exports.WORKFLOW_COMMAND_METADATA_KEY = exports.WorkflowCommand = exports.NestCommandRegistry = exports.WORKFLOW_CLOCK = exports.WORKFLOW_TRANSACTION_RUNNER = exports.WORKFLOW_DEFINITION_REGISTRY = exports.WORKFLOW_GUARD_REGISTRY = exports.WORKFLOW_COMMAND_REGISTRY = exports.WORKFLOW_HISTORY_STORE = exports.WORKFLOW_INSTANCE_STORE = exports.WORKFLOW_RUNTIME = exports.WorkflowTimeoutService = exports.WorkflowService = exports.WorkflowModule = void 0;
3
+ exports.InMemoryGuardRegistry = exports.InMemoryCommandRegistry = exports.InMemoryDefinitionRegistry = exports.WorkflowHandle = exports.WorkflowRuntime = exports.TimeoutResolver = exports.OnEnterExecutor = exports.EventExecutor = exports.CommandExecutor = exports.WorkflowCompiler = exports.WorkflowValidator = exports.OnEnterDepthExceededError = exports.CommandFailureError = exports.InvalidEventError = exports.WorkflowInstanceNotFoundError = exports.WorkflowDefinitionError = exports.WorkflowError = exports.CreateInstanceDto = exports.TimeoutProcessQueryDto = exports.AvailableEventsParamsDto = exports.HistoryParamsDto = exports.HistoryQueryDto = exports.TriggerEventParamsDto = exports.TriggerEventDto = exports.WorkflowExceptionFilter = exports.WorkflowTimeoutController = exports.WorkflowQueryController = exports.WorkflowEventController = exports.WorkflowInstanceController = exports.WORKFLOW_COMMAND_METADATA_KEY = exports.WorkflowCommand = exports.NestCommandRegistry = exports.WORKFLOW_CLOCK = exports.WORKFLOW_TRANSACTION_RUNNER = exports.WORKFLOW_DEFINITION_REGISTRY = exports.WORKFLOW_GUARD_REGISTRY = exports.WORKFLOW_COMMAND_REGISTRY = exports.WORKFLOW_HISTORY_STORE = exports.WORKFLOW_INSTANCE_STORE = exports.WORKFLOW_RUNTIME = exports.WorkflowTimeoutService = exports.WorkflowService = exports.WorkflowModule = void 0;
4
4
  // Module
5
5
  var workflow_module_js_1 = require("./workflow.module.js");
6
6
  Object.defineProperty(exports, "WorkflowModule", { enumerable: true, get: function () { return workflow_module_js_1.WorkflowModule; } });
@@ -34,6 +34,9 @@ var workflow_query_controller_js_1 = require("./controllers/workflow-query.contr
34
34
  Object.defineProperty(exports, "WorkflowQueryController", { enumerable: true, get: function () { return workflow_query_controller_js_1.WorkflowQueryController; } });
35
35
  var workflow_timeout_controller_js_1 = require("./controllers/workflow-timeout.controller.js");
36
36
  Object.defineProperty(exports, "WorkflowTimeoutController", { enumerable: true, get: function () { return workflow_timeout_controller_js_1.WorkflowTimeoutController; } });
37
+ // Filters
38
+ var workflow_exception_filter_js_1 = require("./filters/workflow-exception.filter.js");
39
+ Object.defineProperty(exports, "WorkflowExceptionFilter", { enumerable: true, get: function () { return workflow_exception_filter_js_1.WorkflowExceptionFilter; } });
37
40
  // DTOs
38
41
  var index_js_1 = require("./controllers/dto/index.js");
39
42
  Object.defineProperty(exports, "TriggerEventDto", { enumerable: true, get: function () { return index_js_1.TriggerEventDto; } });
@@ -46,6 +49,7 @@ Object.defineProperty(exports, "CreateInstanceDto", { enumerable: true, get: fun
46
49
  var core_1 = require("@duraflows/core");
47
50
  Object.defineProperty(exports, "WorkflowError", { enumerable: true, get: function () { return core_1.WorkflowError; } });
48
51
  Object.defineProperty(exports, "WorkflowDefinitionError", { enumerable: true, get: function () { return core_1.WorkflowDefinitionError; } });
52
+ Object.defineProperty(exports, "WorkflowInstanceNotFoundError", { enumerable: true, get: function () { return core_1.WorkflowInstanceNotFoundError; } });
49
53
  Object.defineProperty(exports, "InvalidEventError", { enumerable: true, get: function () { return core_1.InvalidEventError; } });
50
54
  Object.defineProperty(exports, "CommandFailureError", { enumerable: true, get: function () { return core_1.CommandFailureError; } });
51
55
  Object.defineProperty(exports, "OnEnterDepthExceededError", { enumerable: true, get: function () { return core_1.OnEnterDepthExceededError; } });
@@ -19,7 +19,24 @@ class NestCommandRegistry {
19
19
  if (!cls) {
20
20
  throw new core_1.WorkflowError(`Command "${name}" not found in registry`);
21
21
  }
22
- return this.moduleRef.get(cls, { strict: false });
22
+ try {
23
+ return this.moduleRef.get(cls, { strict: false });
24
+ }
25
+ catch (error) {
26
+ // `ModuleRef.get()` fails for many reasons — a missing provider, a
27
+ // circular dependency, a throwing constructor — not only unsupported
28
+ // scopes. Wrap every failure with a generic resolution message and only
29
+ // add the singleton-scope hint when the underlying error is Nest's
30
+ // scoped-provider rejection, so the guidance is never misleading. The
31
+ // original error is attached as the cause either way.
32
+ let message = `Command "${name}" could not be resolved from the NestJS container.`;
33
+ if (isScopedProviderError(error)) {
34
+ message +=
35
+ ` Workflow command providers must be singleton-scoped (the default); ` +
36
+ `REQUEST- and TRANSIENT-scoped providers are not supported.`;
37
+ }
38
+ throw new core_1.WorkflowError(message, error);
39
+ }
23
40
  }
24
41
  has(name) {
25
42
  return this.registrations.has(name);
@@ -29,4 +46,16 @@ class NestCommandRegistry {
29
46
  }
30
47
  }
31
48
  exports.NestCommandRegistry = NestCommandRegistry;
49
+ /**
50
+ * Nest throws `InvalidClassScopeException` (message: "... is marked as a scoped
51
+ * provider ...") when `get()` is called on a REQUEST/TRANSIENT provider. That
52
+ * class is not part of Nest's public API, so match on the constructor name with
53
+ * a message-content fallback to survive version drift.
54
+ */
55
+ function isScopedProviderError(error) {
56
+ if (!(error instanceof Error)) {
57
+ return false;
58
+ }
59
+ return error.constructor.name === "InvalidClassScopeException" || /scoped provider/i.test(error.message);
60
+ }
32
61
  //# sourceMappingURL=nest-command-registry.js.map
@@ -1,4 +1,4 @@
1
- import { type DynamicModule, type Type, type InjectionToken } from "@nestjs/common";
1
+ import { type DynamicModule, type Type, type InjectionToken, type OptionalFactoryDependency } from "@nestjs/common";
2
2
  import type { WorkflowDefinition, WorkflowClock, WorkflowPersistenceProvider, WorkflowObserver, ObserverErrorHandler, WorkflowGuard, WorkflowGuardRegistry } from "@duraflows/core";
3
3
  import { type WorkflowCommandRegistration } from "./providers/nest-command-registry.js";
4
4
  export interface WorkflowModuleOptions {
@@ -26,7 +26,14 @@ export interface WorkflowModuleAsyncOptions<TArgs extends unknown[] = unknown[]>
26
26
  commands?: WorkflowCommandRegistration[];
27
27
  enableControllers?: boolean;
28
28
  useFactory: (...args: TArgs) => Promise<WorkflowModuleFactoryConfig> | WorkflowModuleFactoryConfig;
29
- inject?: InjectionToken[];
29
+ /**
30
+ * DI tokens resolved and passed to `useFactory`, positionally. The tuple
31
+ * length is type-checked against the factory's parameter list when `TArgs`
32
+ * is supplied (e.g. `forRootAsync<[Pool, AuditObserver]>({ ... })`).
33
+ */
34
+ inject?: {
35
+ [K in keyof TArgs]: InjectionToken | OptionalFactoryDependency;
36
+ };
30
37
  }
31
38
  export declare class WorkflowModule {
32
39
  static forRoot(options: WorkflowModuleOptions): DynamicModule;
@@ -20,6 +20,12 @@ const workflow_event_controller_js_1 = require("./controllers/workflow-event.con
20
20
  const workflow_query_controller_js_1 = require("./controllers/workflow-query.controller.js");
21
21
  const workflow_timeout_controller_js_1 = require("./controllers/workflow-timeout.controller.js");
22
22
  const workflow_instance_controller_js_1 = require("./controllers/workflow-instance.controller.js");
23
+ // Surfaces non-fatal definition warnings (e.g. unreachable states) that the
24
+ // registry would otherwise compute and discard.
25
+ const validationLogger = new common_1.Logger("WorkflowModule");
26
+ const logValidationWarning = (workflowName, warning) => {
27
+ validationLogger.warn(`Workflow "${workflowName}": ${warning.message} (${warning.path})`);
28
+ };
23
29
  const EXPORTED_TOKENS = [
24
30
  workflow_service_js_1.WorkflowService,
25
31
  workflow_timeout_service_js_1.WorkflowTimeoutService,
@@ -56,10 +62,9 @@ let WorkflowModule = WorkflowModule_1 = class WorkflowModule {
56
62
  },
57
63
  {
58
64
  provide: injection_tokens_js_1.WORKFLOW_GUARD_REGISTRY,
65
+ // guards/guardRegistry mutual exclusion is enforced synchronously at
66
+ // the top of forRoot, before this factory can ever run.
59
67
  useFactory: () => {
60
- if (options.guardRegistry && options.guards && options.guards.length > 0) {
61
- throw new Error("WorkflowModule: cannot supply both `guards` and `guardRegistry` — they are mutually exclusive. Pass guards or a custom registry, not both.");
62
- }
63
68
  if (options.guardRegistry)
64
69
  return options.guardRegistry;
65
70
  const registry = new core_2.InMemoryGuardRegistry();
@@ -81,6 +86,7 @@ let WorkflowModule = WorkflowModule_1 = class WorkflowModule {
81
86
  validator: new core_2.WorkflowValidator(),
82
87
  compiler: new core_2.WorkflowCompiler(),
83
88
  validationOptions: { knownCommandNames, knownGuardNames },
89
+ onValidationWarning: logValidationWarning,
84
90
  });
85
91
  for (const workflow of options.workflows) {
86
92
  registry.register(workflow);
@@ -149,7 +155,7 @@ let WorkflowModule = WorkflowModule_1 = class WorkflowModule {
149
155
  const configProvider = {
150
156
  provide: "WORKFLOW_MODULE_OPTIONS",
151
157
  useFactory: options.useFactory,
152
- inject: options.inject ?? [],
158
+ inject: (options.inject ?? []),
153
159
  };
154
160
  const providers = [
155
161
  configProvider,
@@ -191,6 +197,7 @@ let WorkflowModule = WorkflowModule_1 = class WorkflowModule {
191
197
  validator: new core_2.WorkflowValidator(),
192
198
  compiler: new core_2.WorkflowCompiler(),
193
199
  validationOptions: { knownCommandNames, knownGuardNames },
200
+ onValidationWarning: logValidationWarning,
194
201
  });
195
202
  for (const workflow of config.workflows) {
196
203
  registry.register(workflow);
@@ -1,6 +1,6 @@
1
1
  export declare class HistoryQueryDto {
2
- limit?: string;
3
- offset?: string;
2
+ limit?: number;
3
+ offset?: number;
4
4
  }
5
5
  export declare class HistoryParamsDto {
6
6
  workflowInstanceUuid: string;
@@ -7,20 +7,26 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __metadata = (this && this.__metadata) || function (k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  };
10
- import { IsOptional, IsNumberString, IsUUID } from "class-validator";
10
+ import { Type } from "class-transformer";
11
+ import { IsInt, IsOptional, IsUUID, Max, Min } from "class-validator";
11
12
  export class HistoryQueryDto {
12
13
  limit;
13
14
  offset;
14
15
  }
15
16
  __decorate([
16
17
  IsOptional(),
17
- IsNumberString(),
18
- __metadata("design:type", String)
18
+ Type(() => Number),
19
+ IsInt(),
20
+ Min(1),
21
+ Max(500),
22
+ __metadata("design:type", Number)
19
23
  ], HistoryQueryDto.prototype, "limit", void 0);
20
24
  __decorate([
21
25
  IsOptional(),
22
- IsNumberString(),
23
- __metadata("design:type", String)
26
+ Type(() => Number),
27
+ IsInt(),
28
+ Min(0),
29
+ __metadata("design:type", Number)
24
30
  ], HistoryQueryDto.prototype, "offset", void 0);
25
31
  export class HistoryParamsDto {
26
32
  workflowInstanceUuid;
@@ -1,4 +1,4 @@
1
1
  export declare class TimeoutProcessQueryDto {
2
- limit?: string;
2
+ limit?: number;
3
3
  }
4
4
  //# sourceMappingURL=timeout-process.dto.d.ts.map
@@ -7,13 +7,17 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __metadata = (this && this.__metadata) || function (k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  };
10
- import { IsOptional, IsNumberString } from "class-validator";
10
+ import { Type } from "class-transformer";
11
+ import { IsInt, IsOptional, Max, Min } from "class-validator";
11
12
  export class TimeoutProcessQueryDto {
12
13
  limit;
13
14
  }
14
15
  __decorate([
15
16
  IsOptional(),
16
- IsNumberString(),
17
- __metadata("design:type", String)
17
+ Type(() => Number),
18
+ IsInt(),
19
+ Min(1),
20
+ Max(1000),
21
+ __metadata("design:type", Number)
18
22
  ], TimeoutProcessQueryDto.prototype, "limit", void 0);
19
23
  //# sourceMappingURL=timeout-process.dto.js.map
@@ -10,9 +10,10 @@ var __metadata = (this && this.__metadata) || function (k, v) {
10
10
  var __param = (this && this.__param) || function (paramIndex, decorator) {
11
11
  return function (target, key) { decorator(target, key, paramIndex); }
12
12
  };
13
- import { Controller, Post, Param, Body, UsePipes, ValidationPipe } from "@nestjs/common";
13
+ import { Controller, Post, Param, Body, UsePipes, UseFilters, ValidationPipe } from "@nestjs/common";
14
14
  import { WorkflowService } from "../services/workflow.service.js";
15
15
  import { TriggerEventDto, TriggerEventParamsDto } from "./dto/index.js";
16
+ import { WorkflowExceptionFilter } from "../filters/workflow-exception.filter.js";
16
17
  let WorkflowEventController = class WorkflowEventController {
17
18
  workflowService;
18
19
  constructor(workflowService) {
@@ -38,7 +39,8 @@ __decorate([
38
39
  ], WorkflowEventController.prototype, "triggerEvent", null);
39
40
  WorkflowEventController = __decorate([
40
41
  Controller("workflows"),
41
- UsePipes(new ValidationPipe({ transform: true, whitelist: true })),
42
+ UseFilters(WorkflowExceptionFilter),
43
+ UsePipes(new ValidationPipe({ transform: true, whitelist: true, forbidNonWhitelisted: true })),
42
44
  __metadata("design:paramtypes", [WorkflowService])
43
45
  ], WorkflowEventController);
44
46
  export { WorkflowEventController };
@@ -10,9 +10,10 @@ var __metadata = (this && this.__metadata) || function (k, v) {
10
10
  var __param = (this && this.__param) || function (paramIndex, decorator) {
11
11
  return function (target, key) { decorator(target, key, paramIndex); }
12
12
  };
13
- import { Controller, Post, Get, Param, Body, UsePipes, ValidationPipe, NotFoundException, ParseUUIDPipe, } from "@nestjs/common";
13
+ import { Controller, Post, Get, Param, Body, UsePipes, UseFilters, ValidationPipe, NotFoundException, ParseUUIDPipe, } from "@nestjs/common";
14
14
  import { WorkflowService } from "../services/workflow.service.js";
15
15
  import { CreateInstanceDto } from "./dto/index.js";
16
+ import { WorkflowExceptionFilter } from "../filters/workflow-exception.filter.js";
16
17
  let WorkflowInstanceController = class WorkflowInstanceController {
17
18
  workflowService;
18
19
  constructor(workflowService) {
@@ -50,7 +51,8 @@ __decorate([
50
51
  ], WorkflowInstanceController.prototype, "getInstance", null);
51
52
  WorkflowInstanceController = __decorate([
52
53
  Controller("workflows"),
53
- UsePipes(new ValidationPipe({ transform: true, whitelist: true })),
54
+ UseFilters(WorkflowExceptionFilter),
55
+ UsePipes(new ValidationPipe({ transform: true, whitelist: true, forbidNonWhitelisted: true })),
54
56
  __metadata("design:paramtypes", [WorkflowService])
55
57
  ], WorkflowInstanceController);
56
58
  export { WorkflowInstanceController };
@@ -10,9 +10,10 @@ var __metadata = (this && this.__metadata) || function (k, v) {
10
10
  var __param = (this && this.__param) || function (paramIndex, decorator) {
11
11
  return function (target, key) { decorator(target, key, paramIndex); }
12
12
  };
13
- import { Controller, Get, Param, Query, UsePipes, ValidationPipe } from "@nestjs/common";
13
+ import { Controller, Get, Param, Query, UsePipes, UseFilters, ValidationPipe } from "@nestjs/common";
14
14
  import { WorkflowService } from "../services/workflow.service.js";
15
15
  import { AvailableEventsParamsDto, HistoryQueryDto, HistoryParamsDto } from "./dto/index.js";
16
+ import { WorkflowExceptionFilter } from "../filters/workflow-exception.filter.js";
16
17
  let WorkflowQueryController = class WorkflowQueryController {
17
18
  workflowService;
18
19
  constructor(workflowService) {
@@ -25,8 +26,8 @@ let WorkflowQueryController = class WorkflowQueryController {
25
26
  }
26
27
  async getHistory(params, query) {
27
28
  return this.workflowService.getHistory(params.workflowInstanceUuid, {
28
- limit: query.limit ? parseInt(query.limit, 10) : undefined,
29
- offset: query.offset ? parseInt(query.offset, 10) : undefined,
29
+ limit: query.limit,
30
+ offset: query.offset,
30
31
  });
31
32
  }
32
33
  };
@@ -48,7 +49,8 @@ __decorate([
48
49
  ], WorkflowQueryController.prototype, "getHistory", null);
49
50
  WorkflowQueryController = __decorate([
50
51
  Controller("workflows"),
51
- UsePipes(new ValidationPipe({ transform: true, whitelist: true })),
52
+ UseFilters(WorkflowExceptionFilter),
53
+ UsePipes(new ValidationPipe({ transform: true, whitelist: true, forbidNonWhitelisted: true })),
52
54
  __metadata("design:paramtypes", [WorkflowService])
53
55
  ], WorkflowQueryController);
54
56
  export { WorkflowQueryController };
@@ -10,16 +10,17 @@ var __metadata = (this && this.__metadata) || function (k, v) {
10
10
  var __param = (this && this.__param) || function (paramIndex, decorator) {
11
11
  return function (target, key) { decorator(target, key, paramIndex); }
12
12
  };
13
- import { Controller, Post, Query, UsePipes, ValidationPipe } from "@nestjs/common";
13
+ import { Controller, Post, Query, UsePipes, UseFilters, ValidationPipe } from "@nestjs/common";
14
14
  import { WorkflowTimeoutService } from "../services/workflow-timeout.service.js";
15
15
  import { TimeoutProcessQueryDto } from "./dto/index.js";
16
+ import { WorkflowExceptionFilter } from "../filters/workflow-exception.filter.js";
16
17
  let WorkflowTimeoutController = class WorkflowTimeoutController {
17
18
  timeoutService;
18
19
  constructor(timeoutService) {
19
20
  this.timeoutService = timeoutService;
20
21
  }
21
22
  async processExpired(query) {
22
- return this.timeoutService.processExpiredWorkflows(query.limit ? parseInt(query.limit, 10) : undefined);
23
+ return this.timeoutService.processExpiredWorkflows(query.limit);
23
24
  }
24
25
  };
25
26
  __decorate([
@@ -31,7 +32,8 @@ __decorate([
31
32
  ], WorkflowTimeoutController.prototype, "processExpired", null);
32
33
  WorkflowTimeoutController = __decorate([
33
34
  Controller("workflows/timeouts"),
34
- UsePipes(new ValidationPipe({ transform: true, whitelist: true })),
35
+ UseFilters(WorkflowExceptionFilter),
36
+ UsePipes(new ValidationPipe({ transform: true, whitelist: true, forbidNonWhitelisted: true })),
35
37
  __metadata("design:paramtypes", [WorkflowTimeoutService])
36
38
  ], WorkflowTimeoutController);
37
39
  export { WorkflowTimeoutController };
@@ -0,0 +1,13 @@
1
+ import { type ArgumentsHost, type ExceptionFilter } from "@nestjs/common";
2
+ import { WorkflowError } from "@duraflows/core";
3
+ /**
4
+ * Maps duraflows domain errors to HTTP statuses for the optional REST
5
+ * controllers. Without this filter, a missing instance or an event invalid
6
+ * for the current state surfaces as a generic 500 and leaks internal
7
+ * messages.
8
+ */
9
+ export declare class WorkflowExceptionFilter implements ExceptionFilter {
10
+ private readonly logger;
11
+ catch(exception: WorkflowError, host: ArgumentsHost): void;
12
+ }
13
+ //# sourceMappingURL=workflow-exception.filter.d.ts.map