hierarchical-approval 2.3.0 → 2.5.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.
Files changed (53) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/README.md +27 -0
  3. package/dist/{ApprovalEngine-Ci9urTDI.d.ts → ApprovalEngine-BHWls8-z.d.ts} +59 -7
  4. package/dist/{ApprovalEngine-C1dUPnLM.d.cts → ApprovalEngine-CW7Uu1bV.d.cts} +59 -7
  5. package/dist/{IAuditAdapter-C4OASS6u.d.ts → IAuditAdapter-CMCirvY-.d.ts} +1 -1
  6. package/dist/{IAuditAdapter-BHVKMMv6.d.cts → IAuditAdapter-Dwx8ZP4J.d.cts} +1 -1
  7. package/dist/{IAuthorizationPolicy-CtLkwQ8I.d.cts → IAuthorizationPolicy-B3vaV69v.d.cts} +1 -1
  8. package/dist/{IAuthorizationPolicy-BA_m2Dg9.d.ts → IAuthorizationPolicy-BryQIKko.d.ts} +1 -1
  9. package/dist/{INotificationAdapter-JJAiMyMd.d.cts → INotificationAdapter-AwbhZEqz.d.cts} +1 -1
  10. package/dist/{INotificationAdapter-BdgfUrIn.d.ts → INotificationAdapter-BBq2czpO.d.ts} +1 -1
  11. package/dist/{IOperationMiddleware-D0ksiFM3.d.cts → IOperationMiddleware-3J-_NSGq.d.cts} +1 -1
  12. package/dist/{IOperationMiddleware-BGYrAqep.d.ts → IOperationMiddleware-CqzFklMn.d.ts} +1 -1
  13. package/dist/{IStorageAdapter-BU3sau5W.d.ts → IStorageAdapter-Dw2xXP9B.d.ts} +1 -1
  14. package/dist/{IStorageAdapter-DdHO4Rf1.d.cts → IStorageAdapter-Pq9J60xv.d.cts} +1 -1
  15. package/dist/adapters/MemoryAdapter.d.cts +2 -2
  16. package/dist/adapters/MemoryAdapter.d.ts +2 -2
  17. package/dist/adapters/PostgresAdapter.d.cts +2 -2
  18. package/dist/adapters/PostgresAdapter.d.ts +2 -2
  19. package/dist/index.cjs +117 -6
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +8 -8
  22. package/dist/index.d.ts +8 -8
  23. package/dist/index.js +117 -7
  24. package/dist/index.js.map +1 -1
  25. package/dist/{instance-DUJY_Axf.d.cts → instance-BO-i9-nq.d.cts} +13 -0
  26. package/dist/{instance-DUJY_Axf.d.ts → instance-BO-i9-nq.d.ts} +13 -0
  27. package/dist/nestjs.cjs +49 -6
  28. package/dist/nestjs.cjs.map +1 -1
  29. package/dist/nestjs.d.cts +7 -7
  30. package/dist/nestjs.d.ts +7 -7
  31. package/dist/nestjs.js +49 -6
  32. package/dist/nestjs.js.map +1 -1
  33. package/dist/plugins/audit.d.cts +2 -2
  34. package/dist/plugins/audit.d.ts +2 -2
  35. package/dist/plugins/notify.cjs +105 -9
  36. package/dist/plugins/notify.cjs.map +1 -1
  37. package/dist/plugins/notify.d.cts +91 -3
  38. package/dist/plugins/notify.d.ts +91 -3
  39. package/dist/plugins/notify.js +105 -10
  40. package/dist/plugins/notify.js.map +1 -1
  41. package/dist/plugins/resilience.d.cts +3 -3
  42. package/dist/plugins/resilience.d.ts +3 -3
  43. package/dist/plugins/tracing.d.cts +2 -2
  44. package/dist/plugins/tracing.d.ts +2 -2
  45. package/dist/plugins/webhook.d.cts +2 -2
  46. package/dist/plugins/webhook.d.ts +2 -2
  47. package/dist/testing.cjs +49 -6
  48. package/dist/testing.cjs.map +1 -1
  49. package/dist/testing.d.cts +7 -7
  50. package/dist/testing.d.ts +7 -7
  51. package/dist/testing.js +49 -6
  52. package/dist/testing.js.map +1 -1
  53. package/package.json +1 -1
