hierarchical-approval 2.8.0 → 3.0.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 CHANGED
@@ -7,6 +7,90 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
  _Nothing yet._
9
9
 
10
+ ## [3.0.0] - 2026-09-04
11
+
12
+ Three defects found by auditing the interactions between features added across
13
+ 2.x, rather than by adding anything new.
14
+
15
+ ### Fixed — `updateData()` built condition-added levels wrong
16
+
17
+ - **A level a condition added during `updateData()` silently lost its `group`,
18
+ `subWorkflow`, `escalationAfterHours` and reminder configuration.** Levels
19
+ were constructed in two places — `submit()` and `recomputeFutureChain()` —
20
+ and the second copy had never been updated as fields were added across 1.0.0
21
+ to 2.6.0. The consequences were quiet and serious:
22
+
23
+ - a condition-added **parallel group ran sequentially**, one branch at a time,
24
+ because the levels came back without their `group`;
25
+ - a condition-added **sub-workflow level lost its binding**, then failed with
26
+ "No approvers resolved for this level" when reached — leaving an approval
27
+ that could never advance;
28
+ - hour-based escalation and reminders simply never fired.
29
+
30
+ A level whose configuration was unchanged was carried over intact, so this
31
+ only bit templates whose conditions *add* levels — and it bit them silently.
32
+
33
+ Both paths now go through one `buildLevelInstance()`, so a field cannot be
34
+ added to a level in one place and forgotten in the other. This is the same
35
+ failure the 1.6.0 Postgres column list had, in a different file.
36
+
37
+ ### BREAKING — a finished parent no longer leaves its sub-workflow children running
38
+
39
+ - **Cancelling or rejecting a parent left its child approval pending forever.**
40
+ The child kept notifying, kept escalating, and kept appearing in
41
+ `getWorkload()` — asking people to decide something whose outcome nobody would
42
+ ever read, since `propagateToParent()` ignores a parent that is no longer
43
+ pending. Children of a terminal parent are now cancelled, with the reason
44
+ naming the parent, and the child's own audit trail is left intact rather than
45
+ deleted.
46
+
47
+ **Behaviour change:** a child that used to stay open now reaches `cancelled`.
48
+ Anything counting open approvals, or waiting on a child whose parent has
49
+ ended, will see different numbers — correct ones.
50
+
51
+ - **`purgeInstances()` orphaned sub-workflow children.** It removed the parent
52
+ and left the child behind, holding a `parentInstanceId` pointing at a row that
53
+ no longer existed — unreachable, and invisible to a purge scoped by document
54
+ type, since a child usually has a different one. A purge now takes the whole
55
+ sub-workflow family together, parents first, deduplicated so a parent and
56
+ child sharing a terminal status are each reported once.
57
+
58
+ ## [2.9.0] - 2026-09-04
59
+
60
+ ### Added — `simulate()`
61
+
62
+ - **Dry-runs a document through a template against scripted decisions.**
63
+ `explainChain()` (2.7.0) says what the chain will be; nothing said what
64
+ happens *to* it. Answering "if the CFO rejects at level 3, does it go back to
65
+ the submitter or die?" meant submitting a real approval into real storage and
66
+ cleaning it up afterwards, or reasoning about the state machine by hand.
67
+
68
+ ```ts
69
+ await engine.simulate({
70
+ templateName: 'purchase-order',
71
+ data: { amount: 20000 },
72
+ submittedBy: 'buyer-1',
73
+ decisions: [{ approve: 'mgr-1' }, { reject: 'cfo', reason: 'over budget' }],
74
+ });
75
+ // { finalStatus, levels, transcript, unreachedLevels, incomplete }
76
+ ```
77
+
78
+ - **Nothing escapes the simulation.** It runs against a private in-memory store
79
+ seeded with a copy of the template, with the notification, audit and metrics
80
+ adapters and the authorization policy detached — so a dry run cannot page an
81
+ approver, write somebody's audit log, or move a counter.
82
+
83
+ - **Custom resolvers and approver types are copied across.** A simulation that
84
+ could not resolve the caller's own `dynamic` approvers would answer a
85
+ different question from the one asked.
86
+
87
+ - **A refused decision stops the run and is reported, not thrown** — wrong
88
+ approver, wrong level, already acted. The refusal is usually the answer the
89
+ caller was looking for, and throwing would discard the transcript that
90
+ explains how the run got there.
91
+
92
+ New exports: `SimulationResult`, `SimulationStep`, `SimulatedDecision`.
93
+
10
94
  ## [2.8.0] - 2026-09-04
