hierarchical-approval 0.8.0 → 0.9.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 +41 -0
- package/README.md +36 -0
- package/dist/{ApprovalEngine-DFY53zRK.d.ts → ApprovalEngine-mD-qyxcZ.d.ts} +55 -8
- package/dist/{ApprovalEngine-DVMMtiSm.d.cts → ApprovalEngine-pfQ2v-J9.d.cts} +55 -8
- package/dist/{IAuditAdapter-BODIlw4h.d.cts → IAuditAdapter-0frLfzRq.d.cts} +1 -1
- package/dist/{IAuditAdapter-CaM3A2Kt.d.ts → IAuditAdapter-nlIK1em0.d.ts} +1 -1
- package/dist/{IAuthorizationPolicy-DFD0ELtO.d.ts → IAuthorizationPolicy-DG8vmD5j.d.ts} +2 -2
- package/dist/{IAuthorizationPolicy-cT7LSHtl.d.cts → IAuthorizationPolicy-DXEMaoxF.d.cts} +2 -2
- package/dist/{IMetricsAdapter-D9PUz4tM.d.cts → IMetricsAdapter-t7QpfA1I.d.cts} +1 -1
- package/dist/{IMetricsAdapter-D9PUz4tM.d.ts → IMetricsAdapter-t7QpfA1I.d.ts} +1 -1
- package/dist/{INotificationAdapter-Hn70VShV.d.ts → INotificationAdapter-CFedkDQe.d.cts} +19 -2
- package/dist/{INotificationAdapter-Ci0gf6ac.d.cts → INotificationAdapter-COeQ5kEv.d.ts} +19 -2
- package/dist/{IOperationMiddleware-BCcAqSzT.d.ts → IOperationMiddleware-Bx4_U0ca.d.ts} +1 -1
- package/dist/{IOperationMiddleware-DOlOraCX.d.cts → IOperationMiddleware-CYXTV_TI.d.cts} +1 -1
- package/dist/{IStorageAdapter-D7jsZT6O.d.ts → IStorageAdapter-ecVYcA0z.d.ts} +1 -1
- package/dist/{IStorageAdapter-egPQD6Ry.d.cts → IStorageAdapter-qKgtuTY1.d.cts} +1 -1
- package/dist/adapters/MemoryAdapter.d.cts +2 -2
- package/dist/adapters/MemoryAdapter.d.ts +2 -2
- package/dist/adapters/PostgresAdapter.d.cts +2 -2
- package/dist/adapters/PostgresAdapter.d.ts +2 -2
- package/dist/index.cjs +174 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -9
- package/dist/index.d.ts +9 -9
- package/dist/index.js +174 -3
- package/dist/index.js.map +1 -1
- package/dist/{instance-CtkmEkYa.d.cts → instance-BxUwmrEi.d.cts} +1 -1
- package/dist/{instance-CtkmEkYa.d.ts → instance-BxUwmrEi.d.ts} +1 -1
- package/dist/nestjs.cjs +174 -3
- package/dist/nestjs.cjs.map +1 -1
- package/dist/nestjs.d.cts +8 -8
- package/dist/nestjs.d.ts +8 -8
- package/dist/nestjs.js +174 -3
- package/dist/nestjs.js.map +1 -1
- package/dist/plugins/audit.d.cts +2 -2
- package/dist/plugins/audit.d.ts +2 -2
- package/dist/plugins/metrics.cjs +1 -0
- package/dist/plugins/metrics.cjs.map +1 -1
- package/dist/plugins/metrics.d.cts +1 -1
- package/dist/plugins/metrics.d.ts +1 -1
- package/dist/plugins/metrics.js +1 -0
- package/dist/plugins/metrics.js.map +1 -1
- package/dist/plugins/notify.d.cts +2 -2
- package/dist/plugins/notify.d.ts +2 -2
- package/dist/plugins/resilience.d.cts +3 -3
- package/dist/plugins/resilience.d.ts +3 -3
- package/dist/plugins/tracing.d.cts +2 -2
- package/dist/plugins/tracing.d.ts +2 -2
- package/dist/plugins/webhook.d.cts +2 -2
- package/dist/plugins/webhook.d.ts +2 -2
- package/dist/testing.cjs +174 -3
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +8 -8
- package/dist/testing.d.ts +8 -8
- package/dist/testing.js +174 -3
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,47 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
7
7
|
|
|
8
8
|
_Nothing yet._
|
|
9
9
|
|
|
10
|
+
## [0.9.0] - 2026-09-04
|
|
11
|
+
|
|
12
|
+
### Added — `updateData()`: edit a pending document and recompute its chain
|
|
13
|
+
|
|
14
|
+
- **`engine.updateData(instanceId, opts)` changes an in-flight instance's
|
|
15
|
+
document data and re-evaluates the template's conditions against it.**
|
|
16
|
+
Documents change after submission — a corrected line item, a reclassified
|
|
17
|
+
vendor, a revised amount — and the chain computed at submit time can be wrong
|
|
18
|
+
the moment that happens. The only previous remedy was to cancel and resubmit,
|
|
19
|
+
which discarded every approval already collected along with its audit trail.
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
await engine.updateData(instance.id, {
|
|
23
|
+
updatedBy: 'buyer-1',
|
|
24
|
+
data: { amount: 20000 }, // merged by default; mode: 'replace' swaps wholesale
|
|
25
|
+
reason: 'Corrected line items',
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`recomputeChain: false` applies a data correction without touching the chain.
|
|
30
|
+
|
|
31
|
+
- **Decided history is frozen.** Only levels after the current one are
|
|
32
|
+
recomputed. A level that is already approved, or is actively collecting
|
|
33
|
+
decisions, is never removed: a `skipLevels` condition that would drop it is
|
|
34
|
+
ignored, because editing data must not retract an approval that was given. A
|
|
35
|
+
condition that would *insert* a level at or before the current level throws
|
|
36
|
+
`ApprovalValidationError` rather than silently dropping an approval step the
|
|
37
|
+
template says is required.
|
|
38
|
+
|
|
39
|
+
A future level that survives re-evaluation is preserved object-identical, so a
|
|
40
|
+
delegation already arranged on it survives an unrelated edit elsewhere in the
|
|
41
|
+
document.
|
|
42
|
+
|
|
43
|
+
- **Wiring:** emits `approval:data_updated` (`changedFields`, `addedLevels`,
|
|
44
|
+
`removedLevels`), records a `data_updated` audit entry carrying the before and
|
|
45
|
+
after data, increments `approval.data_updated`, and adds `updateData` to the
|
|
46
|
+
authorization-policy operation set — so it runs through the same
|
|
47
|
+
authz/middleware/audit/notification pipeline as every other operation.
|
|
48
|
+
|
|
49
|
+
New exports: `UpdateDataOptions`, `DataUpdatedEvent`.
|
|
50
|
+
|
|
10
51
|
## [0.8.0] - 2026-09-04
|
|
11
52
|
|
|
12
53
|
### Added — boolean condition expressions
|
package/README.md
CHANGED
|
@@ -399,6 +399,42 @@ engine.registerConditionOperator('between', (actual, expected) => {
|
|
|
399
399
|
});
|
|
400
400
|
```
|
|
401
401
|
|
|
402
|
+
### Editing a document mid-flight
|
|
403
|
+
|
|
404
|
+
Documents change after submission — a line item is corrected, a vendor
|
|
405
|
+
reclassified, an amount revised. `updateData()` applies the change and
|
|
406
|
+
re-evaluates the template's conditions, so the chain reflects the corrected
|
|
407
|
+
document without cancelling and resubmitting (which would throw away the
|
|
408
|
+
approvals already collected):
|
|
409
|
+
|
|
410
|
+
```ts
|
|
411
|
+
const updated = await engine.updateData(instance.id, {
|
|
412
|
+
updatedBy: 'buyer-1',
|
|
413
|
+
data: { amount: 20000 }, // merged into existing data
|
|
414
|
+
reason: 'Corrected line items',
|
|
415
|
+
});
|
|
416
|
+
// amount crossed the 10k threshold -> the CFO level is now in the chain
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
| Option | Default | Meaning |
|
|
420
|
+
|---|---|---|
|
|
421
|
+
| `data` | required | Fields to apply |
|
|
422
|
+
| `mode` | `'merge'` | `'merge'` keeps untouched keys; `'replace'` swaps the whole object |
|
|
423
|
+
| `reason` | — | Recorded on the audit entry |
|
|
424
|
+
| `recomputeChain` | `true` | Set `false` to correct data without touching the chain |
|
|
425
|
+
|
|
426
|
+
**Decided history is frozen.** Only levels *after* the current one are
|
|
427
|
+
recomputed. A level that is already approved, or is actively collecting
|
|
428
|
+
decisions, is never removed — a `skipLevels` condition that would drop it is
|
|
429
|
+
ignored, because an approval that has been given cannot be retracted by editing
|
|
430
|
+
data. A condition that would *insert* a level at or before the current one
|
|
431
|
+
throws rather than silently dropping a required approval step; cancel and
|
|
432
|
+
resubmit if the chain genuinely must change retroactively.
|
|
433
|
+
|
|
434
|
+
Emits `approval:data_updated` with `changedFields`, `addedLevels` and
|
|
435
|
+
`removedLevels`, and records a `data_updated` audit entry holding the before and
|
|
436
|
+
after data. Only pending instances can be edited.
|
|
437
|
+
|
|
402
438
|
---
|
|
403
439
|
|
|
404
440
|
## Installation and setup
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { I as IStorageAdapter, P as PaginationOpts, a as PaginatedResult, b as InstanceFilter, C as CursorPaginationOpts, c as CursorPaginatedResult } from './IStorageAdapter-
|
|
2
|
-
import { k as ConditionExpression, o as ResolverFn, g as ApprovalTemplateConfig, A as ApprovalTemplate, j as AuditContext, a as ApprovalInstance, e as ApprovalMode, b as AuditEntry } from './instance-
|
|
3
|
-
import { I as INotificationAdapter, b as ApprovalEventName, a as ApprovalEventMap } from './INotificationAdapter-
|
|
1
|
+
import { I as IStorageAdapter, P as PaginationOpts, a as PaginatedResult, b as InstanceFilter, C as CursorPaginationOpts, c as CursorPaginatedResult } from './IStorageAdapter-ecVYcA0z.js';
|
|
2
|
+
import { k as ConditionExpression, o as ResolverFn, g as ApprovalTemplateConfig, A as ApprovalTemplate, j as AuditContext, a as ApprovalInstance, e as ApprovalMode, b as AuditEntry } from './instance-BxUwmrEi.js';
|
|
3
|
+
import { I as INotificationAdapter, b as ApprovalEventName, a as ApprovalEventMap } from './INotificationAdapter-COeQ5kEv.js';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { L as Logger } from './Logger-BplhlU7l.js';
|
|
6
6
|
import { C as Clock } from './Clock-3FnOczFJ.js';
|
|
7
|
-
import { I as IOperationMiddleware, a as ApprovalError } from './IOperationMiddleware-
|
|
8
|
-
import { I as IAuditAdapter } from './IAuditAdapter-
|
|
9
|
-
import { I as IMetricsAdapter } from './IMetricsAdapter-
|
|
7
|
+
import { I as IOperationMiddleware, a as ApprovalError } from './IOperationMiddleware-Bx4_U0ca.js';
|
|
8
|
+
import { I as IAuditAdapter } from './IAuditAdapter-nlIK1em0.js';
|
|
9
|
+
import { I as IMetricsAdapter } from './IMetricsAdapter-t7QpfA1I.js';
|
|
10
10
|
import { I as ISchedulerAdapter } from './ISchedulerAdapter-DKv_QjVN.js';
|
|
11
|
-
import { I as IAuthorizationPolicy } from './IAuthorizationPolicy-
|
|
11
|
+
import { I as IAuthorizationPolicy } from './IAuthorizationPolicy-DG8vmD5j.js';
|
|
12
12
|
|
|
13
13
|
declare const SubmitOptionsSchema: z.ZodObject<{
|
|
14
14
|
templateName: z.ZodString;
|
|
@@ -67,6 +67,16 @@ declare const OverrideOptionsSchema: z.ZodObject<{
|
|
|
67
67
|
overriddenBy: z.ZodString;
|
|
68
68
|
justification: z.ZodString;
|
|
69
69
|
}, z.core.$strip>;
|
|
70
|
+
declare const UpdateDataOptionsSchema: z.ZodObject<{
|
|
71
|
+
updatedBy: z.ZodString;
|
|
72
|
+
data: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
73
|
+
mode: z.ZodDefault<z.ZodEnum<{
|
|
74
|
+
merge: "merge";
|
|
75
|
+
replace: "replace";
|
|
76
|
+
}>>;
|
|
77
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
78
|
+
recomputeChain: z.ZodDefault<z.ZodBoolean>;
|
|
79
|
+
}, z.core.$strip>;
|
|
70
80
|
type SubmitOptions = z.infer<typeof SubmitOptionsSchema>;
|
|
71
81
|
type ApproveOptions = z.infer<typeof ApproveOptionsSchema>;
|
|
72
82
|
type RejectOptions = z.infer<typeof RejectOptionsSchema>;
|
|
@@ -77,6 +87,7 @@ type EscalateOptions = z.infer<typeof EscalateOptionsSchema>;
|
|
|
77
87
|
type ResubmitOptions = z.infer<typeof ResubmitOptionsSchema>;
|
|
78
88
|
type AddCommentOptions = z.infer<typeof AddCommentOptionsSchema>;
|
|
79
89
|
type OverrideOptions = z.infer<typeof OverrideOptionsSchema>;
|
|
90
|
+
type UpdateDataOptions = z.infer<typeof UpdateDataOptionsSchema>;
|
|
80
91
|
|
|
81
92
|
/**
|
|
82
93
|
* Computes deadline dates from a number of days. The default engine behaviour
|
|
@@ -373,6 +384,42 @@ declare class ApprovalEngine {
|
|
|
373
384
|
reassign(instanceId: string, raw: ReassignOptions, auditCtx?: AuditContext): Promise<ApprovalInstance>;
|
|
374
385
|
cancel(instanceId: string, raw: CancelOptions, auditCtx?: AuditContext): Promise<ApprovalInstance>;
|
|
375
386
|
escalate(instanceId: string, raw: EscalateOptions, auditCtx?: AuditContext): Promise<ApprovalInstance>;
|
|
387
|
+
/**
|
|
388
|
+
* Change an instance's document data while it is still pending, and
|
|
389
|
+
* re-evaluate the template's conditions against the new values.
|
|
390
|
+
*
|
|
391
|
+
* Documents change after submission — a line item is corrected, a vendor is
|
|
392
|
+
* reclassified, an amount is revised — and the approval chain that was
|
|
393
|
+
* computed at submit time can be wrong the moment that happens. Without this,
|
|
394
|
+
* the only way to reflect a correction was to cancel and resubmit, losing the
|
|
395
|
+
* approvals already collected and the audit trail with them.
|
|
396
|
+
*
|
|
397
|
+
* **Only the part of the chain that has not been reached is recomputed.**
|
|
398
|
+
* Levels before {@link ApprovalInstance.currentLevel}, and the current level
|
|
399
|
+
* itself, are frozen: an approval that has already been given cannot be
|
|
400
|
+
* retracted by editing data, and a level that is actively collecting
|
|
401
|
+
* decisions is not pulled out from under its approvers. Conditions that would
|
|
402
|
+
* skip such a level are therefore ignored — history cannot be rewritten — and
|
|
403
|
+
* a condition that would *insert* a level at or before the current one throws
|
|
404
|
+
* rather than silently dropping an approval step that should have run.
|
|
405
|
+
*
|
|
406
|
+
* @param instanceId - The pending instance to update.
|
|
407
|
+
* @param raw - Who is updating, the new data, and how to apply it.
|
|
408
|
+
* @param auditCtx - Optional compliance context recorded on the audit entry.
|
|
409
|
+
* @returns The updated instance.
|
|
410
|
+
* @throws ApprovalError if the instance is not pending.
|
|
411
|
+
* @throws ApprovalValidationError if re-evaluation would insert a level at or
|
|
412
|
+
* before the current level, or would leave the chain with no levels.
|
|
413
|
+
*/
|
|
414
|
+
updateData(instanceId: string, raw: UpdateDataOptions, auditCtx?: AuditContext): Promise<ApprovalInstance>;
|
|
415
|
+
/**
|
|
416
|
+
* Recompute the not-yet-reached portion of an instance's level chain against
|
|
417
|
+
* new data, mutating `instance.levels` in place.
|
|
418
|
+
*
|
|
419
|
+
* Levels at or before `currentLevel` are treated as immutable history. See
|
|
420
|
+
* {@link updateData} for why.
|
|
421
|
+
*/
|
|
422
|
+
private recomputeFutureChain;
|
|
376
423
|
/** Add a comment to an instance without approving or rejecting. */
|
|
377
424
|
addComment(instanceId: string, raw: AddCommentOptions, auditCtx?: AuditContext): Promise<void>;
|
|
378
425
|
/** Resubmit a rejected instance, creating a new linked instance from level 1. */
|
|
@@ -453,4 +500,4 @@ declare class ApprovalEngine {
|
|
|
453
500
|
private runExternalAudit;
|
|
454
501
|
}
|
|
455
502
|
|
|
456
|
-
export { type AddCommentOptions as A, type BulkResult as B, type CanApproveResult as C, type DelegateOptions as D, type EscalateOptions as E, type HealthResult as H, type IdGeneratorFn as I, type OrgProvider as O, type PreviewChainLevel as P, type ReassignOptions as R, type SubmitOptions as S, type ValidationResult as V, type WeekendCalendarOptions as W, ApprovalEngine as a, type ApprovalEngineOptions as b, type ApprovalStatistics as c, type ApproveOptions as d, type ApproverResolverFn as e, type BusinessCalendar as f, type CancelOptions as g, type ConditionOperatorFn as h, type CycleTimeStats as i, type IdempotencyKeyFn as j, type OverrideOptions as k, type PreviewResult as l, type RejectOptions as m, type ResubmitOptions as n, type RetryPolicy as o, defaultIdGenerator as p, toComparableNumber as t, validateConditionExpression as v, weekendCalendar as w };
|
|
503
|
+
export { type AddCommentOptions as A, type BulkResult as B, type CanApproveResult as C, type DelegateOptions as D, type EscalateOptions as E, type HealthResult as H, type IdGeneratorFn as I, type OrgProvider as O, type PreviewChainLevel as P, type ReassignOptions as R, type SubmitOptions as S, type UpdateDataOptions as U, type ValidationResult as V, type WeekendCalendarOptions as W, ApprovalEngine as a, type ApprovalEngineOptions as b, type ApprovalStatistics as c, type ApproveOptions as d, type ApproverResolverFn as e, type BusinessCalendar as f, type CancelOptions as g, type ConditionOperatorFn as h, type CycleTimeStats as i, type IdempotencyKeyFn as j, type OverrideOptions as k, type PreviewResult as l, type RejectOptions as m, type ResubmitOptions as n, type RetryPolicy as o, defaultIdGenerator as p, toComparableNumber as t, validateConditionExpression as v, weekendCalendar as w };
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { I as IStorageAdapter, P as PaginationOpts, a as PaginatedResult, b as InstanceFilter, C as CursorPaginationOpts, c as CursorPaginatedResult } from './IStorageAdapter-
|
|
2
|
-
import { k as ConditionExpression, o as ResolverFn, g as ApprovalTemplateConfig, A as ApprovalTemplate, j as AuditContext, a as ApprovalInstance, e as ApprovalMode, b as AuditEntry } from './instance-
|
|
3
|
-
import { I as INotificationAdapter, b as ApprovalEventName, a as ApprovalEventMap } from './INotificationAdapter-
|
|
1
|
+
import { I as IStorageAdapter, P as PaginationOpts, a as PaginatedResult, b as InstanceFilter, C as CursorPaginationOpts, c as CursorPaginatedResult } from './IStorageAdapter-qKgtuTY1.cjs';
|
|
2
|
+
import { k as ConditionExpression, o as ResolverFn, g as ApprovalTemplateConfig, A as ApprovalTemplate, j as AuditContext, a as ApprovalInstance, e as ApprovalMode, b as AuditEntry } from './instance-BxUwmrEi.cjs';
|
|
3
|
+
import { I as INotificationAdapter, b as ApprovalEventName, a as ApprovalEventMap } from './INotificationAdapter-CFedkDQe.cjs';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { L as Logger } from './Logger-BplhlU7l.cjs';
|
|
6
6
|
import { C as Clock } from './Clock-3FnOczFJ.cjs';
|
|
7
|
-
import { I as IOperationMiddleware, a as ApprovalError } from './IOperationMiddleware-
|
|
8
|
-
import { I as IAuditAdapter } from './IAuditAdapter-
|
|
9
|
-
import { I as IMetricsAdapter } from './IMetricsAdapter-
|
|
7
|
+
import { I as IOperationMiddleware, a as ApprovalError } from './IOperationMiddleware-CYXTV_TI.cjs';
|
|
8
|
+
import { I as IAuditAdapter } from './IAuditAdapter-0frLfzRq.cjs';
|
|
9
|
+
import { I as IMetricsAdapter } from './IMetricsAdapter-t7QpfA1I.cjs';
|
|
10
10
|
import { I as ISchedulerAdapter } from './ISchedulerAdapter-DKv_QjVN.cjs';
|
|
11
|
-
import { I as IAuthorizationPolicy } from './IAuthorizationPolicy-
|
|
11
|
+
import { I as IAuthorizationPolicy } from './IAuthorizationPolicy-DXEMaoxF.cjs';
|
|
12
12
|
|
|
13
13
|
declare const SubmitOptionsSchema: z.ZodObject<{
|
|
14
14
|
templateName: z.ZodString;
|
|
@@ -67,6 +67,16 @@ declare const OverrideOptionsSchema: z.ZodObject<{
|
|
|
67
67
|
overriddenBy: z.ZodString;
|
|
68
68
|
justification: z.ZodString;
|
|
69
69
|
}, z.core.$strip>;
|
|
70
|
+
declare const UpdateDataOptionsSchema: z.ZodObject<{
|
|
71
|
+
updatedBy: z.ZodString;
|
|
72
|
+
data: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
73
|
+
mode: z.ZodDefault<z.ZodEnum<{
|
|
74
|
+
merge: "merge";
|
|
75
|
+
replace: "replace";
|
|
76
|
+
}>>;
|
|
77
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
78
|
+
recomputeChain: z.ZodDefault<z.ZodBoolean>;
|
|
79
|
+
}, z.core.$strip>;
|
|
70
80
|
type SubmitOptions = z.infer<typeof SubmitOptionsSchema>;
|
|
71
81
|
type ApproveOptions = z.infer<typeof ApproveOptionsSchema>;
|
|
72
82
|
type RejectOptions = z.infer<typeof RejectOptionsSchema>;
|
|
@@ -77,6 +87,7 @@ type EscalateOptions = z.infer<typeof EscalateOptionsSchema>;
|
|
|
77
87
|
type ResubmitOptions = z.infer<typeof ResubmitOptionsSchema>;
|
|
78
88
|
type AddCommentOptions = z.infer<typeof AddCommentOptionsSchema>;
|
|
79
89
|
type OverrideOptions = z.infer<typeof OverrideOptionsSchema>;
|
|
90
|
+
type UpdateDataOptions = z.infer<typeof UpdateDataOptionsSchema>;
|
|
80
91
|
|
|
81
92
|
/**
|
|
82
93
|
* Computes deadline dates from a number of days. The default engine behaviour
|
|
@@ -373,6 +384,42 @@ declare class ApprovalEngine {
|
|
|
373
384
|
reassign(instanceId: string, raw: ReassignOptions, auditCtx?: AuditContext): Promise<ApprovalInstance>;
|
|
374
385
|
cancel(instanceId: string, raw: CancelOptions, auditCtx?: AuditContext): Promise<ApprovalInstance>;
|
|
375
386
|
escalate(instanceId: string, raw: EscalateOptions, auditCtx?: AuditContext): Promise<ApprovalInstance>;
|
|
387
|
+
/**
|
|
388
|
+
* Change an instance's document data while it is still pending, and
|
|
389
|
+
* re-evaluate the template's conditions against the new values.
|
|
390
|
+
*
|
|
391
|
+
* Documents change after submission — a line item is corrected, a vendor is
|
|
392
|
+
* reclassified, an amount is revised — and the approval chain that was
|
|
393
|
+
* computed at submit time can be wrong the moment that happens. Without this,
|
|
394
|
+
* the only way to reflect a correction was to cancel and resubmit, losing the
|
|
395
|
+
* approvals already collected and the audit trail with them.
|
|
396
|
+
*
|
|
397
|
+
* **Only the part of the chain that has not been reached is recomputed.**
|
|
398
|
+
* Levels before {@link ApprovalInstance.currentLevel}, and the current level
|
|
399
|
+
* itself, are frozen: an approval that has already been given cannot be
|
|
400
|
+
* retracted by editing data, and a level that is actively collecting
|
|
401
|
+
* decisions is not pulled out from under its approvers. Conditions that would
|
|
402
|
+
* skip such a level are therefore ignored — history cannot be rewritten — and
|
|
403
|
+
* a condition that would *insert* a level at or before the current one throws
|
|
404
|
+
* rather than silently dropping an approval step that should have run.
|
|
405
|
+
*
|
|
406
|
+
* @param instanceId - The pending instance to update.
|
|
407
|
+
* @param raw - Who is updating, the new data, and how to apply it.
|
|
408
|
+
* @param auditCtx - Optional compliance context recorded on the audit entry.
|
|
409
|
+
* @returns The updated instance.
|
|
410
|
+
* @throws ApprovalError if the instance is not pending.
|
|
411
|
+
* @throws ApprovalValidationError if re-evaluation would insert a level at or
|
|
412
|
+
* before the current level, or would leave the chain with no levels.
|
|
413
|
+
*/
|
|
414
|
+
updateData(instanceId: string, raw: UpdateDataOptions, auditCtx?: AuditContext): Promise<ApprovalInstance>;
|
|
415
|
+
/**
|
|
416
|
+
* Recompute the not-yet-reached portion of an instance's level chain against
|
|
417
|
+
* new data, mutating `instance.levels` in place.
|
|
418
|
+
*
|
|
419
|
+
* Levels at or before `currentLevel` are treated as immutable history. See
|
|
420
|
+
* {@link updateData} for why.
|
|
421
|
+
*/
|
|
422
|
+
private recomputeFutureChain;
|
|
376
423
|
/** Add a comment to an instance without approving or rejecting. */
|
|
377
424
|
addComment(instanceId: string, raw: AddCommentOptions, auditCtx?: AuditContext): Promise<void>;
|
|
378
425
|
/** Resubmit a rejected instance, creating a new linked instance from level 1. */
|
|
@@ -453,4 +500,4 @@ declare class ApprovalEngine {
|
|
|
453
500
|
private runExternalAudit;
|
|
454
501
|
}
|
|
455
502
|
|
|
456
|
-
export { type AddCommentOptions as A, type BulkResult as B, type CanApproveResult as C, type DelegateOptions as D, type EscalateOptions as E, type HealthResult as H, type IdGeneratorFn as I, type OrgProvider as O, type PreviewChainLevel as P, type ReassignOptions as R, type SubmitOptions as S, type ValidationResult as V, type WeekendCalendarOptions as W, ApprovalEngine as a, type ApprovalEngineOptions as b, type ApprovalStatistics as c, type ApproveOptions as d, type ApproverResolverFn as e, type BusinessCalendar as f, type CancelOptions as g, type ConditionOperatorFn as h, type CycleTimeStats as i, type IdempotencyKeyFn as j, type OverrideOptions as k, type PreviewResult as l, type RejectOptions as m, type ResubmitOptions as n, type RetryPolicy as o, defaultIdGenerator as p, toComparableNumber as t, validateConditionExpression as v, weekendCalendar as w };
|
|
503
|
+
export { type AddCommentOptions as A, type BulkResult as B, type CanApproveResult as C, type DelegateOptions as D, type EscalateOptions as E, type HealthResult as H, type IdGeneratorFn as I, type OrgProvider as O, type PreviewChainLevel as P, type ReassignOptions as R, type SubmitOptions as S, type UpdateDataOptions as U, type ValidationResult as V, type WeekendCalendarOptions as W, ApprovalEngine as a, type ApprovalEngineOptions as b, type ApprovalStatistics as c, type ApproveOptions as d, type ApproverResolverFn as e, type BusinessCalendar as f, type CancelOptions as g, type ConditionOperatorFn as h, type CycleTimeStats as i, type IdempotencyKeyFn as j, type OverrideOptions as k, type PreviewResult as l, type RejectOptions as m, type ResubmitOptions as n, type RetryPolicy as o, defaultIdGenerator as p, toComparableNumber as t, validateConditionExpression as v, weekendCalendar as w };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { a as ApprovalInstance, d as ApprovalLevelInstance } from './instance-
|
|
1
|
+
import { a as ApprovalInstance, d as ApprovalLevelInstance } from './instance-BxUwmrEi.js';
|
|
2
2
|
|
|
3
3
|
interface AuthorizationContext {
|
|
4
|
-
operation: 'submit' | 'approve' | 'reject' | 'delegate' | 'reassign' | 'cancel' | 'escalate' | 'override' | 'resubmit' | 'addComment';
|
|
4
|
+
operation: 'submit' | 'approve' | 'reject' | 'delegate' | 'reassign' | 'cancel' | 'escalate' | 'override' | 'resubmit' | 'addComment' | 'updateData';
|
|
5
5
|
actorId: string;
|
|
6
6
|
instance: Readonly<ApprovalInstance>;
|
|
7
7
|
level?: Readonly<ApprovalLevelInstance>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { a as ApprovalInstance, d as ApprovalLevelInstance } from './instance-
|
|
1
|
+
import { a as ApprovalInstance, d as ApprovalLevelInstance } from './instance-BxUwmrEi.cjs';
|
|
2
2
|
|
|
3
3
|
interface AuthorizationContext {
|
|
4
|
-
operation: 'submit' | 'approve' | 'reject' | 'delegate' | 'reassign' | 'cancel' | 'escalate' | 'override' | 'resubmit' | 'addComment';
|
|
4
|
+
operation: 'submit' | 'approve' | 'reject' | 'delegate' | 'reassign' | 'cancel' | 'escalate' | 'override' | 'resubmit' | 'addComment' | 'updateData';
|
|
5
5
|
actorId: string;
|
|
6
6
|
instance: Readonly<ApprovalInstance>;
|
|
7
7
|
level?: Readonly<ApprovalLevelInstance>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
type MetricName = 'approval.submitted' | 'approval.approved' | 'approval.rejected' | 'approval.cancelled' | 'approval.expired' | 'approval.sla_breached' | 'approval.escalated' | 'approval.reassigned' | 'approval.overridden' | 'approval.conflict_retry' | 'approval.operation_duration_ms';
|
|
1
|
+
type MetricName = 'approval.submitted' | 'approval.approved' | 'approval.rejected' | 'approval.cancelled' | 'approval.expired' | 'approval.sla_breached' | 'approval.escalated' | 'approval.reassigned' | 'approval.overridden' | 'approval.data_updated' | 'approval.conflict_retry' | 'approval.operation_duration_ms';
|
|
2
2
|
interface IMetricsAdapter {
|
|
3
3
|
/** Increment a counter. Synchronous — never awaited. */
|
|
4
4
|
increment(metric: MetricName, labels?: Record<string, string>): void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
type MetricName = 'approval.submitted' | 'approval.approved' | 'approval.rejected' | 'approval.cancelled' | 'approval.expired' | 'approval.sla_breached' | 'approval.escalated' | 'approval.reassigned' | 'approval.overridden' | 'approval.conflict_retry' | 'approval.operation_duration_ms';
|
|
1
|
+
type MetricName = 'approval.submitted' | 'approval.approved' | 'approval.rejected' | 'approval.cancelled' | 'approval.expired' | 'approval.sla_breached' | 'approval.escalated' | 'approval.reassigned' | 'approval.overridden' | 'approval.data_updated' | 'approval.conflict_retry' | 'approval.operation_duration_ms';
|
|
2
2
|
interface IMetricsAdapter {
|
|
3
3
|
/** Increment a counter. Synchronous — never awaited. */
|
|
4
4
|
increment(metric: MetricName, labels?: Record<string, string>): void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as ApprovalInstance, b as AuditEntry } from './instance-
|
|
1
|
+
import { a as ApprovalInstance, b as AuditEntry } from './instance-BxUwmrEi.cjs';
|
|
2
2
|
|
|
3
3
|
interface ApprovalEvent {
|
|
4
4
|
instanceId: string;
|
|
@@ -62,6 +62,22 @@ interface ExpiredEvent extends ApprovalEvent {
|
|
|
62
62
|
interface SlaBreachedEvent extends ApprovalEvent {
|
|
63
63
|
slaDeadlineAt: Date;
|
|
64
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Emitted when an instance's document data is changed while it is still
|
|
67
|
+
* pending. {@link addedLevels} and {@link removedLevels} describe how the
|
|
68
|
+
* remaining approval chain was recomputed — both empty when the data change
|
|
69
|
+
* did not affect it.
|
|
70
|
+
*/
|
|
71
|
+
interface DataUpdatedEvent extends ApprovalEvent {
|
|
72
|
+
updatedBy: string;
|
|
73
|
+
reason?: string;
|
|
74
|
+
/** Field paths whose values differ after the update. */
|
|
75
|
+
changedFields: string[];
|
|
76
|
+
/** Level numbers added to the future chain by re-evaluating conditions. */
|
|
77
|
+
addedLevels: number[];
|
|
78
|
+
/** Level numbers removed from the future chain by re-evaluating conditions. */
|
|
79
|
+
removedLevels: number[];
|
|
80
|
+
}
|
|
65
81
|
interface ApprovalEventMap {
|
|
66
82
|
'approval:submitted': SubmittedEvent;
|
|
67
83
|
'approval:approved': ApprovedEvent;
|
|
@@ -76,6 +92,7 @@ interface ApprovalEventMap {
|
|
|
76
92
|
'approval:overridden': OverriddenEvent;
|
|
77
93
|
'approval:expired': ExpiredEvent;
|
|
78
94
|
'approval:sla_breached': SlaBreachedEvent;
|
|
95
|
+
'approval:data_updated': DataUpdatedEvent;
|
|
79
96
|
}
|
|
80
97
|
type ApprovalEventName = keyof ApprovalEventMap;
|
|
81
98
|
interface HistoryEntry extends AuditEntry {
|
|
@@ -99,4 +116,4 @@ interface INotificationAdapter {
|
|
|
99
116
|
notify(event: NotificationEvent): Promise<void>;
|
|
100
117
|
}
|
|
101
118
|
|
|
102
|
-
export type { ApprovalEvent as A, CancelledEvent as C,
|
|
119
|
+
export type { ApprovalEvent as A, CancelledEvent as C, DataUpdatedEvent as D, EscalatedEvent as E, HistoryEntry as H, INotificationAdapter as I, LevelAdvancedEvent as L, NotificationEvent as N, OverriddenEvent as O, ReassignedEvent as R, SlaBreachedEvent as S, ApprovalEventMap as a, ApprovalEventName as b, ApprovedEvent as c, DelegatedEvent as d, ExpiredEvent as e, RejectedEvent as f, ResubmittedEvent as g, SubmittedEvent as h };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as ApprovalInstance, b as AuditEntry } from './instance-
|
|
1
|
+
import { a as ApprovalInstance, b as AuditEntry } from './instance-BxUwmrEi.js';
|
|
2
2
|
|
|
3
3
|
interface ApprovalEvent {
|
|
4
4
|
instanceId: string;
|
|
@@ -62,6 +62,22 @@ interface ExpiredEvent extends ApprovalEvent {
|
|
|
62
62
|
interface SlaBreachedEvent extends ApprovalEvent {
|
|
63
63
|
slaDeadlineAt: Date;
|
|
64
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Emitted when an instance's document data is changed while it is still
|
|
67
|
+
* pending. {@link addedLevels} and {@link removedLevels} describe how the
|
|
68
|
+
* remaining approval chain was recomputed — both empty when the data change
|
|
69
|
+
* did not affect it.
|
|
70
|
+
*/
|
|
71
|
+
interface DataUpdatedEvent extends ApprovalEvent {
|
|
72
|
+
updatedBy: string;
|
|
73
|
+
reason?: string;
|
|
74
|
+
/** Field paths whose values differ after the update. */
|
|
75
|
+
changedFields: string[];
|
|
76
|
+
/** Level numbers added to the future chain by re-evaluating conditions. */
|
|
77
|
+
addedLevels: number[];
|
|
78
|
+
/** Level numbers removed from the future chain by re-evaluating conditions. */
|
|
79
|
+
removedLevels: number[];
|
|
80
|
+
}
|
|
65
81
|
interface ApprovalEventMap {
|
|
66
82
|
'approval:submitted': SubmittedEvent;
|
|
67
83
|
'approval:approved': ApprovedEvent;
|
|
@@ -76,6 +92,7 @@ interface ApprovalEventMap {
|
|
|
76
92
|
'approval:overridden': OverriddenEvent;
|
|
77
93
|
'approval:expired': ExpiredEvent;
|
|
78
94
|
'approval:sla_breached': SlaBreachedEvent;
|
|
95
|
+
'approval:data_updated': DataUpdatedEvent;
|
|
79
96
|
}
|
|
80
97
|
type ApprovalEventName = keyof ApprovalEventMap;
|
|
81
98
|
interface HistoryEntry extends AuditEntry {
|
|
@@ -99,4 +116,4 @@ interface INotificationAdapter {
|
|
|
99
116
|
notify(event: NotificationEvent): Promise<void>;
|
|
100
117
|
}
|
|
101
118
|
|
|
102
|
-
export type { ApprovalEvent as A, CancelledEvent as C,
|
|
119
|
+
export type { ApprovalEvent as A, CancelledEvent as C, DataUpdatedEvent as D, EscalatedEvent as E, HistoryEntry as H, INotificationAdapter as I, LevelAdvancedEvent as L, NotificationEvent as N, OverriddenEvent as O, ReassignedEvent as R, SlaBreachedEvent as S, ApprovalEventMap as a, ApprovalEventName as b, ApprovedEvent as c, DelegatedEvent as d, ExpiredEvent as e, RejectedEvent as f, ResubmittedEvent as g, SubmittedEvent as h };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as ApprovalTemplate, a as ApprovalInstance, f as ApprovalStatus, b as AuditEntry } from './instance-
|
|
1
|
+
import { A as ApprovalTemplate, a as ApprovalInstance, f as ApprovalStatus, b as AuditEntry } from './instance-BxUwmrEi.js';
|
|
2
2
|
|
|
3
3
|
interface PaginationOpts {
|
|
4
4
|
limit: number;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as ApprovalTemplate, a as ApprovalInstance, f as ApprovalStatus, b as AuditEntry } from './instance-
|
|
1
|
+
import { A as ApprovalTemplate, a as ApprovalInstance, f as ApprovalStatus, b as AuditEntry } from './instance-BxUwmrEi.cjs';
|
|
2
2
|
|
|
3
3
|
interface PaginationOpts {
|
|
4
4
|
limit: number;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { I as IStorageAdapter, P as PaginationOpts, a as PaginatedResult, b as InstanceFilter, C as CursorPaginationOpts, c as CursorPaginatedResult } from '../IStorageAdapter-
|
|
2
|
-
import { A as ApprovalTemplate, a as ApprovalInstance, b as AuditEntry } from '../instance-
|
|
1
|
+
import { I as IStorageAdapter, P as PaginationOpts, a as PaginatedResult, b as InstanceFilter, C as CursorPaginationOpts, c as CursorPaginatedResult } from '../IStorageAdapter-qKgtuTY1.cjs';
|
|
2
|
+
import { A as ApprovalTemplate, a as ApprovalInstance, b as AuditEntry } from '../instance-BxUwmrEi.cjs';
|
|
3
3
|
|
|
4
4
|
declare class MemoryAdapter implements IStorageAdapter {
|
|
5
5
|
private templates;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { I as IStorageAdapter, P as PaginationOpts, a as PaginatedResult, b as InstanceFilter, C as CursorPaginationOpts, c as CursorPaginatedResult } from '../IStorageAdapter-
|
|
2
|
-
import { A as ApprovalTemplate, a as ApprovalInstance, b as AuditEntry } from '../instance-
|
|
1
|
+
import { I as IStorageAdapter, P as PaginationOpts, a as PaginatedResult, b as InstanceFilter, C as CursorPaginationOpts, c as CursorPaginatedResult } from '../IStorageAdapter-ecVYcA0z.js';
|
|
2
|
+
import { A as ApprovalTemplate, a as ApprovalInstance, b as AuditEntry } from '../instance-BxUwmrEi.js';
|
|
3
3
|
|
|
4
4
|
declare class MemoryAdapter implements IStorageAdapter {
|
|
5
5
|
private templates;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as tls from 'tls';
|
|
2
2
|
import * as pg from 'pg';
|
|
3
|
-
import { I as IStorageAdapter, P as PaginationOpts, a as PaginatedResult, b as InstanceFilter, C as CursorPaginationOpts, c as CursorPaginatedResult } from '../IStorageAdapter-
|
|
4
|
-
import { A as ApprovalTemplate, a as ApprovalInstance, b as AuditEntry } from '../instance-
|
|
3
|
+
import { I as IStorageAdapter, P as PaginationOpts, a as PaginatedResult, b as InstanceFilter, C as CursorPaginationOpts, c as CursorPaginatedResult } from '../IStorageAdapter-qKgtuTY1.cjs';
|
|
4
|
+
import { A as ApprovalTemplate, a as ApprovalInstance, b as AuditEntry } from '../instance-BxUwmrEi.cjs';
|
|
5
5
|
|
|
6
6
|
interface PostgresAdapterOptions {
|
|
7
7
|
connectionString?: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as tls from 'tls';
|
|
2
2
|
import * as pg from 'pg';
|
|
3
|
-
import { I as IStorageAdapter, P as PaginationOpts, a as PaginatedResult, b as InstanceFilter, C as CursorPaginationOpts, c as CursorPaginatedResult } from '../IStorageAdapter-
|
|
4
|
-
import { A as ApprovalTemplate, a as ApprovalInstance, b as AuditEntry } from '../instance-
|
|
3
|
+
import { I as IStorageAdapter, P as PaginationOpts, a as PaginatedResult, b as InstanceFilter, C as CursorPaginationOpts, c as CursorPaginatedResult } from '../IStorageAdapter-ecVYcA0z.js';
|
|
4
|
+
import { A as ApprovalTemplate, a as ApprovalInstance, b as AuditEntry } from '../instance-BxUwmrEi.js';
|
|
5
5
|
|
|
6
6
|
interface PostgresAdapterOptions {
|
|
7
7
|
connectionString?: string;
|