hierarchical-approval 4.0.3 → 4.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/CHANGELOG.md +28 -6
  2. package/README.md +1 -1
  3. package/dist/{ApprovalEngine-Djdw-JzA.d.cts → ApprovalEngine-BaJ2PNB7.d.cts} +29 -7
  4. package/dist/{ApprovalEngine-BtgQDr_8.d.ts → ApprovalEngine-CeBKYLz4.d.ts} +29 -7
  5. package/dist/{IAuditAdapter-TT2Xhtu6.d.cts → IAuditAdapter-Dqpkg-Tz.d.cts} +2 -1
  6. package/dist/{IAuditAdapter-C-04ar9A.d.ts → IAuditAdapter-ggCTPf02.d.ts} +2 -1
  7. package/dist/{IAuthorizationPolicy-wIE1mpTy.d.ts → IAuthorizationPolicy-BUHKvalu.d.ts} +1 -1
  8. package/dist/{IAuthorizationPolicy-D6tTT3gv.d.cts → IAuthorizationPolicy-D5mAFBTC.d.cts} +1 -1
  9. package/dist/{INotificationAdapter-BcUskJ6z.d.ts → INotificationAdapter-B_9JFH1i.d.ts} +18 -1
  10. package/dist/{INotificationAdapter-CBsJDk-Y.d.cts → INotificationAdapter-D9IOl9G_.d.cts} +18 -1
  11. package/dist/{IOperationMiddleware-C7ciNnJp.d.ts → IOperationMiddleware-C-N8MpHV.d.ts} +13 -1
  12. package/dist/{IOperationMiddleware-D3Yelw9R.d.cts → IOperationMiddleware-CsF_xD4b.d.cts} +13 -1
  13. package/dist/{ISchedulerAdapter-DKv_QjVN.d.cts → ISchedulerAdapter-CLMdBA-5.d.cts} +1 -0
  14. package/dist/{ISchedulerAdapter-DKv_QjVN.d.ts → ISchedulerAdapter-CLMdBA-5.d.ts} +1 -0
  15. package/dist/{IStorageAdapter-D7cy20uD.d.cts → IStorageAdapter-CrbVtEE-.d.cts} +8 -1
  16. package/dist/{IStorageAdapter-CVvNsnnD.d.ts → IStorageAdapter-DDOW9z0L.d.ts} +8 -1
  17. package/dist/adapters/MemoryAdapter.cjs.map +1 -1
  18. package/dist/adapters/MemoryAdapter.d.cts +2 -2
  19. package/dist/adapters/MemoryAdapter.d.ts +2 -2
  20. package/dist/adapters/MemoryAdapter.js.map +1 -1
  21. package/dist/adapters/PostgresAdapter.cjs.map +1 -1
  22. package/dist/adapters/PostgresAdapter.d.cts +2 -2
  23. package/dist/adapters/PostgresAdapter.d.ts +2 -2
  24. package/dist/adapters/PostgresAdapter.js.map +1 -1
  25. package/dist/index.cjs +27 -13
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +9 -9
  28. package/dist/index.d.ts +9 -9
  29. package/dist/index.js +27 -13
  30. package/dist/index.js.map +1 -1
  31. package/dist/{instance-Dd1jQizG.d.cts → instance-Cu6-qPxs.d.cts} +27 -0
  32. package/dist/{instance-Dd1jQizG.d.ts → instance-Cu6-qPxs.d.ts} +27 -0
  33. package/dist/nestjs.cjs +35 -10
  34. package/dist/nestjs.cjs.map +1 -1
  35. package/dist/nestjs.d.cts +19 -8
  36. package/dist/nestjs.d.ts +19 -8
  37. package/dist/nestjs.js +35 -10
  38. package/dist/nestjs.js.map +1 -1
  39. package/dist/plugins/audit.cjs +30 -1
  40. package/dist/plugins/audit.cjs.map +1 -1
  41. package/dist/plugins/audit.d.cts +4 -4
  42. package/dist/plugins/audit.d.ts +4 -4
  43. package/dist/plugins/audit.js +30 -1
  44. package/dist/plugins/audit.js.map +1 -1
  45. package/dist/plugins/notify.cjs +30 -1
  46. package/dist/plugins/notify.cjs.map +1 -1
  47. package/dist/plugins/notify.d.cts +2 -2
  48. package/dist/plugins/notify.d.ts +2 -2
  49. package/dist/plugins/notify.js +30 -1
  50. package/dist/plugins/notify.js.map +1 -1
  51. package/dist/plugins/resilience.cjs +11 -4
  52. package/dist/plugins/resilience.cjs.map +1 -1
  53. package/dist/plugins/resilience.d.cts +3 -3
  54. package/dist/plugins/resilience.d.ts +3 -3
  55. package/dist/plugins/resilience.js +11 -4
  56. package/dist/plugins/resilience.js.map +1 -1
  57. package/dist/plugins/scheduler.d.cts +1 -1
  58. package/dist/plugins/scheduler.d.ts +1 -1
  59. package/dist/plugins/tracing.cjs.map +1 -1
  60. package/dist/plugins/tracing.d.cts +4 -2
  61. package/dist/plugins/tracing.d.ts +4 -2
  62. package/dist/plugins/tracing.js.map +1 -1
  63. package/dist/plugins/webhook.d.cts +2 -2
  64. package/dist/plugins/webhook.d.ts +2 -2
  65. package/dist/testing.cjs +24 -10
  66. package/dist/testing.cjs.map +1 -1
  67. package/dist/testing.d.cts +8 -8
  68. package/dist/testing.d.ts +8 -8
  69. package/dist/testing.js +24 -10
  70. package/dist/testing.js.map +1 -1
  71. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,9 +1,3 @@
