@cqrs-ddd/pipeline 0.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.
- package/COMMERCIAL_LICENSE.txt +34 -0
- package/LICENSE +661 -0
- package/README.md +42 -0
- package/dist/behaviors/logging.behavior.d.ts +195 -0
- package/dist/behaviors/logging.behavior.d.ts.map +1 -0
- package/dist/behaviors/logging.behavior.js +206 -0
- package/dist/behaviors/logging.behavior.js.map +1 -0
- package/dist/constants/pipeline-context.constants.d.ts +34 -0
- package/dist/constants/pipeline-context.constants.d.ts.map +1 -0
- package/dist/constants/pipeline-context.constants.js +34 -0
- package/dist/constants/pipeline-context.constants.js.map +1 -0
- package/dist/create-pipeline.d.ts +122 -0
- package/dist/create-pipeline.d.ts.map +1 -0
- package/dist/create-pipeline.js +193 -0
- package/dist/create-pipeline.js.map +1 -0
- package/dist/entries.d.ts +13 -0
- package/dist/entries.d.ts.map +1 -0
- package/dist/entries.js +3 -0
- package/dist/entries.js.map +1 -0
- package/dist/errors/missing-partition.error.d.ts +27 -0
- package/dist/errors/missing-partition.error.d.ts.map +1 -0
- package/dist/errors/missing-partition.error.js +33 -0
- package/dist/errors/missing-partition.error.js.map +1 -0
- package/dist/errors/missing-pipeline-item.error.d.ts +8 -0
- package/dist/errors/missing-pipeline-item.error.d.ts.map +1 -0
- package/dist/errors/missing-pipeline-item.error.js +16 -0
- package/dist/errors/missing-pipeline-item.error.js.map +1 -0
- package/dist/handler-pipeline.d.ts +62 -0
- package/dist/handler-pipeline.d.ts.map +1 -0
- package/dist/handler-pipeline.js +74 -0
- package/dist/handler-pipeline.js.map +1 -0
- package/dist/helpers/behavior-entries.d.ts +34 -0
- package/dist/helpers/behavior-entries.d.ts.map +1 -0
- package/dist/helpers/behavior-entries.js +50 -0
- package/dist/helpers/behavior-entries.js.map +1 -0
- package/dist/helpers/behavior-id.d.ts +43 -0
- package/dist/helpers/behavior-id.d.ts.map +1 -0
- package/dist/helpers/behavior-id.js +38 -0
- package/dist/helpers/behavior-id.js.map +1 -0
- package/dist/helpers/logging.intent.d.ts +17 -0
- package/dist/helpers/logging.intent.d.ts.map +1 -0
- package/dist/helpers/logging.intent.js +18 -0
- package/dist/helpers/logging.intent.js.map +1 -0
- package/dist/helpers/postgres-json.d.ts +25 -0
- package/dist/helpers/postgres-json.d.ts.map +1 -0
- package/dist/helpers/postgres-json.js +35 -0
- package/dist/helpers/postgres-json.js.map +1 -0
- package/dist/helpers/replace-request.d.ts +19 -0
- package/dist/helpers/replace-request.d.ts.map +1 -0
- package/dist/helpers/replace-request.js +29 -0
- package/dist/helpers/replace-request.js.map +1 -0
- package/dist/helpers/tenant-partition.d.ts +38 -0
- package/dist/helpers/tenant-partition.d.ts.map +1 -0
- package/dist/helpers/tenant-partition.js +27 -0
- package/dist/helpers/tenant-partition.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/context-source.interface.d.ts +42 -0
- package/dist/interfaces/context-source.interface.d.ts.map +1 -0
- package/dist/interfaces/context-source.interface.js +3 -0
- package/dist/interfaces/context-source.interface.js.map +1 -0
- package/dist/interfaces/pipeline-behavior-contract.interface.d.ts +99 -0
- package/dist/interfaces/pipeline-behavior-contract.interface.d.ts.map +1 -0
- package/dist/interfaces/pipeline-behavior-contract.interface.js +22 -0
- package/dist/interfaces/pipeline-behavior-contract.interface.js.map +1 -0
- package/dist/interfaces/pipeline-handler-meta.interface.d.ts +15 -0
- package/dist/interfaces/pipeline-handler-meta.interface.d.ts.map +1 -0
- package/dist/interfaces/pipeline-handler-meta.interface.js +3 -0
- package/dist/interfaces/pipeline-handler-meta.interface.js.map +1 -0
- package/dist/interfaces/pipeline.behavior.interface.d.ts +38 -0
- package/dist/interfaces/pipeline.behavior.interface.d.ts.map +1 -0
- package/dist/interfaces/pipeline.behavior.interface.js +3 -0
- package/dist/interfaces/pipeline.behavior.interface.js.map +1 -0
- package/dist/interfaces/pipeline.context.interface.d.ts +69 -0
- package/dist/interfaces/pipeline.context.interface.d.ts.map +1 -0
- package/dist/interfaces/pipeline.context.interface.js +3 -0
- package/dist/interfaces/pipeline.context.interface.js.map +1 -0
- package/dist/logger.d.ts +45 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +64 -0
- package/dist/logger.js.map +1 -0
- package/dist/options/global-behaviors.options.d.ts +57 -0
- package/dist/options/global-behaviors.options.d.ts.map +1 -0
- package/dist/options/global-behaviors.options.js +3 -0
- package/dist/options/global-behaviors.options.js.map +1 -0
- package/dist/pipeline-items.d.ts +22 -0
- package/dist/pipeline-items.d.ts.map +1 -0
- package/dist/pipeline-items.js +34 -0
- package/dist/pipeline-items.js.map +1 -0
- package/dist/pipeline.context.d.ts +86 -0
- package/dist/pipeline.context.d.ts.map +1 -0
- package/dist/pipeline.context.js +109 -0
- package/dist/pipeline.context.js.map +1 -0
- package/dist/services/pipeline-contracts.d.ts +29 -0
- package/dist/services/pipeline-contracts.d.ts.map +1 -0
- package/dist/services/pipeline-contracts.js +102 -0
- package/dist/services/pipeline-contracts.js.map +1 -0
- package/dist/services/pipeline-plan.d.ts +49 -0
- package/dist/services/pipeline-plan.d.ts.map +1 -0
- package/dist/services/pipeline-plan.js +111 -0
- package/dist/services/pipeline-plan.js.map +1 -0
- package/dist/services/pipeline-runner.d.ts +26 -0
- package/dist/services/pipeline-runner.d.ts.map +1 -0
- package/dist/services/pipeline-runner.js +68 -0
- package/dist/services/pipeline-runner.js.map +1 -0
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
2
|
+
import { untyped } from '@cqrs-ddd/untyped';
|
|
3
|
+
import { getBehaviorId } from '../helpers/behavior-id.js';
|
|
4
|
+
import { PIPELINE_BEHAVIOR_CONTRACT, } from '../interfaces/pipeline-behavior-contract.interface.js';
|
|
5
|
+
/**
|
|
6
|
+
* Validates the ordering rules and option contracts that behavior classes declare
|
|
7
|
+
* through `PIPELINE_BEHAVIOR_CONTRACT`, appending a diagnostic per violation. Framework
|
|
8
|
+
* adapters call it at bootstrap; `createPipeline()` calls it when a function is wrapped.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const diagnostics: PipelineBehaviorDiagnostic[] = [];
|
|
13
|
+
* validateBehaviorContracts({ ...plan, handlerType, handlerName, requestKind, resolvedBehaviors, diagnostics });
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export function validateBehaviorContracts(params) {
|
|
17
|
+
const { handlerType, handlerName, requestKind, behaviorTypes, resolvedBehaviors, mergedOptions, handlerOptions, globalOptions, handlerBehaviorTypes, globalBehaviorIds, diagnostics, } = params;
|
|
18
|
+
for (let i = 0; i < behaviorTypes.length; i++) {
|
|
19
|
+
const BehaviorClass = behaviorTypes[i];
|
|
20
|
+
const id = getBehaviorId(BehaviorClass);
|
|
21
|
+
const instance = resolvedBehaviors.get(i);
|
|
22
|
+
const contract = (instance &&
|
|
23
|
+
untyped(instance)[PIPELINE_BEHAVIOR_CONTRACT]) ??
|
|
24
|
+
untyped(BehaviorClass)[PIPELINE_BEHAVIOR_CONTRACT];
|
|
25
|
+
if (!contract)
|
|
26
|
+
continue;
|
|
27
|
+
const isHandlerDeclared = (handlerBehaviorTypes ?? []).some((t) => getBehaviorId(t) === id);
|
|
28
|
+
const isGlobalDeclared = globalBehaviorIds.has(id);
|
|
29
|
+
const declarationSource = isHandlerDeclared && isGlobalDeclared
|
|
30
|
+
? 'both'
|
|
31
|
+
: isHandlerDeclared
|
|
32
|
+
? 'handler'
|
|
33
|
+
: 'global';
|
|
34
|
+
const rawMerged = mergedOptions.get(id);
|
|
35
|
+
const effectiveOptions = instance && resolvesOptions(instance)
|
|
36
|
+
? instance.resolveEffectiveOptions(rawMerged)
|
|
37
|
+
: rawMerged;
|
|
38
|
+
const validationCtx = {
|
|
39
|
+
handlerType,
|
|
40
|
+
handlerName: handlerName,
|
|
41
|
+
requestKind,
|
|
42
|
+
declarationSource,
|
|
43
|
+
effectiveOptions,
|
|
44
|
+
handlerOptions: handlerOptions?.get(id),
|
|
45
|
+
globalOptions: globalOptions.get(id),
|
|
46
|
+
effectiveBehaviorTypes: behaviorTypes,
|
|
47
|
+
behaviorInstance: instance,
|
|
48
|
+
};
|
|
49
|
+
// 1. Validate ordering constraints
|
|
50
|
+
const orderRule = typeof contract.order === 'function'
|
|
51
|
+
? contract.order(validationCtx)
|
|
52
|
+
: contract.order;
|
|
53
|
+
if (orderRule) {
|
|
54
|
+
const edges = [];
|
|
55
|
+
if (orderRule.after) {
|
|
56
|
+
for (const target of orderRule.after) {
|
|
57
|
+
edges.push({ target, direction: 'after' });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (orderRule.before) {
|
|
61
|
+
for (const target of orderRule.before) {
|
|
62
|
+
edges.push({ target, direction: 'before' });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
for (const { target, direction } of edges) {
|
|
66
|
+
const targetIdx = behaviorTypes.findIndex((b) => typeof target === 'string'
|
|
67
|
+
? getBehaviorId(b) === target || b.name === target
|
|
68
|
+
: b === target || getBehaviorId(b) === getBehaviorId(target));
|
|
69
|
+
// Relative position only: an absent target has no position to
|
|
70
|
+
// violate. A behavior that needs a peer to exist checks
|
|
71
|
+
// effectiveBehaviorTypes in its own validate().
|
|
72
|
+
if (targetIdx === -1)
|
|
73
|
+
continue;
|
|
74
|
+
const isViolation = direction === 'after' ? i <= targetIdx : i >= targetIdx;
|
|
75
|
+
if (isViolation) {
|
|
76
|
+
const targetName = behaviorTypes[targetIdx].name;
|
|
77
|
+
diagnostics.push({
|
|
78
|
+
handlerName: handlerName,
|
|
79
|
+
behaviorName: BehaviorClass.name,
|
|
80
|
+
message: direction === 'after'
|
|
81
|
+
? `${BehaviorClass.name} is positioned before ${targetName} in the pipeline chain, but must execute after it`
|
|
82
|
+
: `${BehaviorClass.name} is positioned after ${targetName} in the pipeline chain, but must execute before it`,
|
|
83
|
+
fix: direction === 'after'
|
|
84
|
+
? `Reorder the pipeline behaviors so that ${targetName} runs before ${BehaviorClass.name}.`
|
|
85
|
+
: `Reorder the pipeline behaviors so that ${BehaviorClass.name} runs before ${targetName}.`,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// 2. Validate behavior options and intent
|
|
91
|
+
if (typeof contract.validate === 'function') {
|
|
92
|
+
const result = contract.validate(validationCtx);
|
|
93
|
+
if (Array.isArray(result))
|
|
94
|
+
diagnostics.push(...result);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function resolvesOptions(instance) {
|
|
99
|
+
return (typeof instance
|
|
100
|
+
.resolveEffectiveOptions === 'function');
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=pipeline-contracts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-contracts.js","sourceRoot":"","sources":["../../src/services/pipeline-contracts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type BehaviorId } from '../helpers/behavior-id.js';
|
|
2
|
+
import type { IPipelineBehavior } from '../interfaces/pipeline.behavior.interface.js';
|
|
3
|
+
import type { GlobalBehaviorsOptions } from '../options/global-behaviors.options.js';
|
|
4
|
+
import type { Constructor } from '../types.js';
|
|
5
|
+
/** The request kinds a pipeline distinguishes; `unknown` matches only `scope: 'all'`. */
|
|
6
|
+
export type RequestKind = 'command' | 'query' | 'event' | 'unknown';
|
|
7
|
+
/** What a handler, or a wrapped function, declares for its pipeline. */
|
|
8
|
+
export interface PipelineDeclaration {
|
|
9
|
+
/** Name used in configuration error messages. */
|
|
10
|
+
handlerName: string;
|
|
11
|
+
requestKind: RequestKind;
|
|
12
|
+
/** Behaviors declared on the handler, deduplicated, in order. */
|
|
13
|
+
handlerBehaviorTypes?: Constructor<IPipelineBehavior>[];
|
|
14
|
+
/** Options of the handler's tuple entries. */
|
|
15
|
+
handlerOptions?: Map<BehaviorId, Record<string, unknown>>;
|
|
16
|
+
/** Global behaviors the handler opts out of. */
|
|
17
|
+
skippedBehaviorTypes?: Constructor<IPipelineBehavior>[];
|
|
18
|
+
globalBehaviors?: GlobalBehaviorsOptions | GlobalBehaviorsOptions[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Compiles a pipeline declaration into its effective, ordered behaviors and merged
|
|
22
|
+
* options, without resolving instances. Global `before` behaviors come first, then
|
|
23
|
+
* the handler's own, then global `after` ones; a handler entry for a global behavior
|
|
24
|
+
* supplies options at the global position.
|
|
25
|
+
*
|
|
26
|
+
* @throws Error when one behavior is both skipped and declared.
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* const plan = compilePipelinePlan({
|
|
30
|
+
* handlerName: 'getPrice',
|
|
31
|
+
* requestKind: 'query',
|
|
32
|
+
* handlerBehaviorTypes: [CacheBehavior],
|
|
33
|
+
* globalBehaviors: { before: [LoggingBehavior] },
|
|
34
|
+
* });
|
|
35
|
+
* plan.behaviorTypes; // [LoggingBehavior, CacheBehavior]
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function compilePipelinePlan(declaration: PipelineDeclaration): {
|
|
39
|
+
behaviorTypes: Constructor<IPipelineBehavior<unknown, unknown>>[];
|
|
40
|
+
mergedOptions: Map<BehaviorId, Record<string, unknown>>;
|
|
41
|
+
hasPipeline: boolean;
|
|
42
|
+
handlerOptions: Map<BehaviorId, Record<string, unknown>> | undefined;
|
|
43
|
+
globalOptions: Map<BehaviorId, Record<string, unknown>>;
|
|
44
|
+
handlerBehaviorTypes: Constructor<IPipelineBehavior<unknown, unknown>>[] | undefined;
|
|
45
|
+
globalBehaviorIds: Set<BehaviorId>;
|
|
46
|
+
};
|
|
47
|
+
/** Normalizes the single-object and array forms of `globalBehaviors`. */
|
|
48
|
+
export declare function toGlobalConfigs(globalBehaviors: GlobalBehaviorsOptions | GlobalBehaviorsOptions[] | undefined): GlobalBehaviorsOptions[];
|
|
49
|
+
//# sourceMappingURL=pipeline-plan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-plan.d.ts","sourceRoot":"","sources":["../../src/services/pipeline-plan.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,UAAU,EAAiB,MAAM,2BAA2B,CAAC;AAC3E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8CAA8C,CAAC;AACtF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AACrF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,yFAAyF;AACzF,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;AAEpE,wEAAwE;AACxE,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,WAAW,CAAC;IACzB,iEAAiE;IACjE,oBAAoB,CAAC,EAAE,WAAW,CAAC,iBAAiB,CAAC,EAAE,CAAC;IACxD,8CAA8C;IAC9C,cAAc,CAAC,EAAE,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1D,gDAAgD;IAChD,oBAAoB,CAAC,EAAE,WAAW,CAAC,iBAAiB,CAAC,EAAE,CAAC;IACxD,eAAe,CAAC,EAAE,sBAAsB,GAAG,sBAAsB,EAAE,CAAC;CACrE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,mBAAmB;;;;;;;;EAkFnE;AAED,yEAAyE;AACzE,wBAAgB,eAAe,CAC7B,eAAe,EACX,sBAAsB,GACtB,sBAAsB,EAAE,GACxB,SAAS,GACZ,sBAAsB,EAAE,CAG1B"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
2
|
+
import { normalizeBehaviorEntries, } from '../helpers/behavior-entries.js';
|
|
3
|
+
import { getBehaviorId } from '../helpers/behavior-id.js';
|
|
4
|
+
/**
|
|
5
|
+
* Compiles a pipeline declaration into its effective, ordered behaviors and merged
|
|
6
|
+
* options, without resolving instances. Global `before` behaviors come first, then
|
|
7
|
+
* the handler's own, then global `after` ones; a handler entry for a global behavior
|
|
8
|
+
* supplies options at the global position.
|
|
9
|
+
*
|
|
10
|
+
* @throws Error when one behavior is both skipped and declared.
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const plan = compilePipelinePlan({
|
|
14
|
+
* handlerName: 'getPrice',
|
|
15
|
+
* requestKind: 'query',
|
|
16
|
+
* handlerBehaviorTypes: [CacheBehavior],
|
|
17
|
+
* globalBehaviors: { before: [LoggingBehavior] },
|
|
18
|
+
* });
|
|
19
|
+
* plan.behaviorTypes; // [LoggingBehavior, CacheBehavior]
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function compilePipelinePlan(declaration) {
|
|
23
|
+
const { handlerName, requestKind, handlerBehaviorTypes, handlerOptions, skippedBehaviorTypes, globalBehaviors, } = declaration;
|
|
24
|
+
if (skippedBehaviorTypes && skippedBehaviorTypes.length > 0) {
|
|
25
|
+
const handlerBehaviorIds = new Set((handlerBehaviorTypes ?? []).map(getBehaviorId));
|
|
26
|
+
for (const skippedType of skippedBehaviorTypes) {
|
|
27
|
+
const id = getBehaviorId(skippedType);
|
|
28
|
+
if (handlerBehaviorIds.has(id) || handlerOptions?.has(id)) {
|
|
29
|
+
throw new Error(`Handler ${handlerName} has contradictory pipeline configuration: ` +
|
|
30
|
+
`behavior ${skippedType.name} is both skipped and declared. ` +
|
|
31
|
+
`Remove either the skip or the declaration.`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const { beforeTypes, afterTypes, globalOptions } = resolveGlobalBehaviors(globalBehaviors, requestKind);
|
|
36
|
+
const skippedBehaviorIds = new Set((skippedBehaviorTypes ?? []).map(getBehaviorId));
|
|
37
|
+
const effectiveBeforeTypes = beforeTypes.filter((type) => !skippedBehaviorIds.has(getBehaviorId(type)));
|
|
38
|
+
const effectiveAfterTypes = afterTypes.filter((type) => !skippedBehaviorIds.has(getBehaviorId(type)));
|
|
39
|
+
// Handler declarations override options for a global behavior of the same
|
|
40
|
+
// class, but must not relocate it. A global security guard configured in
|
|
41
|
+
// `before` must remain outside handler-level cache/idempotency behaviors
|
|
42
|
+
// that can short-circuit without calling next().
|
|
43
|
+
const globalBehaviorIds = new Set([...effectiveBeforeTypes, ...effectiveAfterTypes].map(getBehaviorId));
|
|
44
|
+
const handlerOnlyTypes = (handlerBehaviorTypes ?? []).filter((type) => !globalBehaviorIds.has(getBehaviorId(type)));
|
|
45
|
+
// Effective order: globalBefore → non-global handler behaviors → globalAfter.
|
|
46
|
+
// Matching handler entries supply options at their original global position.
|
|
47
|
+
const behaviorTypes = [
|
|
48
|
+
...effectiveBeforeTypes,
|
|
49
|
+
...handlerOnlyTypes,
|
|
50
|
+
...effectiveAfterTypes,
|
|
51
|
+
];
|
|
52
|
+
// Handler options shallowly override global options; nested values are replaced.
|
|
53
|
+
const mergedOptions = new Map(globalOptions);
|
|
54
|
+
for (const [id, options] of handlerOptions ?? []) {
|
|
55
|
+
const inherited = mergedOptions.get(id);
|
|
56
|
+
mergedOptions.set(id, inherited ? { ...inherited, ...options } : options);
|
|
57
|
+
}
|
|
58
|
+
for (const skippedId of skippedBehaviorIds) {
|
|
59
|
+
mergedOptions.delete(skippedId);
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
behaviorTypes,
|
|
63
|
+
mergedOptions,
|
|
64
|
+
hasPipeline: behaviorTypes.length > 0,
|
|
65
|
+
handlerOptions,
|
|
66
|
+
globalOptions,
|
|
67
|
+
handlerBehaviorTypes,
|
|
68
|
+
globalBehaviorIds,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/** Normalizes the single-object and array forms of `globalBehaviors`. */
|
|
72
|
+
export function toGlobalConfigs(globalBehaviors) {
|
|
73
|
+
if (!globalBehaviors)
|
|
74
|
+
return [];
|
|
75
|
+
return Array.isArray(globalBehaviors) ? globalBehaviors : [globalBehaviors];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Resolves global before/after behaviors that match the given handler kind.
|
|
79
|
+
* `globalBehaviors` may be a single `GlobalBehaviorsOptions` object or an array.
|
|
80
|
+
* Each entry is filtered by its `scope` ('all' | 'commands' | 'queries' | 'events').
|
|
81
|
+
* Matching entries are merged — behaviors accumulate across all matching configs.
|
|
82
|
+
*
|
|
83
|
+
* @returns Behavior types to prepend/append plus any inline options from tuple entries.
|
|
84
|
+
*/
|
|
85
|
+
function resolveGlobalBehaviors(globalBehaviors, requestKind) {
|
|
86
|
+
const configs = toGlobalConfigs(globalBehaviors);
|
|
87
|
+
const beforeTypes = [];
|
|
88
|
+
const afterTypes = [];
|
|
89
|
+
// One accumulator pair across every matching config and both chain positions,
|
|
90
|
+
// so the first occurrence fixes placement while a later tuple can still
|
|
91
|
+
// supply options without the behavior running more than once.
|
|
92
|
+
const accumulators = {
|
|
93
|
+
seen: new Set(),
|
|
94
|
+
options: new Map(),
|
|
95
|
+
};
|
|
96
|
+
const parseEntries = (entries) => normalizeBehaviorEntries(entries, `globalBehaviors for ${requestKind}`, true, accumulators).types;
|
|
97
|
+
for (const config of configs) {
|
|
98
|
+
const scope = config.scope ?? 'all';
|
|
99
|
+
// Scope filtering — skip entries that don't match the handler kind
|
|
100
|
+
if (scope === 'commands' && requestKind !== 'command')
|
|
101
|
+
continue;
|
|
102
|
+
if (scope === 'queries' && requestKind !== 'query')
|
|
103
|
+
continue;
|
|
104
|
+
if (scope === 'events' && requestKind !== 'event')
|
|
105
|
+
continue;
|
|
106
|
+
beforeTypes.push(...parseEntries(config.before ?? []));
|
|
107
|
+
afterTypes.push(...parseEntries(config.after ?? []));
|
|
108
|
+
}
|
|
109
|
+
return { beforeTypes, afterTypes, globalOptions: accumulators.options };
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=pipeline-plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-plan.js","sourceRoot":"","sources":["../../src/services/pipeline-plan.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAGtE,OAAO,EAEL,wBAAwB,GACzB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAmB,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAsB3E;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,mBAAmB,CAAC,WAAgC;IAClE,MAAM,EACJ,WAAW,EACX,WAAW,EACX,oBAAoB,EACpB,cAAc,EACd,oBAAoB,EACpB,eAAe,GAChB,GAAG,WAAW,CAAC;IAEhB,IAAI,oBAAoB,IAAI,oBAAoB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5D,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAChC,CAAC,oBAAoB,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAChD,CAAC;QACF,KAAK,MAAM,WAAW,IAAI,oBAAoB,EAAE,CAAC;YAC/C,MAAM,EAAE,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;YACtC,IAAI,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,cAAc,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC1D,MAAM,IAAI,KAAK,CACb,WAAW,WAAW,6CAA6C;oBACjE,YAAY,WAAW,CAAC,IAAI,iCAAiC;oBAC7D,4CAA4C,CAC/C,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,GAAG,sBAAsB,CACvE,eAAe,EACf,WAAW,CACZ,CAAC;IAEF,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAChC,CAAC,oBAAoB,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAChD,CAAC;IAEF,MAAM,oBAAoB,GAAG,WAAW,CAAC,MAAM,CAC7C,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CACvD,CAAC;IACF,MAAM,mBAAmB,GAAG,UAAU,CAAC,MAAM,CAC3C,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CACvD,CAAC;IAEF,0EAA0E;IAC1E,yEAAyE;IACzE,yEAAyE;IACzE,iDAAiD;IACjD,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAC/B,CAAC,GAAG,oBAAoB,EAAE,GAAG,mBAAmB,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CACrE,CAAC;IACF,MAAM,gBAAgB,GAAG,CAAC,oBAAoB,IAAI,EAAE,CAAC,CAAC,MAAM,CAC1D,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CACtD,CAAC;IAEF,8EAA8E;IAC9E,6EAA6E;IAC7E,MAAM,aAAa,GAAqC;QACtD,GAAG,oBAAoB;QACvB,GAAG,gBAAgB;QACnB,GAAG,mBAAmB;KACvB,CAAC;IAEF,iFAAiF;IACjF,MAAM,aAAa,GAAG,IAAI,GAAG,CAC3B,aAAa,CACd,CAAC;IACF,KAAK,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,cAAc,IAAI,EAAE,EAAE,CAAC;QACjD,MAAM,SAAS,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACxC,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAC5E,CAAC;IACD,KAAK,MAAM,SAAS,IAAI,kBAAkB,EAAE,CAAC;QAC3C,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;IAED,OAAO;QACL,aAAa;QACb,aAAa;QACb,WAAW,EAAE,aAAa,CAAC,MAAM,GAAG,CAAC;QACrC,cAAc;QACd,aAAa;QACb,oBAAoB;QACpB,iBAAiB;KAClB,CAAC;AACJ,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,eAAe,CAC7B,eAGa;IAEb,IAAI,CAAC,eAAe;QAAE,OAAO,EAAE,CAAC;IAChC,OAAO,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC;AAC9E,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,sBAAsB,CAC7B,eAGa,EACb,WAAwB;IAMxB,MAAM,OAAO,GAAG,eAAe,CAAC,eAAe,CAAC,CAAC;IAEjD,MAAM,WAAW,GAAqC,EAAE,CAAC;IACzD,MAAM,UAAU,GAAqC,EAAE,CAAC;IAExD,8EAA8E;IAC9E,wEAAwE;IACxE,8DAA8D;IAC9D,MAAM,YAAY,GAA8B;QAC9C,IAAI,EAAE,IAAI,GAAG,EAAc;QAC3B,OAAO,EAAE,IAAI,GAAG,EAAuC;KACxD,CAAC;IAEF,MAAM,YAAY,GAAG,CAAC,OAAgC,EAAE,EAAE,CACxD,wBAAwB,CACtB,OAAO,EACP,uBAAuB,WAAW,EAAE,EACpC,IAAI,EACJ,YAAY,CACb,CAAC,KAAK,CAAC;IAEV,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC;QAEpC,mEAAmE;QACnE,IAAI,KAAK,KAAK,UAAU,IAAI,WAAW,KAAK,SAAS;YAAE,SAAS;QAChE,IAAI,KAAK,KAAK,SAAS,IAAI,WAAW,KAAK,OAAO;YAAE,SAAS;QAC7D,IAAI,KAAK,KAAK,QAAQ,IAAI,WAAW,KAAK,OAAO;YAAE,SAAS;QAE5D,WAAW,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC;QACvD,UAAU,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;IACvD,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,CAAC,OAAO,EAAE,CAAC;AAC1E,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ContextSources } from '../interfaces/context-source.interface.js';
|
|
2
|
+
import type { IPipelineBehavior } from '../interfaces/pipeline.behavior.interface.js';
|
|
3
|
+
import type { PipelineHandlerMeta } from '../interfaces/pipeline-handler-meta.interface.js';
|
|
4
|
+
/**
|
|
5
|
+
* Runs one execution: `request` is what behaviors see; `args`, when given, are the
|
|
6
|
+
* arguments the handler receives instead of `request` alone.
|
|
7
|
+
*/
|
|
8
|
+
export type PipelineRunner = (self: unknown, request: unknown, args?: readonly unknown[]) => Promise<unknown>;
|
|
9
|
+
/**
|
|
10
|
+
* Builds the runner of one handler: each call creates a pipeline context, takes the
|
|
11
|
+
* tenant and correlation id from `sources` or the enclosing pipeline, composes the
|
|
12
|
+
* behaviors around the handler, and runs them inside those values. Framework adapters
|
|
13
|
+
* use it; `createPipeline()` is the entry point for applications.
|
|
14
|
+
*
|
|
15
|
+
* @param behaviors - Resolved instances, or a resolver called per execution (a
|
|
16
|
+
* framework adapter's request-scoped instances).
|
|
17
|
+
* @param meta - Fixed handler metadata, or a function deriving it from the request and
|
|
18
|
+
* the receiver of the call.
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* const run = createPipelineRunner(handler.execute, meta, [logging], true, sources);
|
|
22
|
+
* await run(handler, command);
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function createPipelineRunner(originalMethod: (this: unknown, ...args: any[]) => unknown, meta: PipelineHandlerMeta | ((request: unknown, self: unknown) => PipelineHandlerMeta), behaviors: readonly IPipelineBehavior[] | ((self: unknown, request: unknown) => Promise<IPipelineBehavior[]>), hasPipeline: boolean, sources?: ContextSources): PipelineRunner;
|
|
26
|
+
//# sourceMappingURL=pipeline-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-runner.d.ts","sourceRoot":"","sources":["../../src/services/pipeline-runner.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAEV,cAAc,EACf,MAAM,2CAA2C,CAAC;AACnD,OAAO,KAAK,EACV,iBAAiB,EAElB,MAAM,8CAA8C,CAAC;AACtD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kDAAkD,CAAC;AAG5F;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,CAC3B,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,OAAO,EAChB,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,KACtB,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAElC,cAAc,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,EAC1D,IAAI,EACA,mBAAmB,GACnB,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,KAAK,mBAAmB,CAAC,EAC9D,SAAS,EACL,SAAS,iBAAiB,EAAE,GAC5B,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC,EACvE,WAAW,EAAE,OAAO,EACpB,OAAO,GAAE,cAAmB,GAC3B,cAAc,CA2DhB"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
2
|
+
import { uuidv7 } from '@cqrs-ddd/uuidv7';
|
|
3
|
+
import { pipelineStore, SET_CORRELATION_ID, SET_RESPONSE, SET_TENANT_ID, } from '../constants/pipeline-context.constants.js';
|
|
4
|
+
import { PipelineContext } from '../pipeline.context.js';
|
|
5
|
+
/**
|
|
6
|
+
* Builds the runner of one handler: each call creates a pipeline context, takes the
|
|
7
|
+
* tenant and correlation id from `sources` or the enclosing pipeline, composes the
|
|
8
|
+
* behaviors around the handler, and runs them inside those values. Framework adapters
|
|
9
|
+
* use it; `createPipeline()` is the entry point for applications.
|
|
10
|
+
*
|
|
11
|
+
* @param behaviors - Resolved instances, or a resolver called per execution (a
|
|
12
|
+
* framework adapter's request-scoped instances).
|
|
13
|
+
* @param meta - Fixed handler metadata, or a function deriving it from the request and
|
|
14
|
+
* the receiver of the call.
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const run = createPipelineRunner(handler.execute, meta, [logging], true, sources);
|
|
18
|
+
* await run(handler, command);
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function createPipelineRunner(
|
|
22
|
+
// biome-ignore lint/suspicious/noExplicitAny: the handler's arguments are opaque here
|
|
23
|
+
originalMethod, meta, behaviors, hasPipeline, sources = {}) {
|
|
24
|
+
const invoke = (self, request, args) => args
|
|
25
|
+
? originalMethod.apply(self, [...args])
|
|
26
|
+
: originalMethod.call(self, request);
|
|
27
|
+
return async (self, request, args) => {
|
|
28
|
+
if (!hasPipeline)
|
|
29
|
+
return invoke(self, request, args);
|
|
30
|
+
const context = new PipelineContext(request, typeof meta === 'function' ? meta(request, self) : meta);
|
|
31
|
+
const localBehaviors = typeof behaviors === 'function'
|
|
32
|
+
? await behaviors(self, request)
|
|
33
|
+
: behaviors;
|
|
34
|
+
const parent = pipelineStore.getStore();
|
|
35
|
+
const { tenantId: tenant, correlationId: correlation } = sources;
|
|
36
|
+
const tenantId = tenant ? tenant.current() : parent?.tenantId;
|
|
37
|
+
const correlationId = correlation
|
|
38
|
+
? (correlation.current() ?? correlation.create())
|
|
39
|
+
: (parent?.correlationId ?? uuidv7());
|
|
40
|
+
context[SET_CORRELATION_ID](correlationId);
|
|
41
|
+
if (tenantId !== undefined)
|
|
42
|
+
context[SET_TENANT_ID](tenantId);
|
|
43
|
+
let chain = async () => {
|
|
44
|
+
// A behavior that replaced the request hands the handler the replacement.
|
|
45
|
+
const current = context.request;
|
|
46
|
+
const replaced = current !== request;
|
|
47
|
+
const result = await invoke(self, current, args && replaced
|
|
48
|
+
? args.length === 1
|
|
49
|
+
? [current]
|
|
50
|
+
: current
|
|
51
|
+
: args);
|
|
52
|
+
context[SET_RESPONSE](result);
|
|
53
|
+
return result;
|
|
54
|
+
};
|
|
55
|
+
for (let i = localBehaviors.length - 1; i >= 0; i--) {
|
|
56
|
+
const behavior = localBehaviors[i];
|
|
57
|
+
const nextInChain = chain;
|
|
58
|
+
chain = () => behavior.handle(context, nextInChain);
|
|
59
|
+
}
|
|
60
|
+
// Behaviors and the handler run inside this execution's values, so a
|
|
61
|
+
// nested dispatch inherits them and cannot see a different tenant.
|
|
62
|
+
return pipelineStore.run(context, () => within(tenant, context.tenantId, () => within(correlation, context.correlationId, chain)));
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function within(source, value, fn) {
|
|
66
|
+
return source ? source.run(value, fn) : fn();
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=pipeline-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-runner.js","sourceRoot":"","sources":["../../src/services/pipeline-runner.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,+FAA+F;AAE/F,MAAM,MAAM,WAAW,CAAC,CAAC,GAAG,OAAO,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,sEAAsE"}
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cqrs-ddd/pipeline",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Framework-neutral pipeline engine: wrap functions and methods with behaviors such as logging, caching or idempotency",
|
|
5
|
+
"author": "Aristotelis",
|
|
6
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"engines": {
|
|
9
|
+
"node": ">=22.12.0"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/aristoteliss/ddd-cqrs.git",
|
|
14
|
+
"directory": "packages/pipeline"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://aristoteliss.github.io/ddd-cqrs/packages/pipeline/",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/aristoteliss/ddd-cqrs/issues"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"pipeline",
|
|
22
|
+
"behaviors",
|
|
23
|
+
"cqrs",
|
|
24
|
+
"ddd",
|
|
25
|
+
"decorators",
|
|
26
|
+
"middleware"
|
|
27
|
+
],
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"default": "./dist/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./package.json": "./package.json"
|
|
34
|
+
},
|
|
35
|
+
"main": "dist/index.js",
|
|
36
|
+
"types": "dist/index.d.ts",
|
|
37
|
+
"files": [
|
|
38
|
+
"dist",
|
|
39
|
+
"LICENSE",
|
|
40
|
+
"COMMERCIAL_LICENSE.txt"
|
|
41
|
+
],
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@cqrs-ddd/safe-stringify": "^0.5.0",
|
|
47
|
+
"@cqrs-ddd/uuidv7": "^0.5.0",
|
|
48
|
+
"@cqrs-ddd/untyped": "^0.5.0"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@vitest/coverage-v8": "^5.0.3",
|
|
52
|
+
"vitest": "^5.0.3"
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"build": "tsc -p tsconfig.build.json",
|
|
56
|
+
"build:watch": "tsc -p tsconfig.build.json --watch",
|
|
57
|
+
"clean": "rm -rf dist tsconfig.tsbuildinfo",
|
|
58
|
+
"rebuild": "pnpm run clean && pnpm run build",
|
|
59
|
+
"lint": "tsc --noEmit",
|
|
60
|
+
"test": "vitest run",
|
|
61
|
+
"test:watch": "vitest"
|
|
62
|
+
}
|
|
63
|
+
}
|