@backendkit-labs/pipeline 0.1.1 → 0.3.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/README.md +448 -447
- package/dist/chunk-GTIMFVE5.js +163 -0
- package/dist/chunk-GTIMFVE5.js.map +1 -0
- package/dist/chunk-N7VFWHTQ.cjs +167 -0
- package/dist/chunk-N7VFWHTQ.cjs.map +1 -0
- package/dist/{define-pipeline-BNKM59ML.d.cts → define-pipeline-CIUhML8D.d.cts} +17 -2
- package/dist/{define-pipeline-BNKM59ML.d.ts → define-pipeline-CIUhML8D.d.ts} +17 -2
- package/dist/index.cjs +3 -3
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1 -1
- package/dist/nestjs/index.cjs +37 -5
- package/dist/nestjs/index.cjs.map +1 -1
- package/dist/nestjs/index.d.cts +1 -1
- package/dist/nestjs/index.d.ts +1 -1
- package/dist/nestjs/index.js +35 -3
- package/dist/nestjs/index.js.map +1 -1
- package/package.json +6 -5
- package/dist/chunk-GHWTXTUB.js +0 -93
- package/dist/chunk-GHWTXTUB.js.map +0 -1
- package/dist/chunk-LPCHUZQE.cjs +0 -97
- package/dist/chunk-LPCHUZQE.cjs.map +0 -1
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
4
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
5
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
6
|
+
if (decorator = decorators[i])
|
|
7
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
8
|
+
if (kind && result) __defProp(target, key, result);
|
|
9
|
+
return result;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/core/pipeline.ts
|
|
13
|
+
var VALID_MODES = ["stop-on-first", "collect-all"];
|
|
14
|
+
function normalizeMode(mode) {
|
|
15
|
+
if (mode === "stop-on-first" || mode === "collect-all") {
|
|
16
|
+
return mode;
|
|
17
|
+
}
|
|
18
|
+
throw new TypeError(
|
|
19
|
+
`Invalid pipeline mode "${String(mode)}". Expected one of: ${VALID_MODES.map((m) => `"${m}"`).join(", ")}`
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
function isStepResult(value) {
|
|
23
|
+
return typeof value === "object" && value !== null && "ok" in value && typeof value.ok === "boolean";
|
|
24
|
+
}
|
|
25
|
+
function buildErrorResult(state, failedStep, cause) {
|
|
26
|
+
return {
|
|
27
|
+
ok: false,
|
|
28
|
+
error: {
|
|
29
|
+
mode: state.mode,
|
|
30
|
+
failedStep,
|
|
31
|
+
cause,
|
|
32
|
+
executedSteps: [...state.executedSteps],
|
|
33
|
+
durationMs: Date.now() - state.start,
|
|
34
|
+
failures: [...state.failures]
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function buildSuccessResult(state) {
|
|
39
|
+
return {
|
|
40
|
+
ok: true,
|
|
41
|
+
value: state.ctx,
|
|
42
|
+
executedSteps: [...state.executedSteps],
|
|
43
|
+
durationMs: Date.now() - state.start
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
var Pipeline = class {
|
|
47
|
+
entries = [];
|
|
48
|
+
options;
|
|
49
|
+
constructor(options = {}) {
|
|
50
|
+
this.options = options;
|
|
51
|
+
}
|
|
52
|
+
pipe(step) {
|
|
53
|
+
this.entries.push({
|
|
54
|
+
instance: step,
|
|
55
|
+
name: step.stepName ?? step.constructor.name
|
|
56
|
+
});
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
pipeIf(condition, step) {
|
|
60
|
+
this.entries.push({
|
|
61
|
+
instance: step,
|
|
62
|
+
name: step.stepName ?? step.constructor.name,
|
|
63
|
+
condition
|
|
64
|
+
});
|
|
65
|
+
return this;
|
|
66
|
+
}
|
|
67
|
+
async run(initialCtx) {
|
|
68
|
+
const state = {
|
|
69
|
+
mode: normalizeMode(this.options.mode ?? "stop-on-first"),
|
|
70
|
+
start: Date.now(),
|
|
71
|
+
executedSteps: [],
|
|
72
|
+
failures: [],
|
|
73
|
+
ctx: initialCtx
|
|
74
|
+
};
|
|
75
|
+
const { onStep, onStepComplete, onError, onComplete } = this.options;
|
|
76
|
+
for (const entry of this.entries) {
|
|
77
|
+
const shouldContinue = await this.#executeEntry(entry, state, { onStep, onStepComplete, onError });
|
|
78
|
+
if (!shouldContinue) {
|
|
79
|
+
return buildErrorResult(state, state.failures[state.failures.length - 1].step, state.failures[state.failures.length - 1].cause);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (state.failures.length > 0) {
|
|
83
|
+
return buildErrorResult(state, state.failures[0].step, state.failures[0].cause);
|
|
84
|
+
}
|
|
85
|
+
const durationMs = Date.now() - state.start;
|
|
86
|
+
try {
|
|
87
|
+
await onComplete?.(state.ctx, durationMs, {
|
|
88
|
+
executedSteps: [...state.executedSteps],
|
|
89
|
+
failures: [...state.failures]
|
|
90
|
+
});
|
|
91
|
+
} catch {
|
|
92
|
+
}
|
|
93
|
+
return buildSuccessResult(state);
|
|
94
|
+
}
|
|
95
|
+
async #executeEntry(entry, state, hooks) {
|
|
96
|
+
const { instance, name, condition } = entry;
|
|
97
|
+
const { onStep, onStepComplete, onError } = hooks;
|
|
98
|
+
if (condition) {
|
|
99
|
+
let shouldRun;
|
|
100
|
+
try {
|
|
101
|
+
shouldRun = condition(state.ctx);
|
|
102
|
+
} catch (cause) {
|
|
103
|
+
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
104
|
+
state.failures.push({ step: name, cause: error });
|
|
105
|
+
if (state.mode === "stop-on-first") {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
state.executedSteps.push(name);
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
if (!shouldRun) return true;
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
await onStep?.(name, state.ctx);
|
|
115
|
+
} catch {
|
|
116
|
+
}
|
|
117
|
+
const stepStart = Date.now();
|
|
118
|
+
const rawResult = await instance.handle(state.ctx);
|
|
119
|
+
const stepMs = Date.now() - stepStart;
|
|
120
|
+
if (!isStepResult(rawResult)) {
|
|
121
|
+
const error = new TypeError(
|
|
122
|
+
`Step "${name}" returned an invalid value. Expected a StepResult (object with "ok" boolean), got ${typeof rawResult}`
|
|
123
|
+
);
|
|
124
|
+
try {
|
|
125
|
+
await onError?.(name, error);
|
|
126
|
+
} catch {
|
|
127
|
+
}
|
|
128
|
+
state.failures.push({ step: name, cause: error });
|
|
129
|
+
if (state.mode === "stop-on-first") {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
state.executedSteps.push(name);
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
const stepResult = rawResult;
|
|
136
|
+
if (!stepResult.ok) {
|
|
137
|
+
try {
|
|
138
|
+
await onError?.(name, stepResult.error);
|
|
139
|
+
} catch {
|
|
140
|
+
}
|
|
141
|
+
state.failures.push({ step: name, cause: stepResult.error });
|
|
142
|
+
if (state.mode === "stop-on-first") {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
state.executedSteps.push(name);
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
state.ctx = stepResult.value;
|
|
149
|
+
state.executedSteps.push(name);
|
|
150
|
+
try {
|
|
151
|
+
await onStepComplete?.(name, state.ctx, stepMs);
|
|
152
|
+
} catch {
|
|
153
|
+
}
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
function pipeline(options) {
|
|
158
|
+
return new Pipeline(options);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export { Pipeline, __decorateClass, pipeline };
|
|
162
|
+
//# sourceMappingURL=chunk-GTIMFVE5.js.map
|
|
163
|
+
//# sourceMappingURL=chunk-GTIMFVE5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/pipeline.ts"],"names":[],"mappings":"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","file":"chunk-GTIMFVE5.js","sourcesContent":["import type {\n PipelineMode,\n PipelineOptions,\n PipelineRunResult,\n PipelineStep,\n PipelineStepFailure,\n StepResult,\n} from './types.js';\n\ninterface StepEntry<TContext, TError> {\n instance: PipelineStep<TContext, TError>;\n name: string;\n condition?: (ctx: TContext) => boolean;\n}\n\ninterface ExecutionState<TContext, TError> {\n readonly mode: PipelineMode;\n readonly start: number;\n readonly executedSteps: string[];\n readonly failures: PipelineStepFailure<TError>[];\n ctx: TContext;\n}\n\nconst VALID_MODES: readonly PipelineMode[] = ['stop-on-first', 'collect-all'];\n\nfunction normalizeMode(mode: unknown): PipelineMode {\n if (mode === 'stop-on-first' || mode === 'collect-all') {\n return mode;\n }\n throw new TypeError(\n `Invalid pipeline mode \"${String(mode)}\". Expected one of: ${VALID_MODES.map(m => `\"${m}\"`).join(', ')}`,\n );\n}\n\nfunction isStepResult<TContext, TError>(\n value: unknown,\n): value is StepResult<TContext, TError> {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'ok' in value &&\n typeof (value as Record<string, unknown>).ok === 'boolean'\n );\n}\n\nfunction buildErrorResult<TContext, TError>(\n state: ExecutionState<TContext, TError>,\n failedStep: string,\n cause: TError,\n): PipelineRunResult<TContext, TError> {\n return {\n ok: false,\n error: {\n mode: state.mode,\n failedStep,\n cause,\n executedSteps: [...state.executedSteps],\n durationMs: Date.now() - state.start,\n failures: [...state.failures],\n },\n };\n}\n\nfunction buildSuccessResult<TContext, TError>(\n state: ExecutionState<TContext, TError>,\n): PipelineRunResult<TContext, TError> {\n return {\n ok: true,\n value: state.ctx,\n executedSteps: [...state.executedSteps],\n durationMs: Date.now() - state.start,\n };\n}\n\nexport class Pipeline<TContext, TError = unknown> {\n private readonly entries: StepEntry<TContext, TError>[] = [];\n private readonly options: PipelineOptions<TContext, TError>;\n\n constructor(options: PipelineOptions<TContext, TError> = {}) {\n this.options = options;\n }\n\n pipe(step: PipelineStep<TContext, TError>): this {\n this.entries.push({\n instance: step,\n name: step.stepName ?? step.constructor.name,\n });\n return this;\n }\n\n pipeIf(condition: (ctx: TContext) => boolean, step: PipelineStep<TContext, TError>): this {\n this.entries.push({\n instance: step,\n name: step.stepName ?? step.constructor.name,\n condition,\n });\n return this;\n }\n\n async run(initialCtx: TContext): Promise<PipelineRunResult<TContext, TError>> {\n const state: ExecutionState<TContext, TError> = {\n mode: normalizeMode(this.options.mode ?? 'stop-on-first'),\n start: Date.now(),\n executedSteps: [],\n failures: [],\n ctx: initialCtx,\n };\n\n const { onStep, onStepComplete, onError, onComplete } = this.options;\n\n for (const entry of this.entries) {\n const shouldContinue = await this.#executeEntry(entry, state, { onStep, onStepComplete, onError });\n if (!shouldContinue) {\n return buildErrorResult(state, state.failures[state.failures.length - 1].step, state.failures[state.failures.length - 1].cause);\n }\n }\n\n if (state.failures.length > 0) {\n return buildErrorResult(state, state.failures[0].step, state.failures[0].cause);\n }\n\n const durationMs = Date.now() - state.start;\n try {\n await onComplete?.(state.ctx, durationMs, {\n executedSteps: [...state.executedSteps],\n failures: [...state.failures],\n });\n } catch { /* noop */ }\n\n return buildSuccessResult(state);\n }\n\n async #executeEntry(\n entry: StepEntry<TContext, TError>,\n state: ExecutionState<TContext, TError>,\n hooks: {\n onStep?: (stepName: string, ctx: TContext) => void | Promise<void>;\n onStepComplete?: (stepName: string, ctx: TContext, durationMs: number) => void | Promise<void>;\n onError?: (stepName: string, error: TError) => void | Promise<void>;\n },\n ): Promise<boolean> {\n const { instance, name, condition } = entry;\n const { onStep, onStepComplete, onError } = hooks;\n\n // Evaluate condition — treat thrown exceptions as pipeline failures\n if (condition) {\n let shouldRun: boolean;\n try {\n shouldRun = condition(state.ctx);\n } catch (cause) {\n const error = cause instanceof Error ? cause : new Error(String(cause));\n state.failures.push({ step: name, cause: error as unknown as TError });\n\n if (state.mode === 'stop-on-first') {\n return false; // signal caller to stop\n }\n\n state.executedSteps.push(name);\n return true; // continue to next entry\n }\n\n if (!shouldRun) return true; // skip step, continue\n }\n\n try { await onStep?.(name, state.ctx); } catch { /* noop */ }\n\n const stepStart = Date.now();\n const rawResult = await instance.handle(state.ctx);\n const stepMs = Date.now() - stepStart;\n\n // Validate step return value shape\n if (!isStepResult<TContext, TError>(rawResult)) {\n const error = new TypeError(\n `Step \"${name}\" returned an invalid value. Expected a StepResult (object with \"ok\" boolean), got ${typeof rawResult}`,\n );\n try { await onError?.(name, error as unknown as TError); } catch { /* noop */ }\n state.failures.push({ step: name, cause: error as unknown as TError });\n\n if (state.mode === 'stop-on-first') {\n return false;\n }\n\n state.executedSteps.push(name);\n return true;\n }\n\n const stepResult = rawResult;\n\n if (!stepResult.ok) {\n try { await onError?.(name, stepResult.error); } catch { /* noop */ }\n state.failures.push({ step: name, cause: stepResult.error });\n\n if (state.mode === 'stop-on-first') {\n return false;\n }\n\n state.executedSteps.push(name);\n return true;\n }\n\n state.ctx = stepResult.value;\n state.executedSteps.push(name);\n try { await onStepComplete?.(name, state.ctx, stepMs); } catch { /* noop */ }\n\n return true;\n }\n}\n\nexport function pipeline<TContext, TError = unknown>(\n options?: PipelineOptions<TContext, TError>,\n): Pipeline<TContext, TError> {\n return new Pipeline(options);\n}\n"]}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
6
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
7
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
8
|
+
if (decorator = decorators[i])
|
|
9
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
10
|
+
if (kind && result) __defProp(target, key, result);
|
|
11
|
+
return result;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// src/core/pipeline.ts
|
|
15
|
+
var VALID_MODES = ["stop-on-first", "collect-all"];
|
|
16
|
+
function normalizeMode(mode) {
|
|
17
|
+
if (mode === "stop-on-first" || mode === "collect-all") {
|
|
18
|
+
return mode;
|
|
19
|
+
}
|
|
20
|
+
throw new TypeError(
|
|
21
|
+
`Invalid pipeline mode "${String(mode)}". Expected one of: ${VALID_MODES.map((m) => `"${m}"`).join(", ")}`
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
function isStepResult(value) {
|
|
25
|
+
return typeof value === "object" && value !== null && "ok" in value && typeof value.ok === "boolean";
|
|
26
|
+
}
|
|
27
|
+
function buildErrorResult(state, failedStep, cause) {
|
|
28
|
+
return {
|
|
29
|
+
ok: false,
|
|
30
|
+
error: {
|
|
31
|
+
mode: state.mode,
|
|
32
|
+
failedStep,
|
|
33
|
+
cause,
|
|
34
|
+
executedSteps: [...state.executedSteps],
|
|
35
|
+
durationMs: Date.now() - state.start,
|
|
36
|
+
failures: [...state.failures]
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function buildSuccessResult(state) {
|
|
41
|
+
return {
|
|
42
|
+
ok: true,
|
|
43
|
+
value: state.ctx,
|
|
44
|
+
executedSteps: [...state.executedSteps],
|
|
45
|
+
durationMs: Date.now() - state.start
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
var Pipeline = class {
|
|
49
|
+
entries = [];
|
|
50
|
+
options;
|
|
51
|
+
constructor(options = {}) {
|
|
52
|
+
this.options = options;
|
|
53
|
+
}
|
|
54
|
+
pipe(step) {
|
|
55
|
+
this.entries.push({
|
|
56
|
+
instance: step,
|
|
57
|
+
name: step.stepName ?? step.constructor.name
|
|
58
|
+
});
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
pipeIf(condition, step) {
|
|
62
|
+
this.entries.push({
|
|
63
|
+
instance: step,
|
|
64
|
+
name: step.stepName ?? step.constructor.name,
|
|
65
|
+
condition
|
|
66
|
+
});
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
async run(initialCtx) {
|
|
70
|
+
const state = {
|
|
71
|
+
mode: normalizeMode(this.options.mode ?? "stop-on-first"),
|
|
72
|
+
start: Date.now(),
|
|
73
|
+
executedSteps: [],
|
|
74
|
+
failures: [],
|
|
75
|
+
ctx: initialCtx
|
|
76
|
+
};
|
|
77
|
+
const { onStep, onStepComplete, onError, onComplete } = this.options;
|
|
78
|
+
for (const entry of this.entries) {
|
|
79
|
+
const shouldContinue = await this.#executeEntry(entry, state, { onStep, onStepComplete, onError });
|
|
80
|
+
if (!shouldContinue) {
|
|
81
|
+
return buildErrorResult(state, state.failures[state.failures.length - 1].step, state.failures[state.failures.length - 1].cause);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (state.failures.length > 0) {
|
|
85
|
+
return buildErrorResult(state, state.failures[0].step, state.failures[0].cause);
|
|
86
|
+
}
|
|
87
|
+
const durationMs = Date.now() - state.start;
|
|
88
|
+
try {
|
|
89
|
+
await onComplete?.(state.ctx, durationMs, {
|
|
90
|
+
executedSteps: [...state.executedSteps],
|
|
91
|
+
failures: [...state.failures]
|
|
92
|
+
});
|
|
93
|
+
} catch {
|
|
94
|
+
}
|
|
95
|
+
return buildSuccessResult(state);
|
|
96
|
+
}
|
|
97
|
+
async #executeEntry(entry, state, hooks) {
|
|
98
|
+
const { instance, name, condition } = entry;
|
|
99
|
+
const { onStep, onStepComplete, onError } = hooks;
|
|
100
|
+
if (condition) {
|
|
101
|
+
let shouldRun;
|
|
102
|
+
try {
|
|
103
|
+
shouldRun = condition(state.ctx);
|
|
104
|
+
} catch (cause) {
|
|
105
|
+
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
106
|
+
state.failures.push({ step: name, cause: error });
|
|
107
|
+
if (state.mode === "stop-on-first") {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
state.executedSteps.push(name);
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
if (!shouldRun) return true;
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
await onStep?.(name, state.ctx);
|
|
117
|
+
} catch {
|
|
118
|
+
}
|
|
119
|
+
const stepStart = Date.now();
|
|
120
|
+
const rawResult = await instance.handle(state.ctx);
|
|
121
|
+
const stepMs = Date.now() - stepStart;
|
|
122
|
+
if (!isStepResult(rawResult)) {
|
|
123
|
+
const error = new TypeError(
|
|
124
|
+
`Step "${name}" returned an invalid value. Expected a StepResult (object with "ok" boolean), got ${typeof rawResult}`
|
|
125
|
+
);
|
|
126
|
+
try {
|
|
127
|
+
await onError?.(name, error);
|
|
128
|
+
} catch {
|
|
129
|
+
}
|
|
130
|
+
state.failures.push({ step: name, cause: error });
|
|
131
|
+
if (state.mode === "stop-on-first") {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
state.executedSteps.push(name);
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
const stepResult = rawResult;
|
|
138
|
+
if (!stepResult.ok) {
|
|
139
|
+
try {
|
|
140
|
+
await onError?.(name, stepResult.error);
|
|
141
|
+
} catch {
|
|
142
|
+
}
|
|
143
|
+
state.failures.push({ step: name, cause: stepResult.error });
|
|
144
|
+
if (state.mode === "stop-on-first") {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
state.executedSteps.push(name);
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
state.ctx = stepResult.value;
|
|
151
|
+
state.executedSteps.push(name);
|
|
152
|
+
try {
|
|
153
|
+
await onStepComplete?.(name, state.ctx, stepMs);
|
|
154
|
+
} catch {
|
|
155
|
+
}
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
function pipeline(options) {
|
|
160
|
+
return new Pipeline(options);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
exports.Pipeline = Pipeline;
|
|
164
|
+
exports.__decorateClass = __decorateClass;
|
|
165
|
+
exports.pipeline = pipeline;
|
|
166
|
+
//# sourceMappingURL=chunk-N7VFWHTQ.cjs.map
|
|
167
|
+
//# sourceMappingURL=chunk-N7VFWHTQ.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/pipeline.ts"],"names":[],"mappings":"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","file":"chunk-N7VFWHTQ.cjs","sourcesContent":["import type {\n PipelineMode,\n PipelineOptions,\n PipelineRunResult,\n PipelineStep,\n PipelineStepFailure,\n StepResult,\n} from './types.js';\n\ninterface StepEntry<TContext, TError> {\n instance: PipelineStep<TContext, TError>;\n name: string;\n condition?: (ctx: TContext) => boolean;\n}\n\ninterface ExecutionState<TContext, TError> {\n readonly mode: PipelineMode;\n readonly start: number;\n readonly executedSteps: string[];\n readonly failures: PipelineStepFailure<TError>[];\n ctx: TContext;\n}\n\nconst VALID_MODES: readonly PipelineMode[] = ['stop-on-first', 'collect-all'];\n\nfunction normalizeMode(mode: unknown): PipelineMode {\n if (mode === 'stop-on-first' || mode === 'collect-all') {\n return mode;\n }\n throw new TypeError(\n `Invalid pipeline mode \"${String(mode)}\". Expected one of: ${VALID_MODES.map(m => `\"${m}\"`).join(', ')}`,\n );\n}\n\nfunction isStepResult<TContext, TError>(\n value: unknown,\n): value is StepResult<TContext, TError> {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'ok' in value &&\n typeof (value as Record<string, unknown>).ok === 'boolean'\n );\n}\n\nfunction buildErrorResult<TContext, TError>(\n state: ExecutionState<TContext, TError>,\n failedStep: string,\n cause: TError,\n): PipelineRunResult<TContext, TError> {\n return {\n ok: false,\n error: {\n mode: state.mode,\n failedStep,\n cause,\n executedSteps: [...state.executedSteps],\n durationMs: Date.now() - state.start,\n failures: [...state.failures],\n },\n };\n}\n\nfunction buildSuccessResult<TContext, TError>(\n state: ExecutionState<TContext, TError>,\n): PipelineRunResult<TContext, TError> {\n return {\n ok: true,\n value: state.ctx,\n executedSteps: [...state.executedSteps],\n durationMs: Date.now() - state.start,\n };\n}\n\nexport class Pipeline<TContext, TError = unknown> {\n private readonly entries: StepEntry<TContext, TError>[] = [];\n private readonly options: PipelineOptions<TContext, TError>;\n\n constructor(options: PipelineOptions<TContext, TError> = {}) {\n this.options = options;\n }\n\n pipe(step: PipelineStep<TContext, TError>): this {\n this.entries.push({\n instance: step,\n name: step.stepName ?? step.constructor.name,\n });\n return this;\n }\n\n pipeIf(condition: (ctx: TContext) => boolean, step: PipelineStep<TContext, TError>): this {\n this.entries.push({\n instance: step,\n name: step.stepName ?? step.constructor.name,\n condition,\n });\n return this;\n }\n\n async run(initialCtx: TContext): Promise<PipelineRunResult<TContext, TError>> {\n const state: ExecutionState<TContext, TError> = {\n mode: normalizeMode(this.options.mode ?? 'stop-on-first'),\n start: Date.now(),\n executedSteps: [],\n failures: [],\n ctx: initialCtx,\n };\n\n const { onStep, onStepComplete, onError, onComplete } = this.options;\n\n for (const entry of this.entries) {\n const shouldContinue = await this.#executeEntry(entry, state, { onStep, onStepComplete, onError });\n if (!shouldContinue) {\n return buildErrorResult(state, state.failures[state.failures.length - 1].step, state.failures[state.failures.length - 1].cause);\n }\n }\n\n if (state.failures.length > 0) {\n return buildErrorResult(state, state.failures[0].step, state.failures[0].cause);\n }\n\n const durationMs = Date.now() - state.start;\n try {\n await onComplete?.(state.ctx, durationMs, {\n executedSteps: [...state.executedSteps],\n failures: [...state.failures],\n });\n } catch { /* noop */ }\n\n return buildSuccessResult(state);\n }\n\n async #executeEntry(\n entry: StepEntry<TContext, TError>,\n state: ExecutionState<TContext, TError>,\n hooks: {\n onStep?: (stepName: string, ctx: TContext) => void | Promise<void>;\n onStepComplete?: (stepName: string, ctx: TContext, durationMs: number) => void | Promise<void>;\n onError?: (stepName: string, error: TError) => void | Promise<void>;\n },\n ): Promise<boolean> {\n const { instance, name, condition } = entry;\n const { onStep, onStepComplete, onError } = hooks;\n\n // Evaluate condition — treat thrown exceptions as pipeline failures\n if (condition) {\n let shouldRun: boolean;\n try {\n shouldRun = condition(state.ctx);\n } catch (cause) {\n const error = cause instanceof Error ? cause : new Error(String(cause));\n state.failures.push({ step: name, cause: error as unknown as TError });\n\n if (state.mode === 'stop-on-first') {\n return false; // signal caller to stop\n }\n\n state.executedSteps.push(name);\n return true; // continue to next entry\n }\n\n if (!shouldRun) return true; // skip step, continue\n }\n\n try { await onStep?.(name, state.ctx); } catch { /* noop */ }\n\n const stepStart = Date.now();\n const rawResult = await instance.handle(state.ctx);\n const stepMs = Date.now() - stepStart;\n\n // Validate step return value shape\n if (!isStepResult<TContext, TError>(rawResult)) {\n const error = new TypeError(\n `Step \"${name}\" returned an invalid value. Expected a StepResult (object with \"ok\" boolean), got ${typeof rawResult}`,\n );\n try { await onError?.(name, error as unknown as TError); } catch { /* noop */ }\n state.failures.push({ step: name, cause: error as unknown as TError });\n\n if (state.mode === 'stop-on-first') {\n return false;\n }\n\n state.executedSteps.push(name);\n return true;\n }\n\n const stepResult = rawResult;\n\n if (!stepResult.ok) {\n try { await onError?.(name, stepResult.error); } catch { /* noop */ }\n state.failures.push({ step: name, cause: stepResult.error });\n\n if (state.mode === 'stop-on-first') {\n return false;\n }\n\n state.executedSteps.push(name);\n return true;\n }\n\n state.ctx = stepResult.value;\n state.executedSteps.push(name);\n try { await onStepComplete?.(name, state.ctx, stepMs); } catch { /* noop */ }\n\n return true;\n }\n}\n\nexport function pipeline<TContext, TError = unknown>(\n options?: PipelineOptions<TContext, TError>,\n): Pipeline<TContext, TError> {\n return new Pipeline(options);\n}\n"]}
|
|
@@ -8,6 +8,17 @@ type StepResult<TContext, TError> = {
|
|
|
8
8
|
interface PipelineStep<TContext, TError = unknown> {
|
|
9
9
|
/** Optional human-readable name used in error reporting and hooks. Defaults to constructor.name. */
|
|
10
10
|
readonly stepName?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Execute this step against the given context.
|
|
13
|
+
*
|
|
14
|
+
* IMPORTANT — Immutability convention:
|
|
15
|
+
* Steps SHOULD return a NEW context object rather than mutating the existing one.
|
|
16
|
+
* Mutating `ctx` and returning `Ok(ctx)` is an anti-pattern that can cause subtle bugs
|
|
17
|
+
* in hooks and subsequent steps. When in doubt, spread: `Ok({ ...ctx, ...changes })`.
|
|
18
|
+
*
|
|
19
|
+
* @param ctx - The current pipeline context (do NOT mutate in place).
|
|
20
|
+
* @returns A StepResult — either `Ok(newCtx)` on success or `Err(error)` on failure.
|
|
21
|
+
*/
|
|
11
22
|
handle(ctx: TContext): Promise<StepResult<TContext, TError>>;
|
|
12
23
|
}
|
|
13
24
|
type PipelineMode = 'stop-on-first' | 'collect-all';
|
|
@@ -32,12 +43,16 @@ type PipelineRunResult<TContext, TError> = {
|
|
|
32
43
|
readonly ok: false;
|
|
33
44
|
readonly error: PipelineError<TError>;
|
|
34
45
|
};
|
|
46
|
+
interface PipelineExecutionMetadata {
|
|
47
|
+
readonly executedSteps: string[];
|
|
48
|
+
readonly failures: PipelineStepFailure<unknown>[];
|
|
49
|
+
}
|
|
35
50
|
interface PipelineOptions<TContext, TError> {
|
|
36
51
|
mode?: PipelineMode;
|
|
37
52
|
onStep?: (stepName: string, ctx: TContext) => void | Promise<void>;
|
|
38
53
|
onStepComplete?: (stepName: string, ctx: TContext, durationMs: number) => void | Promise<void>;
|
|
39
54
|
onError?: (stepName: string, error: TError) => void | Promise<void>;
|
|
40
|
-
onComplete?: (ctx: TContext, durationMs: number) => void | Promise<void>;
|
|
55
|
+
onComplete?: (ctx: TContext, durationMs: number, metadata: PipelineExecutionMetadata) => void | Promise<void>;
|
|
41
56
|
}
|
|
42
57
|
|
|
43
58
|
declare class PipelineToken<TContext, TError = unknown> {
|
|
@@ -49,4 +64,4 @@ declare class PipelineToken<TContext, TError = unknown> {
|
|
|
49
64
|
}
|
|
50
65
|
declare function definePipeline<TContext, TError = unknown>(name: string): PipelineToken<TContext, TError>;
|
|
51
66
|
|
|
52
|
-
export { type PipelineOptions as P, type StepResult as S, type PipelineStep as a, type PipelineRunResult as b, type PipelineError as c, type
|
|
67
|
+
export { type PipelineOptions as P, type StepResult as S, type PipelineStep as a, type PipelineRunResult as b, type PipelineError as c, type PipelineExecutionMetadata as d, type PipelineMode as e, type PipelineStepFailure as f, PipelineToken as g, definePipeline as h };
|
|
@@ -8,6 +8,17 @@ type StepResult<TContext, TError> = {
|
|
|
8
8
|
interface PipelineStep<TContext, TError = unknown> {
|
|
9
9
|
/** Optional human-readable name used in error reporting and hooks. Defaults to constructor.name. */
|
|
10
10
|
readonly stepName?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Execute this step against the given context.
|
|
13
|
+
*
|
|
14
|
+
* IMPORTANT — Immutability convention:
|
|
15
|
+
* Steps SHOULD return a NEW context object rather than mutating the existing one.
|
|
16
|
+
* Mutating `ctx` and returning `Ok(ctx)` is an anti-pattern that can cause subtle bugs
|
|
17
|
+
* in hooks and subsequent steps. When in doubt, spread: `Ok({ ...ctx, ...changes })`.
|
|
18
|
+
*
|
|
19
|
+
* @param ctx - The current pipeline context (do NOT mutate in place).
|
|
20
|
+
* @returns A StepResult — either `Ok(newCtx)` on success or `Err(error)` on failure.
|
|
21
|
+
*/
|
|
11
22
|
handle(ctx: TContext): Promise<StepResult<TContext, TError>>;
|
|
12
23
|
}
|
|
13
24
|
type PipelineMode = 'stop-on-first' | 'collect-all';
|
|
@@ -32,12 +43,16 @@ type PipelineRunResult<TContext, TError> = {
|
|
|
32
43
|
readonly ok: false;
|
|
33
44
|
readonly error: PipelineError<TError>;
|
|
34
45
|
};
|
|
46
|
+
interface PipelineExecutionMetadata {
|
|
47
|
+
readonly executedSteps: string[];
|
|
48
|
+
readonly failures: PipelineStepFailure<unknown>[];
|
|
49
|
+
}
|
|
35
50
|
interface PipelineOptions<TContext, TError> {
|
|
36
51
|
mode?: PipelineMode;
|
|
37
52
|
onStep?: (stepName: string, ctx: TContext) => void | Promise<void>;
|
|
38
53
|
onStepComplete?: (stepName: string, ctx: TContext, durationMs: number) => void | Promise<void>;
|
|
39
54
|
onError?: (stepName: string, error: TError) => void | Promise<void>;
|
|
40
|
-
onComplete?: (ctx: TContext, durationMs: number) => void | Promise<void>;
|
|
55
|
+
onComplete?: (ctx: TContext, durationMs: number, metadata: PipelineExecutionMetadata) => void | Promise<void>;
|
|
41
56
|
}
|
|
42
57
|
|
|
43
58
|
declare class PipelineToken<TContext, TError = unknown> {
|
|
@@ -49,4 +64,4 @@ declare class PipelineToken<TContext, TError = unknown> {
|
|
|
49
64
|
}
|
|
50
65
|
declare function definePipeline<TContext, TError = unknown>(name: string): PipelineToken<TContext, TError>;
|
|
51
66
|
|
|
52
|
-
export { type PipelineOptions as P, type StepResult as S, type PipelineStep as a, type PipelineRunResult as b, type PipelineError as c, type
|
|
67
|
+
export { type PipelineOptions as P, type StepResult as S, type PipelineStep as a, type PipelineRunResult as b, type PipelineError as c, type PipelineExecutionMetadata as d, type PipelineMode as e, type PipelineStepFailure as f, PipelineToken as g, definePipeline as h };
|
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkN7VFWHTQ_cjs = require('./chunk-N7VFWHTQ.cjs');
|
|
4
4
|
|
|
5
5
|
// src/core/define-pipeline.ts
|
|
6
6
|
var PipelineToken = class {
|
|
@@ -25,11 +25,11 @@ function Err(error) {
|
|
|
25
25
|
|
|
26
26
|
Object.defineProperty(exports, "Pipeline", {
|
|
27
27
|
enumerable: true,
|
|
28
|
-
get: function () { return
|
|
28
|
+
get: function () { return chunkN7VFWHTQ_cjs.Pipeline; }
|
|
29
29
|
});
|
|
30
30
|
Object.defineProperty(exports, "pipeline", {
|
|
31
31
|
enumerable: true,
|
|
32
|
-
get: function () { return
|
|
32
|
+
get: function () { return chunkN7VFWHTQ_cjs.pipeline; }
|
|
33
33
|
});
|
|
34
34
|
exports.Err = Err;
|
|
35
35
|
exports.Ok = Ok;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { P as PipelineOptions, a as PipelineStep, b as PipelineRunResult, S as StepResult } from './define-pipeline-
|
|
2
|
-
export { c as PipelineError, d as
|
|
1
|
+
import { P as PipelineOptions, a as PipelineStep, b as PipelineRunResult, S as StepResult } from './define-pipeline-CIUhML8D.cjs';
|
|
2
|
+
export { c as PipelineError, d as PipelineExecutionMetadata, e as PipelineMode, f as PipelineStepFailure, g as PipelineToken, h as definePipeline } from './define-pipeline-CIUhML8D.cjs';
|
|
3
3
|
|
|
4
4
|
declare class Pipeline<TContext, TError = unknown> {
|
|
5
|
+
#private;
|
|
5
6
|
private readonly entries;
|
|
6
7
|
private readonly options;
|
|
7
8
|
constructor(options?: PipelineOptions<TContext, TError>);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { P as PipelineOptions, a as PipelineStep, b as PipelineRunResult, S as StepResult } from './define-pipeline-
|
|
2
|
-
export { c as PipelineError, d as
|
|
1
|
+
import { P as PipelineOptions, a as PipelineStep, b as PipelineRunResult, S as StepResult } from './define-pipeline-CIUhML8D.js';
|
|
2
|
+
export { c as PipelineError, d as PipelineExecutionMetadata, e as PipelineMode, f as PipelineStepFailure, g as PipelineToken, h as definePipeline } from './define-pipeline-CIUhML8D.js';
|
|
3
3
|
|
|
4
4
|
declare class Pipeline<TContext, TError = unknown> {
|
|
5
|
+
#private;
|
|
5
6
|
private readonly entries;
|
|
6
7
|
private readonly options;
|
|
7
8
|
constructor(options?: PipelineOptions<TContext, TError>);
|
package/dist/index.js
CHANGED
package/dist/nestjs/index.cjs
CHANGED
|
@@ -1,20 +1,52 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkN7VFWHTQ_cjs = require('../chunk-N7VFWHTQ.cjs');
|
|
4
4
|
var common = require('@nestjs/common');
|
|
5
5
|
|
|
6
|
+
function validatePipelineDefinition(def, index) {
|
|
7
|
+
if (!def.token) {
|
|
8
|
+
throw new Error(
|
|
9
|
+
`Pipeline definition at index ${index} is missing "token". Use definePipeline() to create one.`
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
if (!Array.isArray(def.steps) || def.steps.length === 0) {
|
|
13
|
+
throw new Error(
|
|
14
|
+
`Pipeline "${def.token.description ?? index}" has no steps. Provide at least one step class.`
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
for (let i = 0; i < def.steps.length; i++) {
|
|
18
|
+
const step = def.steps[i];
|
|
19
|
+
if (typeof step !== "function") {
|
|
20
|
+
throw new Error(
|
|
21
|
+
`Step at index ${i} in pipeline "${def.token.description ?? index}" is not a class/constructor. Expected a Type<PipelineStep>, got ${typeof step}.`
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function isPipelineStep(instance) {
|
|
27
|
+
return typeof instance === "object" && instance !== null && typeof instance.handle === "function";
|
|
28
|
+
}
|
|
6
29
|
exports.PipelineModule = class PipelineModule {
|
|
7
30
|
static forRoot(options) {
|
|
8
31
|
const providers = [];
|
|
9
|
-
for (
|
|
32
|
+
for (let i = 0; i < options.pipelines.length; i++) {
|
|
33
|
+
const def = options.pipelines[i];
|
|
34
|
+
validatePipelineDefinition(def, i);
|
|
10
35
|
for (const step of def.steps) {
|
|
11
36
|
providers.push({ provide: step, useClass: step });
|
|
12
37
|
}
|
|
13
38
|
providers.push({
|
|
14
39
|
provide: def.token.symbol,
|
|
15
40
|
useFactory: (...stepInstances) => {
|
|
16
|
-
const p = new
|
|
17
|
-
for (
|
|
41
|
+
const p = new chunkN7VFWHTQ_cjs.Pipeline(def.options ?? {});
|
|
42
|
+
for (let j = 0; j < stepInstances.length; j++) {
|
|
43
|
+
const instance = stepInstances[j];
|
|
44
|
+
if (!isPipelineStep(instance)) {
|
|
45
|
+
const stepName = def.steps[j]?.name ?? String(j);
|
|
46
|
+
throw new Error(
|
|
47
|
+
`Step "${stepName}" in pipeline "${def.token.description}" does not implement PipelineStep. Expected a class with a "handle(ctx)" method.`
|
|
48
|
+
);
|
|
49
|
+
}
|
|
18
50
|
p.pipe(instance);
|
|
19
51
|
}
|
|
20
52
|
return p;
|
|
@@ -30,7 +62,7 @@ exports.PipelineModule = class PipelineModule {
|
|
|
30
62
|
};
|
|
31
63
|
}
|
|
32
64
|
};
|
|
33
|
-
exports.PipelineModule =
|
|
65
|
+
exports.PipelineModule = chunkN7VFWHTQ_cjs.__decorateClass([
|
|
34
66
|
common.Module({})
|
|
35
67
|
], exports.PipelineModule);
|
|
36
68
|
var InjectPipeline = (token) => common.Inject(token.symbol);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/nestjs/pipeline.module.ts","../../src/nestjs/pipeline.decorator.ts"],"names":["PipelineModule","Pipeline","__decorateClass","Module","Inject"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"sources":["../../src/nestjs/pipeline.module.ts","../../src/nestjs/pipeline.decorator.ts"],"names":["PipelineModule","Pipeline","__decorateClass","Module","Inject"],"mappings":"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","file":"index.cjs","sourcesContent":["import { DynamicModule, Module, Provider, Type } from '@nestjs/common';\nimport { Pipeline } from '../core/pipeline.js';\nimport type { PipelineStep } from '../core/types.js';\nimport type { PipelineDefinition, PipelineModuleOptions } from './pipeline.options.js';\n\nfunction validatePipelineDefinition(\n def: PipelineDefinition,\n index: number,\n): void {\n if (!def.token) {\n throw new Error(\n `Pipeline definition at index ${index} is missing \"token\". Use definePipeline() to create one.`,\n );\n }\n\n if (!Array.isArray(def.steps) || def.steps.length === 0) {\n throw new Error(\n `Pipeline \"${def.token.description ?? index}\" has no steps. Provide at least one step class.`,\n );\n }\n\n for (let i = 0; i < def.steps.length; i++) {\n const step = def.steps[i];\n if (typeof step !== 'function') {\n throw new Error(\n `Step at index ${i} in pipeline \"${def.token.description ?? index}\" is not a class/constructor. ` +\n `Expected a Type<PipelineStep>, got ${typeof step}.`,\n );\n }\n }\n}\n\nfunction isPipelineStep(instance: unknown): instance is PipelineStep<unknown, unknown> {\n return (\n typeof instance === 'object' &&\n instance !== null &&\n typeof (instance as PipelineStep<unknown, unknown>).handle === 'function'\n );\n}\n\n@Module({})\nexport class PipelineModule {\n static forRoot(options: PipelineModuleOptions): DynamicModule {\n const providers: Provider[] = [];\n\n for (let i = 0; i < options.pipelines.length; i++) {\n const def = options.pipelines[i];\n validatePipelineDefinition(def, i);\n\n for (const step of def.steps) {\n providers.push({ provide: step as Type, useClass: step as Type });\n }\n\n providers.push({\n provide: def.token.symbol,\n useFactory: (...stepInstances: unknown[]) => {\n const p = new Pipeline(def.options ?? {});\n\n for (let j = 0; j < stepInstances.length; j++) {\n const instance = stepInstances[j];\n\n if (!isPipelineStep(instance)) {\n const stepName = (def.steps[j] as Type)?.name ?? String(j);\n throw new Error(\n `Step \"${stepName}\" in pipeline \"${def.token.description}\" does not implement PipelineStep. ` +\n `Expected a class with a \"handle(ctx)\" method.`,\n );\n }\n\n p.pipe(instance);\n }\n\n return p;\n },\n inject: def.steps as Type[],\n });\n }\n\n return {\n module: PipelineModule,\n providers,\n exports: providers,\n global: true,\n };\n }\n}\n","import { Inject } from '@nestjs/common';\nimport type { PipelineToken } from '../core/define-pipeline.js';\n\nexport const InjectPipeline = <TContext, TError>(\n token: PipelineToken<TContext, TError>,\n): ReturnType<typeof Inject> => Inject(token.symbol);\n"]}
|
package/dist/nestjs/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Type, DynamicModule, Inject } from '@nestjs/common';
|
|
2
|
-
import {
|
|
2
|
+
import { g as PipelineToken, a as PipelineStep, P as PipelineOptions } from '../define-pipeline-CIUhML8D.cjs';
|
|
3
3
|
|
|
4
4
|
interface PipelineDefinition<TContext = unknown, TError = unknown> {
|
|
5
5
|
token: PipelineToken<TContext, TError>;
|
package/dist/nestjs/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Type, DynamicModule, Inject } from '@nestjs/common';
|
|
2
|
-
import {
|
|
2
|
+
import { g as PipelineToken, a as PipelineStep, P as PipelineOptions } from '../define-pipeline-CIUhML8D.js';
|
|
3
3
|
|
|
4
4
|
interface PipelineDefinition<TContext = unknown, TError = unknown> {
|
|
5
5
|
token: PipelineToken<TContext, TError>;
|