@rytass/bpm-core-nestjs-module 0.22.0 → 0.24.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 (161) hide show
  1. package/CHANGELOG.md +95 -0
  2. package/README.md +68 -1
  3. package/package.json +2 -2
  4. package/src/index.d.ts +1 -0
  5. package/src/index.js +1 -0
  6. package/src/index.js.map +1 -1
  7. package/src/lib/bpm/bpm-root-options.d.ts +57 -0
  8. package/src/lib/bpm/bpm-root-options.js.map +1 -1
  9. package/src/lib/bpm/bpm-root.module.d.ts +21 -0
  10. package/src/lib/bpm/bpm-root.module.js +6 -0
  11. package/src/lib/bpm/bpm-root.module.js.map +1 -1
  12. package/src/lib/form/dto/form-definition.input.d.ts +5 -0
  13. package/src/lib/form/dto/form-definition.input.js.map +1 -1
  14. package/src/lib/form/form-definition.entity.d.ts +5 -0
  15. package/src/lib/form/form-definition.entity.js +7 -0
  16. package/src/lib/form/form-definition.entity.js.map +1 -1
  17. package/src/lib/form/form-schema.validator.js +17 -5
  18. package/src/lib/form/form-schema.validator.js.map +1 -1
  19. package/src/lib/form/form.queries.d.ts +2 -2
  20. package/src/lib/form/form.queries.js +17 -5
  21. package/src/lib/form/form.queries.js.map +1 -1
  22. package/src/lib/form/form.service.d.ts +2 -1
  23. package/src/lib/form/form.service.js +10 -5
  24. package/src/lib/form/form.service.js.map +1 -1
  25. package/src/lib/form-data-source/form-data-source-value-resolver.service.js +22 -2
  26. package/src/lib/form-data-source/form-data-source-value-resolver.service.js.map +1 -1
  27. package/src/lib/form-data-source/form-data-source.errors.d.ts +11 -0
  28. package/src/lib/form-data-source/form-data-source.errors.js +14 -1
  29. package/src/lib/form-data-source/form-data-source.errors.js.map +1 -1
  30. package/src/lib/form-data-source/form-data-source.service.d.ts +6 -0
  31. package/src/lib/form-data-source/form-data-source.service.js +37 -3
  32. package/src/lib/form-data-source/form-data-source.service.js.map +1 -1
  33. package/src/lib/instance-event/approval-instance-event.entity.d.ts +27 -0
  34. package/src/lib/instance-event/approval-instance-event.entity.js +93 -0
  35. package/src/lib/instance-event/approval-instance-event.entity.js.map +1 -0
  36. package/src/lib/instance-event/index.d.ts +13 -0
  37. package/src/lib/instance-event/index.js +17 -0
  38. package/src/lib/instance-event/index.js.map +1 -0
  39. package/src/lib/instance-event/instance-event.delivery-scheduler.service.d.ts +21 -0
  40. package/src/lib/instance-event/instance-event.delivery-scheduler.service.js +81 -0
  41. package/src/lib/instance-event/instance-event.delivery-scheduler.service.js.map +1 -0
  42. package/src/lib/instance-event/instance-event.delivery.service.d.ts +69 -0
  43. package/src/lib/instance-event/instance-event.delivery.service.js +259 -0
  44. package/src/lib/instance-event/instance-event.delivery.service.js.map +1 -0
  45. package/src/lib/instance-event/instance-event.delivery.subscriber.d.ts +24 -0
  46. package/src/lib/instance-event/instance-event.delivery.subscriber.js +85 -0
  47. package/src/lib/instance-event/instance-event.delivery.subscriber.js.map +1 -0
  48. package/src/lib/instance-event/instance-event.enums.d.ts +12 -0
  49. package/src/lib/instance-event/instance-event.enums.js +28 -0
  50. package/src/lib/instance-event/instance-event.enums.js.map +1 -0
  51. package/src/lib/instance-event/instance-event.module.d.ts +13 -0
  52. package/src/lib/instance-event/instance-event.module.js +52 -0
  53. package/src/lib/instance-event/instance-event.module.js.map +1 -0
  54. package/src/lib/instance-event/instance-event.object.d.ts +24 -0
  55. package/src/lib/instance-event/instance-event.object.js +73 -0
  56. package/src/lib/instance-event/instance-event.object.js.map +1 -0
  57. package/src/lib/instance-event/instance-event.options.d.ts +26 -0
  58. package/src/lib/instance-event/instance-event.options.js +35 -0
  59. package/src/lib/instance-event/instance-event.options.js.map +1 -0
  60. package/src/lib/instance-event/instance-event.resolver.d.ts +10 -0
  61. package/src/lib/instance-event/instance-event.resolver.js +75 -0
  62. package/src/lib/instance-event/instance-event.resolver.js.map +1 -0
  63. package/src/lib/instance-event/instance-event.service.d.ts +18 -0
  64. package/src/lib/instance-event/instance-event.service.js +37 -0
  65. package/src/lib/instance-event/instance-event.service.js.map +1 -0
  66. package/src/lib/instance-event/instance-event.token.d.ts +19 -0
  67. package/src/lib/instance-event/instance-event.token.js +9 -0
  68. package/src/lib/instance-event/instance-event.token.js.map +1 -0
  69. package/src/lib/instance-event/instance-event.types.d.ts +67 -0
  70. package/src/lib/instance-event/instance-event.types.js +9 -0
  71. package/src/lib/instance-event/instance-event.types.js.map +1 -0
  72. package/src/lib/instance-event/instance-event.writer.d.ts +21 -0
  73. package/src/lib/instance-event/instance-event.writer.js +45 -0
  74. package/src/lib/instance-event/instance-event.writer.js.map +1 -0
  75. package/src/lib/migrations/0000000032000-host-integration-round.d.ts +25 -0
  76. package/src/lib/migrations/0000000032000-host-integration-round.js +104 -0
  77. package/src/lib/migrations/0000000032000-host-integration-round.js.map +1 -0
  78. package/src/lib/migrations/0000000033000-activity-log-advance-failed-index.d.ts +35 -0
  79. package/src/lib/migrations/0000000033000-activity-log-advance-failed-index.js +51 -0
  80. package/src/lib/migrations/0000000033000-activity-log-advance-failed-index.js.map +1 -0
  81. package/src/lib/migrations/index.d.ts +2 -0
  82. package/src/lib/migrations/index.js +6 -0
  83. package/src/lib/migrations/index.js.map +1 -1
  84. package/src/lib/notification/notification.service.d.ts +3 -2
  85. package/src/lib/notification/notification.service.js +52 -10
  86. package/src/lib/notification/notification.service.js.map +1 -1
  87. package/src/lib/template/approval-template-version.entity.d.ts +9 -1
  88. package/src/lib/template/approval-template-version.entity.js +11 -1
  89. package/src/lib/template/approval-template-version.entity.js.map +1 -1
  90. package/src/lib/template/approval-template.entity.d.ts +18 -0
  91. package/src/lib/template/approval-template.entity.js +23 -0
  92. package/src/lib/template/approval-template.entity.js.map +1 -1
  93. package/src/lib/template/dto/approval-template.input.d.ts +21 -0
  94. package/src/lib/template/dto/approval-template.input.js +38 -0
  95. package/src/lib/template/dto/approval-template.input.js.map +1 -1
  96. package/src/lib/template/dto/compose-approval-template.input.d.ts +23 -0
  97. package/src/lib/template/dto/compose-approval-template.input.js +37 -0
  98. package/src/lib/template/dto/compose-approval-template.input.js.map +1 -1
  99. package/src/lib/template/template-key.d.ts +26 -0
  100. package/src/lib/template/template-key.js +67 -0
  101. package/src/lib/template/template-key.js.map +1 -0
  102. package/src/lib/template/template.enums.d.ts +11 -0
  103. package/src/lib/template/template.enums.js +17 -1
  104. package/src/lib/template/template.enums.js.map +1 -1
  105. package/src/lib/template/template.queries.d.ts +3 -2
  106. package/src/lib/template/template.queries.js +29 -4
  107. package/src/lib/template/template.queries.js.map +1 -1
  108. package/src/lib/template/template.service.d.ts +8 -1
  109. package/src/lib/template/template.service.js +111 -17
  110. package/src/lib/template/template.service.js.map +1 -1
  111. package/src/lib/template/workflow-definition.validator.js +12 -6
  112. package/src/lib/template/workflow-definition.validator.js.map +1 -1
  113. package/src/lib/workflow-engine/approver-filled-table-columns.d.ts +91 -0
  114. package/src/lib/workflow-engine/approver-filled-table-columns.js +301 -0
  115. package/src/lib/workflow-engine/approver-filled-table-columns.js.map +1 -0
  116. package/src/lib/workflow-engine/dto/admin-cancel-approval-instance.input.d.ts +9 -0
  117. package/src/lib/workflow-engine/dto/admin-cancel-approval-instance.input.js +24 -0
  118. package/src/lib/workflow-engine/dto/admin-cancel-approval-instance.input.js.map +1 -0
  119. package/src/lib/workflow-engine/dto/dry-run-approval-workflow.input.d.ts +7 -0
  120. package/src/lib/workflow-engine/dto/dry-run-approval-workflow.input.js +9 -0
  121. package/src/lib/workflow-engine/dto/dry-run-approval-workflow.input.js.map +1 -1
  122. package/src/lib/workflow-engine/dto/reassign-member-tasks.input.d.ts +2 -0
  123. package/src/lib/workflow-engine/dto/reassign-member-tasks.input.js +8 -0
  124. package/src/lib/workflow-engine/dto/reassign-member-tasks.input.js.map +1 -1
  125. package/src/lib/workflow-engine/index.d.ts +3 -0
  126. package/src/lib/workflow-engine/index.js +3 -0
  127. package/src/lib/workflow-engine/index.js.map +1 -1
  128. package/src/lib/workflow-engine/instance-advance-failure.d.ts +28 -0
  129. package/src/lib/workflow-engine/instance-advance-failure.js +20 -0
  130. package/src/lib/workflow-engine/instance-advance-failure.js.map +1 -0
  131. package/src/lib/workflow-engine/instance-guard.runner.d.ts +19 -0
  132. package/src/lib/workflow-engine/instance-guard.runner.js +102 -0
  133. package/src/lib/workflow-engine/instance-guard.runner.js.map +1 -0
  134. package/src/lib/workflow-engine/instance-guard.token.d.ts +101 -0
  135. package/src/lib/workflow-engine/instance-guard.token.js +9 -0
  136. package/src/lib/workflow-engine/instance-guard.token.js.map +1 -0
  137. package/src/lib/workflow-engine/missing-form-fields.d.ts +12 -0
  138. package/src/lib/workflow-engine/missing-form-fields.js +27 -0
  139. package/src/lib/workflow-engine/missing-form-fields.js.map +1 -0
  140. package/src/lib/workflow-engine/stuck-approval-instance.object.d.ts +22 -0
  141. package/src/lib/workflow-engine/stuck-approval-instance.object.js +107 -0
  142. package/src/lib/workflow-engine/stuck-approval-instance.object.js.map +1 -0
  143. package/src/lib/workflow-engine/stuck-approval-instance.query.d.ts +22 -0
  144. package/src/lib/workflow-engine/stuck-approval-instance.query.js +139 -0
  145. package/src/lib/workflow-engine/stuck-approval-instance.query.js.map +1 -0
  146. package/src/lib/workflow-engine/workflow-engine.enums.d.ts +11 -0
  147. package/src/lib/workflow-engine/workflow-engine.enums.js +16 -1
  148. package/src/lib/workflow-engine/workflow-engine.enums.js.map +1 -1
  149. package/src/lib/workflow-engine/workflow-engine.module.d.ts +2 -0
  150. package/src/lib/workflow-engine/workflow-engine.module.js +3 -0
  151. package/src/lib/workflow-engine/workflow-engine.module.js.map +1 -1
  152. package/src/lib/workflow-engine/workflow-engine.mutations.d.ts +3 -1
  153. package/src/lib/workflow-engine/workflow-engine.mutations.js +39 -6
  154. package/src/lib/workflow-engine/workflow-engine.mutations.js.map +1 -1
  155. package/src/lib/workflow-engine/workflow-engine.queries.d.ts +10 -8
  156. package/src/lib/workflow-engine/workflow-engine.queries.js +131 -28
  157. package/src/lib/workflow-engine/workflow-engine.queries.js.map +1 -1
  158. package/src/lib/workflow-engine/workflow-engine.service.d.ts +348 -10
  159. package/src/lib/workflow-engine/workflow-engine.service.js +1396 -118
  160. package/src/lib/workflow-engine/workflow-engine.service.js.map +1 -1
  161. package/src/lib/workflow-engine/workflow-engine.tokens.d.ts +5 -0
