hierarchical-approval 4.0.1 → 4.0.3
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 +34 -5
- package/README.md +1 -1
- package/dist/{ApprovalEngine-BfKL6iGQ.d.ts → ApprovalEngine-BtgQDr_8.d.ts} +201 -10
- package/dist/{ApprovalEngine-DcD6s_jB.d.cts → ApprovalEngine-Djdw-JzA.d.cts} +201 -10
- package/dist/Clock-D8Qp39q_.d.cts +8 -0
- package/dist/Clock-D8Qp39q_.d.ts +8 -0
- package/dist/{IAuditAdapter-DkbyFFjb.d.ts → IAuditAdapter-C-04ar9A.d.ts} +1 -1
- package/dist/{IAuditAdapter-Dt8qjkQL.d.cts → IAuditAdapter-TT2Xhtu6.d.cts} +1 -1
- package/dist/{IAuthorizationPolicy-eo6glbpE.d.ts → IAuthorizationPolicy-D6tTT3gv.d.cts} +6 -1
- package/dist/{IAuthorizationPolicy-YJ_08Mof.d.cts → IAuthorizationPolicy-wIE1mpTy.d.ts} +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-BcUskJ6z.d.ts} +9 -1
- package/dist/{INotificationAdapter-XbD69gss.d.cts → INotificationAdapter-CBsJDk-Y.d.cts} +9 -1
- package/dist/{IOperationMiddleware-CX7lo4lp.d.ts → IOperationMiddleware-C7ciNnJp.d.ts} +3 -2
- package/dist/{IOperationMiddleware-BBLk8MIz.d.cts → IOperationMiddleware-D3Yelw9R.d.cts} +3 -2
- package/dist/{IStorageAdapter-CdXMggPK.d.ts → IStorageAdapter-CVvNsnnD.d.ts} +7 -1
- package/dist/{IStorageAdapter-Cjw5zDwQ.d.cts → IStorageAdapter-D7cy20uD.d.cts} +7 -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 +20 -2
- package/dist/adapters/MemoryAdapter.d.ts +20 -2
- package/dist/adapters/MemoryAdapter.js.map +1 -1
- package/dist/adapters/PostgresAdapter.cjs.map +1 -1
- package/dist/adapters/PostgresAdapter.d.cts +18 -2
- package/dist/adapters/PostgresAdapter.d.ts +18 -2
- package/dist/adapters/PostgresAdapter.js.map +1 -1
- package/dist/index.cjs +270 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -13
- package/dist/index.d.ts +13 -13
- package/dist/index.js +270 -21
- package/dist/index.js.map +1 -1
- package/dist/{instance-uUQh5XW3.d.cts → instance-Dd1jQizG.d.cts} +19 -0
- package/dist/{instance-uUQh5XW3.d.ts → instance-Dd1jQizG.d.ts} +19 -0
- package/dist/nestjs.cjs +269 -20
- package/dist/nestjs.cjs.map +1 -1
- package/dist/nestjs.d.cts +10 -10
- package/dist/nestjs.d.ts +10 -10
- package/dist/nestjs.js +269 -20
- 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 +3 -1
- package/dist/plugins/notify.cjs.map +1 -1
- package/dist/plugins/notify.d.cts +6 -4
- package/dist/plugins/notify.d.ts +6 -4
- package/dist/plugins/notify.js +3 -1
- 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 +2 -2
- package/dist/plugins/scheduler.d.ts +2 -2
- package/dist/plugins/scheduler.js.map +1 -1
- package/dist/plugins/tracing.d.cts +2 -2
- package/dist/plugins/tracing.d.ts +2 -2
- 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 +281 -20
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +31 -10
- package/dist/testing.d.ts +31 -10
- package/dist/testing.js +281 -20
- 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/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
## 4.0.
|
|
1
|
+
## 4.0.3 - 2026-09-22
|
|
2
2
|
|
|
3
|
-
- fix(
|
|
4
|
-
- fix(
|
|
5
|
-
- fix(
|
|
6
|
-
- fix(postgres): let FakePool pass an explicit null rowCount through
|
|
3
|
+
- fix(engine): name the level in assertApproverOnLevel's error
|
|
4
|
+
- fix(utils): name the offending start date in businessHoursCalendar's error
|
|
5
|
+
- fix(engine): name the offending instance id in assertStatus's error
|
|
7
6
|
|
|
8
7
|
# Changelog
|
|
9
8
|
|
|
@@ -14,9 +13,39 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
14
13
|
|
|
15
14
|
### Fixed
|
|
16
15
|
|
|
16
|
+
- `assertStatus`'s `INVALID_STATUS` error now names the instance that failed
|
|
17
|
+
the check, instead of a message that gave no clue which instance it was.
|
|
18
|
+
- `businessHoursCalendar`'s "no working day found" error now names the start
|
|
19
|
+
date that triggered it, instead of a message that gave no clue which call
|
|
20
|
+
misconfigured the calendar.
|
|
21
|
+
- `assertApproverOnLevel`'s forbidden-approver error now names the level,
|
|
22
|
+
matching every sibling guard in `StateMachine.ts`, instead of a bare level
|
|
23
|
+
number with no human-readable name.
|
|
24
|
+
|
|
25
|
+
## [4.0.2] - 2026-09-20
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- `EventBus` (and therefore `engine.on()`/`off()`) no longer leaks a listener
|
|
30
|
+
when the same function is registered twice with `on()`: each registration
|
|
31
|
+
now needs its own `off()` call to undo, instead of the second registration
|
|
32
|
+
silently overwriting the bookkeeping for the first and leaving it permanently
|
|
33
|
+
attached.
|
|
34
|
+
- `DigestNotificationAdapter`'s `intervalMs` validation error now names the
|
|
35
|
+
offending value, instead of a message that gave no clue which value failed.
|
|
36
|
+
- The default-sleep regression test for `WebhookNotificationAdapter` no longer
|
|
37
|
+
flakes under CI's timer coalescing, which could report elapsed time a
|
|
38
|
+
millisecond or two short of the asserted floor.
|
|
39
|
+
|
|
40
|
+
## [4.0.1] - 2026-09-14
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
|
|
17
44
|
- `InMemorySchedulerAdapter.scheduleAt()`'s post-shutdown error now names the
|
|
18
45
|
rejected job id, so a caller can tell which scheduled job was dropped
|
|
19
46
|
without adding their own logging around every call.
|
|
47
|
+
- `RateLimitMiddleware` errors now include the offending value that tripped
|
|
48
|
+
the limit, instead of a message that named the limit but not the input.
|
|
20
49
|
|
|
21
50
|
## [4.0.0] - 2026-09-04
|
|
22
51
|
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Multi-tenant · audit-ready · fully pluggable · zero runtime dependencies you
|
|
|
11
11
|
[](https://www.typescriptlang.org/)
|
|
12
12
|
[](https://bundlephobia.com/package/hierarchical-approval)
|
|
13
13
|
[](./LICENSE)
|
|
14
|
-
[](./tests)
|
|
15
15
|
|
|
16
16
|
[**Documentation**](https://hierarchical-approval.matthewswong.com) ·
|
|
17
17
|
[**npm**](https://www.npmjs.com/package/hierarchical-approval) ·
|
|
@@ -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 { m as ConditionExpression, r as ResolverFn, g as ApprovalTemplateConfig, A as ApprovalTemplate, k as AuditContext, a as ApprovalInstance, C as Comment, e as ApprovalMode, f as ApprovalStatus, L as LevelStatus, 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-CVvNsnnD.js';
|
|
2
|
+
import { m as ConditionExpression, r as ResolverFn, g as ApprovalTemplateConfig, A as ApprovalTemplate, k as AuditContext, a as ApprovalInstance, C as Comment, e as ApprovalMode, f as ApprovalStatus, L as LevelStatus, b as AuditEntry } from './instance-Dd1jQizG.js';
|
|
3
|
+
import { I as INotificationAdapter, b as ApprovalEventName, a as ApprovalEventMap } from './INotificationAdapter-BcUskJ6z.js';
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
-
import { L as Logger } from './Logger-
|
|
6
|
-
import { C as Clock } from './Clock-
|
|
7
|
-
import { I as IOperationMiddleware, a as ApprovalError } from './IOperationMiddleware-
|
|
8
|
-
import { I as IAuditAdapter } from './IAuditAdapter-
|
|
9
|
-
import { I as IMetricsAdapter } from './IMetricsAdapter-
|
|
5
|
+
import { L as Logger } from './Logger-hqFbBCtB.js';
|
|
6
|
+
import { C as Clock } from './Clock-D8Qp39q_.js';
|
|
7
|
+
import { I as IOperationMiddleware, a as ApprovalError } from './IOperationMiddleware-C7ciNnJp.js';
|
|
8
|
+
import { I as IAuditAdapter } from './IAuditAdapter-C-04ar9A.js';
|
|
9
|
+
import { I as IMetricsAdapter } from './IMetricsAdapter-WROxYSXd.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-wIE1mpTy.js';
|
|
12
12
|
|
|
13
13
|
declare const SubmitOptionsSchema: z.ZodObject<{
|
|
14
14
|
templateName: z.ZodString;
|
|
@@ -201,11 +201,15 @@ interface BusinessHoursCalendarOptions extends WeekendCalendarOptions {
|
|
|
201
201
|
*/
|
|
202
202
|
declare function businessHoursCalendar(options?: BusinessHoursCalendarOptions): Required<Pick<BusinessCalendar, 'addBusinessDays' | 'addBusinessHours'>>;
|
|
203
203
|
|
|
204
|
+
/** Entity kind an id is generated for: instance, template, attachment, or comment. */
|
|
204
205
|
type IdGeneratorPrefix = 'inst' | 'tpl' | 'att' | 'cmt';
|
|
206
|
+
/** Produces a unique id for the given entity kind. */
|
|
205
207
|
type IdGeneratorFn = (prefix: IdGeneratorPrefix) => string;
|
|
208
|
+
/** {@link IdGeneratorFn} used when no custom generator is configured. */
|
|
206
209
|
declare const defaultIdGenerator: IdGeneratorFn;
|
|
207
210
|
|
|
208
211
|
interface OrgProvider {
|
|
212
|
+
/** Required: resolve users holding a named role. */
|
|
209
213
|
getUsersByRole(role: string, tenantId?: string): Promise<string[]> | string[];
|
|
210
214
|
/** Optional: resolve users by department name. */
|
|
211
215
|
getUsersByDepartment?(dept: string, tenantId?: string): Promise<string[]> | string[];
|
|
@@ -625,18 +629,71 @@ declare class ApprovalEngine {
|
|
|
625
629
|
/** Set by {@link shutdown}; stops the self-rescheduling loop from scheduling another tick. */
|
|
626
630
|
private schedulerStopped;
|
|
627
631
|
constructor(opts: ApprovalEngineOptions);
|
|
632
|
+
/**
|
|
633
|
+
* Subscribe to a lifecycle event (see {@link ApprovalEventMap} for the full
|
|
634
|
+
* catalog and each payload's shape). A listener that throws, or returns a
|
|
635
|
+
* rejecting promise, cannot abort the operation that emitted the event or
|
|
636
|
+
* block the remaining listeners — the failure is reported via the engine's
|
|
637
|
+
* logger instead.
|
|
638
|
+
*
|
|
639
|
+
* @returns `this`, for chaining multiple subscriptions.
|
|
640
|
+
*/
|
|
628
641
|
on<K extends ApprovalEventName>(event: K, listener: (payload: ApprovalEventMap[K]) => void): this;
|
|
642
|
+
/**
|
|
643
|
+
* Unsubscribe a listener previously registered with {@link on}. A no-op if
|
|
644
|
+
* `listener` was never registered for `event`.
|
|
645
|
+
*
|
|
646
|
+
* @returns `this`, for chaining.
|
|
647
|
+
*/
|
|
629
648
|
off<K extends ApprovalEventName>(event: K, listener: (payload: ApprovalEventMap[K]) => void): this;
|
|
649
|
+
/**
|
|
650
|
+
* Register a dynamic-approver resolver under `name`, for use by a level whose
|
|
651
|
+
* approver config is `{ type: 'dynamic', resolver: name }`. Overwrites any
|
|
652
|
+
* resolver already registered under the same name.
|
|
653
|
+
*/
|
|
630
654
|
registerResolver(name: string, fn: ResolverFn): void;
|
|
655
|
+
/**
|
|
656
|
+
* Register a custom approver type under `typeName`, for use by a level whose
|
|
657
|
+
* approver config carries `{ type: typeName, ... }`. Overwrites any approver
|
|
658
|
+
* type already registered under the same type name.
|
|
659
|
+
*/
|
|
631
660
|
registerApproverType(typeName: string, fn: ApproverResolverFn): void;
|
|
661
|
+
/**
|
|
662
|
+
* Register a custom condition operator under `name`, for use by template
|
|
663
|
+
* condition rules whose `operator` is `name`. Operators are shared process-wide
|
|
664
|
+
* across every engine instance, not scoped to this tenant.
|
|
665
|
+
*
|
|
666
|
+
* @throws {@link ApprovalValidationError} if `name` is already taken by a
|
|
667
|
+
* built-in operator (`>`, `<`, `>=`, `<=`, `==`, `!=`, `in`, `not_in`).
|
|
668
|
+
*/
|
|
632
669
|
registerConditionOperator(name: string, fn: ConditionOperatorFn): void;
|
|
633
670
|
/** Validate a template config without persisting. Synchronous; never throws. */
|
|
634
671
|
validateTemplate(config: ApprovalTemplateConfig): ValidationResult;
|
|
635
672
|
defineTemplate(config: ApprovalTemplateConfig): Promise<string>;
|
|
636
673
|
/** Update an existing template, incrementing its version. In-flight instances are protected by their templateSnapshot. */
|
|
637
674
|
updateTemplate(config: ApprovalTemplateConfig): Promise<string>;
|
|
675
|
+
/**
|
|
676
|
+
* Fetch the current version of a defined template.
|
|
677
|
+
*
|
|
678
|
+
* @throws {@link ApprovalTemplateNotFoundError} if no template is registered under `name`.
|
|
679
|
+
*/
|
|
638
680
|
getTemplate(name: string): Promise<ApprovalTemplate>;
|
|
681
|
+
/** List every template currently defined for this tenant. */
|
|
639
682
|
listTemplates(): Promise<ApprovalTemplate[]>;
|
|
683
|
+
/**
|
|
684
|
+
* Start a new approval instance from a defined template.
|
|
685
|
+
*
|
|
686
|
+
* Evaluates the template's conditions against `raw.data` first, so the
|
|
687
|
+
* levels an instance opens with can differ from the template's static
|
|
688
|
+
* declaration (added, skipped, or reordered). If a prior call with the
|
|
689
|
+
* same tenant, document, template and data produced a non-terminal
|
|
690
|
+
* instance, that instance is returned unchanged instead of creating a
|
|
691
|
+
* duplicate — safe to retry on network failure.
|
|
692
|
+
*
|
|
693
|
+
* @throws {@link ApprovalTemplateNotFoundError} if `raw.templateName` is not defined.
|
|
694
|
+
* @throws {@link ApprovalValidationError} if `raw` fails schema validation, or if
|
|
695
|
+
* condition evaluation leaves no levels (or a duplicate level number) to open.
|
|
696
|
+
*/
|
|
640
697
|
submit(raw: SubmitOptions, auditCtx?: AuditContext,
|
|
641
698
|
/**
|
|
642
699
|
* @internal Set only when the engine spawns a sub-workflow child. Passed at
|
|
@@ -649,8 +706,63 @@ declare class ApprovalEngine {
|
|
|
649
706
|
parentLevel: number;
|
|
650
707
|
depth: number;
|
|
651
708
|
}): Promise<ApprovalInstance>;
|
|
709
|
+
/**
|
|
710
|
+
* Record `opts.approverId`'s approval of their open level on `instanceId`.
|
|
711
|
+
*
|
|
712
|
+
* When more than one level is open in parallel and the approver sits on
|
|
713
|
+
* exactly one of them, that level is inferred; pass `opts.level` explicitly
|
|
714
|
+
* when it must be disambiguated (e.g. the approver sits on several).
|
|
715
|
+
*
|
|
716
|
+
* @throws {@link ApprovalNotFoundError} if `instanceId` does not exist.
|
|
717
|
+
* @throws {@link ApprovalError} (code `INVALID_STATUS`) if the instance is not `pending`,
|
|
718
|
+
* (code `INVALID_LEVEL`) if no level (or the explicit `opts.level`) is awaiting a decision,
|
|
719
|
+
* or (code `ALREADY_ACTED`) if this approver already approved or rejected that level.
|
|
720
|
+
* @throws {@link ApprovalForbiddenError} if `opts.approverId` submitted the instance
|
|
721
|
+
* (self-approval), is not an approver on the resolved level, or is denied by the
|
|
722
|
+
* configured {@link IAuthorizationPolicy}.
|
|
723
|
+
* @throws {@link ApprovalValidationError} if `opts.approverId` sits on more than one
|
|
724
|
+
* open parallel level and `opts.level` was not supplied to disambiguate.
|
|
725
|
+
*/
|
|
652
726
|
approve(instanceId: string, raw: ApproveOptions, auditCtx?: AuditContext): Promise<ApprovalInstance>;
|
|
727
|
+
/**
|
|
728
|
+
* Record `opts.approverId`'s rejection of their open level on `instanceId`.
|
|
729
|
+
*
|
|
730
|
+
* A single rejection does not necessarily fail the level — under `'quorum'`
|
|
731
|
+
* or `'weighted'` mode it only fails once the remaining approvers can no
|
|
732
|
+
* longer reach threshold. When the level does fail, `opts.returnTo`
|
|
733
|
+
* controls what happens next: `'originator'` (default) fails the whole
|
|
734
|
+
* instance; `'previous'` resets every level after the prior one and sends
|
|
735
|
+
* the instance back there to replay.
|
|
736
|
+
*
|
|
737
|
+
* @throws {@link ApprovalNotFoundError} if `instanceId` does not exist.
|
|
738
|
+
* @throws {@link ApprovalError} (code `INVALID_STATUS`) if the instance is not `pending`,
|
|
739
|
+
* (code `INVALID_LEVEL`) if no level (or the explicit `opts.level`) is awaiting a decision,
|
|
740
|
+
* or (code `ALREADY_ACTED`) if this approver already approved or rejected that level.
|
|
741
|
+
* @throws {@link ApprovalForbiddenError} if `opts.approverId` submitted the instance
|
|
742
|
+
* (self-rejection), is not an approver on the resolved level, or is denied by the
|
|
743
|
+
* configured {@link IAuthorizationPolicy}.
|
|
744
|
+
* @throws {@link ApprovalValidationError} if `opts.approverId` sits on more than one
|
|
745
|
+
* open parallel level with `opts.level` unset, or if `opts.returnTo === 'previous'`
|
|
746
|
+
* but the failing level is already the first level in the chain.
|
|
747
|
+
*/
|
|
653
748
|
reject(instanceId: string, raw: RejectOptions, auditCtx?: AuditContext): Promise<ApprovalInstance>;
|
|
749
|
+
/**
|
|
750
|
+
* Reassign `opts.fromApprover`'s seat on their open level to `opts.toApprover`,
|
|
751
|
+
* carrying across any 'weighted'-mode vote weight. When `opts.until` is set,
|
|
752
|
+
* the level records `delegatedFrom`/`delegatedTo`/`delegatedUntil`, and the
|
|
753
|
+
* scheduled escalation tick reassigns the seat back to `opts.fromApprover`
|
|
754
|
+
* once that time passes (still pending); omit `opts.until` for a permanent
|
|
755
|
+
* handoff.
|
|
756
|
+
*
|
|
757
|
+
* @throws {@link ApprovalNotFoundError} if `instanceId` does not exist.
|
|
758
|
+
* @throws {@link ApprovalError} (code `INVALID_STATUS`) if the instance is not `pending`,
|
|
759
|
+
* or (code `INVALID_LEVEL`) if no level (or the explicit `opts.level`) is awaiting a decision.
|
|
760
|
+
* @throws {@link ApprovalForbiddenError} if `opts.fromApprover` equals `opts.toApprover`,
|
|
761
|
+
* is not an approver on the resolved level, already acted on it, or is denied by the
|
|
762
|
+
* configured {@link IAuthorizationPolicy}.
|
|
763
|
+
* @throws {@link ApprovalValidationError} if `opts.fromApprover` sits on more than one
|
|
764
|
+
* open parallel level and `opts.level` was not supplied to disambiguate.
|
|
765
|
+
*/
|
|
654
766
|
delegate(instanceId: string, raw: DelegateOptions, auditCtx?: AuditContext): Promise<void>;
|
|
655
767
|
/**
|
|
656
768
|
* Administratively replace an approver on the current level. Unlike delegate(),
|
|
@@ -660,7 +772,36 @@ declare class ApprovalEngine {
|
|
|
660
772
|
* cannot be reassigned.
|
|
661
773
|
*/
|
|
662
774
|
reassign(instanceId: string, raw: ReassignOptions, auditCtx?: AuditContext): Promise<ApprovalInstance>;
|
|
775
|
+
/**
|
|
776
|
+
* Withdraw an approval before it reaches a final decision.
|
|
777
|
+
*
|
|
778
|
+
* Cancelling cascades: any sub-workflow children spawned by this instance
|
|
779
|
+
* are cancelled in turn (an orphaned child left running would eventually
|
|
780
|
+
* report back to a parent that already moved on), and if this instance is
|
|
781
|
+
* itself a sub-workflow child, its own parent is unblocked as if this
|
|
782
|
+
* approval had been rejected.
|
|
783
|
+
*
|
|
784
|
+
* @param instanceId - The instance to cancel.
|
|
785
|
+
* @param raw - Who is cancelling and why.
|
|
786
|
+
* @param auditCtx - Optional compliance context recorded on the audit entry.
|
|
787
|
+
* @returns The cancelled instance.
|
|
788
|
+
* @throws ApprovalError if the instance is already `approved` or `rejected`.
|
|
789
|
+
*/
|
|
663
790
|
cancel(instanceId: string, raw: CancelOptions, auditCtx?: AuditContext): Promise<ApprovalInstance>;
|
|
791
|
+
/**
|
|
792
|
+
* Manually escalate the instance's current (lowest pending) level to the
|
|
793
|
+
* next rung of its escalation ladder, adding whatever the rung's
|
|
794
|
+
* `escalateTo` resolves to as extra approvers on that level. This is the
|
|
795
|
+
* same path the scheduled tick uses for a deadline-driven escalation — call
|
|
796
|
+
* it directly to escalate on demand instead of waiting for the ladder timer.
|
|
797
|
+
*
|
|
798
|
+
* A no-op (returns the instance unchanged, does not throw) when: the
|
|
799
|
+
* instance is not `pending`; the ladder has no rung configured for the
|
|
800
|
+
* current step; or every resolved approver turns out to be the submitter
|
|
801
|
+
* (nobody new to add).
|
|
802
|
+
*
|
|
803
|
+
* @throws {@link ApprovalNotFoundError} if `instanceId` does not exist.
|
|
804
|
+
*/
|
|
664
805
|
escalate(instanceId: string, raw: EscalateOptions, auditCtx?: AuditContext): Promise<ApprovalInstance>;
|
|
665
806
|
/**
|
|
666
807
|
* Change an instance's document data while it is still pending, and
|
|
@@ -822,6 +963,17 @@ declare class ApprovalEngine {
|
|
|
822
963
|
submittedBy: string;
|
|
823
964
|
decisions?: SimulatedDecision[];
|
|
824
965
|
}): Promise<SimulationResult>;
|
|
966
|
+
/**
|
|
967
|
+
* Check whether a user could approve an instance right now, without acting.
|
|
968
|
+
*
|
|
969
|
+
* The read-only counterpart to calling {@link approve} and handling the
|
|
970
|
+
* rejection — useful for deciding whether to show an approve button at all.
|
|
971
|
+
* `eligible: false` never throws; the reason names why: the instance is not
|
|
972
|
+
* `pending`, the user submitted it, they hold no open level (or delegated
|
|
973
|
+
* theirs away), or they already voted on it.
|
|
974
|
+
*
|
|
975
|
+
* @returns `{ eligible: true }`, or `{ eligible: false, reason }`.
|
|
976
|
+
*/
|
|
825
977
|
canApprove(instanceId: string, userId: string): Promise<CanApproveResult>;
|
|
826
978
|
/** Emergency bypass — completes the instance as 'approved', skipping remaining levels. Requires template.allowOverride = true. */
|
|
827
979
|
override(instanceId: string, raw: OverrideOptions, auditCtx?: AuditContext): Promise<ApprovalInstance>;
|
|
@@ -848,13 +1000,34 @@ declare class ApprovalEngine {
|
|
|
848
1000
|
* @returns What moved, what did not, and why. With `dryRun` nothing is written.
|
|
849
1001
|
*/
|
|
850
1002
|
transferApprovals(raw: TransferApprovalsOptions, auditCtx?: AuditContext): Promise<TransferResult>;
|
|
1003
|
+
/** Approve multiple instances in one call. Never throws — failures collected in result.failed. */
|
|
851
1004
|
bulkApprove(instanceIds: string[], raw: ApproveOptions, auditCtx?: AuditContext): Promise<BulkResult>;
|
|
852
1005
|
/** Reject multiple instances in one call. Never throws — failures collected in result.failed. */
|
|
853
1006
|
bulkReject(instanceIds: string[], raw: RejectOptions, auditCtx?: AuditContext): Promise<BulkResult>;
|
|
1007
|
+
/**
|
|
1008
|
+
* Fetch a single instance by id.
|
|
1009
|
+
*
|
|
1010
|
+
* @throws {@link ApprovalNotFoundError} if no instance exists with that id.
|
|
1011
|
+
*/
|
|
854
1012
|
getInstance(instanceId: string): Promise<ApprovalInstance>;
|
|
1013
|
+
/** Page through every instance with an open level assigned to one approver. */
|
|
855
1014
|
getPendingFor(approverId: string, opts?: PaginationOpts): Promise<PaginatedResult<ApprovalInstance>>;
|
|
1015
|
+
/** Page through instances matching an arbitrary filter (status, document type, date range, ...). */
|
|
856
1016
|
queryInstances(filter: InstanceFilter, opts?: PaginationOpts): Promise<PaginatedResult<ApprovalInstance>>;
|
|
1017
|
+
/**
|
|
1018
|
+
* Cursor-paginated variant of {@link queryInstances}, for stable paging
|
|
1019
|
+
* through large or actively-changing result sets that offset pagination
|
|
1020
|
+
* would skip or duplicate rows in.
|
|
1021
|
+
*
|
|
1022
|
+
* @throws {@link ApprovalError} (`NOT_SUPPORTED`) if the configured storage
|
|
1023
|
+
* adapter does not implement `getInstancesByCursor`.
|
|
1024
|
+
*/
|
|
857
1025
|
queryInstancesByCursor(filter: InstanceFilter, opts: CursorPaginationOpts): Promise<CursorPaginatedResult<ApprovalInstance>>;
|
|
1026
|
+
/**
|
|
1027
|
+
* The full audit trail for an instance, in the order it was recorded.
|
|
1028
|
+
*
|
|
1029
|
+
* @throws {@link ApprovalNotFoundError} if no instance exists with that id.
|
|
1030
|
+
*/
|
|
858
1031
|
getHistory(instanceId: string): Promise<AuditEntry[]>;
|
|
859
1032
|
/**
|
|
860
1033
|
* The levels currently collecting decisions, ascending.
|
|
@@ -867,6 +1040,16 @@ declare class ApprovalEngine {
|
|
|
867
1040
|
* Empty once the instance is terminal.
|
|
868
1041
|
*/
|
|
869
1042
|
getOpenLevels(instanceId: string): Promise<number[]>;
|
|
1043
|
+
/**
|
|
1044
|
+
* Everyone who currently owes a decision on an instance.
|
|
1045
|
+
*
|
|
1046
|
+
* A union across every open branch, so a parallel group with more than one
|
|
1047
|
+
* level collecting decisions at once still names every approver, not just
|
|
1048
|
+
* the one at {@link ApprovalInstance.currentLevel}. Empty once the instance
|
|
1049
|
+
* is no longer `pending`.
|
|
1050
|
+
*
|
|
1051
|
+
* @throws {@link ApprovalNotFoundError} if no instance exists with that id.
|
|
1052
|
+
*/
|
|
870
1053
|
getCurrentApprovers(instanceId: string): Promise<string[]>;
|
|
871
1054
|
/** Check adapter connectivity and escalation scheduler health. */
|
|
872
1055
|
healthCheck(): Promise<HealthResult>;
|
|
@@ -956,6 +1139,15 @@ declare class ApprovalEngine {
|
|
|
956
1139
|
limit?: number;
|
|
957
1140
|
dryRun?: boolean;
|
|
958
1141
|
}): Promise<PurgeResult>;
|
|
1142
|
+
/**
|
|
1143
|
+
* Aggregate reporting numbers for a tenant: counts by status, approval
|
|
1144
|
+
* rate, cycle-time stats, and a per-template breakdown.
|
|
1145
|
+
*
|
|
1146
|
+
* `filter.status` is ignored — the breakdown covers every status by
|
|
1147
|
+
* design, so scoping it to one would make the counts misleading.
|
|
1148
|
+
*
|
|
1149
|
+
* @param filter - Optional scoping by document type, submitter, or date range.
|
|
1150
|
+
*/
|
|
959
1151
|
getStatistics(filter?: Omit<InstanceFilter, 'status'>): Promise<ApprovalStatistics>;
|
|
960
1152
|
/** Stops the escalation scheduler and any scheduler-adapter background loop; call once when tearing the engine down. */
|
|
961
1153
|
shutdown(): Promise<void>;
|
|
@@ -1206,7 +1398,6 @@ declare class ApprovalEngine {
|
|
|
1206
1398
|
* approved document that one branch had rejected and another had never seen.
|
|
1207
1399
|
*/
|
|
1208
1400
|
private assertFullyApproved;
|
|
1209
|
-
private findNextLevel;
|
|
1210
1401
|
/**
|
|
1211
1402
|
* The level to send an instance back to, given the level being rejected.
|
|
1212
1403
|
*
|