@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.
- package/CHANGELOG.md +95 -0
- package/README.md +68 -1
- package/package.json +2 -2
- package/src/index.d.ts +1 -0
- package/src/index.js +1 -0
- package/src/index.js.map +1 -1
- package/src/lib/bpm/bpm-root-options.d.ts +57 -0
- package/src/lib/bpm/bpm-root-options.js.map +1 -1
- package/src/lib/bpm/bpm-root.module.d.ts +21 -0
- package/src/lib/bpm/bpm-root.module.js +6 -0
- package/src/lib/bpm/bpm-root.module.js.map +1 -1
- package/src/lib/form/dto/form-definition.input.d.ts +5 -0
- package/src/lib/form/dto/form-definition.input.js.map +1 -1
- package/src/lib/form/form-definition.entity.d.ts +5 -0
- package/src/lib/form/form-definition.entity.js +7 -0
- package/src/lib/form/form-definition.entity.js.map +1 -1
- package/src/lib/form/form-schema.validator.js +17 -5
- package/src/lib/form/form-schema.validator.js.map +1 -1
- package/src/lib/form/form.queries.d.ts +2 -2
- package/src/lib/form/form.queries.js +17 -5
- package/src/lib/form/form.queries.js.map +1 -1
- package/src/lib/form/form.service.d.ts +2 -1
- package/src/lib/form/form.service.js +10 -5
- package/src/lib/form/form.service.js.map +1 -1
- package/src/lib/form-data-source/form-data-source-value-resolver.service.js +22 -2
- package/src/lib/form-data-source/form-data-source-value-resolver.service.js.map +1 -1
- package/src/lib/form-data-source/form-data-source.errors.d.ts +11 -0
- package/src/lib/form-data-source/form-data-source.errors.js +14 -1
- package/src/lib/form-data-source/form-data-source.errors.js.map +1 -1
- package/src/lib/form-data-source/form-data-source.service.d.ts +6 -0
- package/src/lib/form-data-source/form-data-source.service.js +37 -3
- package/src/lib/form-data-source/form-data-source.service.js.map +1 -1
- package/src/lib/instance-event/approval-instance-event.entity.d.ts +27 -0
- package/src/lib/instance-event/approval-instance-event.entity.js +93 -0
- package/src/lib/instance-event/approval-instance-event.entity.js.map +1 -0
- package/src/lib/instance-event/index.d.ts +13 -0
- package/src/lib/instance-event/index.js +17 -0
- package/src/lib/instance-event/index.js.map +1 -0
- package/src/lib/instance-event/instance-event.delivery-scheduler.service.d.ts +21 -0
- package/src/lib/instance-event/instance-event.delivery-scheduler.service.js +81 -0
- package/src/lib/instance-event/instance-event.delivery-scheduler.service.js.map +1 -0
- package/src/lib/instance-event/instance-event.delivery.service.d.ts +69 -0
- package/src/lib/instance-event/instance-event.delivery.service.js +259 -0
- package/src/lib/instance-event/instance-event.delivery.service.js.map +1 -0
- package/src/lib/instance-event/instance-event.delivery.subscriber.d.ts +24 -0
- package/src/lib/instance-event/instance-event.delivery.subscriber.js +85 -0
- package/src/lib/instance-event/instance-event.delivery.subscriber.js.map +1 -0
- package/src/lib/instance-event/instance-event.enums.d.ts +12 -0
- package/src/lib/instance-event/instance-event.enums.js +28 -0
- package/src/lib/instance-event/instance-event.enums.js.map +1 -0
- package/src/lib/instance-event/instance-event.module.d.ts +13 -0
- package/src/lib/instance-event/instance-event.module.js +52 -0
- package/src/lib/instance-event/instance-event.module.js.map +1 -0
- package/src/lib/instance-event/instance-event.object.d.ts +24 -0
- package/src/lib/instance-event/instance-event.object.js +73 -0
- package/src/lib/instance-event/instance-event.object.js.map +1 -0
- package/src/lib/instance-event/instance-event.options.d.ts +26 -0
- package/src/lib/instance-event/instance-event.options.js +35 -0
- package/src/lib/instance-event/instance-event.options.js.map +1 -0
- package/src/lib/instance-event/instance-event.resolver.d.ts +10 -0
- package/src/lib/instance-event/instance-event.resolver.js +75 -0
- package/src/lib/instance-event/instance-event.resolver.js.map +1 -0
- package/src/lib/instance-event/instance-event.service.d.ts +18 -0
- package/src/lib/instance-event/instance-event.service.js +37 -0
- package/src/lib/instance-event/instance-event.service.js.map +1 -0
- package/src/lib/instance-event/instance-event.token.d.ts +19 -0
- package/src/lib/instance-event/instance-event.token.js +9 -0
- package/src/lib/instance-event/instance-event.token.js.map +1 -0
- package/src/lib/instance-event/instance-event.types.d.ts +67 -0
- package/src/lib/instance-event/instance-event.types.js +9 -0
- package/src/lib/instance-event/instance-event.types.js.map +1 -0
- package/src/lib/instance-event/instance-event.writer.d.ts +21 -0
- package/src/lib/instance-event/instance-event.writer.js +45 -0
- package/src/lib/instance-event/instance-event.writer.js.map +1 -0
- package/src/lib/migrations/0000000032000-host-integration-round.d.ts +25 -0
- package/src/lib/migrations/0000000032000-host-integration-round.js +104 -0
- package/src/lib/migrations/0000000032000-host-integration-round.js.map +1 -0
- package/src/lib/migrations/0000000033000-activity-log-advance-failed-index.d.ts +35 -0
- package/src/lib/migrations/0000000033000-activity-log-advance-failed-index.js +51 -0
- package/src/lib/migrations/0000000033000-activity-log-advance-failed-index.js.map +1 -0
- package/src/lib/migrations/index.d.ts +2 -0
- package/src/lib/migrations/index.js +6 -0
- package/src/lib/migrations/index.js.map +1 -1
- package/src/lib/notification/notification.service.d.ts +3 -2
- package/src/lib/notification/notification.service.js +52 -10
- package/src/lib/notification/notification.service.js.map +1 -1
- package/src/lib/template/approval-template-version.entity.d.ts +9 -1
- package/src/lib/template/approval-template-version.entity.js +11 -1
- package/src/lib/template/approval-template-version.entity.js.map +1 -1
- package/src/lib/template/approval-template.entity.d.ts +18 -0
- package/src/lib/template/approval-template.entity.js +23 -0
- package/src/lib/template/approval-template.entity.js.map +1 -1
- package/src/lib/template/dto/approval-template.input.d.ts +21 -0
- package/src/lib/template/dto/approval-template.input.js +38 -0
- package/src/lib/template/dto/approval-template.input.js.map +1 -1
- package/src/lib/template/dto/compose-approval-template.input.d.ts +23 -0
- package/src/lib/template/dto/compose-approval-template.input.js +37 -0
- package/src/lib/template/dto/compose-approval-template.input.js.map +1 -1
- package/src/lib/template/template-key.d.ts +26 -0
- package/src/lib/template/template-key.js +67 -0
- package/src/lib/template/template-key.js.map +1 -0
- package/src/lib/template/template.enums.d.ts +11 -0
- package/src/lib/template/template.enums.js +17 -1
- package/src/lib/template/template.enums.js.map +1 -1
- package/src/lib/template/template.queries.d.ts +3 -2
- package/src/lib/template/template.queries.js +29 -4
- package/src/lib/template/template.queries.js.map +1 -1
- package/src/lib/template/template.service.d.ts +8 -1
- package/src/lib/template/template.service.js +111 -17
- package/src/lib/template/template.service.js.map +1 -1
- package/src/lib/template/workflow-definition.validator.js +12 -6
- package/src/lib/template/workflow-definition.validator.js.map +1 -1
- package/src/lib/workflow-engine/approver-filled-table-columns.d.ts +91 -0
- package/src/lib/workflow-engine/approver-filled-table-columns.js +301 -0
- package/src/lib/workflow-engine/approver-filled-table-columns.js.map +1 -0
- package/src/lib/workflow-engine/dto/admin-cancel-approval-instance.input.d.ts +9 -0
- package/src/lib/workflow-engine/dto/admin-cancel-approval-instance.input.js +24 -0
- package/src/lib/workflow-engine/dto/admin-cancel-approval-instance.input.js.map +1 -0
- package/src/lib/workflow-engine/dto/dry-run-approval-workflow.input.d.ts +7 -0
- package/src/lib/workflow-engine/dto/dry-run-approval-workflow.input.js +9 -0
- package/src/lib/workflow-engine/dto/dry-run-approval-workflow.input.js.map +1 -1
- package/src/lib/workflow-engine/dto/reassign-member-tasks.input.d.ts +2 -0
- package/src/lib/workflow-engine/dto/reassign-member-tasks.input.js +8 -0
- package/src/lib/workflow-engine/dto/reassign-member-tasks.input.js.map +1 -1
- package/src/lib/workflow-engine/index.d.ts +3 -0
- package/src/lib/workflow-engine/index.js +3 -0
- package/src/lib/workflow-engine/index.js.map +1 -1
- package/src/lib/workflow-engine/instance-advance-failure.d.ts +28 -0
- package/src/lib/workflow-engine/instance-advance-failure.js +20 -0
- package/src/lib/workflow-engine/instance-advance-failure.js.map +1 -0
- package/src/lib/workflow-engine/instance-guard.runner.d.ts +19 -0
- package/src/lib/workflow-engine/instance-guard.runner.js +102 -0
- package/src/lib/workflow-engine/instance-guard.runner.js.map +1 -0
- package/src/lib/workflow-engine/instance-guard.token.d.ts +101 -0
- package/src/lib/workflow-engine/instance-guard.token.js +9 -0
- package/src/lib/workflow-engine/instance-guard.token.js.map +1 -0
- package/src/lib/workflow-engine/missing-form-fields.d.ts +12 -0
- package/src/lib/workflow-engine/missing-form-fields.js +27 -0
- package/src/lib/workflow-engine/missing-form-fields.js.map +1 -0
- package/src/lib/workflow-engine/stuck-approval-instance.object.d.ts +22 -0
- package/src/lib/workflow-engine/stuck-approval-instance.object.js +107 -0
- package/src/lib/workflow-engine/stuck-approval-instance.object.js.map +1 -0
- package/src/lib/workflow-engine/stuck-approval-instance.query.d.ts +22 -0
- package/src/lib/workflow-engine/stuck-approval-instance.query.js +139 -0
- package/src/lib/workflow-engine/stuck-approval-instance.query.js.map +1 -0
- package/src/lib/workflow-engine/workflow-engine.enums.d.ts +11 -0
- package/src/lib/workflow-engine/workflow-engine.enums.js +16 -1
- package/src/lib/workflow-engine/workflow-engine.enums.js.map +1 -1
- package/src/lib/workflow-engine/workflow-engine.module.d.ts +2 -0
- package/src/lib/workflow-engine/workflow-engine.module.js +3 -0
- package/src/lib/workflow-engine/workflow-engine.module.js.map +1 -1
- package/src/lib/workflow-engine/workflow-engine.mutations.d.ts +3 -1
- package/src/lib/workflow-engine/workflow-engine.mutations.js +39 -6
- package/src/lib/workflow-engine/workflow-engine.mutations.js.map +1 -1
- package/src/lib/workflow-engine/workflow-engine.queries.d.ts +10 -8
- package/src/lib/workflow-engine/workflow-engine.queries.js +131 -28
- package/src/lib/workflow-engine/workflow-engine.queries.js.map +1 -1
- package/src/lib/workflow-engine/workflow-engine.service.d.ts +348 -10
- package/src/lib/workflow-engine/workflow-engine.service.js +1396 -118
- package/src/lib/workflow-engine/workflow-engine.service.js.map +1 -1
- package/src/lib/workflow-engine/workflow-engine.tokens.d.ts +5 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_BPM_INSTANCE_EVENT_DELIVERY_OPTIONS = void 0;
|
|
4
|
+
exports.resolveInstanceEventDeliveryOptions = resolveInstanceEventDeliveryOptions;
|
|
5
|
+
exports.DEFAULT_BPM_INSTANCE_EVENT_DELIVERY_OPTIONS = {
|
|
6
|
+
batchSize: 25,
|
|
7
|
+
dispatchTimeoutMs: 10_000,
|
|
8
|
+
maxAttempts: 6,
|
|
9
|
+
maxRetryDelayMs: 3_600_000,
|
|
10
|
+
retentionDays: 30,
|
|
11
|
+
retryBaseDelayMs: 30_000,
|
|
12
|
+
scanIntervalMs: 15_000,
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Fills every unset or non-positive field from the defaults. A host that sets
|
|
16
|
+
* `batchSize: 0` gets 25, not an outbox that never delivers.
|
|
17
|
+
*/
|
|
18
|
+
function resolveInstanceEventDeliveryOptions(overrides) {
|
|
19
|
+
const defaults = exports.DEFAULT_BPM_INSTANCE_EVENT_DELIVERY_OPTIONS;
|
|
20
|
+
return {
|
|
21
|
+
batchSize: readPositive(overrides?.batchSize, defaults.batchSize),
|
|
22
|
+
dispatchTimeoutMs: readPositive(overrides?.dispatchTimeoutMs, defaults.dispatchTimeoutMs),
|
|
23
|
+
maxAttempts: readPositive(overrides?.maxAttempts, defaults.maxAttempts),
|
|
24
|
+
maxRetryDelayMs: readPositive(overrides?.maxRetryDelayMs, defaults.maxRetryDelayMs),
|
|
25
|
+
retentionDays: readPositive(overrides?.retentionDays, defaults.retentionDays),
|
|
26
|
+
retryBaseDelayMs: readPositive(overrides?.retryBaseDelayMs, defaults.retryBaseDelayMs),
|
|
27
|
+
scanIntervalMs: readPositive(overrides?.scanIntervalMs, defaults.scanIntervalMs),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function readPositive(value, fallback) {
|
|
31
|
+
return typeof value === 'number' && Number.isFinite(value) && value > 0
|
|
32
|
+
? Math.floor(value)
|
|
33
|
+
: fallback;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=instance-event.options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance-event.options.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/instance-event/instance-event.options.ts"],"names":[],"mappings":";;;AAoCA,kFA6BC;AA5CY,QAAA,2CAA2C,GACtD;IACE,SAAS,EAAE,EAAE;IACb,iBAAiB,EAAE,MAAM;IACzB,WAAW,EAAE,CAAC;IACd,eAAe,EAAE,SAAS;IAC1B,aAAa,EAAE,EAAE;IACjB,gBAAgB,EAAE,MAAM;IACxB,cAAc,EAAE,MAAM;CACvB,CAAC;AAEJ;;;GAGG;AACH,SAAgB,mCAAmC,CACjD,SAA+D;IAE/D,MAAM,QAAQ,GAAG,mDAA2C,CAAC;IAE7D,OAAO;QACL,SAAS,EAAE,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC;QACjE,iBAAiB,EAAE,YAAY,CAC7B,SAAS,EAAE,iBAAiB,EAC5B,QAAQ,CAAC,iBAAiB,CAC3B;QACD,WAAW,EAAE,YAAY,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,CAAC;QACvE,eAAe,EAAE,YAAY,CAC3B,SAAS,EAAE,eAAe,EAC1B,QAAQ,CAAC,eAAe,CACzB;QACD,aAAa,EAAE,YAAY,CACzB,SAAS,EAAE,aAAa,EACxB,QAAQ,CAAC,aAAa,CACvB;QACD,gBAAgB,EAAE,YAAY,CAC5B,SAAS,EAAE,gBAAgB,EAC3B,QAAQ,CAAC,gBAAgB,CAC1B;QACD,cAAc,EAAE,YAAY,CAC1B,SAAS,EAAE,cAAc,EACzB,QAAQ,CAAC,cAAc,CACxB;KACF,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,KAAyB,EAAE,QAAgB;IAC/D,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC;QACrE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;QACnB,CAAC,CAAC,QAAQ,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { InstanceEventDeliveryService } from './instance-event.delivery.service';
|
|
2
|
+
import { ApprovalInstanceEventStatusEnum } from './instance-event.enums';
|
|
3
|
+
import { ApprovalInstanceEventObject, ApprovalInstanceEventPageObject } from './instance-event.object';
|
|
4
|
+
/** Admin access to the outbox: triage failed deliveries and retry them. */
|
|
5
|
+
export declare class InstanceEventResolver {
|
|
6
|
+
private readonly deliveryService;
|
|
7
|
+
constructor(deliveryService: InstanceEventDeliveryService);
|
|
8
|
+
approvalInstanceEvents(instanceId?: string | null, status?: ApprovalInstanceEventStatusEnum | null, page?: number, pageSize?: number): Promise<ApprovalInstanceEventPageObject>;
|
|
9
|
+
retryApprovalInstanceEvent(id: string): Promise<ApprovalInstanceEventObject>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InstanceEventResolver = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const graphql_1 = require("@nestjs/graphql");
|
|
6
|
+
const bpm_auth_1 = require("../bpm-auth");
|
|
7
|
+
const instance_event_delivery_service_1 = require("./instance-event.delivery.service");
|
|
8
|
+
const instance_event_enums_1 = require("./instance-event.enums");
|
|
9
|
+
const instance_event_object_1 = require("./instance-event.object");
|
|
10
|
+
/** Admin access to the outbox: triage failed deliveries and retry them. */
|
|
11
|
+
let InstanceEventResolver = class InstanceEventResolver {
|
|
12
|
+
constructor(deliveryService) {
|
|
13
|
+
this.deliveryService = deliveryService;
|
|
14
|
+
}
|
|
15
|
+
async approvalInstanceEvents(instanceId, status, page = 1, pageSize = 50) {
|
|
16
|
+
const result = await this.deliveryService.listEvents({
|
|
17
|
+
instanceId: instanceId ?? null,
|
|
18
|
+
page,
|
|
19
|
+
pageSize,
|
|
20
|
+
status: status ? instance_event_enums_1.APPROVAL_INSTANCE_EVENT_ENUM_TO_STATUS[status] : null,
|
|
21
|
+
});
|
|
22
|
+
return Object.assign(new instance_event_object_1.ApprovalInstanceEventPageObject(), {
|
|
23
|
+
items: result.items.map((row) => toObject(row)),
|
|
24
|
+
total: result.total,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
async retryApprovalInstanceEvent(id) {
|
|
28
|
+
return toObject(await this.deliveryService.retryFailedEvent(id));
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
exports.InstanceEventResolver = InstanceEventResolver;
|
|
32
|
+
tslib_1.__decorate([
|
|
33
|
+
(0, graphql_1.Query)(() => instance_event_object_1.ApprovalInstanceEventPageObject),
|
|
34
|
+
tslib_1.__param(0, (0, graphql_1.Args)('instanceId', { nullable: true, type: () => graphql_1.ID })),
|
|
35
|
+
tslib_1.__param(1, (0, graphql_1.Args)('status', {
|
|
36
|
+
nullable: true,
|
|
37
|
+
type: () => instance_event_enums_1.ApprovalInstanceEventStatusEnum,
|
|
38
|
+
})),
|
|
39
|
+
tslib_1.__param(2, (0, graphql_1.Args)('page', { defaultValue: 1, type: () => graphql_1.Int })),
|
|
40
|
+
tslib_1.__param(3, (0, graphql_1.Args)('pageSize', { defaultValue: 50, type: () => graphql_1.Int })),
|
|
41
|
+
tslib_1.__metadata("design:type", Function),
|
|
42
|
+
tslib_1.__metadata("design:paramtypes", [Object, Object, Object, Object]),
|
|
43
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
44
|
+
], InstanceEventResolver.prototype, "approvalInstanceEvents", null);
|
|
45
|
+
tslib_1.__decorate([
|
|
46
|
+
(0, graphql_1.Mutation)(() => instance_event_object_1.ApprovalInstanceEventObject),
|
|
47
|
+
tslib_1.__param(0, (0, graphql_1.Args)('id', { type: () => graphql_1.ID })),
|
|
48
|
+
tslib_1.__metadata("design:type", Function),
|
|
49
|
+
tslib_1.__metadata("design:paramtypes", [String]),
|
|
50
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
51
|
+
], InstanceEventResolver.prototype, "retryApprovalInstanceEvent", null);
|
|
52
|
+
exports.InstanceEventResolver = InstanceEventResolver = tslib_1.__decorate([
|
|
53
|
+
(0, graphql_1.Resolver)(),
|
|
54
|
+
(0, bpm_auth_1.BPMAdminOnly)(),
|
|
55
|
+
tslib_1.__metadata("design:paramtypes", [instance_event_delivery_service_1.InstanceEventDeliveryService])
|
|
56
|
+
], InstanceEventResolver);
|
|
57
|
+
/**
|
|
58
|
+
* Field by field, so `payload` and `claimedAt` never reach the GraphQL
|
|
59
|
+
* response even if the entity gains fields later.
|
|
60
|
+
*/
|
|
61
|
+
function toObject(row) {
|
|
62
|
+
return Object.assign(new instance_event_object_1.ApprovalInstanceEventObject(), {
|
|
63
|
+
attemptCount: row.attemptCount,
|
|
64
|
+
deliveredAt: row.deliveredAt,
|
|
65
|
+
id: row.id,
|
|
66
|
+
instanceId: row.instanceId,
|
|
67
|
+
lastError: row.lastError,
|
|
68
|
+
nextAttemptAt: row.nextAttemptAt,
|
|
69
|
+
occurredAt: row.occurredAt,
|
|
70
|
+
seq: row.seq,
|
|
71
|
+
status: instance_event_enums_1.APPROVAL_INSTANCE_EVENT_STATUS_TO_ENUM[row.status],
|
|
72
|
+
type: row.type,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=instance-event.resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance-event.resolver.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/instance-event/instance-event.resolver.ts"],"names":[],"mappings":";;;;AAAA,6CAA2E;AAC3E,0CAA2C;AAE3C,uFAAiF;AACjF,iEAIgC;AAChC,mEAGiC;AAEjC,2EAA2E;AAGpE,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;IAChC,YAA6B,eAA6C;QAA7C,oBAAe,GAAf,eAAe,CAA8B;IAAG,CAAC;IAGxE,AAAN,KAAK,CAAC,sBAAsB,CAE1B,UAA0B,EAK1B,MAA+C,EACK,OAAO,CAAC,EACH,WAAW,EAAE;QAEtE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC;YACnD,UAAU,EAAE,UAAU,IAAI,IAAI;YAC9B,IAAI;YACJ,QAAQ;YACR,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,6DAAsC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI;SACvE,CAAC,CAAC;QAEH,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,uDAA+B,EAAE,EAAE;YAC1D,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YAC/C,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB,CAAC,CAAC;IACL,CAAC;IAGK,AAAN,KAAK,CAAC,0BAA0B,CACE,EAAU;QAE1C,OAAO,QAAQ,CAAC,MAAM,IAAI,CAAC,eAAe,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC;IACnE,CAAC;CACF,CAAA;AAlCY,sDAAqB;AAI1B;IADL,IAAA,eAAK,EAAC,GAAG,EAAE,CAAC,uDAA+B,CAAC;IAE1C,mBAAA,IAAA,cAAI,EAAC,YAAY,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,YAAE,EAAE,CAAC,CAAA;IAEtD,mBAAA,IAAA,cAAI,EAAC,QAAQ,EAAE;QACd,QAAQ,EAAE,IAAI;QACd,IAAI,EAAE,GAAG,EAAE,CAAC,sDAA+B;KAC5C,CAAC,CAAA;IAED,mBAAA,IAAA,cAAI,EAAC,MAAM,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,aAAG,EAAE,CAAC,CAAA;IAClD,mBAAA,IAAA,cAAI,EAAC,UAAU,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,aAAG,EAAE,CAAC,CAAA;;;;mEAazD;AAGK;IADL,IAAA,kBAAQ,EAAC,GAAG,EAAE,CAAC,mDAA2B,CAAC;IAEzC,mBAAA,IAAA,cAAI,EAAC,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,YAAE,EAAE,CAAC,CAAA;;;;uEAGhC;gCAjCU,qBAAqB;IAFjC,IAAA,kBAAQ,GAAE;IACV,IAAA,uBAAY,GAAE;6CAEiC,8DAA4B;GAD/D,qBAAqB,CAkCjC;AAED;;;GAGG;AACH,SAAS,QAAQ,CACf,GAAgC;IAEhC,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,mDAA2B,EAAE,EAAE;QACtD,YAAY,EAAE,GAAG,CAAC,YAAY;QAC9B,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,aAAa,EAAE,GAAG,CAAC,aAAa;QAChC,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,MAAM,EAAE,6DAAsC,CAAC,GAAG,CAAC,MAAM,CAAC;QAC1D,IAAI,EAAE,GAAG,CAAC,IAAI;KACf,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { BPMRootRuntimeOptions } from '../bpm/bpm-root-options';
|
|
2
|
+
import { BPMInstanceEventDeliveryOptions } from './instance-event.options';
|
|
3
|
+
import { BPMInstanceEventObserver } from './instance-event.token';
|
|
4
|
+
/**
|
|
5
|
+
* Holds the host observer for instance lifecycle events. `observer` is `null`
|
|
6
|
+
* when the host bound none; the engine then writes no outbox rows.
|
|
7
|
+
*
|
|
8
|
+
* Resolution: the Nest provider (`BPM_INSTANCE_EVENT_OBSERVER`) wins over the
|
|
9
|
+
* runtime option `BPMRootRuntimeOptions.instanceEventObserver`.
|
|
10
|
+
*
|
|
11
|
+
* `delivery` is the resolved outbox tuning, with unset fields defaulted.
|
|
12
|
+
*/
|
|
13
|
+
export declare class InstanceEventService {
|
|
14
|
+
readonly observer: BPMInstanceEventObserver | null;
|
|
15
|
+
readonly delivery: BPMInstanceEventDeliveryOptions;
|
|
16
|
+
constructor(injectedObserver: BPMInstanceEventObserver | undefined, rootOptions: BPMRootRuntimeOptions | undefined);
|
|
17
|
+
get enabled(): boolean;
|
|
18
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InstanceEventService = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const bpm_root_options_1 = require("../bpm/bpm-root-options");
|
|
7
|
+
const instance_event_options_1 = require("./instance-event.options");
|
|
8
|
+
const instance_event_token_1 = require("./instance-event.token");
|
|
9
|
+
/**
|
|
10
|
+
* Holds the host observer for instance lifecycle events. `observer` is `null`
|
|
11
|
+
* when the host bound none; the engine then writes no outbox rows.
|
|
12
|
+
*
|
|
13
|
+
* Resolution: the Nest provider (`BPM_INSTANCE_EVENT_OBSERVER`) wins over the
|
|
14
|
+
* runtime option `BPMRootRuntimeOptions.instanceEventObserver`.
|
|
15
|
+
*
|
|
16
|
+
* `delivery` is the resolved outbox tuning, with unset fields defaulted.
|
|
17
|
+
*/
|
|
18
|
+
let InstanceEventService = class InstanceEventService {
|
|
19
|
+
constructor(injectedObserver, rootOptions) {
|
|
20
|
+
this.observer =
|
|
21
|
+
injectedObserver ?? rootOptions?.instanceEventObserver ?? null;
|
|
22
|
+
this.delivery = (0, instance_event_options_1.resolveInstanceEventDeliveryOptions)(rootOptions?.instanceEventDelivery);
|
|
23
|
+
}
|
|
24
|
+
get enabled() {
|
|
25
|
+
return this.observer !== null;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
exports.InstanceEventService = InstanceEventService;
|
|
29
|
+
exports.InstanceEventService = InstanceEventService = tslib_1.__decorate([
|
|
30
|
+
(0, common_1.Injectable)(),
|
|
31
|
+
tslib_1.__param(0, (0, common_1.Optional)()),
|
|
32
|
+
tslib_1.__param(0, (0, common_1.Inject)(instance_event_token_1.BPM_INSTANCE_EVENT_OBSERVER)),
|
|
33
|
+
tslib_1.__param(1, (0, common_1.Optional)()),
|
|
34
|
+
tslib_1.__param(1, (0, common_1.Inject)(bpm_root_options_1.BPM_ROOT_OPTIONS)),
|
|
35
|
+
tslib_1.__metadata("design:paramtypes", [Object, Object])
|
|
36
|
+
], InstanceEventService);
|
|
37
|
+
//# sourceMappingURL=instance-event.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance-event.service.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/instance-event/instance-event.service.ts"],"names":[],"mappings":";;;;AAAA,2CAA8D;AAC9D,8DAGiC;AACjC,qEAGkC;AAClC,iEAGgC;AAEhC;;;;;;;;GAQG;AAEI,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IAI/B,YAGE,gBAAsD,EAGtD,WAA8C;QAE9C,IAAI,CAAC,QAAQ;YACX,gBAAgB,IAAI,WAAW,EAAE,qBAAqB,IAAI,IAAI,CAAC;QACjE,IAAI,CAAC,QAAQ,GAAG,IAAA,4DAAmC,EACjD,WAAW,EAAE,qBAAqB,CACnC,CAAC;IACJ,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC;IAChC,CAAC;CACF,CAAA;AAtBY,oDAAoB;+BAApB,oBAAoB;IADhC,IAAA,mBAAU,GAAE;IAMR,mBAAA,IAAA,iBAAQ,GAAE,CAAA;IACV,mBAAA,IAAA,eAAM,EAAC,kDAA2B,CAAC,CAAA;IAEnC,mBAAA,IAAA,iBAAQ,GAAE,CAAA;IACV,mBAAA,IAAA,eAAM,EAAC,mCAAgB,CAAC,CAAA;;GAThB,oBAAoB,CAsBhC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { InjectionToken } from '@nestjs/common';
|
|
2
|
+
import type { BPMInstanceEvent } from './instance-event.types';
|
|
3
|
+
/**
|
|
4
|
+
* Host hook that receives approval instance lifecycle events (ADR 27 §1).
|
|
5
|
+
*
|
|
6
|
+
* Delivery is at-least-once and runs after the state change has committed. A
|
|
7
|
+
* redelivered event carries the same `event.id`, so the host dedupes on it.
|
|
8
|
+
* Events of one instance arrive in `seq` order; events of different instances
|
|
9
|
+
* have no ordering guarantee. A thrown error is retried with backoff and the
|
|
10
|
+
* event is marked FAILED after the retry limit.
|
|
11
|
+
*/
|
|
12
|
+
export interface BPMInstanceEventObserver {
|
|
13
|
+
onInstanceEvent(event: BPMInstanceEvent): Promise<void> | void;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Optional host binding for {@link BPMInstanceEventObserver}. Without an
|
|
17
|
+
* observer, the engine writes no event rows at all.
|
|
18
|
+
*/
|
|
19
|
+
export declare const BPM_INSTANCE_EVENT_OBSERVER: InjectionToken<BPMInstanceEventObserver>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BPM_INSTANCE_EVENT_OBSERVER = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Optional host binding for {@link BPMInstanceEventObserver}. Without an
|
|
6
|
+
* observer, the engine writes no event rows at all.
|
|
7
|
+
*/
|
|
8
|
+
exports.BPM_INSTANCE_EVENT_OBSERVER = Symbol('BPM_INSTANCE_EVENT_OBSERVER');
|
|
9
|
+
//# sourceMappingURL=instance-event.token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance-event.token.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/instance-event/instance-event.token.ts"],"names":[],"mappings":";;;AAgBA;;;GAGG;AACU,QAAA,2BAA2B,GACtC,MAAM,CAAC,6BAA6B,CAAC,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { ApprovalInstanceStateEnum } from '../workflow-engine/workflow-engine.enums';
|
|
2
|
+
/** Empty payload for event types that carry no type-specific fields. */
|
|
3
|
+
export type BPMInstanceEventNoPayload = Readonly<Record<never, never>>;
|
|
4
|
+
/**
|
|
5
|
+
* Type-specific fields per event type (ADR 27 §1.3). `formData` is never part
|
|
6
|
+
* of an event: a host that needs it reads the instance by `instanceId`.
|
|
7
|
+
*/
|
|
8
|
+
export interface BPMInstanceEventTypePayloads {
|
|
9
|
+
readonly INSTANCE_APPROVED: BPMInstanceEventNoPayload;
|
|
10
|
+
readonly INSTANCE_CANCELLED: {
|
|
11
|
+
readonly actorMemberId: string | null;
|
|
12
|
+
};
|
|
13
|
+
readonly INSTANCE_EXPIRED: BPMInstanceEventNoPayload;
|
|
14
|
+
readonly INSTANCE_REJECTED: {
|
|
15
|
+
readonly actorMemberId: string | null;
|
|
16
|
+
};
|
|
17
|
+
readonly INSTANCE_RESUBMITTED: {
|
|
18
|
+
readonly actorMemberId: string | null;
|
|
19
|
+
};
|
|
20
|
+
readonly INSTANCE_RETURNED: {
|
|
21
|
+
readonly actorMemberId: string | null;
|
|
22
|
+
readonly nodeId: string;
|
|
23
|
+
};
|
|
24
|
+
readonly INSTANCE_SUBMITTED: {
|
|
25
|
+
readonly actorMemberId: string | null;
|
|
26
|
+
};
|
|
27
|
+
readonly NODE_ACTIVATED: {
|
|
28
|
+
readonly nodeId: string;
|
|
29
|
+
readonly taskIds: readonly string[];
|
|
30
|
+
};
|
|
31
|
+
readonly TASK_AUTO_DECISION_FAILED: {
|
|
32
|
+
readonly reason: string;
|
|
33
|
+
readonly taskId: string;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export type BPMInstanceEventType = keyof BPMInstanceEventTypePayloads;
|
|
37
|
+
/**
|
|
38
|
+
* Template and state at the moment the event was written. The table has no
|
|
39
|
+
* columns for these, so they are stored inside `payload`.
|
|
40
|
+
*/
|
|
41
|
+
export interface BPMInstanceEventSnapshot {
|
|
42
|
+
readonly instanceState: ApprovalInstanceStateEnum;
|
|
43
|
+
readonly templateId: string;
|
|
44
|
+
readonly templateKey: string | null;
|
|
45
|
+
readonly templateVersionId: string;
|
|
46
|
+
}
|
|
47
|
+
/** Columns that every delivered event carries. */
|
|
48
|
+
export interface BPMInstanceEventHeader {
|
|
49
|
+
/** Generated by the database. Stable across redeliveries; dedupe on it. */
|
|
50
|
+
readonly id: string;
|
|
51
|
+
readonly instanceId: string;
|
|
52
|
+
/** Write order, assigned by the database. A bigint, so a string. */
|
|
53
|
+
readonly seq: string;
|
|
54
|
+
readonly occurredAt: string;
|
|
55
|
+
}
|
|
56
|
+
/** The payload stored in `approval_instance_events.payload`. */
|
|
57
|
+
export type BPMInstanceEventPayload = {
|
|
58
|
+
readonly [K in BPMInstanceEventType]: BPMInstanceEventSnapshot & BPMInstanceEventTypePayloads[K];
|
|
59
|
+
}[BPMInstanceEventType];
|
|
60
|
+
/** What the observer receives. Discriminated on `type`. */
|
|
61
|
+
export type BPMInstanceEvent = {
|
|
62
|
+
readonly [K in BPMInstanceEventType]: BPMInstanceEventHeader & {
|
|
63
|
+
readonly type: K;
|
|
64
|
+
} & BPMInstanceEventSnapshot & BPMInstanceEventTypePayloads[K];
|
|
65
|
+
}[BPMInstanceEventType];
|
|
66
|
+
export declare const BPM_INSTANCE_EVENT_STATUSES: readonly ["PENDING", "DELIVERED", "FAILED"];
|
|
67
|
+
export type BPMInstanceEventStatus = (typeof BPM_INSTANCE_EVENT_STATUSES)[number];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BPM_INSTANCE_EVENT_STATUSES = void 0;
|
|
4
|
+
exports.BPM_INSTANCE_EVENT_STATUSES = [
|
|
5
|
+
'PENDING',
|
|
6
|
+
'DELIVERED',
|
|
7
|
+
'FAILED',
|
|
8
|
+
];
|
|
9
|
+
//# sourceMappingURL=instance-event.types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance-event.types.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/instance-event/instance-event.types.ts"],"names":[],"mappings":";;;AAmEa,QAAA,2BAA2B,GAAG;IACzC,SAAS;IACT,WAAW;IACX,QAAQ;CACA,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { EntityManager } from 'typeorm';
|
|
2
|
+
import { InstanceEventService } from './instance-event.service';
|
|
3
|
+
import type { BPMInstanceEventSnapshot, BPMInstanceEventType, BPMInstanceEventTypePayloads } from './instance-event.types';
|
|
4
|
+
/**
|
|
5
|
+
* Writes outbox rows inside the caller's transaction (ADR 27 §1.2). Rows are
|
|
6
|
+
* written only when a host observer is bound; otherwise this is a no-op and
|
|
7
|
+
* the engine behaves as it did in 0.22.0.
|
|
8
|
+
*
|
|
9
|
+
* Uses `save` rather than `insert` so the TypeORM `afterInsert` event fires
|
|
10
|
+
* and the delivery subscriber can stage the new id for after-commit delivery.
|
|
11
|
+
*/
|
|
12
|
+
export declare class InstanceEventWriter {
|
|
13
|
+
private readonly events;
|
|
14
|
+
constructor(events: InstanceEventService);
|
|
15
|
+
/**
|
|
16
|
+
* Whether a host observer is bound. Callers use this to skip building a
|
|
17
|
+
* snapshot (for example a template lookup) when no row would be written.
|
|
18
|
+
*/
|
|
19
|
+
get enabled(): boolean;
|
|
20
|
+
record<K extends BPMInstanceEventType>(manager: EntityManager, instanceId: string, snapshot: BPMInstanceEventSnapshot, type: K, fields: BPMInstanceEventTypePayloads[K]): Promise<void>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InstanceEventWriter = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const approval_instance_event_entity_1 = require("./approval-instance-event.entity");
|
|
7
|
+
const instance_event_service_1 = require("./instance-event.service");
|
|
8
|
+
/**
|
|
9
|
+
* Writes outbox rows inside the caller's transaction (ADR 27 §1.2). Rows are
|
|
10
|
+
* written only when a host observer is bound; otherwise this is a no-op and
|
|
11
|
+
* the engine behaves as it did in 0.22.0.
|
|
12
|
+
*
|
|
13
|
+
* Uses `save` rather than `insert` so the TypeORM `afterInsert` event fires
|
|
14
|
+
* and the delivery subscriber can stage the new id for after-commit delivery.
|
|
15
|
+
*/
|
|
16
|
+
let InstanceEventWriter = class InstanceEventWriter {
|
|
17
|
+
constructor(events) {
|
|
18
|
+
this.events = events;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Whether a host observer is bound. Callers use this to skip building a
|
|
22
|
+
* snapshot (for example a template lookup) when no row would be written.
|
|
23
|
+
*/
|
|
24
|
+
get enabled() {
|
|
25
|
+
return this.events.enabled;
|
|
26
|
+
}
|
|
27
|
+
async record(manager, instanceId, snapshot, type, fields) {
|
|
28
|
+
if (!this.events.enabled) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const repository = manager.getRepository(approval_instance_event_entity_1.ApprovalInstanceEventEntity);
|
|
32
|
+
const row = repository.create({
|
|
33
|
+
instanceId,
|
|
34
|
+
payload: { ...snapshot, ...fields },
|
|
35
|
+
type,
|
|
36
|
+
});
|
|
37
|
+
await repository.save(row);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
exports.InstanceEventWriter = InstanceEventWriter;
|
|
41
|
+
exports.InstanceEventWriter = InstanceEventWriter = tslib_1.__decorate([
|
|
42
|
+
(0, common_1.Injectable)(),
|
|
43
|
+
tslib_1.__metadata("design:paramtypes", [instance_event_service_1.InstanceEventService])
|
|
44
|
+
], InstanceEventWriter);
|
|
45
|
+
//# sourceMappingURL=instance-event.writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance-event.writer.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/instance-event/instance-event.writer.ts"],"names":[],"mappings":";;;;AAAA,2CAA4C;AAE5C,qFAA+E;AAC/E,qEAAgE;AAOhE;;;;;;;GAOG;AAEI,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IAC9B,YAA6B,MAA4B;QAA5B,WAAM,GAAN,MAAM,CAAsB;IAAG,CAAC;IAE7D;;;OAGG;IACH,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,MAAM,CACV,OAAsB,EACtB,UAAkB,EAClB,QAAkC,EAClC,IAAO,EACP,MAAuC;QAEvC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACzB,OAAO;QACT,CAAC;QAED,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,4DAA2B,CAAC,CAAC;QACtE,MAAM,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC;YAC5B,UAAU;YACV,OAAO,EAAE,EAAE,GAAG,QAAQ,EAAE,GAAG,MAAM,EAAE;YACnC,IAAI;SACL,CAAC,CAAC;QAEH,MAAM,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;CACF,CAAA;AA/BY,kDAAmB;8BAAnB,mBAAmB;IAD/B,IAAA,mBAAU,GAAE;6CAE0B,6CAAoB;GAD9C,mBAAmB,CA+B/B"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from 'typeorm';
|
|
2
|
+
/**
|
|
3
|
+
* Schema for ADR 27 (host integration round). Every change is additive and its
|
|
4
|
+
* default is the behaviour before this migration, so `down` can drop it all.
|
|
5
|
+
*
|
|
6
|
+
* - `approval_templates.key`: a key the host declares for a template it owns
|
|
7
|
+
* (§6). Unique among templates that are not soft-deleted, so a deleted
|
|
8
|
+
* template frees its key.
|
|
9
|
+
* - `approval_templates.host_managed` / `form_definitions.host_managed`: the
|
|
10
|
+
* definition is maintained by host code and BPM's own lists leave it out by
|
|
11
|
+
* default (§9). Not a lock.
|
|
12
|
+
* - `approval_template_versions.launch_mode`: `HOST_ONLY` refuses submission
|
|
13
|
+
* and resubmission through GraphQL (§5). Versioned with
|
|
14
|
+
* `initiator_policy_cel`, which it sits beside.
|
|
15
|
+
* - `approval_instance_events`: outbox of instance lifecycle events (§1). A row
|
|
16
|
+
* is written inside the transaction that changes the instance and delivered
|
|
17
|
+
* to the host's observer after it commits. `seq` orders the events of one
|
|
18
|
+
* instance; it is not a cursor across instances, because identity values are
|
|
19
|
+
* assigned at insert, not at commit.
|
|
20
|
+
*/
|
|
21
|
+
export declare class HostIntegrationRound0000000032000 implements MigrationInterface {
|
|
22
|
+
name: string;
|
|
23
|
+
up(queryRunner: QueryRunner): Promise<void>;
|
|
24
|
+
down(queryRunner: QueryRunner): Promise<void>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HostIntegrationRound0000000032000 = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Schema for ADR 27 (host integration round). Every change is additive and its
|
|
6
|
+
* default is the behaviour before this migration, so `down` can drop it all.
|
|
7
|
+
*
|
|
8
|
+
* - `approval_templates.key`: a key the host declares for a template it owns
|
|
9
|
+
* (§6). Unique among templates that are not soft-deleted, so a deleted
|
|
10
|
+
* template frees its key.
|
|
11
|
+
* - `approval_templates.host_managed` / `form_definitions.host_managed`: the
|
|
12
|
+
* definition is maintained by host code and BPM's own lists leave it out by
|
|
13
|
+
* default (§9). Not a lock.
|
|
14
|
+
* - `approval_template_versions.launch_mode`: `HOST_ONLY` refuses submission
|
|
15
|
+
* and resubmission through GraphQL (§5). Versioned with
|
|
16
|
+
* `initiator_policy_cel`, which it sits beside.
|
|
17
|
+
* - `approval_instance_events`: outbox of instance lifecycle events (§1). A row
|
|
18
|
+
* is written inside the transaction that changes the instance and delivered
|
|
19
|
+
* to the host's observer after it commits. `seq` orders the events of one
|
|
20
|
+
* instance; it is not a cursor across instances, because identity values are
|
|
21
|
+
* assigned at insert, not at commit.
|
|
22
|
+
*/
|
|
23
|
+
class HostIntegrationRound0000000032000 {
|
|
24
|
+
constructor() {
|
|
25
|
+
this.name = 'HostIntegrationRound0000000032000';
|
|
26
|
+
}
|
|
27
|
+
async up(queryRunner) {
|
|
28
|
+
await queryRunner.query(`
|
|
29
|
+
ALTER TABLE "approval_templates"
|
|
30
|
+
ADD COLUMN IF NOT EXISTS "key" text NULL,
|
|
31
|
+
ADD COLUMN IF NOT EXISTS "host_managed" boolean NOT NULL DEFAULT false
|
|
32
|
+
`);
|
|
33
|
+
await queryRunner.query(`
|
|
34
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "UQ_approval_templates_key_live"
|
|
35
|
+
ON "approval_templates" ("key")
|
|
36
|
+
WHERE "key" IS NOT NULL AND "deleted_at" IS NULL
|
|
37
|
+
`);
|
|
38
|
+
await queryRunner.query(`
|
|
39
|
+
ALTER TABLE "form_definitions"
|
|
40
|
+
ADD COLUMN IF NOT EXISTS "host_managed" boolean NOT NULL DEFAULT false
|
|
41
|
+
`);
|
|
42
|
+
await queryRunner.query(`
|
|
43
|
+
ALTER TABLE "approval_template_versions"
|
|
44
|
+
ADD COLUMN IF NOT EXISTS "launch_mode" text NOT NULL DEFAULT 'OPEN'
|
|
45
|
+
`);
|
|
46
|
+
await queryRunner.query(`
|
|
47
|
+
ALTER TABLE "approval_template_versions"
|
|
48
|
+
DROP CONSTRAINT IF EXISTS "CHK_approval_template_versions_launch_mode"
|
|
49
|
+
`);
|
|
50
|
+
await queryRunner.query(`
|
|
51
|
+
ALTER TABLE "approval_template_versions"
|
|
52
|
+
ADD CONSTRAINT "CHK_approval_template_versions_launch_mode"
|
|
53
|
+
CHECK ("launch_mode" IN ('OPEN', 'HOST_ONLY'))
|
|
54
|
+
`);
|
|
55
|
+
await queryRunner.query(`
|
|
56
|
+
CREATE TABLE IF NOT EXISTS "approval_instance_events" (
|
|
57
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
58
|
+
"seq" bigint GENERATED ALWAYS AS IDENTITY,
|
|
59
|
+
"instance_id" uuid NOT NULL,
|
|
60
|
+
"type" text NOT NULL,
|
|
61
|
+
"payload" jsonb NOT NULL,
|
|
62
|
+
"status" text NOT NULL DEFAULT 'PENDING',
|
|
63
|
+
"attempt_count" integer NOT NULL DEFAULT 0,
|
|
64
|
+
"next_attempt_at" timestamptz NOT NULL DEFAULT now(),
|
|
65
|
+
"claimed_at" timestamptz NULL,
|
|
66
|
+
"delivered_at" timestamptz NULL,
|
|
67
|
+
"last_error" text NULL,
|
|
68
|
+
"occurred_at" timestamptz NOT NULL DEFAULT now(),
|
|
69
|
+
CONSTRAINT "FK_approval_instance_events_instance"
|
|
70
|
+
FOREIGN KEY ("instance_id") REFERENCES "approval_instances"("id")
|
|
71
|
+
ON DELETE CASCADE,
|
|
72
|
+
CONSTRAINT "CHK_approval_instance_events_status"
|
|
73
|
+
CHECK ("status" IN ('PENDING', 'DELIVERED', 'FAILED'))
|
|
74
|
+
)
|
|
75
|
+
`);
|
|
76
|
+
await queryRunner.query(`
|
|
77
|
+
CREATE INDEX IF NOT EXISTS "IDX_approval_instance_events_due"
|
|
78
|
+
ON "approval_instance_events" ("status", "next_attempt_at")
|
|
79
|
+
`);
|
|
80
|
+
await queryRunner.query(`
|
|
81
|
+
CREATE INDEX IF NOT EXISTS "IDX_approval_instance_events_instance_seq"
|
|
82
|
+
ON "approval_instance_events" ("instance_id", "seq")
|
|
83
|
+
`);
|
|
84
|
+
}
|
|
85
|
+
async down(queryRunner) {
|
|
86
|
+
await queryRunner.query(`DROP TABLE IF EXISTS "approval_instance_events"`);
|
|
87
|
+
await queryRunner.query(`
|
|
88
|
+
ALTER TABLE "approval_template_versions"
|
|
89
|
+
DROP CONSTRAINT IF EXISTS "CHK_approval_template_versions_launch_mode",
|
|
90
|
+
DROP COLUMN IF EXISTS "launch_mode"
|
|
91
|
+
`);
|
|
92
|
+
await queryRunner.query(`
|
|
93
|
+
ALTER TABLE "form_definitions" DROP COLUMN IF EXISTS "host_managed"
|
|
94
|
+
`);
|
|
95
|
+
await queryRunner.query(`DROP INDEX IF EXISTS "UQ_approval_templates_key_live"`);
|
|
96
|
+
await queryRunner.query(`
|
|
97
|
+
ALTER TABLE "approval_templates"
|
|
98
|
+
DROP COLUMN IF EXISTS "host_managed",
|
|
99
|
+
DROP COLUMN IF EXISTS "key"
|
|
100
|
+
`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.HostIntegrationRound0000000032000 = HostIntegrationRound0000000032000;
|
|
104
|
+
//# sourceMappingURL=0000000032000-host-integration-round.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"0000000032000-host-integration-round.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/migrations/0000000032000-host-integration-round.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAa,iCAAiC;IAA9C;QACE,SAAI,GAAG,mCAAmC,CAAC;IAgF7C,CAAC;IA9EC,KAAK,CAAC,EAAE,CAAC,WAAwB;QAC/B,MAAM,WAAW,CAAC,KAAK,CAAC;;;;KAIvB,CAAC,CAAC;QACH,MAAM,WAAW,CAAC,KAAK,CAAC;;;;KAIvB,CAAC,CAAC;QACH,MAAM,WAAW,CAAC,KAAK,CAAC;;;KAGvB,CAAC,CAAC;QACH,MAAM,WAAW,CAAC,KAAK,CAAC;;;KAGvB,CAAC,CAAC;QACH,MAAM,WAAW,CAAC,KAAK,CAAC;;;KAGvB,CAAC,CAAC;QACH,MAAM,WAAW,CAAC,KAAK,CAAC;;;;KAIvB,CAAC,CAAC;QACH,MAAM,WAAW,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;KAoBvB,CAAC,CAAC;QACH,MAAM,WAAW,CAAC,KAAK,CAAC;;;KAGvB,CAAC,CAAC;QACH,MAAM,WAAW,CAAC,KAAK,CAAC;;;KAGvB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,WAAwB;QACjC,MAAM,WAAW,CAAC,KAAK,CAAC,iDAAiD,CAAC,CAAC;QAC3E,MAAM,WAAW,CAAC,KAAK,CAAC;;;;KAIvB,CAAC,CAAC;QACH,MAAM,WAAW,CAAC,KAAK,CAAC;;KAEvB,CAAC,CAAC;QACH,MAAM,WAAW,CAAC,KAAK,CACrB,uDAAuD,CACxD,CAAC;QACF,MAAM,WAAW,CAAC,KAAK,CAAC;;;;KAIvB,CAAC,CAAC;IACL,CAAC;CACF;AAjFD,8EAiFC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from 'typeorm';
|
|
2
|
+
/**
|
|
3
|
+
* A partial index on the `ADVANCE_FAILED` rows of `activity_logs`, for the
|
|
4
|
+
* administrator's stuck list (`stuckApprovalInstances` /
|
|
5
|
+
* `stuckApprovalInstanceCount`). That query starts from the RUNNING and
|
|
6
|
+
* RETURNED instances and looks up their failures; without this index each
|
|
7
|
+
* lookup reads every activity row of the instance and drops the ones that are
|
|
8
|
+
* not failures, so the cost grows with the history of the cases in flight.
|
|
9
|
+
* With it, only failure rows are read. `seq` is the second column because the
|
|
10
|
+
* query keeps each instance's highest one.
|
|
11
|
+
*
|
|
12
|
+
* Built without `CONCURRENTLY` and without `transaction = false`, so it runs
|
|
13
|
+
* inside the migration transaction under TypeORM's default transaction mode
|
|
14
|
+
* (declaring a non-transactional migration fails the whole batch when the mode
|
|
15
|
+
* is `all`). The cost: the build takes a SHARE lock on `activity_logs`, which
|
|
16
|
+
* blocks every submit, decision and history write for as long as it runs. It
|
|
17
|
+
* reads the whole table but writes only the failure rows, which are few.
|
|
18
|
+
*
|
|
19
|
+
* A host with a large `activity_logs` table should build the index first,
|
|
20
|
+
* outside any transaction, with the same name:
|
|
21
|
+
*
|
|
22
|
+
* CREATE INDEX CONCURRENTLY IF NOT EXISTS "IDX_activity_logs_advance_failed"
|
|
23
|
+
* ON "activity_logs" ("instance_id", "seq")
|
|
24
|
+
* WHERE "event_type" = 'ADVANCE_FAILED';
|
|
25
|
+
*
|
|
26
|
+
* `IF NOT EXISTS` then skips this step. Nothing else depends on how the index
|
|
27
|
+
* was built.
|
|
28
|
+
*
|
|
29
|
+
* No table, column or backfill is involved. `down` drops only the index.
|
|
30
|
+
*/
|
|
31
|
+
export declare class ActivityLogAdvanceFailedIndex0000000033000 implements MigrationInterface {
|
|
32
|
+
name: string;
|
|
33
|
+
up(queryRunner: QueryRunner): Promise<void>;
|
|
34
|
+
down(queryRunner: QueryRunner): Promise<void>;
|
|
35
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ActivityLogAdvanceFailedIndex0000000033000 = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* A partial index on the `ADVANCE_FAILED` rows of `activity_logs`, for the
|
|
6
|
+
* administrator's stuck list (`stuckApprovalInstances` /
|
|
7
|
+
* `stuckApprovalInstanceCount`). That query starts from the RUNNING and
|
|
8
|
+
* RETURNED instances and looks up their failures; without this index each
|
|
9
|
+
* lookup reads every activity row of the instance and drops the ones that are
|
|
10
|
+
* not failures, so the cost grows with the history of the cases in flight.
|
|
11
|
+
* With it, only failure rows are read. `seq` is the second column because the
|
|
12
|
+
* query keeps each instance's highest one.
|
|
13
|
+
*
|
|
14
|
+
* Built without `CONCURRENTLY` and without `transaction = false`, so it runs
|
|
15
|
+
* inside the migration transaction under TypeORM's default transaction mode
|
|
16
|
+
* (declaring a non-transactional migration fails the whole batch when the mode
|
|
17
|
+
* is `all`). The cost: the build takes a SHARE lock on `activity_logs`, which
|
|
18
|
+
* blocks every submit, decision and history write for as long as it runs. It
|
|
19
|
+
* reads the whole table but writes only the failure rows, which are few.
|
|
20
|
+
*
|
|
21
|
+
* A host with a large `activity_logs` table should build the index first,
|
|
22
|
+
* outside any transaction, with the same name:
|
|
23
|
+
*
|
|
24
|
+
* CREATE INDEX CONCURRENTLY IF NOT EXISTS "IDX_activity_logs_advance_failed"
|
|
25
|
+
* ON "activity_logs" ("instance_id", "seq")
|
|
26
|
+
* WHERE "event_type" = 'ADVANCE_FAILED';
|
|
27
|
+
*
|
|
28
|
+
* `IF NOT EXISTS` then skips this step. Nothing else depends on how the index
|
|
29
|
+
* was built.
|
|
30
|
+
*
|
|
31
|
+
* No table, column or backfill is involved. `down` drops only the index.
|
|
32
|
+
*/
|
|
33
|
+
class ActivityLogAdvanceFailedIndex0000000033000 {
|
|
34
|
+
constructor() {
|
|
35
|
+
this.name = 'ActivityLogAdvanceFailedIndex0000000033000';
|
|
36
|
+
}
|
|
37
|
+
async up(queryRunner) {
|
|
38
|
+
await queryRunner.query(`
|
|
39
|
+
CREATE INDEX IF NOT EXISTS "IDX_activity_logs_advance_failed"
|
|
40
|
+
ON "activity_logs" ("instance_id", "seq")
|
|
41
|
+
WHERE "event_type" = 'ADVANCE_FAILED'
|
|
42
|
+
`);
|
|
43
|
+
}
|
|
44
|
+
async down(queryRunner) {
|
|
45
|
+
await queryRunner.query(`
|
|
46
|
+
DROP INDEX IF EXISTS "IDX_activity_logs_advance_failed"
|
|
47
|
+
`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.ActivityLogAdvanceFailedIndex0000000033000 = ActivityLogAdvanceFailedIndex0000000033000;
|
|
51
|
+
//# sourceMappingURL=0000000033000-activity-log-advance-failed-index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"0000000033000-activity-log-advance-failed-index.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/migrations/0000000033000-activity-log-advance-failed-index.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAa,0CAA0C;IAAvD;QACE,SAAI,GAAG,4CAA4C,CAAC;IAetD,CAAC;IAbC,KAAK,CAAC,EAAE,CAAC,WAAwB;QAC/B,MAAM,WAAW,CAAC,KAAK,CAAC;;;;KAIvB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,WAAwB;QACjC,MAAM,WAAW,CAAC,KAAK,CAAC;;KAEvB,CAAC,CAAC;IACL,CAAC;CACF;AAhBD,gGAgBC"}
|
|
@@ -32,3 +32,5 @@ export * from './0000000028000-notification-updated-at';
|
|
|
32
32
|
export * from './0000000029000-activity-log-seq';
|
|
33
33
|
export * from './0000000030000-delegation-scope-condition-dialect';
|
|
34
34
|
export * from './0000000031000-approval-instance-form-data-gin';
|
|
35
|
+
export * from './0000000032000-host-integration-round';
|
|
36
|
+
export * from './0000000033000-activity-log-advance-failed-index';
|