@@ -1,4 +1,4 @@
1
- import { MemberMetadata, type ApprovalInstanceFieldFilter, type ApprovalInstanceSort } from '@rytass/bpm-core-shared';
1
+ import { MemberMetadata, type FieldAccessFillUnit, type ApprovalInstanceFieldFilter, type ApprovalInstanceSort } from '@rytass/bpm-core-shared';
2
2
  import { WorkflowWebhookDeliveryService } from '../workflow-webhook/workflow-webhook-delivery.service';
3
3
  import { Repository } from 'typeorm';
4
4
  import { AttachmentService } from '../attachment/attachment.service';
@@ -27,9 +27,11 @@ import { ApprovalInstanceEntity } from './approval-instance.entity';
27
27
  import { TaskDecisionEntity } from './task-decision.entity';
28
28
  import { TaskCandidateEntity } from './task-candidate.entity';
29
29
  import { TaskEntity } from './task.entity';
30
- import { ApprovalInstanceListViewEnum, ApprovalInstanceStateEnum, MemberTaskRoleEnum, TaskCandidateStatusEnum, TaskReassignmentErrorCodeEnum, TaskReassignmentOutcomeEnum } from './workflow-engine.enums';
30
+ import { ApprovalInstanceListViewEnum, ApprovalInstanceStateEnum, MemberTaskRoleEnum, StuckApprovalInstanceKindEnum, TaskCandidateStatusEnum, TaskReassignmentErrorCodeEnum, TaskReassignmentOutcomeEnum } from './workflow-engine.enums';
31
31
  import { WorkflowDryRunResultObject } from './workflow-dry-run.object';
