hierarchical-approval 2.1.0 → 2.2.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 +37 -0
- package/README.md +26 -0
- package/dist/{ApprovalEngine-CJwnpnpL.d.ts → ApprovalEngine-B3ChZxS7.d.ts} +57 -1
- package/dist/{ApprovalEngine-DqRIadYg.d.cts → ApprovalEngine-CbFBAMlO.d.cts} +57 -1
- package/dist/index.cjs +114 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +114 -1
- package/dist/index.js.map +1 -1
- package/dist/nestjs.cjs +113 -0
- package/dist/nestjs.cjs.map +1 -1
- package/dist/nestjs.d.cts +1 -1
- package/dist/nestjs.d.ts +1 -1
- package/dist/nestjs.js +113 -0
- package/dist/nestjs.js.map +1 -1
- package/dist/testing.cjs +113 -0
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +113 -0
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,43 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
7
7
|
|
|
8
8
|
_Nothing yet._
|
|
9
9
|
|
|
10
|
+
## [2.2.0] - 2026-09-04
|
|
11
|
+
|
|
12
|
+
### Added — template export / import
|
|
13
|
+
|
|
14
|
+
- **`exportTemplates()` and `importTemplates()` move approval configuration
|
|
15
|
+
between environments.** Templates are authored in a sandbox, reviewed, then
|
|
16
|
+
promoted — but the only way to carry them across was to read `listTemplates()`
|
|
17
|
+
and re-post the rows, which dragged each environment's own `id`, `tenantId`
|
|
18
|
+
and version lineage along. Those either collided on arrival or silently
|
|
19
|
+
claimed a history the target never had.
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
const bundle = await sandbox.exportTemplates(['PO', 'INV']);
|
|
23
|
+
await production.importTemplates(bundle, { mode: 'upsert', dryRun: true });
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
A bundle is plain JSON, version-stamped, and carries no environment-specific
|
|
27
|
+
fields — they are stripped, not blanked, so a round trip cannot reintroduce a
|
|
28
|
+
stale id. The target assigns its own identity.
|
|
29
|
+
|
|
30
|
+
- **`mode: 'create'`** (default) skips templates that already exist;
|
|
31
|
+
**`'upsert'`** updates them, bumping the version and recording
|
|
32
|
+
`previousVersionId` exactly as `updateTemplate()` does. `dryRun` reports
|
|
33
|
+
without writing.
|
|
34
|
+
|
|
35
|
+
- **Every template is validated before any is written.** A half-applied bundle
|
|
36
|
+
is worse than one rejected outright: the tenant ends up matching neither
|
|
37
|
+
environment and the operator cannot tell which half landed. Validation
|
|
38
|
+
failures reject the whole bundle and name the offending template; storage
|
|
39
|
+
errors during the write phase are still reported per template, since those can
|
|
40
|
+
occur after validation passes.
|
|
41
|
+
|
|
42
|
+
Import also rejects an unsupported `bundleVersion`, an empty bundle, and
|
|
43
|
+
duplicate names within one bundle.
|
|
44
|
+
|
|
45
|
+
New exports: `TemplateBundle`, `ImportResult`, `TEMPLATE_BUNDLE_VERSION`.
|
|
46
|
+
|
|
10
47
|
## [2.1.0] - 2026-09-04
|
|
11
48
|
|
|
12
49
|
### Added — sub-workflows
|
package/README.md
CHANGED
|
@@ -468,6 +468,32 @@ The sweep is **not atomic**: it reports per-instance failures rather than rollin
|
|
|
468
468
|
back. A partial transfer is the useful outcome — the approvals that can move
|
|
469
469
|
should move, and the ones that cannot are named so a human can look at them.
|
|
470
470
|
|
|
471
|
+
### Promoting templates between environments
|
|
472
|
+
|
|
473
|
+
Approval configuration is authored somewhere safe, reviewed, then promoted.
|
|
474
|
+
`exportTemplates()` produces a portable bundle and `importTemplates()` applies
|
|
475
|
+
it:
|
|
476
|
+
|
|
477
|
+
```ts
|
|
478
|
+
const bundle = await sandbox.exportTemplates(['PO', 'INV']); // omit names for all
|
|
479
|
+
const result = await production.importTemplates(bundle, { mode: 'upsert', dryRun: true });
|
|
480
|
+
// { created: [], updated: ['PO', 'INV'], skipped: [], errors: [], dryRun: true }
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
A bundle is plain JSON and carries **no** `id`, `tenantId`, `createdAt`,
|
|
484
|
+
`version` or `previousVersionId` — those describe one row in one database, and
|
|
485
|
+
importing them would either collide with the target's ids or claim a lineage the
|
|
486
|
+
target never had. The target assigns its own.
|
|
487
|
+
|
|
488
|
+
`mode: 'create'` (the default) skips templates that already exist; `'upsert'`
|
|
489
|
+
updates them, bumping the version and recording `previousVersionId` as a normal
|
|
490
|
+
`updateTemplate()` would.
|
|
491
|
+
|
|
492
|
+
**Every template is validated before any is written.** A half-applied bundle
|
|
493
|
+
leaves the tenant matching neither environment with no way to tell which half
|
|
494
|
+
landed, so a bundle that fails validation is rejected whole, naming the
|
|
495
|
+
offending template.
|
|
496
|
+
|
|
471
497
|
### Sub-workflows
|
|
472
498
|
|
|
473
499
|
A level can delegate to a whole separate approval instead of to a list of
|
|
@@ -305,6 +305,32 @@ interface ApproverWorkload {
|
|
|
305
305
|
/** Age of that oldest item. `0` when they hold nothing. */
|
|
306
306
|
oldestAgeMs: number;
|
|
307
307
|
}
|
|
308
|
+
/** Version stamp on an exported bundle, so an importer can reject a shape it does not understand. */
|
|
309
|
+
declare const TEMPLATE_BUNDLE_VERSION = 1;
|
|
310
|
+
/**
|
|
311
|
+
* A portable set of templates, safe to move between environments.
|
|
312
|
+
*
|
|
313
|
+
* Deliberately carries no `id`, `tenantId`, `createdAt`, `version` or
|
|
314
|
+
* `previousVersionId`: those describe one row in one database, and importing
|
|
315
|
+
* them would either collide with the target's own ids or silently claim a
|
|
316
|
+
* lineage the target never had.
|
|
317
|
+
*/
|
|
318
|
+
interface TemplateBundle {
|
|
319
|
+
bundleVersion: number;
|
|
320
|
+
exportedAt: Date;
|
|
321
|
+
templates: ApprovalTemplateConfig[];
|
|
322
|
+
}
|
|
323
|
+
/** Outcome of {@link ApprovalEngine.importTemplates}. */
|
|
324
|
+
interface ImportResult {
|
|
325
|
+
created: string[];
|
|
326
|
+
updated: string[];
|
|
327
|
+
skipped: string[];
|
|
328
|
+
errors: Array<{
|
|
329
|
+
name: string;
|
|
330
|
+
message: string;
|
|
331
|
+
}>;
|
|
332
|
+
dryRun: boolean;
|
|
333
|
+
}
|
|
308
334
|
interface ApprovalStatistics {
|
|
309
335
|
/** Total instances matching the filter (across all statuses). */
|
|
310
336
|
total: number;
|
|
@@ -660,6 +686,36 @@ declare class ApprovalEngine {
|
|
|
660
686
|
* @returns One row per approver holding at least one open level.
|
|
661
687
|
*/
|
|
662
688
|
getWorkload(filter?: Omit<InstanceFilter, 'status'>): Promise<ApproverWorkload[]>;
|
|
689
|
+
/**
|
|
690
|
+
* Export templates as a portable bundle.
|
|
691
|
+
*
|
|
692
|
+
* Approval configuration is written once and then has to travel — authored in
|
|
693
|
+
* a sandbox, reviewed, promoted to production. Reading `listTemplates()` and
|
|
694
|
+
* re-posting the rows carried each environment's own `id`, `tenantId` and
|
|
695
|
+
* version lineage with it, which either collided on arrival or silently
|
|
696
|
+
* claimed a history the target never had. This strips all of it.
|
|
697
|
+
*
|
|
698
|
+
* @param names - Templates to include; omit for all of them.
|
|
699
|
+
*/
|
|
700
|
+
exportTemplates(names?: string[]): Promise<TemplateBundle>;
|
|
701
|
+
/**
|
|
702
|
+
* Import a bundle produced by {@link exportTemplates}.
|
|
703
|
+
*
|
|
704
|
+
* **Every template is validated before any is written.** A bundle that is
|
|
705
|
+
* half-applied is worse than one rejected outright: the tenant is left in a
|
|
706
|
+
* state matching neither environment, and the operator has no way to tell
|
|
707
|
+
* which half landed. Per-template failures during the write phase are still
|
|
708
|
+
* reported individually, since a storage error can occur after validation
|
|
709
|
+
* passes.
|
|
710
|
+
*
|
|
711
|
+
* @param bundle - The bundle to apply.
|
|
712
|
+
* @param opts - `mode: 'create'` (default) refuses to touch existing
|
|
713
|
+
* templates; `'upsert'` updates them. `dryRun` reports without writing.
|
|
714
|
+
*/
|
|
715
|
+
importTemplates(bundle: TemplateBundle, opts?: {
|
|
716
|
+
mode?: 'create' | 'upsert';
|
|
717
|
+
dryRun?: boolean;
|
|
718
|
+
}): Promise<ImportResult>;
|
|
663
719
|
getStatistics(filter?: Omit<InstanceFilter, 'status'>): Promise<ApprovalStatistics>;
|
|
664
720
|
shutdown(): Promise<void>;
|
|
665
721
|
/**
|
|
@@ -791,4 +847,4 @@ declare class ApprovalEngine {
|
|
|
791
847
|
private runExternalAudit;
|
|
792
848
|
}
|
|
793
849
|
|
|
794
|
-
export { type AddCommentOptions as A, type BulkResult as B, type CanApproveResult as C, type DelegateOptions as D, type EscalateOptions as E, type HealthResult as H, type IdGeneratorFn as I, type OrgProvider as O, type PreviewChainLevel as P, type ReassignOptions as R, type SubmitOptions as S,
|
|
850
|
+
export { type AddCommentOptions as A, type BulkResult as B, type CanApproveResult as C, type DelegateOptions as D, type EscalateOptions as E, type HealthResult as H, type IdGeneratorFn as I, type OrgProvider as O, type PreviewChainLevel as P, type ReassignOptions as R, type SubmitOptions as S, 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 CancelOptions as h, type ConditionOperatorFn as i, type CycleTimeStats as j, type IdempotencyKeyFn as k, type ImportResult as l, type OutOfOfficeProvider as m, type OverrideOptions as n, type PreviewResult as o, type ProvideInfoOptions as p, type RejectOptions as q, type RequestInfoOptions as r, type ResubmitOptions as s, type RetryPolicy as t, type TemplateBundle as u, type TransferResult as v, defaultIdGenerator as w, toComparableNumber as x, validateConditionExpression as y, weekendCalendar as z };
|
|
@@ -305,6 +305,32 @@ interface ApproverWorkload {
|
|
|
305
305
|
/** Age of that oldest item. `0` when they hold nothing. */
|
|
306
306
|
oldestAgeMs: number;
|
|
307
307
|
}
|
|
308
|
+
/** Version stamp on an exported bundle, so an importer can reject a shape it does not understand. */
|
|
309
|
+
declare const TEMPLATE_BUNDLE_VERSION = 1;
|
|
310
|
+
/**
|
|
311
|
+
* A portable set of templates, safe to move between environments.
|
|
312
|
+
*
|
|
313
|
+
* Deliberately carries no `id`, `tenantId`, `createdAt`, `version` or
|
|
314
|
+
* `previousVersionId`: those describe one row in one database, and importing
|
|
315
|
+
* them would either collide with the target's own ids or silently claim a
|
|
316
|
+
* lineage the target never had.
|
|
317
|
+
*/
|
|
318
|
+
interface TemplateBundle {
|
|
319
|
+
bundleVersion: number;
|
|
320
|
+
exportedAt: Date;
|
|
321
|
+
templates: ApprovalTemplateConfig[];
|
|
322
|
+
}
|
|
323
|
+
/** Outcome of {@link ApprovalEngine.importTemplates}. */
|
|
324
|
+
interface ImportResult {
|
|
325
|
+
created: string[];
|
|
326
|
+
updated: string[];
|
|
327
|
+
skipped: string[];
|
|
328
|
+
errors: Array<{
|
|
329
|
+
name: string;
|
|
330
|
+
message: string;
|
|
331
|
+
}>;
|
|
332
|
+
dryRun: boolean;
|
|
333
|
+
}
|
|
308
334
|
interface ApprovalStatistics {
|
|
309
335
|
/** Total instances matching the filter (across all statuses). */
|
|
310
336
|
total: number;
|
|
@@ -660,6 +686,36 @@ declare class ApprovalEngine {
|
|
|
660
686
|
* @returns One row per approver holding at least one open level.
|
|
661
687
|
*/
|
|
662
688
|
getWorkload(filter?: Omit<InstanceFilter, 'status'>): Promise<ApproverWorkload[]>;
|
|
689
|
+
/**
|
|
690
|
+
* Export templates as a portable bundle.
|
|
691
|
+
*
|
|
692
|
+
* Approval configuration is written once and then has to travel — authored in
|
|
693
|
+
* a sandbox, reviewed, promoted to production. Reading `listTemplates()` and
|
|
694
|
+
* re-posting the rows carried each environment's own `id`, `tenantId` and
|
|
695
|
+
* version lineage with it, which either collided on arrival or silently
|
|
696
|
+
* claimed a history the target never had. This strips all of it.
|
|
697
|
+
*
|
|
698
|
+
* @param names - Templates to include; omit for all of them.
|
|
699
|
+
*/
|
|
700
|
+
exportTemplates(names?: string[]): Promise<TemplateBundle>;
|
|
701
|
+
/**
|
|
702
|
+
* Import a bundle produced by {@link exportTemplates}.
|
|
703
|
+
*
|
|
704
|
+
* **Every template is validated before any is written.** A bundle that is
|
|
705
|
+
* half-applied is worse than one rejected outright: the tenant is left in a
|
|
706
|
+
* state matching neither environment, and the operator has no way to tell
|
|
707
|
+
* which half landed. Per-template failures during the write phase are still
|
|
708
|
+
* reported individually, since a storage error can occur after validation
|
|
709
|
+
* passes.
|
|
710
|
+
*
|
|
711
|
+
* @param bundle - The bundle to apply.
|
|
712
|
+
* @param opts - `mode: 'create'` (default) refuses to touch existing
|
|
713
|
+
* templates; `'upsert'` updates them. `dryRun` reports without writing.
|
|
714
|
+
*/
|
|
715
|
+
importTemplates(bundle: TemplateBundle, opts?: {
|
|
716
|
+
mode?: 'create' | 'upsert';
|
|
717
|
+
dryRun?: boolean;
|
|
718
|
+
}): Promise<ImportResult>;
|
|
663
719
|
getStatistics(filter?: Omit<InstanceFilter, 'status'>): Promise<ApprovalStatistics>;
|
|
664
720
|
shutdown(): Promise<void>;
|
|
665
721
|
/**
|
|
@@ -791,4 +847,4 @@ declare class ApprovalEngine {
|
|
|
791
847
|
private runExternalAudit;
|
|
792
848
|
}
|
|
793
849
|
|
|
794
|
-
export { type AddCommentOptions as A, type BulkResult as B, type CanApproveResult as C, type DelegateOptions as D, type EscalateOptions as E, type HealthResult as H, type IdGeneratorFn as I, type OrgProvider as O, type PreviewChainLevel as P, type ReassignOptions as R, type SubmitOptions as S,
|
|
850
|
+
export { type AddCommentOptions as A, type BulkResult as B, type CanApproveResult as C, type DelegateOptions as D, type EscalateOptions as E, type HealthResult as H, type IdGeneratorFn as I, type OrgProvider as O, type PreviewChainLevel as P, type ReassignOptions as R, type SubmitOptions as S, 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 CancelOptions as h, type ConditionOperatorFn as i, type CycleTimeStats as j, type IdempotencyKeyFn as k, type ImportResult as l, type OutOfOfficeProvider as m, type OverrideOptions as n, type PreviewResult as o, type ProvideInfoOptions as p, type RejectOptions as q, type RequestInfoOptions as r, type ResubmitOptions as s, type RetryPolicy as t, type TemplateBundle as u, type TransferResult as v, defaultIdGenerator as w, toComparableNumber as x, validateConditionExpression as y, weekendCalendar as z };
|
package/dist/index.cjs
CHANGED
|
@@ -926,6 +926,7 @@ var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
|
926
926
|
]);
|
|
927
927
|
var CYCLE_TIME_STATUSES = ["approved", "rejected", "cancelled"];
|
|
928
928
|
var CYCLE_TIME_FETCH_BATCH_SIZE = 500;
|
|
929
|
+
var TEMPLATE_BUNDLE_VERSION = 1;
|
|
929
930
|
var ApprovalEngine = class _ApprovalEngine {
|
|
930
931
|
constructor(opts) {
|
|
931
932
|
this.opts = opts;
|
|
@@ -3007,6 +3008,118 @@ var ApprovalEngine = class _ApprovalEngine {
|
|
|
3007
3008
|
oldestAgeMs: Number.isFinite(row.oldest) ? now.getTime() - row.oldest : 0
|
|
3008
3009
|
})).sort((a, b) => b.pending - a.pending || a.approverId.localeCompare(b.approverId));
|
|
3009
3010
|
}
|
|
3011
|
+
/**
|
|
3012
|
+
* Export templates as a portable bundle.
|
|
3013
|
+
*
|
|
3014
|
+
* Approval configuration is written once and then has to travel — authored in
|
|
3015
|
+
* a sandbox, reviewed, promoted to production. Reading `listTemplates()` and
|
|
3016
|
+
* re-posting the rows carried each environment's own `id`, `tenantId` and
|
|
3017
|
+
* version lineage with it, which either collided on arrival or silently
|
|
3018
|
+
* claimed a history the target never had. This strips all of it.
|
|
3019
|
+
*
|
|
3020
|
+
* @param names - Templates to include; omit for all of them.
|
|
3021
|
+
*/
|
|
3022
|
+
async exportTemplates(names) {
|
|
3023
|
+
const all = await this.registry.list();
|
|
3024
|
+
const wanted = names ? all.filter((t) => names.includes(t.name)) : all;
|
|
3025
|
+
if (names) {
|
|
3026
|
+
const missing = names.filter((n) => !all.some((t) => t.name === n));
|
|
3027
|
+
if (missing.length > 0) {
|
|
3028
|
+
throw new ApprovalTemplateNotFoundError(missing.join(", "));
|
|
3029
|
+
}
|
|
3030
|
+
}
|
|
3031
|
+
return {
|
|
3032
|
+
bundleVersion: TEMPLATE_BUNDLE_VERSION,
|
|
3033
|
+
exportedAt: this.clock.now(),
|
|
3034
|
+
templates: wanted.map((t) => {
|
|
3035
|
+
const {
|
|
3036
|
+
id: _id,
|
|
3037
|
+
tenantId: _tenantId,
|
|
3038
|
+
createdAt: _createdAt,
|
|
3039
|
+
version: _version,
|
|
3040
|
+
previousVersionId: _previousVersionId,
|
|
3041
|
+
...config
|
|
3042
|
+
} = t;
|
|
3043
|
+
return config;
|
|
3044
|
+
})
|
|
3045
|
+
};
|
|
3046
|
+
}
|
|
3047
|
+
/**
|
|
3048
|
+
* Import a bundle produced by {@link exportTemplates}.
|
|
3049
|
+
*
|
|
3050
|
+
* **Every template is validated before any is written.** A bundle that is
|
|
3051
|
+
* half-applied is worse than one rejected outright: the tenant is left in a
|
|
3052
|
+
* state matching neither environment, and the operator has no way to tell
|
|
3053
|
+
* which half landed. Per-template failures during the write phase are still
|
|
3054
|
+
* reported individually, since a storage error can occur after validation
|
|
3055
|
+
* passes.
|
|
3056
|
+
*
|
|
3057
|
+
* @param bundle - The bundle to apply.
|
|
3058
|
+
* @param opts - `mode: 'create'` (default) refuses to touch existing
|
|
3059
|
+
* templates; `'upsert'` updates them. `dryRun` reports without writing.
|
|
3060
|
+
*/
|
|
3061
|
+
async importTemplates(bundle, opts = {}) {
|
|
3062
|
+
const mode = opts.mode ?? "create";
|
|
3063
|
+
const dryRun = opts.dryRun ?? false;
|
|
3064
|
+
if (bundle.bundleVersion !== TEMPLATE_BUNDLE_VERSION) {
|
|
3065
|
+
throw new ApprovalValidationError(
|
|
3066
|
+
`Unsupported template bundle version ${bundle.bundleVersion}; this engine reads version ${TEMPLATE_BUNDLE_VERSION}.`
|
|
3067
|
+
);
|
|
3068
|
+
}
|
|
3069
|
+
if (!Array.isArray(bundle.templates) || bundle.templates.length === 0) {
|
|
3070
|
+
throw new ApprovalValidationError("Template bundle contains no templates.");
|
|
3071
|
+
}
|
|
3072
|
+
const duplicates = bundle.templates.map((t) => t.name).filter((name, i, all) => all.indexOf(name) !== i);
|
|
3073
|
+
if (duplicates.length > 0) {
|
|
3074
|
+
throw new ApprovalValidationError(
|
|
3075
|
+
`Template bundle contains duplicate names: ${[...new Set(duplicates)].join(", ")}.`
|
|
3076
|
+
);
|
|
3077
|
+
}
|
|
3078
|
+
const invalid = [];
|
|
3079
|
+
for (const config of bundle.templates) {
|
|
3080
|
+
const result2 = this.validateTemplate(config);
|
|
3081
|
+
if (!result2.valid) {
|
|
3082
|
+
invalid.push({
|
|
3083
|
+
name: config.name,
|
|
3084
|
+
message: result2.errors[0]?.message ?? "unknown validation error"
|
|
3085
|
+
});
|
|
3086
|
+
}
|
|
3087
|
+
}
|
|
3088
|
+
if (invalid.length > 0) {
|
|
3089
|
+
throw new ApprovalValidationError(
|
|
3090
|
+
`Template bundle failed validation and was not applied: ${invalid.map((e) => `${e.name}: ${e.message}`).join("; ")}`
|
|
3091
|
+
);
|
|
3092
|
+
}
|
|
3093
|
+
const result = { created: [], updated: [], skipped: [], errors: [], dryRun };
|
|
3094
|
+
for (const config of bundle.templates) {
|
|
3095
|
+
const existing = await this.opts.adapter.getTemplate(this.tenantId, config.name);
|
|
3096
|
+
try {
|
|
3097
|
+
if (existing && mode === "create") {
|
|
3098
|
+
result.skipped.push(config.name);
|
|
3099
|
+
continue;
|
|
3100
|
+
}
|
|
3101
|
+
if (existing) {
|
|
3102
|
+
if (!dryRun) await this.registry.update(config);
|
|
3103
|
+
result.updated.push(config.name);
|
|
3104
|
+
} else {
|
|
3105
|
+
if (!dryRun) await this.registry.define(config);
|
|
3106
|
+
result.created.push(config.name);
|
|
3107
|
+
}
|
|
3108
|
+
} catch (err) {
|
|
3109
|
+
result.errors.push({ name: config.name, message: err.message });
|
|
3110
|
+
}
|
|
3111
|
+
}
|
|
3112
|
+
this.logger.info("importTemplates: bundle applied", {
|
|
3113
|
+
tenantId: this.tenantId,
|
|
3114
|
+
mode,
|
|
3115
|
+
dryRun,
|
|
3116
|
+
created: result.created.length,
|
|
3117
|
+
updated: result.updated.length,
|
|
3118
|
+
skipped: result.skipped.length,
|
|
3119
|
+
errors: result.errors.length
|
|
3120
|
+
});
|
|
3121
|
+
return result;
|
|
3122
|
+
}
|
|
3010
3123
|
async getStatistics(filter = {}) {
|
|
3011
3124
|
const statuses = [
|
|
3012
3125
|
"pending",
|
|
@@ -4106,6 +4219,7 @@ exports.ApprovalTemplateNotFoundError = ApprovalTemplateNotFoundError;
|
|
|
4106
4219
|
exports.ApprovalValidationError = ApprovalValidationError;
|
|
4107
4220
|
exports.EscalationScheduler = EscalationScheduler;
|
|
4108
4221
|
exports.MemoryAdapter = MemoryAdapter;
|
|
4222
|
+
exports.TEMPLATE_BUNDLE_VERSION = TEMPLATE_BUNDLE_VERSION;
|
|
4109
4223
|
exports.defaultIdGenerator = defaultIdGenerator;
|
|
4110
4224
|
exports.noopLogger = noopLogger;
|
|
4111
4225
|
exports.systemClock = systemClock;
|