11
95
 
12
96
  ### Added — comment threads
package/README.md CHANGED
@@ -495,6 +495,35 @@ the current approvers: a remark aimed at somebody should reach them, and one
495
495
  aimed at nobody should not page the whole level. Comments are still written to
496
496
  the audit trail, since the record of who said what belongs there.
497
497
 
498
+ ### Dry-running a workflow
499
+
500
+ `explainChain()` says what the chain will be; `simulate()` says what happens to
501
+ it — "if the CFO rejects at level 3, does it go back to the submitter or die?":
502
+
503
+ ```ts
504
+ const result = await engine.simulate({
505
+ templateName: 'purchase-order',
506
+ data: { amount: 20000 },
507
+ submittedBy: 'buyer-1',
508
+ decisions: [
509
+ { approve: 'mgr-1' },
510
+ { approve: 'fin-1' },
511
+ { reject: 'cfo', reason: 'over budget' },
512
+ ],
513
+ });
514
+ // { finalStatus: 'rejected', levels: [...], transcript: [...], unreachedLevels: [], incomplete: false }
515
+ ```
516
+
517
+ The run executes against a **private in-memory store** seeded with a copy of the
518
+ template, so your storage is untouched and no events reach your notification
519
+ adapters. Custom resolvers and approver types are copied across — a simulation
520
+ that couldn't resolve your own `dynamic` approvers would answer a different
521
+ question from the one you asked.
522
+
523
+ A refused decision (wrong approver, wrong level, already acted) stops the run
524
+ and appears in the transcript with its reason rather than throwing: the refusal
525
+ is usually the answer you were looking for.
526
+
498
527
  ### Why does this chain look like this?
499
528
 
500
529
  `previewApprovalChain()` answers *what* the chain will be. `explainChain()`
@@ -660,6 +689,13 @@ Collapsing the non-approved outcomes into one rejection is deliberate: a parent
660
689
  that treated a cancelled child as "carry on" would advance past a gate nobody
661
690
  cleared.
662
691
 
692
+ **A finished parent ends its children.** If a parent is cancelled or rejected
693
+ while a child is still running, the child is cancelled too, with the reason
694
+ naming the parent — otherwise it would keep asking people to decide something
695
+ whose outcome nobody will read. A child that already finished is left alone.
696
+ `purgeInstances()` likewise removes a whole sub-workflow family together, so a
697
+ child is never orphaned behind a deleted parent.
698
+
663
699
  Children link back via `parentInstanceId` and `parentLevel`, and the level
664
700
  records `childInstanceId`. Nesting is allowed up to five levels deep, and
665
701
  `validateTemplate()` rejects a template that would spawn itself. Emits
@@ -1,5 +1,5 @@
1
1
  import { I as IStorageAdapter, P as PaginationOpts, a as PaginatedResult, b as InstanceFilter, C as CursorPaginationOpts, c as CursorPaginatedResult } from './IStorageAdapter-C0qeZgs4.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, b as AuditEntry } from './instance-BvOyT00S.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-BvOyT00S.cjs';
3
3
  import { I as INotificationAdapter, b as ApprovalEventName, a as ApprovalEventMap } from './INotificationAdapter-DFKvGpOp.cjs';
4
4
  import { z } from 'zod';
5
5
  import { L as Logger } from './Logger-BplhlU7l.cjs';
@@ -347,6 +347,45 @@ interface ChainExplanation {
347
347
  skipped: ExplainedSkip[];
348
348
  rules: ExplainedRule[];
349
349
  }