package/dist/nestjs.d.cts CHANGED
@@ -1,16 +1,16 @@
1
1
  import { OnModuleDestroy, DynamicModule, ModuleMetadata, InjectionToken, OptionalFactoryDependency, Inject } from '@nestjs/common';
2
- import { a as ApprovalEngine, b as ApprovalEngineOptions } from './ApprovalEngine-C1dUPnLM.cjs';
3
- import './IStorageAdapter-DdHO4Rf1.cjs';
4
- import './instance-DUJY_Axf.cjs';
5
- import './INotificationAdapter-JJAiMyMd.cjs';
2
+ import { a as ApprovalEngine, b as ApprovalEngineOptions } from './ApprovalEngine-CW7Uu1bV.cjs';
3
+ import './IStorageAdapter-Pq9J60xv.cjs';
4
+ import './instance-BO-i9-nq.cjs';
5
+ import './INotificationAdapter-AwbhZEqz.cjs';
6
6
  import 'zod';
7
7
  import './Logger-BplhlU7l.cjs';
8
8
  import './Clock-3FnOczFJ.cjs';
9
- import './IOperationMiddleware-D0ksiFM3.cjs';
10
- import './IAuditAdapter-BHVKMMv6.cjs';
9
+ import './IOperationMiddleware-3J-_NSGq.cjs';
10
+ import './IAuditAdapter-Dwx8ZP4J.cjs';
11
11
  import './IMetricsAdapter-DWq8IFaf.cjs';
12
12
  import './ISchedulerAdapter-DKv_QjVN.cjs';
13
- import './IAuthorizationPolicy-CtLkwQ8I.cjs';
13
+ import './IAuthorizationPolicy-B3vaV69v.cjs';
14
14
 
15
15
  /** Options for {@link HierarchicalApprovalModule.forRoot}. */
16
16
  interface HierarchicalApprovalModuleOptions extends ApprovalEngineOptions {
package/dist/nestjs.d.ts CHANGED
@@ -1,16 +1,16 @@
1
1
  import { OnModuleDestroy, DynamicModule, ModuleMetadata, InjectionToken, OptionalFactoryDependency, Inject } from '@nestjs/common';
2
- import { a as ApprovalEngine, b as ApprovalEngineOptions } from './ApprovalEngine-Ci9urTDI.js';
3
- import './IStorageAdapter-BU3sau5W.js';
4
- import './instance-DUJY_Axf.js';
5
- import './INotificationAdapter-BdgfUrIn.js';
2
+ import { a as ApprovalEngine, b as ApprovalEngineOptions } from './ApprovalEngine-BHWls8-z.js';
3
+ import './IStorageAdapter-Dw2xXP9B.js';
4
+ import './instance-BO-i9-nq.js';
5
+ import './INotificationAdapter-BBq2czpO.js';
6
6
  import 'zod';
7
7
  import './Logger-BplhlU7l.js';
8
8
  import './Clock-3FnOczFJ.js';
9
- import './IOperationMiddleware-BGYrAqep.js';
10
- import './IAuditAdapter-C4OASS6u.js';
9
+ import './IOperationMiddleware-CqzFklMn.js';
10
+ import './IAuditAdapter-CMCirvY-.js';
11
11
  import './IMetricsAdapter-DWq8IFaf.js';
12
12
  import './ISchedulerAdapter-DKv_QjVN.js';
13
- import './IAuthorizationPolicy-BA_m2Dg9.js';
13
+ import './IAuthorizationPolicy-BryQIKko.js';
14
14
 
15
15
  /** Options for {@link HierarchicalApprovalModule.forRoot}. */
16
16
  interface HierarchicalApprovalModuleOptions extends ApprovalEngineOptions {
package/dist/nestjs.js CHANGED
@@ -1066,6 +1066,18 @@ var ApprovalEngine = class _ApprovalEngine {
1066
1066
  message: `Level ${l.level} sets reminderEveryDays without reminderAfterDays, so no reminder would ever be sent.`
1067
1067
  });
1068
1068
  }