32
32
  import { BPMInitiatorCustomFieldsResolver } from './initiator-custom-fields-resolver.token';
33
+ import { InstanceEventWriter } from '../instance-event/instance-event.writer';
34
+ import { BPMInstanceGuard } from './instance-guard.token';
33
35
  import { BPMWorkflowServiceTaskDispatcher } from './workflow-service-task-dispatcher.token';
34
36
  import { WorkflowTokenEntity } from './workflow-token.entity';
35
37
  import { BPMRootRuntimeOptions } from '../bpm/bpm-root-options';
@@ -59,6 +61,15 @@ type SubmitApprovalInstanceCommand = SubmitApprovalInstanceInput & {
59
61
  * unset and may prefill them.
60
62
  */
61
63
  readonly endUserSubmission?: boolean;
64
+ /**
65
+ * Service layer only (ADR 27 §5): fields a host adds to the initiator's
66
+ * `customFields`. The engine still builds the default snapshot and calls the
67
+ * `customFields` resolver; these values are merged over what it returned, so
68
+ * a key given here wins. Cannot be combined with
69
+ * `initiatorMetadataSnapshotJson` (400). The GraphQL mutation always passes
70
+ * `null`.
71
+ */
72
+ readonly initiatorCustomFields?: Readonly<Record<string, unknown>> | null;
62
73
  };