350
+ /** One scripted decision in a {@link ApprovalEngine.simulate} run. */
351
+ type SimulatedDecision = {
352
+ approve: string;
353
+ level?: number;
354
+ comment?: string;
355
+ } | {
356
+ reject: string;
357
+ level?: number;
358
+ reason?: string;
359
+ };
360
+ /** What one scripted decision did. */
361
+ interface SimulationStep {
362
+ /** 1-based position in the script. */
363
+ step: number;
364
+ action: 'approve' | 'reject';
365
+ actorId: string;
366
+ /** The level the decision landed on, when it was accepted. */
367
+ level?: number;
368
+ /** Instance status after the decision. */
369
+ status: ApprovalStatus;
370
+ /** Why the decision was refused, when it was. The run stops at the first refusal. */
371
+ error?: string;
372
+ }
373
+ /** Outcome of a {@link ApprovalEngine.simulate} run. */
374
+ interface SimulationResult {
375
+ finalStatus: ApprovalStatus;
376
+ /** The chain the document would get, in order. */
377
+ levels: Array<{
378
+ level: number;
379
+ name: string;
380
+ status: LevelStatus;
381
+ approvers: string[];
382
+ }>;
383
+ transcript: SimulationStep[];
384
+ /** Levels never reached because the run ended first. */
385
+ unreachedLevels: number[];
386
+ /** True when the script ran out before the approval finished. */
387
+ incomplete: boolean;
388
+ }
350
389
  interface BulkResult {
351
390
  succeeded: ApprovalInstance[];
352
391
  failed: Array<{
@@ -756,6 +795,33 @@ declare class ApprovalEngine {
756
795
  * @param submittedBy - Submitter, used for approver resolution.
757
796
  */
758
797
  explainChain(templateName: string, data: Record<string, unknown>, submittedBy: string): Promise<ChainExplanation>;
798
+ /**
799
+ * Run a document through a template against scripted decisions, without
800
+ * persisting anything.
801
+ *
802
+ * `explainChain()` says what the chain will be; this says what happens to it —
803
+ * "if the CFO rejects at level 3, does it go back to the submitter or die?" —
804
+ * which previously meant submitting a real approval into a real store and
805
+ * cleaning it up afterwards, or reasoning about the state machine by hand.
806
+ *
807
+ * The run executes against a private in-memory store seeded with a copy of
808
+ * the template, so the caller's storage is untouched and no events reach the
809
+ * caller's notification adapters. Custom resolvers and approver types are
810
+ * copied across, because a simulation that could not resolve the caller's own
811
+ * `dynamic` approvers would answer a different question from the one asked.
812
+ *
813
+ * A refused decision — wrong approver, wrong level, already acted — stops the
814
+ * run and is reported in the transcript rather than thrown: the refusal is
815
+ * usually the answer the caller was looking for.
816
+ *
817
+ * @param opts - Template, document data, submitter and the decisions to play.
818
+ */
819
+ simulate(opts: {
820
+ templateName: string;
821
+ data: Record<string, unknown>;
822
+ submittedBy: string;
823
+ decisions?: SimulatedDecision[];
824
+ }): Promise<SimulationResult>;
759
825
  canApprove(instanceId: string, userId: string): Promise<CanApproveResult>;
760
826
  /** Emergency bypass — completes the instance as 'approved', skipping remaining levels. Requires template.allowOverride = true. */
761
827
  override(instanceId: string, raw: OverrideOptions, auditCtx?: AuditContext): Promise<ApprovalInstance>;
@@ -929,6 +995,19 @@ declare class ApprovalEngine {
929
995
  * `businessHoursCalendar` to have hours skip evenings and weekends.
930
996
  */
931
997
  private deadlineFromHours;
998
+ /**
999
+ * Build a level instance from its template config.
1000
+ *
1001
+ * The single place a level is constructed. It previously happened twice — in
1002
+ * `submit()` and again in `recomputeFutureChain()` — and the second copy was
1003
+ * missing `group`, `subWorkflowTemplate`, `escalationAfterHours` and the
1004
+ * reminder fields, so a level added by a condition during `updateData()` came
1005
+ * out silently different from the same level created at submit.
1006
+ *
1007
+ * @param cfg - The template's configuration for this level.
1008
+ * @param opts - `open` activates the level now, computing deadlines from `now`.
1009
+ */
1010
+ private buildLevelInstance;
932
1011
  /** Level deadline from whichever of days/hours the template configured. */
933
1012
  private levelEscalationDue;
934
1013
  /** First rung of a ladder, sorted by delay, or undefined when there is none. */
@@ -1032,6 +1111,27 @@ declare class ApprovalEngine {
1032
1111
  * about them, so a slow child template would surface as a spurious conflict
1033
1112
  * on the decision the user just made.
1034
1113
  */
1114
+ /**
1115
+ * An instance and every sub-workflow descendant beneath it, parents first.
1116
+ *
1117
+ * A child is only reachable through its parent's `childInstanceId`, so a
1118
+ * purge that removed the parent alone would strand the rest of the tree.
1119
+ * Depth is bounded by the same cap that limits spawning, and an already-seen
1120
+ * id is skipped so a corrupted link cannot loop.
1121
+ */
1122
+ private collectSubWorkflowFamily;
1123
+ /**
1124
+ * Cancel sub-workflow children whose parent has finished.
1125
+ *
1126
+ * A child outlives its parent otherwise: it stays pending, keeps notifying
1127
+ * and escalating, and keeps appearing in {@link getWorkload} — asking people
1128
+ * to decide something whose outcome nobody will ever read, because
1129
+ * {@link propagateToParent} ignores a parent that is no longer pending.
1130
+ *
1131
+ * Cancelling rather than deleting keeps the child's own audit trail intact:
1132
+ * the people who were asked, and why the request stopped, stay on the record.
1133
+ */
1134
+ private cancelOrphanedChildren;
1035
1135
  private afterDecision;
1036
1136
  private findNextLevel;
1037
1137
  private findPreviousLevel;
@@ -1043,4 +1143,4 @@ declare class ApprovalEngine {
1043
1143
  private runExternalAudit;
1044
1144
  }
1045
1145
 
1046
- export { type AddCommentOptions as A, type BulkResult as B, type CanApproveResult as C, type DelegateOptions as D, type EscalateOptions as E, type TemplateBundle as F, type TransferResult as G, type HealthResult as H, type IdGeneratorFn as I, businessHoursCalendar as J, defaultIdGenerator as K, toComparableNumber as L, validateConditionExpression as M, weekendCalendar as N, type OrgProvider as O, type PreviewChainLevel as P, type ReassignOptions as R, type SubmitOptions as S, TEMPLATE_BUNDLE_VERSION as T, 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 ApproverWorkload as f, type BusinessCalendar as g, type BusinessHoursCalendarOptions as h, type CancelOptions as i, type ChainExplanation as j, type ConditionOperatorFn as k, type CycleTimeStats as l, type ExplainedLevel as m, type ExplainedRule as n, type ExplainedSkip as o, type IdempotencyKeyFn as p, type ImportResult as q, type OutOfOfficeProvider as r, type OverrideOptions as s, type PreviewResult as t, type ProvideInfoOptions as u, type PurgeResult as v, type RejectOptions as w, type RequestInfoOptions as x, type ResubmitOptions as y, type RetryPolicy as z };
1146
+ export { type AddCommentOptions as A, type BulkResult as B, type CanApproveResult as C, type DelegateOptions as D, type EscalateOptions as E, type SimulationResult as F, type SimulationStep as G, type HealthResult as H, type IdGeneratorFn as I, type SubmitOptions as J, type TemplateBundle as K, type TransferResult as L, businessHoursCalendar as M, defaultIdGenerator as N, type OrgProvider as O, type PreviewChainLevel as P, toComparableNumber as Q, type ReassignOptions as R, type SimulatedDecision as S, TEMPLATE_BUNDLE_VERSION as T, type UpdateDataOptions as U, type ValidationResult as V, type WeekendCalendarOptions as W, validateConditionExpression as X, weekendCalendar as Y, ApprovalEngine as a, type ApprovalEngineOptions as b, type ApprovalStatistics as c, type ApproveOptions as d, type ApproverResolverFn as e, type ApproverWorkload as f, type BusinessCalendar as g, type BusinessHoursCalendarOptions as h, type CancelOptions as i, type ChainExplanation as j, type ConditionOperatorFn as k, type CycleTimeStats as l, type ExplainedLevel as m, type ExplainedRule as n, type ExplainedSkip as o, type IdempotencyKeyFn as p, type ImportResult as q, type OutOfOfficeProvider as r, type OverrideOptions as s, type PreviewResult as t, type ProvideInfoOptions as u, type PurgeResult as v, type RejectOptions as w, type RequestInfoOptions as x, type ResubmitOptions as y, type RetryPolicy as z };
@@ -1,5 +1,5 @@
1
1
  import { I as IStorageAdapter, P as PaginationOpts, a as PaginatedResult, b as InstanceFilter, C as CursorPaginationOpts, c as CursorPaginatedResult } from './IStorageAdapter-C2QxUwbX.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, b as AuditEntry } from './instance-BvOyT00S.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-BvOyT00S.js';
3
3
  import { I as INotificationAdapter, b as ApprovalEventName, a as ApprovalEventMap } from './INotificationAdapter-DMvA4R-c.js';
4
4
  import { z } from 'zod';
5
5
  import { L as Logger } from './Logger-BplhlU7l.js';
@@ -347,6 +347,45 @@ interface ChainExplanation {
347
347
  skipped: ExplainedSkip[];
348
348
  rules: ExplainedRule[];
349
349
  }
350
+ /** One scripted decision in a {@link ApprovalEngine.simulate} run. */
351
+ type SimulatedDecision = {
352
+ approve: string;
353
+ level?: number;
354
+ comment?: string;
355
+ } | {
356
+ reject: string;
357
+ level?: number;
358
+ reason?: string;
359
+ };
360
+ /** What one scripted decision did. */
361
+ interface SimulationStep {
362
+ /** 1-based position in the script. */
363
+ step: number;
364
+ action: 'approve' | 'reject';
365
+ actorId: string;
366
+ /** The level the decision landed on, when it was accepted. */
367
+ level?: number;
368
+ /** Instance status after the decision. */
369
+ status: ApprovalStatus;
370
+ /** Why the decision was refused, when it was. The run stops at the first refusal. */
371
+ error?: string;
372
+ }
373
+ /** Outcome of a {@link ApprovalEngine.simulate} run. */
374
+ interface SimulationResult {
375
+ finalStatus: ApprovalStatus;
376
+ /** The chain the document would get, in order. */
377
+ levels: Array<{
378
+ level: number;
379
+ name: string;
380
+ status: LevelStatus;
381
+ approvers: string[];
382
+ }>;
383
+ transcript: SimulationStep[];
384
+ /** Levels never reached because the run ended first. */
385
+ unreachedLevels: number[];
386
+ /** True when the script ran out before the approval finished. */
387
+ incomplete: boolean;
388
+ }
350
389
  interface BulkResult {
351
390
  succeeded: ApprovalInstance[];
352
391
  failed: Array<{
@@ -756,6 +795,33 @@ declare class ApprovalEngine {
756
795
  * @param submittedBy - Submitter, used for approver resolution.
757
796
  */
758
797
  explainChain(templateName: string, data: Record<string, unknown>, submittedBy: string): Promise<ChainExplanation>;
798
+ /**
799
+ * Run a document through a template against scripted decisions, without
800
+ * persisting anything.
801
+ *
802
+ * `explainChain()` says what the chain will be; this says what happens to it —
803
+ * "if the CFO rejects at level 3, does it go back to the submitter or die?" —
804
+ * which previously meant submitting a real approval into a real store and
805
+ * cleaning it up afterwards, or reasoning about the state machine by hand.
806
+ *
807
+ * The run executes against a private in-memory store seeded with a copy of
808
+ * the template, so the caller's storage is untouched and no events reach the
809
+ * caller's notification adapters. Custom resolvers and approver types are
810
+ * copied across, because a simulation that could not resolve the caller's own
811
+ * `dynamic` approvers would answer a different question from the one asked.
812
+ *
813
+ * A refused decision — wrong approver, wrong level, already acted — stops the
814
+ * run and is reported in the transcript rather than thrown: the refusal is
815
+ * usually the answer the caller was looking for.
816
+ *
817
+ * @param opts - Template, document data, submitter and the decisions to play.
818
+ */
819
+ simulate(opts: {
820
+ templateName: string;
821
+ data: Record<string, unknown>;
822
+ submittedBy: string;
823
+ decisions?: SimulatedDecision[];
824
+ }): Promise<SimulationResult>;
759
825
  canApprove(instanceId: string, userId: string): Promise<CanApproveResult>;
760
826
  /** Emergency bypass — completes the instance as 'approved', skipping remaining levels. Requires template.allowOverride = true. */
761
827
  override(instanceId: string, raw: OverrideOptions, auditCtx?: AuditContext): Promise<ApprovalInstance>;
@@ -929,6 +995,19 @@ declare class ApprovalEngine {
929
995
  * `businessHoursCalendar` to have hours skip evenings and weekends.
930
996
  */
931
997
  private deadlineFromHours;
998
+ /**
999
+ * Build a level instance from its template config.
1000
+ *
1001
+ * The single place a level is constructed. It previously happened twice — in
1002
+ * `submit()` and again in `recomputeFutureChain()` — and the second copy was
1003
+ * missing `group`, `subWorkflowTemplate`, `escalationAfterHours` and the
1004
+ * reminder fields, so a level added by a condition during `updateData()` came
1005
+ * out silently different from the same level created at submit.
1006
+ *
1007
+ * @param cfg - The template's configuration for this level.
1008
+ * @param opts - `open` activates the level now, computing deadlines from `now`.
1009
+ */
1010
+ private buildLevelInstance;
932
1011
  /** Level deadline from whichever of days/hours the template configured. */
933
1012
  private levelEscalationDue;
934
1013
  /** First rung of a ladder, sorted by delay, or undefined when there is none. */
@@ -1032,6 +1111,27 @@ declare class ApprovalEngine {
1032
1111
  * about them, so a slow child template would surface as a spurious conflict
1033
1112
  * on the decision the user just made.
1034
1113
  */
1114
+ /**
1115
+ * An instance and every sub-workflow descendant beneath it, parents first.
1116
+ *
1117
+ * A child is only reachable through its parent's `childInstanceId`, so a
1118
+ * purge that removed the parent alone would strand the rest of the tree.
1119
+ * Depth is bounded by the same cap that limits spawning, and an already-seen
1120
+ * id is skipped so a corrupted link cannot loop.
1121
+ */
1122
+ private collectSubWorkflowFamily;
1123
+ /**
1124
+ * Cancel sub-workflow children whose parent has finished.
1125
+ *
1126
+ * A child outlives its parent otherwise: it stays pending, keeps notifying
1127
+ * and escalating, and keeps appearing in {@link getWorkload} — asking people
1128
+ * to decide something whose outcome nobody will ever read, because
1129
+ * {@link propagateToParent} ignores a parent that is no longer pending.
1130
+ *
1131
+ * Cancelling rather than deleting keeps the child's own audit trail intact:
1132
+ * the people who were asked, and why the request stopped, stay on the record.
1133
+ */
1134
+ private cancelOrphanedChildren;
1035
1135
  private afterDecision;
1036
1136
  private findNextLevel;
1037
1137
  private findPreviousLevel;
@@ -1043,4 +1143,4 @@ declare class ApprovalEngine {
1043
1143
  private runExternalAudit;
1044
1144
  }
1045
1145
 
1046
- export { type AddCommentOptions as A, type BulkResult as B, type CanApproveResult as C, type DelegateOptions as D, type EscalateOptions as E, type TemplateBundle as F, type TransferResult as G, type HealthResult as H, type IdGeneratorFn as I, businessHoursCalendar as J, defaultIdGenerator as K, toComparableNumber as L, validateConditionExpression as M, weekendCalendar as N, type OrgProvider as O, type PreviewChainLevel as P, type ReassignOptions as R, type SubmitOptions as S, TEMPLATE_BUNDLE_VERSION as T, 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 ApproverWorkload as f, type BusinessCalendar as g, type BusinessHoursCalendarOptions as h, type CancelOptions as i, type ChainExplanation as j, type ConditionOperatorFn as k, type CycleTimeStats as l, type ExplainedLevel as m, type ExplainedRule as n, type ExplainedSkip as o, type IdempotencyKeyFn as p, type ImportResult as q, type OutOfOfficeProvider as r, type OverrideOptions as s, type PreviewResult as t, type ProvideInfoOptions as u, type PurgeResult as v, type RejectOptions as w, type RequestInfoOptions as x, type ResubmitOptions as y, type RetryPolicy as z };
1146
+ export { type AddCommentOptions as A, type BulkResult as B, type CanApproveResult as C, type DelegateOptions as D, type EscalateOptions as E, type SimulationResult as F, type SimulationStep as G, type HealthResult as H, type IdGeneratorFn as I, type SubmitOptions as J, type TemplateBundle as K, type TransferResult as L, businessHoursCalendar as M, defaultIdGenerator as N, type OrgProvider as O, type PreviewChainLevel as P, toComparableNumber as Q, type ReassignOptions as R, type SimulatedDecision as S, TEMPLATE_BUNDLE_VERSION as T, type UpdateDataOptions as U, type ValidationResult as V, type WeekendCalendarOptions as W, validateConditionExpression as X, weekendCalendar as Y, ApprovalEngine as a, type ApprovalEngineOptions as b, type ApprovalStatistics as c, type ApproveOptions as d, type ApproverResolverFn as e, type ApproverWorkload as f, type BusinessCalendar as g, type BusinessHoursCalendarOptions as h, type CancelOptions as i, type ChainExplanation as j, type ConditionOperatorFn as k, type CycleTimeStats as l, type ExplainedLevel as m, type ExplainedRule as n, type ExplainedSkip as o, type IdempotencyKeyFn as p, type ImportResult as q, type OutOfOfficeProvider as r, type OverrideOptions as s, type PreviewResult as t, type ProvideInfoOptions as u, type PurgeResult as v, type RejectOptions as w, type RequestInfoOptions as x, type ResubmitOptions as y, type RetryPolicy as z };