1069
+ if (l.escalationAfterHours !== void 0 && l.escalationAfterHours <= 0) {
1070
+ errors.push({
1071
+ field: `levels[${i}].escalationAfterHours`,
1072
+ message: `Level ${l.level} escalationAfterHours must be a positive number.`
1073
+ });
1074
+ }
1075
+ if (l.escalationAfterDays !== void 0 && l.escalationAfterHours !== void 0) {
1076
+ errors.push({
1077
+ field: `levels[${i}].escalationAfterHours`,
1078
+ message: `Level ${l.level} sets both escalationAfterDays and escalationAfterHours; pick one so the deadline is unambiguous.`
1079
+ });
1080
+ }
1069
1081
  if (l.escalationAfterDays !== void 0 && l.escalationAfterDays <= 0) {
1070
1082
  errors.push({
1071
1083
  field: `levels[${i}].escalationAfterDays`,
@@ -1130,6 +1142,18 @@ var ApprovalEngine = class _ApprovalEngine {
1130
1142
  }
1131
1143
  });
1132
1144
  }
1145
+ if (config.slaDeadlineDays !== void 0 && config.slaDeadlineHours !== void 0) {
1146
+ errors.push({
1147
+ field: "slaDeadlineHours",
1148
+ message: "Template sets both slaDeadlineDays and slaDeadlineHours; pick one so the SLA is unambiguous."
1149
+ });
1150
+ }
1151
+ if (config.slaDeadlineHours !== void 0 && config.slaDeadlineHours <= 0) {
1152
+ errors.push({
1153
+ field: "slaDeadlineHours",
1154
+ message: "slaDeadlineHours must be a positive number."
1155
+ });
1156
+ }
1133
1157
  if (config.conditions) {
1134
1158
  config.conditions.forEach((rule, ruleIdx) => {
1135
1159
  errors.push(...validateConditionExpression(rule.when, `conditions[${ruleIdx}].when`));
@@ -1243,7 +1267,8 @@ var ApprovalEngine = class _ApprovalEngine {
1243
1267
  threshold: cfg.threshold,
1244
1268
  weights: cfg.weights,
1245
1269
  escalationAfterDays: cfg.escalationAfterDays,
1246
- escalationDueAt: inFirstGroup && cfg.escalationAfterDays ? this.deadlineFrom(now, cfg.escalationAfterDays) : void 0,
1270
+ escalationAfterHours: cfg.escalationAfterHours,
1271
+ escalationDueAt: inFirstGroup ? this.levelEscalationDue(now, cfg) : void 0,
1247
1272
  subWorkflowTemplate: cfg.subWorkflow?.templateName,
1248
1273
  reminderAfterDays: cfg.reminderAfterDays,
1249
1274
  reminderEveryDays: cfg.reminderEveryDays,
@@ -1273,7 +1298,7 @@ var ApprovalEngine = class _ApprovalEngine {
1273
1298
  timestamp: now,
1274
1299
  ...auditCtx
1275
1300
  };
1276
- const slaDeadlineAt = template.slaDeadlineDays ? this.deadlineFrom(now, template.slaDeadlineDays) : void 0;
1301
+ const slaDeadlineAt = template.slaDeadlineHours ? this.deadlineFromHours(now, template.slaDeadlineHours) : template.slaDeadlineDays ? this.deadlineFrom(now, template.slaDeadlineDays) : void 0;
1277
1302
  const instance = {
1278
1303
  id: instanceId,
1279
1304
  tenantId: this.tenantId,
@@ -1301,6 +1326,7 @@ var ApprovalEngine = class _ApprovalEngine {
1301
1326
  templateSnapshot: {
1302
1327
  escalation: template.escalation,
1303
1328
  slaDeadlineDays: template.slaDeadlineDays,
1329
+ slaDeadlineHours: template.slaDeadlineHours,
1304
1330
  allowOverride: template.allowOverride
1305
1331
  }
1306
1332
  };
@@ -2572,7 +2598,7 @@ var ApprovalEngine = class _ApprovalEngine {
2572
2598
  reason: opts.reason,
2573
2599
  ...auditCtx
2574
2600
  };
2575
- const slaDeadlineAt = template.slaDeadlineDays ? this.deadlineFrom(now, template.slaDeadlineDays) : void 0;
2601
+ const slaDeadlineAt = template.slaDeadlineHours ? this.deadlineFromHours(now, template.slaDeadlineHours) : template.slaDeadlineDays ? this.deadlineFrom(now, template.slaDeadlineDays) : void 0;
2576
2602
  const newInstance = {
2577
2603
  id: newInstanceId,
2578
2604
  tenantId: this.tenantId,
@@ -2595,6 +2621,7 @@ var ApprovalEngine = class _ApprovalEngine {
2595
2621
  templateSnapshot: {
2596
2622
  escalation: template.escalation,
2597
2623
  slaDeadlineDays: template.slaDeadlineDays,
2624
+ slaDeadlineHours: template.slaDeadlineHours,
2598
2625
  allowOverride: template.allowOverride
2599
2626
  }
2600
2627
  };
@@ -3537,6 +3564,24 @@ var ApprovalEngine = class _ApprovalEngine {
3537
3564
  deadlineFrom(from, days) {
3538
3565
  return this.calendar ? this.calendar.addBusinessDays(from, days) : new Date(from.getTime() + days * 864e5);
3539
3566
  }
3567
+ /**
3568
+ * Resolve an hour-based deadline.
3569
+ *
3570
+ * A calendar that only knows whole days — `weekendCalendar`, say — has no
3571
+ * `addBusinessHours`, and this falls back to elapsed clock time rather than
3572
+ * quietly pretending the calendar was applied. Configure
3573
+ * `businessHoursCalendar` to have hours skip evenings and weekends.
3574
+ */
3575
+ deadlineFromHours(from, hours) {
3576
+ const addHours = this.calendar?.addBusinessHours?.bind(this.calendar);
3577
+ return addHours ? addHours(from, hours) : new Date(from.getTime() + hours * 36e5);
3578
+ }
3579
+ /** Level deadline from whichever of days/hours the template configured. */
3580
+ levelEscalationDue(from, level) {
3581
+ if (level.escalationAfterHours) return this.deadlineFromHours(from, level.escalationAfterHours);
3582
+ if (level.escalationAfterDays) return this.deadlineFrom(from, level.escalationAfterDays);
3583
+ return void 0;
3584
+ }
3540
3585
  async requireInstance(id) {
3541
3586
  const instance = await this.opts.adapter.getInstance(this.tenantId, id);
3542
3587
  if (!instance) throw new ApprovalNotFoundError("Instance", id);
@@ -3642,9 +3687,7 @@ var ApprovalEngine = class _ApprovalEngine {
3642
3687
  now
3643
3688
  );
3644
3689
  }
3645
- if (lvl.escalationAfterDays) {
3646
- lvl.escalationDueAt = this.deadlineFrom(now, lvl.escalationAfterDays);
3647
- }
3690
+ lvl.escalationDueAt = this.levelEscalationDue(now, lvl);
3648
3691
  this.scheduleReminder(lvl, now);
3649
3692
  lvl.status = "pending";
3650
3693
  }