1
- ## 4.0.3 - 2026-09-22
2
-
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
6
-
7
1
  # Changelog
8
2
 
9
3
  All notable changes to `hierarchical-approval` are documented here. This project
@@ -11,6 +5,34 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
11
5
 
12
6
  ## [Unreleased]
13
7
 
8
+ ## [4.0.5] - 2026-09-25
9
+
10
+ ### Fixed
11
+
12
+ - `RateLimitMiddleware`'s constructor validation now throws
13
+ `ApprovalValidationError`, instead of a plain `Error` a caller catching
14
+ `ApprovalValidationError` to distinguish config problems would miss.
15
+ - `DigestNotificationAdapter`'s `intervalMs` validation now throws
16
+ `ApprovalValidationError` for the same reason.
17
+ - `HashChainAuditAdapter`'s missing-`reader` validation now throws
18
+ `ApprovalValidationError` for the same reason.
19
+ - `businessHoursCalendar`'s three configuration guards now throw
20
+ `ApprovalValidationError` for the same reason.
21
+
22
+ ## [4.0.4] - 2026-09-24
23
+
24
+ ### Fixed
25
+
26
+ - `resubmit`'s duplicate-level error now names the offending level numbers,
27
+ instead of a message that gave no clue which levels collided.
28
+ - `purgeInstances`'s date-validation error now names the offending value,
29
+ instead of a message that gave no clue which value failed.
30
+ - `delegate`'s, `reassign`'s, and `override`'s self-action guards now name
31
+ the offending id, matching every sibling guard in the same methods that
32
+ already named theirs.
33
+
34
+ ## [4.0.3] - 2026-09-22
35
+
14
36
  ### Fixed
15
37
 
16
38
  - `assertStatus`'s `INVALID_STATUS` error now names the instance that failed