63
74
  type ResubmitApprovalInstanceCommand = ResubmitApprovalInstanceInput & {
64
75
  readonly initiatorMemberId: string;
@@ -92,6 +103,13 @@ export interface ReassignTaskOptions {
92
103
  readonly reason: string;
93
104
  readonly toMemberId: string;
94
105
  }
106
+ export interface ReassignMemberTasksOptions extends ReassignTaskOptions {
107
+ /**
108
+ * Only these tasks. Omitted or null means every open task the member holds;
109
+ * an empty list is refused, never read as "all".
110
+ */
111
+ readonly taskIds?: readonly string[] | null;
112
+ }
95
113
  export interface MemberOpenTaskRecord {
96
114
  readonly candidateStatus: TaskCandidateStatusEnum | null;
97
115
  readonly createdAt: Date;
@@ -107,6 +125,32 @@ export interface MemberOpenTaskRecord {
107
125
  readonly templateId: string;
108
126
  readonly templateName: string | null;
109
127
  }
128
+ /** Paging of {@link WorkflowEngineService.listStuckApprovalInstances}. */
129
+ export interface ListStuckApprovalInstancesOptions {
130
+ /** 1-based; defaults to 1. */
131
+ readonly page?: number;
132
+ /** Defaults to 20, at most 100. */
133
+ readonly pageSize?: number;
134
+ }
135
+ /** An instance that could not move on, as the administrator's stuck list reads it. */
136
+ export interface StuckApprovalInstanceRecord {
137
+ /** `'SLA_AUTO_APPROVE'` when the failed attempt was the timeout approving. */
138
+ readonly automatic: 'SLA_AUTO_APPROVE' | null;
139
+ readonly failedActorMemberId: string | null;
140
+ readonly failedAt: Date;
141
+ readonly initiatorMemberId: string;
142
+ readonly instanceId: string;
143
+ readonly instanceTitle: string;
144
+ readonly kind: StuckApprovalInstanceKindEnum;
145
+ readonly message: string;
146
+ readonly nodeId: string | null;
147
+ readonly nodeLabel: string | null;
148
+ /** Who has to press again now; read when the list is loaded. */
149
+ readonly pendingActorMemberIds: readonly string[];
150
+ readonly taskId: string | null;
151
+ readonly templateId: string;
152
+ readonly templateName: string | null;
153
+ }
110
154
  /** Paging of a member's task list; both absent means unpaged. */
111
155
  export interface TaskListPageOptions {
112
156
  /** 1-based; defaults to 1 once paging is asked for. */
@@ -114,8 +158,22 @@ export interface TaskListPageOptions {
114
158
  /** Defaults to 20, at most 100, once paging is asked for. */
115
159
  readonly pageSize?: number;
116
160
  }
161
+ /**
162
+ * Narrows a member's task list to the tasks of some templates. Absent fields
163
+ * do not filter. An empty `templateIds` matches nothing, as `IN ()` would.
164
+ * When both fields are given a task must satisfy both.
165
+ */
166
+ export interface TaskTemplateFilter {
167
+ /** Only tasks whose instance was started from one of these templates. */
168
+ readonly templateIds?: readonly string[];
169
+ /** Only tasks whose instance's template carries this key (ADR 27 §6). */
170
+ readonly templateKey?: string;
171
+ }
172
+ /** Options of {@link WorkflowEngineService.listInboxTasks}. */
173
+ export interface InboxTaskListOptions extends TaskListPageOptions, TaskTemplateFilter {
174
+ }
117
175
  /** Options of {@link WorkflowEngineService.listApprovalHistoryTasks}. */
118
- export interface ApprovalHistoryTaskListOptions extends TaskListPageOptions {
176
+ export interface ApprovalHistoryTaskListOptions extends TaskListPageOptions, TaskTemplateFilter {
119
177
  /** Only tasks of instances in this state. */
120
178
  readonly instanceState?: ApprovalInstanceStateEnum;
121
179
  }
@@ -127,6 +185,13 @@ export interface InactiveMemberOpenTasksRecord {
127
185
  /** Same count as {@link WorkflowEngineService.listMemberOpenTasks} returns rows. */
128
186
  readonly openTaskCount: number;
129
187
  }
188
+ /** Input of {@link WorkflowEngineService.adminCancelApprovalInstance}. */
189
+ export interface AdminCancelApprovalInstanceCommand {
190
+ readonly cancelledByMemberId: string;
191
+ readonly instanceId: string;
192
+ /** Why the administrator ends it; stored and sent to the initiator. */
193
+ readonly reason: string;
194
+ }
130
195
  /**
131
196
  * Engine-internal decision knobs that are deliberately kept out of
132
197
  * {@link DecideTaskInput} so they never reach the GraphQL schema.
@@ -152,6 +217,13 @@ export interface DecideTaskOptions {
152
217
  * transfer. Defaults to {@link MANUAL_TRANSFER_DELEGATION_REASON}.
153
218
  */
154
219
  readonly transferReason?: string;
220
+ /**
221
+ * The approver's own auth context, passed by the GraphQL mutation. Data
222
+ * source providers receive it when an approver-filled dynamic field is
223
+ * resolved. Absent for engine-made decisions (SLA auto-approve), which then
224
+ * act as the decider's member id only.
225
+ */
226
+ readonly approverAuthContext?: BPMAuthContext;
155
227
  }
156
228
  export interface ListApprovalInstancesOptions {
157
229
  /** ADR 25 §7: conditions on form fields. Needs `templateId` when not empty. */
@@ -163,6 +235,11 @@ export interface ListApprovalInstancesOptions {
163
235
  readonly sort?: readonly ApprovalInstanceSort[];
164
236
  readonly state?: readonly ApprovalInstanceStateEnum[];
165
237
  readonly templateId?: string;
238
+ /**
239
+ * ADR 27 §6: the template's `key`. Resolved to its id; with `templateId`
240
+ * as well, both must name the same template. An unknown key matches nothing.
241
+ */
242
+ readonly templateKey?: string;
166
243
  readonly view?: ApprovalInstanceListViewEnum;
167
244
  }
168
245
  interface WorkflowDashboardSummaryOptions {
@@ -190,14 +267,38 @@ export declare class WorkflowEngineService {
190
267
  private readonly slaScheduleService;
191
268
  private readonly formDataSourceValueResolver?;
192
269
  private readonly webhookDeliveryService?;
270
+ private readonly instanceEventWriter?;
193
271
  private readonly logger;
194
272
  /** In-flight inbox reads by member; see `readSharedOpenInboxTasks`. */
195
273
  private readonly openInboxReadsInFlight;
196
274
  private readonly approvalInstanceFieldFilterCompiler;
197
275
  private readonly approvalInstanceFilterableFieldPolicy;
198
- constructor(approvalInstanceRepository: Repository<ApprovalInstanceEntity>, workflowTokenRepository: Repository<WorkflowTokenEntity>, taskRepository: Repository<TaskEntity>, taskCandidateRepository: Repository<TaskCandidateEntity>, taskDecisionRepository: Repository<TaskDecisionEntity>, notificationRepository: Repository<NotificationEntity>, activityLogRepository: Repository<ActivityLogEntity>, adhocDirectiveRepository: Repository<AdhocDirectiveEntity>, approvalTemplateRepository: Repository<ApprovalTemplateEntity>, approvalTemplateVersionRepository: Repository<ApprovalTemplateVersionEntity>, formDefinitionVersionRepository: Repository<FormDefinitionVersionEntity>, attachmentService: AttachmentService, conditionService: ConditionService, delegationService: DelegationService, notificationService: NotificationService, signatureService: SignatureService, slaScheduleService: BPMSlaScheduleService, injectedServiceTaskDispatcher?: BPMWorkflowServiceTaskDispatcher, formDataSourceValueResolver?: BPMFormDataSourceValueResolver | undefined, rootOptions?: BPMRootRuntimeOptions, webhookDeliveryService?: WorkflowWebhookDeliveryService | undefined, injectedInitiatorCustomFieldsResolver?: BPMInitiatorCustomFieldsResolver);
276
+ constructor(approvalInstanceRepository: Repository<ApprovalInstanceEntity>, workflowTokenRepository: Repository<WorkflowTokenEntity>, taskRepository: Repository<TaskEntity>, taskCandidateRepository: Repository<TaskCandidateEntity>, taskDecisionRepository: Repository<TaskDecisionEntity>, notificationRepository: Repository<NotificationEntity>, activityLogRepository: Repository<ActivityLogEntity>, adhocDirectiveRepository: Repository<AdhocDirectiveEntity>, approvalTemplateRepository: Repository<ApprovalTemplateEntity>, approvalTemplateVersionRepository: Repository<ApprovalTemplateVersionEntity>, formDefinitionVersionRepository: Repository<FormDefinitionVersionEntity>, attachmentService: AttachmentService, conditionService: ConditionService, delegationService: DelegationService, notificationService: NotificationService, signatureService: SignatureService, slaScheduleService: BPMSlaScheduleService, injectedServiceTaskDispatcher?: BPMWorkflowServiceTaskDispatcher, formDataSourceValueResolver?: BPMFormDataSourceValueResolver | undefined, rootOptions?: BPMRootRuntimeOptions, webhookDeliveryService?: WorkflowWebhookDeliveryService | undefined, injectedInitiatorCustomFieldsResolver?: BPMInitiatorCustomFieldsResolver, injectedInstanceGuard?: BPMInstanceGuard, instanceEventWriter?: InstanceEventWriter | undefined);
277
+ /** ADR 27 §3; see `BPMRootRuntimeOptions.expressionMissingFormFieldsAsNull`. */
278
+ private readonly expressionMissingFormFieldsAsNull;
199
279
  private readonly serviceTaskDispatcher;
200
280
  private readonly initiatorCustomFieldsResolver;
281
+ /** ADR 27 §2; `null` means no guard is bound and no guard code runs. */
282
+ private readonly instanceGuard;
283
+ private readonly instanceGuardTimeoutMs;
284
+ /**
285
+ * Runs the bound guard for one engine path inside its transaction. A no-op
286
+ * when no guard is bound, so a host without one sees no behavior change.
287
+ */
288
+ private guardInstanceChange;
289
+ /**
290
+ * Writes one case-lifecycle event (ADR 27 §1) in the caller's transaction.
291
+ * Returns before any lookup when no observer is bound, so a host without
292
+ * one pays nothing. `instanceState` is the state the change commits, not the
293
+ * state the instance held before it.
294
+ */
295
+ private recordInstanceEvent;
296
+ /**
297
+ * Reads the template version a case runs on, inside the engine transaction,
298
+ * so the guard sees the same snapshot as the decision. A missing row fails
299
+ * the change rather than handing the guard a partial input.
300
+ */
301
+ private readBoundTemplateVersionOrThrow;
201
302
  /** Webhooks each open engine transaction will send once it has committed. */
202
303
  private readonly deferredWebhookDispatches;
203
304
  private readonly organizationTimeZone;
@@ -219,6 +320,49 @@ export declare class WorkflowEngineService {
219
320
  * by the time a mutation returns, as it always has been.
220
321
  */
221
322
  private runEngineTransaction;
323
+ /**
324
+ * Runs a public operation whose engine transaction may fail with an
325
+ * {@link InstanceAdvanceFailure}. The transaction has rolled back by the time
326
+ * it lands here, so the record is written in a transaction of its own, and
327
+ * the caller then gets the original error: same class, same message, as if
328
+ * none of this existed. The wrapper type never leaves this method.
329
+ */
330
+ private withAdvanceFailureRecorded;
331
+ /**
332
+ * Writes the `ADVANCE_FAILED` row for a rolled-back attempt, trying again
333
+ * once if the write fails. If every try fails the failure is logged as an
334
+ * error with what the row would have held, and swallowed: the caller must
335
+ * see the error that stopped the case, not the one that stopped its record.
336
+ * Such an instance is missing from the stuck list, so the log is the only
337
+ * trace of it.
338
+ */
339
+ private recordAdvanceFailure;
340
+ /** One try of {@link recordAdvanceFailure}, in a transaction of its own. */
341
+ private writeAdvanceFailure;
342
+ /**
343
+ * The `ADVANCE_FAILED` rows of one instance that still describe how it is
344
+ * stuck, oldest first. Whether a decision went through is not read from
345
+ * `TASK_DECIDED`: a countersign leaves one behind from an earlier voter while
346
+ * the last vote is the one that failed. What counts is whether the situation
347
+ * the row describes still holds.
348
+ *
349
+ * - `DECISION`: the task is still open and the instance is still RUNNING.
350
+ * Once the task is done, cancelled, transferred or the instance has ended,
351
+ * the case has moved on or been taken over.
352
+ * - `RESUBMIT`: the instance is still RETURNED and no later
353
+ * `INSTANCE_RESUBMITTED` exists.
354
+ *
355
+ * The rule itself is `readUnresolvedInstanceFailures` in
356
+ * `stuck-approval-instance.query.ts`, which also holds the SQL the stuck list
357
+ * pages with; the two must agree. This is the duplicate check's side.
358
+ */
359
+ private readUnresolvedAdvanceFailures;
360
+ /**
361
+ * {@link readUnresolvedAdvanceFailures} for many instances at once, in two
362
+ * queries whatever their number: one for their activity rows, one for the
363
+ * tasks those rows name. Instances with nothing unresolved are absent.
364
+ */
365
+ private readUnresolvedAdvanceFailuresByInstance;
222
366
  /**
223
367
  * Queues a webhook for after the commit. A manager this service did not open
224
368
  * has no queue and no commit it can see, so that webhook goes out on the spot
@@ -239,10 +383,76 @@ export declare class WorkflowEngineService {
239
383
  */
240
384
  findApprovalInstanceByBusinessKey(templateId: string, businessKey: string): Promise<ApprovalInstanceEntity | null>;
241
385
  private resolveFormDataOptionSnapshots;
386
+ /**
387
+ * ADR 27 §4(b): asks the data-source providers again, under the decision
388
+ * lock and as the approver, for the options of the approver-fillable fields.
389
+ * A value that is no longer among the options is refused by the resolver
390
+ * (`VALUE_NOT_RESOLVED`). Returns snapshots for the scoped fields only; the
391
+ * caller swaps them in for the stored ones.
392
+ */
393
+ private refreshApproverFilledOptionSnapshots;
394
+ /**
395
+ * ADR 27 §4(b): asks the data-source providers again, as the approver, for
396
+ * the open data-source cells of column-mode tables. `revalidateAll` false lets
397
+ * the resolver reuse the stored options of cells whose value and bindings did
398
+ * not move. Returns snapshots for the cells of `cellSchema` only.
399
+ */
400
+ private refreshApproverFilledOpenCellSnapshots;
401
+ /**
402
+ * Refuses an end user's resubmission of an instance bound to a `HOST_ONLY`
403
+ * version (ADR 27 §5). Checked before any data source is called and outside
404
+ * the lock: an instance never changes version and a published version never
405
+ * changes `launchMode`, so the answer cannot go stale. An instance that does
406
+ * not exist is left to the locked read, which reports it.
407
+ */
408
+ private assertEndUserMayResubmit;
242
409
  private prepareResubmitFormDataOptions;
243
410
  processInstance(instanceId: string): Promise<void>;
411
+ /**
412
+ * Records `TASK_AUTO_DECISION_FAILED` (ADR 27 §3) in its own transaction.
413
+ * Used after an automatic decision was refused by the instance guard: the
414
+ * decision's transaction has already rolled back, so the event cannot ride
415
+ * on it. Returns before any query when no observer is bound.
416
+ */
417
+ recordTaskAutoDecisionFailed(input: {
418
+ readonly instanceId: string;
419
+ readonly taskId: string;
420
+ readonly reason: string;
421
+ }): Promise<void>;
244
422
  decideTask(input: DecideTaskInput, options?: DecideTaskOptions): Promise<TaskDecisionEntity>;
423
+ private decideTaskInTransaction;
245
424
  cancelApprovalInstance(input: CancelApprovalInstanceInput): Promise<ApprovalInstanceEntity>;
425
+ /**
426
+ * Administrator: ends a running or returned instance on the initiator's
427
+ * behalf, whoever started it. The reason is required; it is recorded as the
428
+ * comment of the INSTANCE_CANCELLED activity (flagged
429
+ * `cancelledByAdministrator`, so a host can tell this from the initiator
430
+ * withdrawing) and sent to the initiator as an in-app notification. An
431
+ * administrator ending their own instance is not told.
432
+ *
433
+ * The notification is written only after the cancellation has committed,
434
+ * so nobody is told of a cancellation that then rolled back. A failure to
435
+ * write it is logged and does not undo the cancellation.
436
+ *
437
+ * Like the other administrator operations of this service it does not check
438
+ * who `cancelledByMemberId` is: the GraphQL mutation is guarded by
439
+ * `@BPMAdminOnly()`, and a host calling this directly must check first. That
440
+ * member is recorded as the actor of the INSTANCE_CANCELLED activity.
441
+ */
442
+ adminCancelApprovalInstance(input: AdminCancelApprovalInstanceCommand): Promise<ApprovalInstanceEntity>;
443
+ /**
444
+ * Tells the initiator, after the commit, that an administrator ended their
445
+ * instance. Written outside any transaction, so external channels go out
446
+ * straight away and an observer is told the rows are committed.
447
+ */
448
+ private notifyInitiatorOfAdminCancel;
449
+ /**
450
+ * The cancel transaction both paths share. The order is part of the
451
+ * contract: read, authorize, check the state, close, record. A non-initiator who tries to withdraw an already
452
+ * approved instance must keep getting the "initiator" refusal, not
453
+ * "not cancellable".
454
+ */
455
+ private cancelApprovalInstanceInTransaction;
246
456
  /**
247
457
  * Ends a running or returned instance because a task on it ran past its SLA
248
458
  * with `onTimeout: 'TERMINATE_INSTANCE'`. It closes the instance exactly as
@@ -254,6 +464,7 @@ export declare class WorkflowEngineService {
254
464
  expireApprovalInstance(input: ExpireApprovalInstanceCommand): Promise<ApprovalInstanceEntity>;
255
465
  private closeInstance;
256
466
  resubmitApprovalInstance(input: ResubmitApprovalInstanceCommand, authContext?: BPMAuthContext): Promise<ApprovalInstanceEntity>;
467
+ private resubmitApprovalInstanceInTransaction;
257
468
  requestAdhocCountersign({ comment, requestedByMemberId, target, taskId, }: {
258
469
  readonly comment?: string | null;
259
470
  readonly requestedByMemberId: string;
@@ -332,6 +543,16 @@ export declare class WorkflowEngineService {
332
543
  */
333
544
  private readDryRunMemberIds;
334
545
  getApprovalInstance(id: string, scope?: WorkflowReadScope): Promise<ApprovalInstanceEntity>;
546
+ /**
547
+ * ADR 27 §4.2 (gap 1): the fill units an approver may use to resolve runtime
548
+ * data-source options on a RUNNING instance. Only tasks the member can act on
549
+ * count: the member is the assignee or a PENDING/CLAIMED candidate of a
550
+ * PENDING or IN_PROGRESS, non-ad-hoc task. A task whose candidate row is
551
+ * WAITING or already decided grants nothing, even though its status is open.
552
+ * A field counts only when its node lists it as SHOW; a HIDE entry never
553
+ * grants, whatever its fill is. Returns `[]` when the instance is not RUNNING.
554
+ */
555
+ listApproverFillUnits(instanceId: string, memberId: string): Promise<readonly FieldAccessFillUnit[]>;
335
556
  /**
336
557
  * ADR 25 §6: a value written to a filterable field must fit its type, on
337
558
  * every path that writes form data. The fields checked are the ones the
@@ -415,9 +636,31 @@ export declare class WorkflowEngineService {
415
636
  * {@link countInboxTasks} and the counters cannot disagree; only the page is
416
637
  * given its candidate summaries.
417
638
  */
418
- listInboxTasks(assigneeMemberId: string, options?: TaskListPageOptions): Promise<readonly TaskEntity[]>;
639
+ listInboxTasks(assigneeMemberId: string, options?: InboxTaskListOptions): Promise<readonly TaskEntity[]>;
419
640
  /** How many tasks {@link listInboxTasks} pages through. */
420
- countInboxTasks(assigneeMemberId: string): Promise<number>;
641
+ countInboxTasks(assigneeMemberId: string, filter?: TaskTemplateFilter): Promise<number>;
642
+ /**
643
+ * The template ids a {@link TaskTemplateFilter} allows, or `null` when it
644
+ * does not filter. A `templateKey` that names no template allows nothing.
645
+ */
646
+ private readTaskTemplateFilterIds;
647
+ /**
648
+ * Turns `templateKey` into `templateId` (ADR 27 §6), or `null` when the
649
+ * options can match nothing: an unknown key, or a key naming another
650
+ * template than `templateId` does.
651
+ */
652
+ private resolveApprovalInstanceTemplateKey;
653
+ /**
654
+ * The id of the live template carrying `key`, as a list so a key that names
655
+ * nothing filters everything out. At most one live template holds a key.
656
+ */
657
+ private readTemplateIdsByKey;
658
+ /**
659
+ * Keeps the tasks whose instance belongs to the filter's templates. The open
660
+ * task read is shared with the dashboard counters, so the filter is applied
661
+ * to its result rather than pushed into it.
662
+ */
663
+ private filterTasksByTemplate;
421
664
  /**
422
665
  * {@link readOpenInboxTasks} for the inbox list and its count, joining a
423
666
  * read for the same member that is still in flight. The client asks for
@@ -452,7 +695,7 @@ export declare class WorkflowEngineService {
452
695
  */
453
696
  listApprovalHistoryTasks(assigneeMemberId: string, options?: ApprovalHistoryTaskListOptions): Promise<readonly TaskEntity[]>;
454
697
  /** How many tasks {@link listApprovalHistoryTasks} pages through. */
455
- countApprovalHistoryTasks(assigneeMemberId: string, options?: Pick<ApprovalHistoryTaskListOptions, 'instanceState'>): Promise<number>;
698
+ countApprovalHistoryTasks(assigneeMemberId: string, options?: Omit<ApprovalHistoryTaskListOptions, 'page' | 'pageSize'>): Promise<number>;
456
699
  /** The rows of {@link listApprovalHistoryTasks}, unordered and unpaged. */
457
700
  private createApprovalHistoryTaskQuery;
458
701
  /** When the member acted on a history task; see {@link listApprovalHistoryTasks}. */
@@ -471,7 +714,7 @@ export declare class WorkflowEngineService {
471
714
  * snapshot without a `nodes` array, and a blank or non-string label all
472
715
  * leave the task without a label, as `readWorkflowNodeLabel` does. Only the
473
716
  * node's `fieldAccess` leaves the database for the fill flag, which
474
- * `readNodeFillableFieldKeys` then reads as tolerantly as the engine does.
717
+ * `readNodeFillGrantFieldKeys` then reads as tolerantly as the engine does.
475
718
  */
476
719
  private readTaskNodeSummaries;
477
720
  private readDefaultInitiatorMetadataSnapshot;
@@ -586,14 +829,40 @@ export declare class WorkflowEngineService {
586
829
  * its own transaction, and reports one result per task. A failing task does
587
830
  * not stop the others: a refusal is a REJECTED result, and an unexpected
588
831
  * error is reported as REJECTED with UNEXPECTED_ERROR for that task alone.
832
+ *
833
+ * `taskIds` narrows the batch to those tasks. Omitted or null keeps every
834
+ * open task. An empty list throws a BadRequestException before anything is
835
+ * read: it must never be taken for "all", the write is not reversible. An id
836
+ * the member does not hold (already moved, instance finished, unknown) yields
837
+ * no result row and no error; the others still run.
589
838
  */
590
- reassignMemberTasks(options: ReassignTaskOptions): Promise<readonly TaskReassignmentResult[]>;
839
+ reassignMemberTasks(options: ReassignMemberTasksOptions): Promise<readonly TaskReassignmentResult[]>;
591
840
  /**
592
841
  * The open tasks a member holds, for the administrator's reassignment screen.
593
842
  * Same definition as the inbox, plus WAITING sequential seats, restricted to
594
843
  * RUNNING instances.
595
844
  */
596
845
  listMemberOpenTasks(memberId: string): Promise<readonly MemberOpenTaskRecord[]>;
846
+ /**
847
+ * The instances that could not move on and still cannot, newest failure
848
+ * first, one row each, described by their latest unresolved `ADVANCE_FAILED`.
849
+ *
850
+ * Which failures are unresolved, the order and the page are decided by the
851
+ * database (`readStuckFailurePage`, the SQL form of the rule the duplicate
852
+ * check applies in {@link readUnresolvedAdvanceFailures}); the stuck set is
853
+ * still evaluated whole before LIMIT applies, but only the page's rows leave
854
+ * the database. This decorates that page.
855
+ *
856
+ * Who has to press again is read now, not copied from the failure: a task
857
+ * the administrator has reassigned since shows its new holder.
858
+ * - `DECISION`: the candidates whose seat is PENDING or CLAIMED. A WAITING
859
+ * seat of a sequential task is not that member's turn yet. A task without
860
+ * a single candidate row is a direct task, held by its assignee.
861
+ * - `RESUBMIT`: the initiator.
862
+ */
863
+ listStuckApprovalInstances(options?: ListStuckApprovalInstancesOptions): Promise<readonly StuckApprovalInstanceRecord[]>;
864
+ /** How many instances {@link listStuckApprovalInstances} pages through. */
865
+ countStuckApprovalInstances(): Promise<number>;
597
866
  /**
598
867
  * Deactivated members who still hold open tasks, so an administrator can find
599
868
  * them: a deactivated member no longer shows up in the member search.
@@ -664,7 +933,9 @@ export declare class WorkflowEngineService {
664
933
  * Resolves who gets the node's task. A {@link SkippedRuntimeTask} means the
665
934
  * node asked to be skipped (`excludeInitiator.whenEmpty` or
666
935
  * `excludeNodeActors.whenEmpty` = SKIP_NODE) because everyone left was kept
667
- * out: the sole caller creates no task and advances the token instead.
936
+ * out, or its manager chain found the level it asks for already reached
937
+ * (`skipWhenStartReached`, or an earlier stage it continues): the sole
938
+ * caller creates no task and advances the token instead.
668
939
  *
669
940
  * With both exclusions set the initiator rule runs first. When it alone
670
941
  * leaves nobody, `excludeInitiator.whenEmpty` decides; when it leaves
@@ -672,6 +943,58 @@ export declare class WorkflowEngineService {
672
943
  * `excludeNodeActors.whenEmpty` decides.
673
944
  */
674
945
  private resolveRuntimeTaskCandidates;
946
+ /**
947
+ * What the walk of `node`'s manager chain has to know first, or `null`
948
+ * for a node that is not a manager chain using one of the two settings that
949
+ * need it (continuing an earlier chain, or skipping when the start already
950
+ * qualifies); such a node is resolved exactly as before.
951
+ *
952
+ * The settings are checked again here, since the instance runs on its own
953
+ * snapshot of the definition and a definition from another build can carry
954
+ * a shape this one never published. A setting that does not hold throws a
955
+ * {@link ConflictException} naming the node.
956
+ *
957
+ * `skipped` is set when the level the chain asks for is already there: the
958
+ * start person's own level for `skipWhenStartReached`, the level the earlier
959
+ * stage got a signature from for a continuation.
960
+ */
961
+ private resolveOrgManagerChainContext;
962
+ /**
963
+ * `skipWhenStartReached`: whether the person the chain starts from already
964
+ * holds a position level of `minPositionLevel` or more today. No start
965
+ * person, or one without a graded position, reads as "not reached" so the
966
+ * chain is walked as usual.
967
+ */
968
+ private isOrgManagerChainStartLevelReached;
969
+ /**
970
+ * The position level the manager-chain stage `stageNodeId` actually got a
971
+ * signature from in its latest round (`T`), or `null` when none counts.
972
+ *
973
+ * - A stage whose latest round was a skip for `skippedByManagerChainReached`
974
+ * got nobody to sign, so its older approvals do not count: `null`.
975
+ * - Otherwise the people who really approved its latest batch
976
+ * ({@link readNodeActorApprovals}: no ad-hoc countersign, no SLA
977
+ * auto-approval), each at the level they held on the day they approved.
978
+ * `Position.level` has no history, but memberships are dated, so a
979
+ * promotion that took effect after the approval does not raise `T`. The day
980
+ * is the organisation's, the same one "today" is.
981
+ *
982
+ * The people counted are those who pressed approve, delegates and transfer
983
+ * receivers included, not the seat they sat in.
984
+ */
985
+ private readChainStageReachedLevel;
986
+ /**
987
+ * Whether the latest thing that happened to the stage `stageNodeId` was a
988
+ * skip for `skippedByManagerChainReached`, rather than a task being made for
989
+ * it: the newest such `TOKEN_ADVANCED` is newer than the newest
990
+ * `TASK_CREATED` of one of the stage's own (non-ad-hoc) tasks. Newer is
991
+ * decided by the log's `seq` (the order the database wrote the rows in;
992
+ * `created_at` is the transaction start and ties within one transaction).
993
+ *
994
+ * The `TASK_CREATED` payload does not say whether its task is ad-hoc, so the
995
+ * task is looked up by the id the log carries.
996
+ */
997
+ private wasChainStageSkippedLastRound;
675
998
  /**
676
999
  * Everyone `node` keeps out of its approvers, per rule: the initiator and
677
1000
  * the submitter for `excludeInitiator`, and everyone who actually approved
@@ -708,6 +1031,13 @@ export declare class WorkflowEngineService {
708
1031
  */
709
1032
  private readApprovalPrincipalMemberIds;
710
1033
  private resolveInitiatorManagerReplacements;
1034
+ /**
1035
+ * The context workflow expressions on `instance` read. Its `form` is the
1036
+ * stored data, or with `expressionMissingFormFieldsAsNull` on, a copy with
1037
+ * every unfilled top-level field present (ADR 27 §3).
1038
+ */
1039
+ private buildExpressionContext;
1040
+ private readExpressionFormData;
711
1041
  private buildDelegationContext;
712
1042
  private delegateResolvedCandidates;
713
1043
  /** One member's delegation, grade-gated as {@link applyGradeGate} says. */
@@ -794,6 +1124,14 @@ export declare class WorkflowEngineService {
794
1124
  * past without joining the chain or counting as the stopping point, and so
795
1125
  * are managers below `startPositionLevel`, until the first one at or above
796
1126
  * it starts the chain.
1127
+ *
1128
+ * A chain that continues an earlier stage climbs from that stage's start and
1129
+ * walks past every manager whose level is not above the one the stage got a
1130
+ * signature from, as if that level were the last one already added. Both it
1131
+ * and a chain that skips when its start already qualifies are only walked
1132
+ * with the `chainContext` task creation worked out; without one they are
1133
+ * refused, which keeps every other entry point (a notify node's recipients,
1134
+ * for one) from reading them as an ordinary chain.
797
1135
  */
798
1136
  private resolveOrgManagerChainCandidates;
799
1137
  /**