hierarchical-approval 4.0.2 → 4.0.4
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 +20 -6
- package/README.md +1 -1
- package/dist/{ApprovalEngine-XgGBQLC_.d.cts → ApprovalEngine-D0_F5OPZ.d.cts} +35 -10
- package/dist/{ApprovalEngine-Dqe-rC6K.d.ts → ApprovalEngine-D4bXQrKD.d.ts} +35 -10
- package/dist/Clock-D8Qp39q_.d.cts +8 -0
- package/dist/Clock-D8Qp39q_.d.ts +8 -0
- package/dist/{IAuditAdapter-Dt8qjkQL.d.cts → IAuditAdapter-D9WE0t7A.d.cts} +2 -1
- package/dist/{IAuditAdapter-DkbyFFjb.d.ts → IAuditAdapter-FI_RF_XU.d.ts} +2 -1
- package/dist/{IAuthorizationPolicy-YJ_08Mof.d.cts → IAuthorizationPolicy-BKKw7jGN.d.ts} +6 -1
- package/dist/{IAuthorizationPolicy-eo6glbpE.d.ts → IAuthorizationPolicy-DDmjeYV-.d.cts} +6 -1
- package/dist/{IMetricsAdapter-DWq8IFaf.d.cts → IMetricsAdapter-WROxYSXd.d.cts} +1 -0
- package/dist/{IMetricsAdapter-DWq8IFaf.d.ts → IMetricsAdapter-WROxYSXd.d.ts} +1 -0
- package/dist/{INotificationAdapter-BTO9FSKy.d.ts → INotificationAdapter-CLROEfRd.d.ts} +26 -1
- package/dist/{INotificationAdapter-XbD69gss.d.cts → INotificationAdapter-J0wSPLIC.d.cts} +26 -1
- package/dist/{IOperationMiddleware-CX7lo4lp.d.ts → IOperationMiddleware-B32a2dwP.d.ts} +15 -2
- package/dist/{IOperationMiddleware-BBLk8MIz.d.cts → IOperationMiddleware-UUKqztxM.d.cts} +15 -2
- package/dist/{ISchedulerAdapter-DKv_QjVN.d.cts → ISchedulerAdapter-CLMdBA-5.d.cts} +1 -0
- package/dist/{ISchedulerAdapter-DKv_QjVN.d.ts → ISchedulerAdapter-CLMdBA-5.d.ts} +1 -0
- package/dist/{IStorageAdapter-CdXMggPK.d.ts → IStorageAdapter-DSKJ1onF.d.ts} +14 -1
- package/dist/{IStorageAdapter-Cjw5zDwQ.d.cts → IStorageAdapter-Dhrc4ES6.d.cts} +14 -1
- package/dist/{Logger-BplhlU7l.d.cts → Logger-hqFbBCtB.d.cts} +7 -0
- package/dist/{Logger-BplhlU7l.d.ts → Logger-hqFbBCtB.d.ts} +7 -0
- package/dist/adapters/MemoryAdapter.cjs.map +1 -1
- package/dist/adapters/MemoryAdapter.d.cts +2 -2
- package/dist/adapters/MemoryAdapter.d.ts +2 -2
- package/dist/adapters/MemoryAdapter.js.map +1 -1
- package/dist/adapters/PostgresAdapter.cjs.map +1 -1
- package/dist/adapters/PostgresAdapter.d.cts +2 -2
- package/dist/adapters/PostgresAdapter.d.ts +2 -2
- package/dist/adapters/PostgresAdapter.js.map +1 -1
- package/dist/index.cjs +51 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -14
- package/dist/index.d.ts +14 -14
- package/dist/index.js +51 -8
- package/dist/index.js.map +1 -1
- package/dist/{instance-uUQh5XW3.d.cts → instance-CUZcHWK2.d.cts} +28 -0
- package/dist/{instance-uUQh5XW3.d.ts → instance-CUZcHWK2.d.ts} +28 -0
- package/dist/nestjs.cjs +61 -7
- package/dist/nestjs.cjs.map +1 -1
- package/dist/nestjs.d.cts +22 -11
- package/dist/nestjs.d.ts +22 -11
- package/dist/nestjs.js +61 -7
- package/dist/nestjs.js.map +1 -1
- package/dist/plugins/audit.cjs.map +1 -1
- package/dist/plugins/audit.d.cts +3 -3
- package/dist/plugins/audit.d.ts +3 -3
- package/dist/plugins/audit.js.map +1 -1
- package/dist/plugins/metrics.cjs.map +1 -1
- package/dist/plugins/metrics.d.cts +2 -2
- package/dist/plugins/metrics.d.ts +2 -2
- package/dist/plugins/metrics.js.map +1 -1
- package/dist/plugins/notify.cjs.map +1 -1
- package/dist/plugins/notify.d.cts +4 -4
- package/dist/plugins/notify.d.ts +4 -4
- package/dist/plugins/notify.js.map +1 -1
- package/dist/plugins/resilience.cjs.map +1 -1
- package/dist/plugins/resilience.d.cts +5 -5
- package/dist/plugins/resilience.d.ts +5 -5
- package/dist/plugins/resilience.js.map +1 -1
- package/dist/plugins/scheduler.cjs.map +1 -1
- package/dist/plugins/scheduler.d.cts +3 -3
- package/dist/plugins/scheduler.d.ts +3 -3
- package/dist/plugins/scheduler.js.map +1 -1
- package/dist/plugins/tracing.cjs.map +1 -1
- package/dist/plugins/tracing.d.cts +4 -2
- package/dist/plugins/tracing.d.ts +4 -2
- package/dist/plugins/tracing.js.map +1 -1
- package/dist/plugins/webhook.cjs.map +1 -1
- package/dist/plugins/webhook.d.cts +4 -4
- package/dist/plugins/webhook.d.ts +4 -4
- package/dist/plugins/webhook.js.map +1 -1
- package/dist/testing.cjs +50 -7
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +11 -11
- package/dist/testing.d.ts +11 -11
- package/dist/testing.js +50 -7
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
- package/dist/Clock-3FnOczFJ.d.cts +0 -6
- package/dist/Clock-3FnOczFJ.d.ts +0 -6
package/dist/index.cjs
CHANGED
|
@@ -556,6 +556,7 @@ var TemplateRegistry = class {
|
|
|
556
556
|
delete resolved.removeLevels;
|
|
557
557
|
return resolved;
|
|
558
558
|
}
|
|
559
|
+
/** Register a new template. Throws if a template with this name already exists for the tenant. */
|
|
559
560
|
async define(config) {
|
|
560
561
|
const existing = await this.adapter.getTemplate(this.tenantId, config.name);
|
|
561
562
|
if (existing) {
|
|
@@ -592,11 +593,13 @@ var TemplateRegistry = class {
|
|
|
592
593
|
await this.adapter.saveTemplate(updated);
|
|
593
594
|
return newId;
|
|
594
595
|
}
|
|
596
|
+
/** Fetch a template by name. Throws if no template with this name exists for the tenant. */
|
|
595
597
|
async get(name) {
|
|
596
598
|
const template = await this.adapter.getTemplate(this.tenantId, name);
|
|
597
599
|
if (!template) throw new ApprovalTemplateNotFoundError(name);
|
|
598
600
|
return template;
|
|
599
601
|
}
|
|
602
|
+
/** List every template registered for the tenant. */
|
|
600
603
|
async list() {
|
|
601
604
|
return this.adapter.listTemplates(this.tenantId);
|
|
602
605
|
}
|
|
@@ -636,6 +639,32 @@ var LevelResolver = class {
|
|
|
636
639
|
for (const [name, fn] of this.resolvers) target.register(name, fn);
|
|
637
640
|
for (const [name, fn] of this.approverTypes) target.registerApproverType(name, fn);
|
|
638
641
|
}
|
|
642
|
+
/**
|
|
643
|
+
* Resolve a level's `approvers` config down to a deduplicated list of user
|
|
644
|
+
* ids, applying out-of-office cover last so a substitute never sees a stale
|
|
645
|
+
* approver id.
|
|
646
|
+
*
|
|
647
|
+
* @param approvers - The level's approver configs (`user`, `role`,
|
|
648
|
+
* `dynamic`, or a custom type registered via {@link registerApproverType}).
|
|
649
|
+
* @param submittedBy - Passed through to `dynamic` resolvers and custom
|
|
650
|
+
* approver-type functions as routing context.
|
|
651
|
+
* @param data - The instance's document data, passed through the same way.
|
|
652
|
+
* @param orgProvider - Required to resolve `role` approvers; omit only when
|
|
653
|
+
* the template uses no `role` approvers.
|
|
654
|
+
* @param outOfOffice - Optional cover lookup, consulted after every other
|
|
655
|
+
* approver type has resolved.
|
|
656
|
+
* @param at - The moment out-of-office cover is resolved for. Defaults to
|
|
657
|
+
* now.
|
|
658
|
+
* @param substitutions - Filled with `original -> stand-in` for each
|
|
659
|
+
* approver replaced by out-of-office cover, so the caller can carry
|
|
660
|
+
* anything keyed by the original id (such as a weighted level's vote
|
|
661
|
+
* weight) across to the substitute.
|
|
662
|
+
* @returns The resolved, deduplicated approver ids (post-substitution).
|
|
663
|
+
* @throws {ApprovalValidationError} If no approvers resolve at all, a
|
|
664
|
+
* `role` approver is configured without an `orgProvider`, a `dynamic`
|
|
665
|
+
* approver names a resolver that was never registered, or a custom
|
|
666
|
+
* approver type was never registered.
|
|
667
|
+
*/
|
|
639
668
|
async resolveApprovers(approvers, submittedBy, data, orgProvider, outOfOffice, at, substitutions) {
|
|
640
669
|
const resolved = [];
|
|
641
670
|
for (const approver of approvers) {
|
|
@@ -1047,7 +1076,7 @@ function evaluateConditions(conditions, data) {
|
|
|
1047
1076
|
function assertStatus(instance, expected) {
|
|
1048
1077
|
if (instance.status !== expected) {
|
|
1049
1078
|
throw new ApprovalError(
|
|
1050
|
-
`
|
|
1079
|
+
`Instance "${instance.id}": expected status "${expected}" but got "${instance.status}".`,
|
|
1051
1080
|
"INVALID_STATUS"
|
|
1052
1081
|
);
|
|
1053
1082
|
}
|
|
@@ -1055,7 +1084,7 @@ function assertStatus(instance, expected) {
|
|
|
1055
1084
|
function assertApproverOnLevel(level, approverId) {
|
|
1056
1085
|
if (!level.approverIds.includes(approverId)) {
|
|
1057
1086
|
throw new ApprovalForbiddenError(
|
|
1058
|
-
`User "${approverId}" is not an approver for level ${level.level}.`
|
|
1087
|
+
`User "${approverId}" is not an approver for level ${level.level} ("${level.name}").`
|
|
1059
1088
|
);
|
|
1060
1089
|
}
|
|
1061
1090
|
}
|
|
@@ -2099,7 +2128,7 @@ var ApprovalEngine = class _ApprovalEngine {
|
|
|
2099
2128
|
await this.withOptimisticRetry(instanceId, async (instance) => {
|
|
2100
2129
|
assertStatus(instance, "pending");
|
|
2101
2130
|
if (opts.fromApprover === opts.toApprover) {
|
|
2102
|
-
throw new ApprovalForbiddenError(
|
|
2131
|
+
throw new ApprovalForbiddenError(`Cannot delegate to yourself: "${opts.fromApprover}".`);
|
|
2103
2132
|
}
|
|
2104
2133
|
const level = this.resolveActorLevel(instance, opts.fromApprover, opts.level);
|
|
2105
2134
|
this.inheritWeight(level, opts.fromApprover, opts.toApprover);
|
|
@@ -2182,7 +2211,9 @@ var ApprovalEngine = class _ApprovalEngine {
|
|
|
2182
2211
|
return this.withOptimisticRetry(instanceId, async (instance) => {
|
|
2183
2212
|
assertStatus(instance, "pending");
|
|
2184
2213
|
if (opts.fromApprover === opts.toApprover) {
|
|
2185
|
-
throw new ApprovalForbiddenError(
|
|
2214
|
+
throw new ApprovalForbiddenError(
|
|
2215
|
+
`Cannot reassign an approver to themselves: "${opts.fromApprover}".`
|
|
2216
|
+
);
|
|
2186
2217
|
}
|
|
2187
2218
|
const level = this.resolveActorLevel(instance, opts.fromApprover, opts.level);
|
|
2188
2219
|
this.inheritWeight(level, opts.fromApprover, opts.toApprover);
|
|
@@ -3008,7 +3039,15 @@ var ApprovalEngine = class _ApprovalEngine {
|
|
|
3008
3039
|
}
|
|
3009
3040
|
const levelNums = new Set(allLevelCfgs.map((l) => l.level));
|
|
3010
3041
|
if (levelNums.size !== allLevelCfgs.length) {
|
|
3011
|
-
|
|
3042
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3043
|
+
const duplicates = /* @__PURE__ */ new Set();
|
|
3044
|
+
for (const l of allLevelCfgs) {
|
|
3045
|
+
if (seen.has(l.level)) duplicates.add(l.level);
|
|
3046
|
+
seen.add(l.level);
|
|
3047
|
+
}
|
|
3048
|
+
throw new ApprovalValidationError(
|
|
3049
|
+
`Duplicate level numbers after condition evaluation: ${[...duplicates].join(", ")}.`
|
|
3050
|
+
);
|
|
3012
3051
|
}
|
|
3013
3052
|
const now = this.clock.now();
|
|
3014
3053
|
const newInstanceId = this.generateId("inst");
|
|
@@ -3380,7 +3419,9 @@ var ApprovalEngine = class _ApprovalEngine {
|
|
|
3380
3419
|
);
|
|
3381
3420
|
}
|
|
3382
3421
|
if (opts.overriddenBy === instance.submittedBy) {
|
|
3383
|
-
throw new ApprovalForbiddenError(
|
|
3422
|
+
throw new ApprovalForbiddenError(
|
|
3423
|
+
`Override cannot be performed by the original submitter: "${opts.overriddenBy}".`
|
|
3424
|
+
);
|
|
3384
3425
|
}
|
|
3385
3426
|
await this.runAuthorizationPolicy({
|
|
3386
3427
|
operation: "override",
|
|
@@ -3874,7 +3915,9 @@ var ApprovalEngine = class _ApprovalEngine {
|
|
|
3874
3915
|
const dryRun = opts.dryRun ?? false;
|
|
3875
3916
|
const limit = opts.limit ?? DEFAULT_PURGE_LIMIT;
|
|
3876
3917
|
if (!(opts.olderThan instanceof Date) || Number.isNaN(opts.olderThan.getTime())) {
|
|
3877
|
-
throw new ApprovalValidationError(
|
|
3918
|
+
throw new ApprovalValidationError(
|
|
3919
|
+
`purgeInstances requires a valid olderThan date, got ${String(opts.olderThan)}.`
|
|
3920
|
+
);
|
|
3878
3921
|
}
|
|
3879
3922
|
const requested = opts.statuses ?? [...TERMINAL_STATUSES];
|
|
3880
3923
|
const nonTerminal = requested.filter((st) => !TERMINAL_STATUSES.has(st));
|
|
@@ -5170,7 +5213,7 @@ function businessHoursCalendar(options = {}) {
|
|
|
5170
5213
|
return cursor;
|
|
5171
5214
|
}
|
|
5172
5215
|
throw new Error(
|
|
5173
|
-
|
|
5216
|
+
`businessHoursCalendar: no working day found within 10 years of ${from.toISOString()} \u2014 check weekendDays and holidays.`
|
|
5174
5217
|
);
|
|
5175
5218
|
};
|
|
5176
5219
|
const base = weekendCalendar(options);
|