package/README.md CHANGED
@@ -11,7 +11,7 @@ Multi-tenant · audit-ready · fully pluggable · zero runtime dependencies you
11
11
  [![types](https://img.shields.io/npm/types/hierarchical-approval.svg?logo=typescript&logoColor=white&color=3178c6)](https://www.typescriptlang.org/)
12
12
  [![minzipped size](https://img.shields.io/bundlephobia/minzip/hierarchical-approval?color=44cc11)](https://bundlephobia.com/package/hierarchical-approval)
13
13
  [![license](https://img.shields.io/npm/l/hierarchical-approval.svg?color=blue)](./LICENSE)
14
- [![tests](https://img.shields.io/badge/tests-1256%20passing-44cc11.svg?logo=vitest&logoColor=white)](./tests)
14
+ [![tests](https://img.shields.io/badge/tests-1271%20passing-44cc11.svg?logo=vitest&logoColor=white)](./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-D7cy20uD.cjs';
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.cjs';
3
- import { I as INotificationAdapter, b as ApprovalEventName, a as ApprovalEventMap } from './INotificationAdapter-CBsJDk-Y.cjs';
1
+ import { I as IStorageAdapter, P as PaginationOpts, a as PaginatedResult, b as InstanceFilter, C as CursorPaginationOpts, c as CursorPaginatedResult } from './IStorageAdapter-CrbVtEE-.cjs';
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-Cu6-qPxs.cjs';
3
+ import { I as INotificationAdapter, b as ApprovalEventName, a as ApprovalEventMap } from './INotificationAdapter-D9IOl9G_.cjs';
4
4
  import { z } from 'zod';
5
5
  import { L as Logger } from './Logger-hqFbBCtB.cjs';
6
6
  import { C as Clock } from './Clock-D8Qp39q_.cjs';
7
- import { I as IOperationMiddleware, a as ApprovalError } from './IOperationMiddleware-D3Yelw9R.cjs';
8
- import { I as IAuditAdapter } from './IAuditAdapter-TT2Xhtu6.cjs';
7
+ import { I as IOperationMiddleware, a as ApprovalError } from './IOperationMiddleware-CsF_xD4b.cjs';
8
+ import { I as IAuditAdapter } from './IAuditAdapter-Dqpkg-Tz.cjs';
9
9
  import { I as IMetricsAdapter } from './IMetricsAdapter-WROxYSXd.cjs';
10
- import { I as ISchedulerAdapter } from './ISchedulerAdapter-DKv_QjVN.cjs';
11
- import { I as IAuthorizationPolicy } from './IAuthorizationPolicy-D6tTT3gv.cjs';
10
+ import { I as ISchedulerAdapter } from './ISchedulerAdapter-CLMdBA-5.cjs';
11
+ import { I as IAuthorizationPolicy } from './IAuthorizationPolicy-D5mAFBTC.cjs';
12
12
 
13
13
  declare const SubmitOptionsSchema: z.ZodObject<{
14
14
  templateName: z.ZodString;
@@ -208,6 +208,7 @@ type IdGeneratorFn = (prefix: IdGeneratorPrefix) => string;
208
208
  /** {@link IdGeneratorFn} used when no custom generator is configured. */
209
209
  declare const defaultIdGenerator: IdGeneratorFn;
210
210
 
211
+ /** Backs `{ type: 'role' }` approvers, so a level can name an org role instead of a fixed user id. */
211
212
  interface OrgProvider {
212
213
  /** Required: resolve users holding a named role. */
213
214
  getUsersByRole(role: string, tenantId?: string): Promise<string[]> | string[];
@@ -237,6 +238,11 @@ interface OutOfOfficeProvider {
237
238
  */
238
239
  getDelegateFor(userId: string, at: Date): Promise<string | null | undefined> | string | null | undefined;
239
240
  }
241
+ /**
242
+ * Resolves a custom approver type's config to concrete user ids. Registered
243
+ * via {@link ApprovalEngine.registerApproverType} to back a level whose
244
+ * approver config carries an app-defined `type`.
245
+ */
240
246
  type ApproverResolverFn = (config: Record<string, unknown>, ctx: {
241
247
  submittedBy: string;
242
248
  data: Record<string, unknown>;
@@ -283,6 +289,7 @@ declare function validateConditionExpression(expression: ConditionExpression, pa
283
289
  message: string;
284
290
  }>;
285
291
 
292
+ /** Outcome of {@link ApprovalEngine.validateTemplate}. */
286
293
  interface ValidationResult {
287
294
  valid: boolean;
288
295
  errors: Array<{
@@ -290,13 +297,16 @@ interface ValidationResult {
290
297
  message: string;
291
298
  }>;
292
299
  }
300
+ /** Outcome of {@link ApprovalEngine.canApprove}. */
293
301
  interface CanApproveResult {
294
302
  eligible: boolean;
295
303
  reason?: 'not_an_approver' | 'already_acted' | 'self_approval' | 'wrong_status' | 'delegated_away';
296
304
  }
305
+ /** One entry in a {@link ApprovalEngine.preview} result, resolved against the given data without persisting anything. */
297
306
  interface PreviewChainLevel {
298
307
  level: number;
299
308
  name: string;
309
+ /** Approver ids resolved as of preview time; dynamic/role approvers may resolve differently at submit time. */
300
310
  resolvedApprovers: string[];
301
311
  mode: ApprovalMode;
302
312
  }
@@ -390,12 +400,16 @@ interface SimulationResult {
390
400
  /** True when the script ran out before the approval finished. */
391
401
  incomplete: boolean;
392
402
  }
403
+ /** Outcome of a {@link ApprovalEngine.bulkApprove}/{@link ApprovalEngine.bulkReject} sweep. */
393
404
  interface BulkResult {
405
+ /** Instances that reached the requested decision. */
394
406
  succeeded: ApprovalInstance[];
407
+ /** Instances that could not be decided, with the reason. */
395
408
  failed: Array<{
396
409
  instanceId: string;
397
410
  error: ApprovalError;
398
411
  }>;
412
+ /** Number of instance ids passed in, equal to `succeeded.length + failed.length`. */
399
413
  total: number;
400
414
  }
401
415
  /** Outcome of a {@link ApprovalEngine.transferApprovals} sweep. */
@@ -541,6 +555,7 @@ interface CycleTimeStats {
541
555
  /** Largest observed time-to-decision. `0` when {@link count} is `0`. */
542
556
  maxMs: number;
543
557
  }
558
+ /** Outcome of {@link ApprovalEngine.healthCheck}. */
544
559
  interface HealthResult {
545
560
  status: 'healthy' | 'degraded' | 'unhealthy';
546
561
  adapter: 'connected' | 'error';
@@ -549,12 +564,18 @@ interface HealthResult {
549
564
  escalationRunning: boolean;
550
565
  lastTickAt?: Date;
551
566
  }
567
+ /** Controls how {@link ApprovalEngine}'s optimistic-lock retry backs off on write conflicts. Defaults to 3 attempts with a 50ms base delay. */
552
568
  interface RetryPolicy {
569
+ /** Number of attempts before giving up and rethrowing the conflict. */
553
570
  maxAttempts: number;
571
+ /** Linear backoff unit; attempt N waits roughly `baseDelayMs * N` before retrying. */
554
572
  baseDelayMs: number;
573
+ /** Upper bound on the computed delay. Defaults to unbounded. */
555
574
  maxDelayMs?: number;
575
+ /** Adds up to one `baseDelayMs` of random jitter to each delay. Defaults to `true`. */
556
576
  jitter?: boolean;
557
577
  }
578
+ /** Derives the idempotency key used to dedupe a {@link ApprovalEngine.submit} call from its tenant and document identity. */
558
579
  type IdempotencyKeyFn = (tenantId: string, documentType: string, documentId: string, templateName: string, data: Record<string, unknown>) => string;
559
580
  interface ApprovalEngineOptions {
560
581
  adapter: IStorageAdapter;
@@ -566,6 +587,7 @@ interface ApprovalEngineOptions {
566
587
  */
567
588
  outOfOfficeProvider?: OutOfOfficeProvider;
568
589
  logger?: Logger;
590
+ /** Interval, in milliseconds, between automatic escalation sweeps. Default: 60000 (1 minute). */
569
591
  escalationPollIntervalMs?: number;
570
592
  /** Maximum number of instances allowed in a single bulk operation. Default: 200. */
571
593
  maxBulkItems?: number;
@@ -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-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';
1
+ import { I as IStorageAdapter, P as PaginationOpts, a as PaginatedResult, b as InstanceFilter, C as CursorPaginationOpts, c as CursorPaginatedResult } from './IStorageAdapter-DDOW9z0L.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-Cu6-qPxs.js';
3
+ import { I as INotificationAdapter, b as ApprovalEventName, a as ApprovalEventMap } from './INotificationAdapter-B_9JFH1i.js';
4
4
  import { z } from 'zod';
5
5
  import { L as Logger } from './Logger-hqFbBCtB.js';
6
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';
7
+ import { I as IOperationMiddleware, a as ApprovalError } from './IOperationMiddleware-C-N8MpHV.js';
8
+ import { I as IAuditAdapter } from './IAuditAdapter-ggCTPf02.js';
9
9
  import { I as IMetricsAdapter } from './IMetricsAdapter-WROxYSXd.js';
10
- import { I as ISchedulerAdapter } from './ISchedulerAdapter-DKv_QjVN.js';
11
- import { I as IAuthorizationPolicy } from './IAuthorizationPolicy-wIE1mpTy.js';
10
+ import { I as ISchedulerAdapter } from './ISchedulerAdapter-CLMdBA-5.js';
11
+ import { I as IAuthorizationPolicy } from './IAuthorizationPolicy-BUHKvalu.js';
12
12
 
13
13
  declare const SubmitOptionsSchema: z.ZodObject<{
14
14
  templateName: z.ZodString;
@@ -208,6 +208,7 @@ type IdGeneratorFn = (prefix: IdGeneratorPrefix) => string;
208
208
  /** {@link IdGeneratorFn} used when no custom generator is configured. */
209
209
  declare const defaultIdGenerator: IdGeneratorFn;
210
210
 
211
+ /** Backs `{ type: 'role' }` approvers, so a level can name an org role instead of a fixed user id. */
211
212
  interface OrgProvider {
212
213
  /** Required: resolve users holding a named role. */
213
214
  getUsersByRole(role: string, tenantId?: string): Promise<string[]> | string[];
@@ -237,6 +238,11 @@ interface OutOfOfficeProvider {
237
238
  */
238
239
  getDelegateFor(userId: string, at: Date): Promise<string | null | undefined> | string | null | undefined;
239
240
  }
241
+ /**
242
+ * Resolves a custom approver type's config to concrete user ids. Registered
243
+ * via {@link ApprovalEngine.registerApproverType} to back a level whose
244
+ * approver config carries an app-defined `type`.
245
+ */
240
246
  type ApproverResolverFn = (config: Record<string, unknown>, ctx: {
241
247
  submittedBy: string;
242
248
  data: Record<string, unknown>;
@@ -283,6 +289,7 @@ declare function validateConditionExpression(expression: ConditionExpression, pa
283
289
  message: string;
284
290
  }>;
285
291
 
292
+ /** Outcome of {@link ApprovalEngine.validateTemplate}. */
286
293
  interface ValidationResult {
287
294
  valid: boolean;
288
295
  errors: Array<{
@@ -290,13 +297,16 @@ interface ValidationResult {
290
297
  message: string;
291
298
  }>;
292
299
  }
300
+ /** Outcome of {@link ApprovalEngine.canApprove}. */
293
301
  interface CanApproveResult {
294
302
  eligible: boolean;
295
303
  reason?: 'not_an_approver' | 'already_acted' | 'self_approval' | 'wrong_status' | 'delegated_away';
296
304
  }
305
+ /** One entry in a {@link ApprovalEngine.preview} result, resolved against the given data without persisting anything. */
297
306
  interface PreviewChainLevel {
298
307
  level: number;
299
308
  name: string;
309
+ /** Approver ids resolved as of preview time; dynamic/role approvers may resolve differently at submit time. */
300
310
  resolvedApprovers: string[];
301
311
  mode: ApprovalMode;
302
312
  }
@@ -390,12 +400,16 @@ interface SimulationResult {
390
400
  /** True when the script ran out before the approval finished. */
391
401
  incomplete: boolean;
392
402
  }
403
+ /** Outcome of a {@link ApprovalEngine.bulkApprove}/{@link ApprovalEngine.bulkReject} sweep. */
393
404
  interface BulkResult {
405
+ /** Instances that reached the requested decision. */
394
406
  succeeded: ApprovalInstance[];
407
+ /** Instances that could not be decided, with the reason. */
395
408
  failed: Array<{
396
409
  instanceId: string;
397
410
  error: ApprovalError;
398
411
  }>;
412
+ /** Number of instance ids passed in, equal to `succeeded.length + failed.length`. */
399
413
  total: number;
400
414
  }
401
415
  /** Outcome of a {@link ApprovalEngine.transferApprovals} sweep. */
@@ -541,6 +555,7 @@ interface CycleTimeStats {
541
555
  /** Largest observed time-to-decision. `0` when {@link count} is `0`. */
542
556
  maxMs: number;
543
557
  }
558
+ /** Outcome of {@link ApprovalEngine.healthCheck}. */
544
559
  interface HealthResult {
545
560
  status: 'healthy' | 'degraded' | 'unhealthy';
546
561
  adapter: 'connected' | 'error';
@@ -549,12 +564,18 @@ interface HealthResult {
549
564
  escalationRunning: boolean;
550
565
  lastTickAt?: Date;
551
566
  }
567
+ /** Controls how {@link ApprovalEngine}'s optimistic-lock retry backs off on write conflicts. Defaults to 3 attempts with a 50ms base delay. */
552
568
  interface RetryPolicy {
569
+ /** Number of attempts before giving up and rethrowing the conflict. */
553
570
  maxAttempts: number;
571
+ /** Linear backoff unit; attempt N waits roughly `baseDelayMs * N` before retrying. */
554
572
  baseDelayMs: number;
573
+ /** Upper bound on the computed delay. Defaults to unbounded. */
555
574
  maxDelayMs?: number;
575
+ /** Adds up to one `baseDelayMs` of random jitter to each delay. Defaults to `true`. */
556
576
  jitter?: boolean;
557
577
  }
578
+ /** Derives the idempotency key used to dedupe a {@link ApprovalEngine.submit} call from its tenant and document identity. */
558
579
  type IdempotencyKeyFn = (tenantId: string, documentType: string, documentId: string, templateName: string, data: Record<string, unknown>) => string;
559
580
  interface ApprovalEngineOptions {
560
581
  adapter: IStorageAdapter;
@@ -566,6 +587,7 @@ interface ApprovalEngineOptions {
566
587
  */
567
588
  outOfOfficeProvider?: OutOfOfficeProvider;
568
589
  logger?: Logger;
590
+ /** Interval, in milliseconds, between automatic escalation sweeps. Default: 60000 (1 minute). */
569
591
  escalationPollIntervalMs?: number;
570
592
  /** Maximum number of instances allowed in a single bulk operation. Default: 200. */
571
593
  maxBulkItems?: number;
@@ -1,5 +1,6 @@
1
- import { b as AuditEntry, a as ApprovalInstance } from './instance-Dd1jQizG.cjs';
1
+ import { b as AuditEntry, a as ApprovalInstance } from './instance-Cu6-qPxs.cjs';
2
2
 
3
+ /** Secondary write sink for audit entries, alongside the primary storage adapter. */
3
4
  interface IAuditAdapter {
4
5
  /**
5
6
  * Called after every state-mutating operation, in addition to the primary storage adapter.
@@ -1,5 +1,6 @@
1
- import { b as AuditEntry, a as ApprovalInstance } from './instance-Dd1jQizG.js';
1
+ import { b as AuditEntry, a as ApprovalInstance } from './instance-Cu6-qPxs.js';
2
2
 
3
+ /** Secondary write sink for audit entries, alongside the primary storage adapter. */
3
4
  interface IAuditAdapter {
4
5
  /**
5
6
  * Called after every state-mutating operation, in addition to the primary storage adapter.
@@ -1,4 +1,4 @@
1
- import { a as ApprovalInstance, d as ApprovalLevelInstance } from './instance-Dd1jQizG.js';
1
+ import { a as ApprovalInstance, d as ApprovalLevelInstance } from './instance-Cu6-qPxs.js';
2
2
 
3
3
  interface AuthorizationContext {
4
4
  /** The engine method the actor is attempting to call. */
@@ -1,4 +1,4 @@
1
- import { a as ApprovalInstance, d as ApprovalLevelInstance } from './instance-Dd1jQizG.cjs';
1
+ import { a as ApprovalInstance, d as ApprovalLevelInstance } from './instance-Cu6-qPxs.cjs';
2
2
 
3
3
  interface AuthorizationContext {
4
4
  /** The engine method the actor is attempting to call. */
@@ -1,33 +1,43 @@
1
- import { a as ApprovalInstance, b as AuditEntry } from './instance-Dd1jQizG.js';
1
+ import { a as ApprovalInstance, b as AuditEntry } from './instance-Cu6-qPxs.js';
2
2
 
3
+ /** Common fields carried by every lifecycle event emitted for an approval instance. */
3
4
  interface ApprovalEvent {
5
+ /** The `ApprovalInstance.id` this event pertains to. */
4
6
  instanceId: string;
7
+ /** The id of the business document the instance was raised against. */
5
8
  documentId: string;
9
+ /** The document type, matching the template used to raise the instance. */
6
10
  documentType: string;
11
+ /** When the event occurred. */
7
12
  timestamp: Date;
8
13
  }
14
+ /** Emitted as `approval:submitted` when a new instance is raised. */
9
15
  interface SubmittedEvent extends ApprovalEvent {
10
16
  submittedBy: string;
11
17
  currentApprovers: string[];
12
18
  }
19
+ /** Emitted as `approval:approved` when an approver accepts a level. */
13
20
  interface ApprovedEvent extends ApprovalEvent {
14
21
  approverId: string;
15
22
  level: number;
16
23
  comment?: string;
17
24
  isFinal: boolean;
18
25
  }
26
+ /** Emitted as `approval:rejected` when an approver rejects a level. */
19
27
  interface RejectedEvent extends ApprovalEvent {
20
28
  approverId: string;
21
29
  level: number;
22
30
  reason: string;
23
31
  returnTo: 'originator' | 'previous' | null;
24
32
  }
33
+ /** Emitted as `approval:delegated` when an approver hands their decision to someone else. */
25
34
  interface DelegatedEvent extends ApprovalEvent {
26
35
  fromApprover: string;
27
36
  toApprover: string;
28
37
  level: number;
29
38
  reason: string;
30
39
  }
40
+ /** Emitted as `approval:reassigned` when an admin moves a level to a different approver. */
31
41
  interface ReassignedEvent extends ApprovalEvent {
32
42
  reassignedBy: string;
33
43
  fromApprover: string;
@@ -35,30 +45,37 @@ interface ReassignedEvent extends ApprovalEvent {
35
45
  level: number;
36
46
  reason: string;
37
47
  }
48
+ /** Emitted as `approval:escalated` when a level's SLA rung hands off to a new approver. */
38
49
  interface EscalatedEvent extends ApprovalEvent {
39
50
  level: number;
40
51
  escalatedTo: string;
41
52
  }
53
+ /** Emitted as `approval:cancelled` when the instance is withdrawn before completion. */
42
54
  interface CancelledEvent extends ApprovalEvent {
43
55
  cancelledBy: string;
44
56
  reason: string;
45
57
  }
58
+ /** Emitted as `approval:level_advanced` when the chain moves to its next open level. */
46
59
  interface LevelAdvancedEvent extends ApprovalEvent {
47
60
  fromLevel: number;
48
61
  toLevel: number;
49
62
  newApprovers: string[];
50
63
  }
64
+ /** Emitted as `approval:resubmitted` when a rejected instance is raised again. */
51
65
  interface ResubmittedEvent extends ApprovalEvent {
52
66
  resubmittedBy: string;
53
67
  originalInstanceId: string;
54
68
  }
69
+ /** Emitted as `approval:overridden` when an admin force-approves past the normal chain. */
55
70
  interface OverriddenEvent extends ApprovalEvent {
56
71
  overriddenBy: string;
57
72
  justification: string;
58
73
  }
74
+ /** Emitted as `approval:expired` when the instance's deadline passes unresolved. */
59
75
  interface ExpiredEvent extends ApprovalEvent {
60
76
  deadlineAction: 'cancel' | 'reject';
61
77
  }
78
+ /** Emitted as `approval:sla_breached` when a level's deadline passes without expiring the instance. */
62
79
  interface SlaBreachedEvent extends ApprovalEvent {
63
80
  slaDeadlineAt: Date;
64
81
  }
@@ -1,33 +1,43 @@
1
- import { a as ApprovalInstance, b as AuditEntry } from './instance-Dd1jQizG.cjs';
1
+ import { a as ApprovalInstance, b as AuditEntry } from './instance-Cu6-qPxs.cjs';
2
2
 
3
+ /** Common fields carried by every lifecycle event emitted for an approval instance. */
3
4
  interface ApprovalEvent {
5
+ /** The `ApprovalInstance.id` this event pertains to. */
4
6
  instanceId: string;
7
+ /** The id of the business document the instance was raised against. */
5
8
  documentId: string;
9
+ /** The document type, matching the template used to raise the instance. */
6
10
  documentType: string;
11
+ /** When the event occurred. */
7
12
  timestamp: Date;
8
13
  }
14
+ /** Emitted as `approval:submitted` when a new instance is raised. */
9
15
  interface SubmittedEvent extends ApprovalEvent {
10
16
  submittedBy: string;
11
17
  currentApprovers: string[];
12
18
  }
19
+ /** Emitted as `approval:approved` when an approver accepts a level. */
13
20
  interface ApprovedEvent extends ApprovalEvent {
14
21
  approverId: string;
15
22
  level: number;
16
23
  comment?: string;
17
24
  isFinal: boolean;
18
25
  }
26
+ /** Emitted as `approval:rejected` when an approver rejects a level. */
19
27
  interface RejectedEvent extends ApprovalEvent {
20
28
  approverId: string;
21
29
  level: number;
22
30
  reason: string;
23
31
  returnTo: 'originator' | 'previous' | null;
24
32
  }
33
+ /** Emitted as `approval:delegated` when an approver hands their decision to someone else. */
25
34
  interface DelegatedEvent extends ApprovalEvent {
26
35
  fromApprover: string;
27
36
  toApprover: string;
28
37
  level: number;
29
38
  reason: string;
30
39
  }
40
+ /** Emitted as `approval:reassigned` when an admin moves a level to a different approver. */
31
41
  interface ReassignedEvent extends ApprovalEvent {
32
42
  reassignedBy: string;
33
43
  fromApprover: string;
@@ -35,30 +45,37 @@ interface ReassignedEvent extends ApprovalEvent {
35
45
  level: number;
36
46
  reason: string;
37
47
  }
48
+ /** Emitted as `approval:escalated` when a level's SLA rung hands off to a new approver. */
38
49
  interface EscalatedEvent extends ApprovalEvent {
39
50
  level: number;
40
51
  escalatedTo: string;
41
52
  }
53
+ /** Emitted as `approval:cancelled` when the instance is withdrawn before completion. */
42
54
  interface CancelledEvent extends ApprovalEvent {
43
55
  cancelledBy: string;
44
56
  reason: string;
45
57
  }
58
+ /** Emitted as `approval:level_advanced` when the chain moves to its next open level. */
46
59
  interface LevelAdvancedEvent extends ApprovalEvent {
47
60
  fromLevel: number;
48
61
  toLevel: number;
49
62
  newApprovers: string[];
50
63
  }
64
+ /** Emitted as `approval:resubmitted` when a rejected instance is raised again. */
51
65
  interface ResubmittedEvent extends ApprovalEvent {
52
66
  resubmittedBy: string;
53
67
  originalInstanceId: string;
54
68
  }
69
+ /** Emitted as `approval:overridden` when an admin force-approves past the normal chain. */
55
70
  interface OverriddenEvent extends ApprovalEvent {
56
71
  overriddenBy: string;
57
72
  justification: string;
58
73
  }
74
+ /** Emitted as `approval:expired` when the instance's deadline passes unresolved. */
59
75
  interface ExpiredEvent extends ApprovalEvent {
60
76
  deadlineAction: 'cancel' | 'reject';
61
77
  }
78
+ /** Emitted as `approval:sla_breached` when a level's deadline passes without expiring the instance. */
62
79
  interface SlaBreachedEvent extends ApprovalEvent {
63
80
  slaDeadlineAt: Date;
64
81
  }
@@ -1,5 +1,6 @@
1
- import { a as ApprovalInstance } from './instance-Dd1jQizG.js';
1
+ import { a as ApprovalInstance } from './instance-Cu6-qPxs.js';
2
2
 
3
+ /** Base class for all errors thrown by this library; carries a stable machine-readable `code`. */
3
4
  declare class ApprovalError extends Error {
4
5
  readonly code: string;
5
6
  constructor(message: string, code: string);
@@ -10,29 +11,40 @@ declare class ApprovalError extends Error {
10
11
  };
11
12
  toHttpStatus(): number;
12
13
  }
14
+ /** Thrown when a requested resource (instance, template, etc.) does not exist. */
13
15
  declare class ApprovalNotFoundError extends ApprovalError {
14
16
  constructor(resource: string, id: string);
15
17
  }
18
+ /** Thrown when an instance was modified by another process since it was last read. */
16
19
  declare class ApprovalConflictError extends ApprovalError {
17
20
  constructor(instanceId: string);
18
21
  }
22
+ /** Thrown when the caller is not authorized to perform the requested action. */
19
23
  declare class ApprovalForbiddenError extends ApprovalError {
20
24
  constructor(message: string);
21
25
  }
26
+ /** Thrown when input or configuration fails validation; `cause` may hold the originating error. */
22
27
  declare class ApprovalValidationError extends ApprovalError {
23
28
  readonly cause?: unknown | undefined;
24
29
  constructor(message: string, cause?: unknown | undefined);
25
30
  }
31
+ /** Thrown when a template lookup by name finds no registered template. */
26
32
  declare class ApprovalTemplateNotFoundError extends ApprovalError {
27
33
  constructor(name: string);
28
34
  }
29
35
 
36
+ /** The engine method a middleware hook is running around. */
30
37
  type EngineOperation = 'submit' | 'approve' | 'reject' | 'delegate' | 'reassign' | 'cancel' | 'updateData' | 'requestInfo' | 'provideInfo' | 'addAttachment' | 'removeAttachment' | 'addComment' | 'resubmit' | 'override';
38
+ /** Context passed to an {@link IOperationMiddleware} hook for one engine call. */
31
39
  interface OperationContext<T = unknown> {
32
40
  operation: EngineOperation;
41
+ /** The target instance's id, for operations that act on an existing instance. */
33
42
  instanceId?: string;
43
+ /** Id of the user or system performing the operation, when known. */
34
44
  actorId?: string;
45
+ /** The engine's configured tenant id (defaults to `'default'`). */
35
46
  tenantId: string;
47
+ /** The caller's own input for this operation, e.g. the submit payload or decision comment. */
36
48
  input: T;
37
49
  }
38
50
  interface IOperationMiddleware {
@@ -1,5 +1,6 @@
1
- import { a as ApprovalInstance } from './instance-Dd1jQizG.cjs';
1
+ import { a as ApprovalInstance } from './instance-Cu6-qPxs.cjs';
2
2
 
3
+ /** Base class for all errors thrown by this library; carries a stable machine-readable `code`. */
3
4
  declare class ApprovalError extends Error {
4
5
  readonly code: string;
5
6
  constructor(message: string, code: string);
@@ -10,29 +11,40 @@ declare class ApprovalError extends Error {
10
11
  };
11
12
  toHttpStatus(): number;
12
13
  }
14
+ /** Thrown when a requested resource (instance, template, etc.) does not exist. */
13
15
  declare class ApprovalNotFoundError extends ApprovalError {
14
16
  constructor(resource: string, id: string);
15
17
  }
18
+ /** Thrown when an instance was modified by another process since it was last read. */
16
19
  declare class ApprovalConflictError extends ApprovalError {
17
20
  constructor(instanceId: string);
18
21
  }
22
+ /** Thrown when the caller is not authorized to perform the requested action. */
19
23
  declare class ApprovalForbiddenError extends ApprovalError {
20
24
  constructor(message: string);
21
25
  }
26
+ /** Thrown when input or configuration fails validation; `cause` may hold the originating error. */
22
27
  declare class ApprovalValidationError extends ApprovalError {
23
28
  readonly cause?: unknown | undefined;
24
29
  constructor(message: string, cause?: unknown | undefined);
25
30
  }
31
+ /** Thrown when a template lookup by name finds no registered template. */
26
32
  declare class ApprovalTemplateNotFoundError extends ApprovalError {
27
33
  constructor(name: string);
28
34
  }
29
35
 
36
+ /** The engine method a middleware hook is running around. */
30
37
  type EngineOperation = 'submit' | 'approve' | 'reject' | 'delegate' | 'reassign' | 'cancel' | 'updateData' | 'requestInfo' | 'provideInfo' | 'addAttachment' | 'removeAttachment' | 'addComment' | 'resubmit' | 'override';
38
+ /** Context passed to an {@link IOperationMiddleware} hook for one engine call. */
31
39
  interface OperationContext<T = unknown> {
32
40
  operation: EngineOperation;
41
+ /** The target instance's id, for operations that act on an existing instance. */
33
42
  instanceId?: string;
43
+ /** Id of the user or system performing the operation, when known. */
34
44
  actorId?: string;
45
+ /** The engine's configured tenant id (defaults to `'default'`). */
35
46
  tenantId: string;
47
+ /** The caller's own input for this operation, e.g. the submit payload or decision comment. */
36
48
  input: T;
37
49
  }
38
50
  interface IOperationMiddleware {
@@ -1,3 +1,4 @@
1
+ /** Pluggable port for escalation-tick scheduling, so the engine can be backed by BullMQ, Temporal, a cron job, or an in-process timer. */
1
2
  interface ISchedulerAdapter {
2
3
  /**
3
4
  * Schedule a one-shot callback to run at the given date.
@@ -1,3 +1,4 @@
1
+ /** Pluggable port for escalation-tick scheduling, so the engine can be backed by BullMQ, Temporal, a cron job, or an in-process timer. */
1
2
  interface ISchedulerAdapter {
2
3
  /**
3
4
  * Schedule a one-shot callback to run at the given date.
@@ -1,9 +1,11 @@
1
- import { A as ApprovalTemplate, a as ApprovalInstance, f as ApprovalStatus, b as AuditEntry } from './instance-Dd1jQizG.cjs';
1
+ import { A as ApprovalTemplate, a as ApprovalInstance, f as ApprovalStatus, b as AuditEntry } from './instance-Cu6-qPxs.cjs';
2
2
 
3
+ /** Offset-based pagination request. */
3
4
  interface PaginationOpts {
4
5
  limit: number;
5
6
  offset: number;
6
7
  }
8
+ /** Offset-based pagination response, including the total matching count. */
7
9
  interface PaginatedResult<T> {
8
10
  items: T[];
9
11
  total: number;
@@ -14,10 +16,14 @@ interface CursorPaginationOpts {
14
16
  limit: number;
15
17
  direction?: 'forward' | 'backward';
16
18
  }
19
+ /** Cursor-based pagination response. */
17
20
  interface CursorPaginatedResult<T> {
18
21
  items: T[];
22
+ /** Pass as `cursor` with `direction: 'forward'` to fetch the next page, if any. */
19
23
  nextCursor?: string;
24
+ /** Pass as `cursor` with `direction: 'backward'` to fetch the previous page, if any. */
20
25
  prevCursor?: string;
26
+ /** Whether another page exists in the requested direction. */
21
27
  hasMore: boolean;
22
28
  }
23
29
  interface InstanceFilter {
@@ -38,6 +44,7 @@ interface InstanceFilter {
38
44
  */
39
45
  data?: Record<string, unknown>;
40
46
  }
47
+ /** The primary persistence contract `ApprovalEngine` reads and writes through — implement this to bring your own store. */
41
48
  interface IStorageAdapter {
42
49
  saveTemplate(template: ApprovalTemplate): Promise<void>;
43
50
  getTemplate(tenantId: string, name: string): Promise<ApprovalTemplate | null>;