rest-pipeline-js 1.3.6 → 1.3.7
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 +46 -0
- package/README.md +254 -0
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/pipeline-builder.js +121 -0
- package/dist/cjs/pipeline-orchestrator.js +215 -23
- package/dist/cjs/pipeline-validator.js +113 -0
- package/dist/cjs/react.js +3 -1
- package/dist/cjs/rest-client.js +34 -21
- package/dist/cjs/usePipelineStageResult-react.js +28 -0
- package/dist/cjs/usePipelineStageResult-vue.js +29 -0
- package/dist/cjs/vue.js +3 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/pipeline-builder.d.ts +84 -0
- package/dist/esm/pipeline-builder.js +115 -0
- package/dist/esm/pipeline-orchestrator.d.ts +23 -4
- package/dist/esm/pipeline-orchestrator.js +215 -23
- package/dist/esm/pipeline-validator.d.ts +17 -0
- package/dist/esm/pipeline-validator.js +110 -0
- package/dist/esm/react.d.ts +1 -0
- package/dist/esm/react.js +1 -0
- package/dist/esm/rest-client.js +34 -21
- package/dist/esm/types.d.ts +126 -2
- package/dist/esm/usePipelineStageResult-react.d.ts +16 -0
- package/dist/esm/usePipelineStageResult-react.js +25 -0
- package/dist/esm/usePipelineStageResult-vue.d.ts +17 -0
- package/dist/esm/usePipelineStageResult-vue.js +26 -0
- package/dist/esm/usePipelineStepEvents-react.d.ts +1 -1
- package/dist/esm/usePipelineStepEvents-vue.d.ts +1 -1
- package/dist/esm/vue.d.ts +1 -0
- package/dist/esm/vue.js +1 -0
- package/new.md +501 -0
- package/package.json +1 -1
- package/src/index.ts +2 -0
- package/src/pipeline-builder.ts +158 -0
- package/src/pipeline-orchestrator.ts +236 -16
- package/src/pipeline-validator.ts +151 -0
- package/src/react.ts +1 -0
- package/src/rest-client.ts +34 -26
- package/src/types.ts +171 -2
- package/src/usePipelineStageResult-react.ts +32 -0
- package/src/usePipelineStageResult-vue.ts +34 -0
- package/src/vue.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.3.7] - 2026-04-04
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
#### Pipeline Orchestrator
|
|
8
|
+
|
|
9
|
+
- **Pipeline metrics** — `PipelineConfig.metrics` with three callbacks:
|
|
10
|
+
- `onPipelineStart({ timestamp })` — fires at the beginning of `run()`
|
|
11
|
+
- `onPipelineEnd({ durationMs, success, stageResults })` — fires when `run()` completes
|
|
12
|
+
- `onStepDuration({ stepKey, durationMs, status })` — fires after every executed step
|
|
13
|
+
- **Plugin system** — `options.plugins` accepts an array of `PipelinePlugin` objects. Each plugin receives the orchestrator instance in `install(orchestrator)` and can subscribe to events, add middleware hooks, etc. Returning a function from `install()` registers it as a cleanup callback.
|
|
14
|
+
- **`destroy()`** — new public method that invokes cleanup functions from all installed plugins.
|
|
15
|
+
- **Persist adapter** — `options.persistAdapter` accepts a `PipelineStateAdapter` object with `save` / `load` methods. When set: state is automatically loaded at the start of `run()` (via `importState`) and saved after each successfully completed step.
|
|
16
|
+
- **Stream stages** — new `StreamStageConfig` element type for `PipelineItem`. The `stream` function returns an `AsyncIterable<T>`; the orchestrator iterates it and collects chunks into an array (the stage result). The optional `onChunk(chunk, sharedData)` callback fires for each chunk in real time. Stream stages honour `abort()`, `continueOnError`, and emit standard step events.
|
|
17
|
+
- **Generic step keys** — `PipelineOrchestrator<TKeys extends string = string>` now accepts a generic type parameter for typed auto-complete in `on()`, `rerunStep()`, and `subscribeStepProgress()`.
|
|
18
|
+
|
|
19
|
+
#### DX utilities
|
|
20
|
+
|
|
21
|
+
- **`createPipeline(stages, options?)`** — factory function that creates a `PipelineOrchestrator` without the nested `{ config: { stages } }` boilerplate.
|
|
22
|
+
- **`pipe()`** — fluent builder API. Methods: `.step()`, `.parallel()`, `.subPipeline()`, `.stream()`, `.build(options?)`, `.toConfig(options?)`.
|
|
23
|
+
- **`validatePipelineConfig(config, context?)`** — validates a `PipelineConfig` before runtime. Checks for duplicate keys, empty keys, empty `stages` array, invalid field types, and recursively validates nested sub-pipelines. Returns `{ valid: boolean; errors: string[] }`.
|
|
24
|
+
- **`getStageResults()`** — synchronous snapshot of all stage results (no subscription needed).
|
|
25
|
+
|
|
26
|
+
#### Vue / React hooks
|
|
27
|
+
|
|
28
|
+
- **`usePipelineStageResultVue(orchestrator, stepKey)`** — reactive `Ref<PipelineStepResult | null>` for a single step.
|
|
29
|
+
- **`usePipelineStageResultReact(orchestrator, stepKey)`** — state hook for a single step, updates on every `stageResults` change.
|
|
30
|
+
|
|
31
|
+
#### RestClient
|
|
32
|
+
|
|
33
|
+
- **`HttpAdapter`** — new `adapter` field in `HttpConfig`. When provided, replaces the built-in axios client with a custom implementation (e.g. native `fetch`). All other features (auth, interceptors, retry, sanitization, metrics) continue to work on top of the adapter.
|
|
34
|
+
|
|
35
|
+
#### Types
|
|
36
|
+
|
|
37
|
+
- `PipelineMetrics` interface
|
|
38
|
+
- `PipelinePlugin` type
|
|
39
|
+
- `PipelineStateAdapter` type
|
|
40
|
+
- `StreamStageConfig<T>` type; updated `PipelineItem` union to include it
|
|
41
|
+
- `HttpAdapter` type
|
|
42
|
+
- `PipelineLogEventType` union — exhaustive list of all log event type strings
|
|
43
|
+
- Extended `PipelineConfig` with `metrics?`
|
|
44
|
+
- Extended `PipelineOptions` with `persistAdapter?` and `plugins?`
|
|
45
|
+
- Extended `HttpConfig` with `adapter?`
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
3
49
|
## [1.3.6] - 2026-04-03
|
|
4
50
|
|
|
5
51
|
### Added
|
package/README.md
CHANGED
|
@@ -161,6 +161,7 @@ Creates a REST client with advanced HTTP features.
|
|
|
161
161
|
| `sanitizeHeaders` | Mask sensitive headers in metrics callbacks (default: `false`) |
|
|
162
162
|
| `sensitiveHeaders` | Additional headers to mask (extends `DEFAULT_SENSITIVE_HEADERS`) |
|
|
163
163
|
| `retry.maxRetryAfterMs` | Max wait from `Retry-After` header in ms (default: `60000`) |
|
|
164
|
+
| `adapter` | Custom HTTP adapter (e.g. native `fetch`) — replaces built-in axios |
|
|
164
165
|
|
|
165
166
|
**Per-request cache override:**
|
|
166
167
|
|
|
@@ -290,6 +291,8 @@ new PipelineOrchestrator({
|
|
|
290
291
|
| `isPaused()` | Check if pipeline is paused |
|
|
291
292
|
| `exportState()` | Serialize stageResults and logs to a plain object |
|
|
292
293
|
| `importState(state)` | Restore stageResults and logs from a snapshot |
|
|
294
|
+
| `getStageResults()` | Synchronous snapshot of all stage results (no subscription needed) |
|
|
295
|
+
| `destroy()` | Run cleanup callbacks from all installed plugins |
|
|
293
296
|
| `subscribeProgress(listener)` | Subscribe to progress updates |
|
|
294
297
|
| `subscribeStageResults(listener)` | Subscribe to stageResults changes |
|
|
295
298
|
| `subscribeStepProgress(stepKey, listener)` | Subscribe to a specific stage's progress |
|
|
@@ -457,6 +460,255 @@ console.log(orchestrator2.getLogs()); // restored logs (timestamps as Date objec
|
|
|
457
460
|
|
|
458
461
|
---
|
|
459
462
|
|
|
463
|
+
### Pipeline metrics
|
|
464
|
+
|
|
465
|
+
Observe pipeline execution without modifying stage logic:
|
|
466
|
+
|
|
467
|
+
```js
|
|
468
|
+
const orchestrator = new PipelineOrchestrator({
|
|
469
|
+
config: {
|
|
470
|
+
stages: [ /* ... */ ],
|
|
471
|
+
metrics: {
|
|
472
|
+
onPipelineStart: ({ timestamp }) => {
|
|
473
|
+
console.log("Pipeline started at", new Date(timestamp).toISOString());
|
|
474
|
+
},
|
|
475
|
+
onPipelineEnd: ({ durationMs, success, stageResults }) => {
|
|
476
|
+
analytics.track("pipeline_complete", { durationMs, success });
|
|
477
|
+
},
|
|
478
|
+
onStepDuration: ({ stepKey, durationMs, status }) => {
|
|
479
|
+
console.log(`[${stepKey}] ${status} in ${durationMs}ms`);
|
|
480
|
+
},
|
|
481
|
+
},
|
|
482
|
+
},
|
|
483
|
+
});
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
| Callback | Receives | Description |
|
|
487
|
+
|----------|----------|-------------|
|
|
488
|
+
| `onPipelineStart` | `{ timestamp }` | Fires at the beginning of `run()` |
|
|
489
|
+
| `onPipelineEnd` | `{ durationMs, success, stageResults }` | Fires when `run()` completes |
|
|
490
|
+
| `onStepDuration` | `{ stepKey, durationMs, status }` | Fires after every executed step |
|
|
491
|
+
|
|
492
|
+
---
|
|
493
|
+
|
|
494
|
+
### createPipeline() + pipe() builder
|
|
495
|
+
|
|
496
|
+
#### createPipeline() — short factory
|
|
497
|
+
|
|
498
|
+
```js
|
|
499
|
+
import { createPipeline } from "rest-pipeline-js";
|
|
500
|
+
|
|
501
|
+
const orchestrator = createPipeline(
|
|
502
|
+
[
|
|
503
|
+
{ key: "fetchUser", request: async () => fetchUser() },
|
|
504
|
+
{ key: "process", request: async ({ prev }) => process(prev) },
|
|
505
|
+
],
|
|
506
|
+
{
|
|
507
|
+
httpConfig: { baseURL: "https://api.example.com" },
|
|
508
|
+
sharedData: { userId: 42 },
|
|
509
|
+
pipelineOptions: { continueOnError: false },
|
|
510
|
+
metrics: { onStepDuration: ({ stepKey, durationMs }) => console.log(stepKey, durationMs) },
|
|
511
|
+
},
|
|
512
|
+
);
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
#### pipe() — fluent builder
|
|
516
|
+
|
|
517
|
+
```js
|
|
518
|
+
import { pipe } from "rest-pipeline-js";
|
|
519
|
+
|
|
520
|
+
const orchestrator = pipe()
|
|
521
|
+
.step({ key: "auth", request: async () => getToken() })
|
|
522
|
+
.step({ key: "fetchUser", request: async ({ prev }) => fetchUser(prev) })
|
|
523
|
+
.parallel([
|
|
524
|
+
{ key: "loadPosts", request: async () => fetchPosts() },
|
|
525
|
+
{ key: "loadNotifs", request: async () => fetchNotifications() },
|
|
526
|
+
])
|
|
527
|
+
.stream({
|
|
528
|
+
key: "liveUpdates",
|
|
529
|
+
stream: async function* () { yield* subscribe("/events"); },
|
|
530
|
+
onChunk: (chunk) => updateUI(chunk),
|
|
531
|
+
})
|
|
532
|
+
.build({ httpConfig: { baseURL: "https://api.example.com" } });
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
| Builder method | Description |
|
|
536
|
+
|----------------|-------------|
|
|
537
|
+
| `.step(stage)` | Add a sequential stage |
|
|
538
|
+
| `.parallel(stages, options?)` | Add a parallel group (`key` auto-generated if omitted) |
|
|
539
|
+
| `.subPipeline(item)` | Embed a sub-pipeline as a stage |
|
|
540
|
+
| `.stream(stage)` | Add a stream stage (AsyncIterable) |
|
|
541
|
+
| `.build(options?)` | Create and return a `PipelineOrchestrator` |
|
|
542
|
+
| `.toConfig(options?)` | Return `PipelineConfig` without creating an orchestrator |
|
|
543
|
+
|
|
544
|
+
---
|
|
545
|
+
|
|
546
|
+
### validatePipelineConfig()
|
|
547
|
+
|
|
548
|
+
Catch configuration errors before runtime:
|
|
549
|
+
|
|
550
|
+
```js
|
|
551
|
+
import { validatePipelineConfig } from "rest-pipeline-js";
|
|
552
|
+
|
|
553
|
+
const { valid, errors } = validatePipelineConfig({
|
|
554
|
+
stages: [
|
|
555
|
+
{ key: "step1", request: async () => data },
|
|
556
|
+
{ key: "step1", request: async () => other }, // duplicate!
|
|
557
|
+
{ key: "", request: async () => other }, // empty key!
|
|
558
|
+
],
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
if (!valid) console.error(errors);
|
|
562
|
+
// ["[root] duplicate stage key: "step1"", "[root] stage key must be a non-empty string"]
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
Validates: duplicate keys, empty/invalid keys, empty `stages` array, invalid field types (`request`, `condition`, `retryCount`, `timeoutMs`), and recursively validates nested `subPipeline` configs.
|
|
566
|
+
|
|
567
|
+
---
|
|
568
|
+
|
|
569
|
+
### Plugin system
|
|
570
|
+
|
|
571
|
+
Package reusable orchestrator behavior into plugins:
|
|
572
|
+
|
|
573
|
+
```js
|
|
574
|
+
const loggingPlugin = {
|
|
575
|
+
name: "logging",
|
|
576
|
+
install(orchestrator) {
|
|
577
|
+
const off = orchestrator.on("log", (event) => {
|
|
578
|
+
if (event.type === "step:success") console.log("✓", event.stepKey);
|
|
579
|
+
if (event.type === "step:error") console.error("✗", event.stepKey, event.error);
|
|
580
|
+
});
|
|
581
|
+
return () => off(); // cleanup on orchestrator.destroy()
|
|
582
|
+
},
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
const orchestrator = new PipelineOrchestrator({
|
|
586
|
+
config: {
|
|
587
|
+
stages: [ /* ... */ ],
|
|
588
|
+
options: {
|
|
589
|
+
plugins: [loggingPlugin, analyticsPlugin],
|
|
590
|
+
},
|
|
591
|
+
},
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
// Call when the orchestrator is no longer needed:
|
|
595
|
+
orchestrator.destroy();
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
- `install(orchestrator)` — receives the orchestrator instance; may subscribe to events, set up middleware, etc.
|
|
599
|
+
- If `install` returns a function, it is registered as a cleanup callback and invoked by `destroy()`.
|
|
600
|
+
|
|
601
|
+
---
|
|
602
|
+
|
|
603
|
+
### Persist adapter
|
|
604
|
+
|
|
605
|
+
Automatically save and restore pipeline state across page reloads:
|
|
606
|
+
|
|
607
|
+
```js
|
|
608
|
+
const localStorageAdapter = {
|
|
609
|
+
save: (state) => localStorage.setItem("pipeline", JSON.stringify(state)),
|
|
610
|
+
load: () => {
|
|
611
|
+
const raw = localStorage.getItem("pipeline");
|
|
612
|
+
return raw ? JSON.parse(raw) : null;
|
|
613
|
+
},
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
const orchestrator = new PipelineOrchestrator({
|
|
617
|
+
config: {
|
|
618
|
+
stages: [ /* ... */ ],
|
|
619
|
+
options: { persistAdapter: localStorageAdapter },
|
|
620
|
+
},
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
// run() loads saved state at start; saves after each completed step
|
|
624
|
+
await orchestrator.run();
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
The adapter interface:
|
|
628
|
+
|
|
629
|
+
```ts
|
|
630
|
+
type PipelineStateAdapter = {
|
|
631
|
+
save(state: PipelineExportedState): void | Promise<void>;
|
|
632
|
+
load(): PipelineExportedState | null | Promise<PipelineExportedState | null>;
|
|
633
|
+
};
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
Both methods may be async (useful for IndexedDB or remote storage).
|
|
637
|
+
|
|
638
|
+
---
|
|
639
|
+
|
|
640
|
+
### Stream stages (SSE / AsyncIterable)
|
|
641
|
+
|
|
642
|
+
A stage whose `stream` function returns an `AsyncIterable<T>`. The orchestrator collects all emitted chunks into an array (the stage result). `onChunk` is called for each chunk in real time.
|
|
643
|
+
|
|
644
|
+
```js
|
|
645
|
+
const orchestrator = createPipeline([
|
|
646
|
+
{ key: "auth", request: async () => getToken() },
|
|
647
|
+
{
|
|
648
|
+
key: "liveData",
|
|
649
|
+
stream: async function* ({ prev }) {
|
|
650
|
+
// prev is the result of "auth"
|
|
651
|
+
const source = new EventSource(`/api/stream?token=${prev}`);
|
|
652
|
+
yield* eventSourceToAsyncIterable(source);
|
|
653
|
+
},
|
|
654
|
+
onChunk: (chunk, sharedData) => {
|
|
655
|
+
sharedData.partial = (sharedData.partial ?? "") + chunk;
|
|
656
|
+
updateUI(sharedData.partial);
|
|
657
|
+
},
|
|
658
|
+
},
|
|
659
|
+
{
|
|
660
|
+
key: "finalize",
|
|
661
|
+
// allResults.liveData.data is the full array of chunks
|
|
662
|
+
request: async ({ allResults }) => allResults.liveData.data.join(""),
|
|
663
|
+
},
|
|
664
|
+
]);
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
- Respects `abort()` — checks the abort signal between each chunk.
|
|
668
|
+
- Supports `continueOnError` — failed stream stages can be skipped like any other step.
|
|
669
|
+
- Emits standard step events: `step:start`, `step:success`, `step:error`.
|
|
670
|
+
|
|
671
|
+
---
|
|
672
|
+
|
|
673
|
+
### HTTP Adapter (custom fetch / edge environments)
|
|
674
|
+
|
|
675
|
+
Replace the built-in axios client with any HTTP implementation:
|
|
676
|
+
|
|
677
|
+
```js
|
|
678
|
+
const fetchAdapter = {
|
|
679
|
+
async request(config) {
|
|
680
|
+
const url = `${config.baseURL ?? ""}${config.url ?? ""}`;
|
|
681
|
+
const res = await fetch(url, {
|
|
682
|
+
method: config.method ?? "GET",
|
|
683
|
+
body: config.data ? JSON.stringify(config.data) : undefined,
|
|
684
|
+
headers: { "Content-Type": "application/json", ...config.headers },
|
|
685
|
+
signal: config.signal,
|
|
686
|
+
});
|
|
687
|
+
const data = await res.json();
|
|
688
|
+
return { data, status: res.status, statusText: res.statusText,
|
|
689
|
+
headers: Object.fromEntries(res.headers.entries()) };
|
|
690
|
+
},
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
const client = createRestClient({
|
|
694
|
+
baseURL: "https://api.example.com",
|
|
695
|
+
adapter: fetchAdapter,
|
|
696
|
+
// Auth, interceptors, sanitizeHeaders, metrics still work on top of the adapter
|
|
697
|
+
auth: { getToken: async () => token },
|
|
698
|
+
interceptors: { request: [addCorrelationId] },
|
|
699
|
+
});
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
```ts
|
|
703
|
+
type HttpAdapter = {
|
|
704
|
+
request<T = unknown>(
|
|
705
|
+
config: RestRequestConfig & { baseURL?: string },
|
|
706
|
+
): Promise<ApiResponse<T>>;
|
|
707
|
+
};
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
---
|
|
711
|
+
|
|
460
712
|
### Vue integration
|
|
461
713
|
|
|
462
714
|
#### Example: use in Vue component
|
|
@@ -504,6 +756,7 @@ Composition functions (import from `rest-pipeline-js/vue`):
|
|
|
504
756
|
| `usePipelineLogsVue(orchestrator)` | `Ref<log[]>` | Reactive logs |
|
|
505
757
|
| `useRerunPipelineStepVue(orchestrator)` | `function` | Bound `rerunStep` |
|
|
506
758
|
| `useRestClientVue(config)` | `ComputedRef<RestClient>` | Reactive REST client |
|
|
759
|
+
| `usePipelineStageResultVue(orchestrator, stepKey)` | `Ref<PipelineStepResult \| null>` | Reactive result of a single stage |
|
|
507
760
|
|
|
508
761
|
---
|
|
509
762
|
|
|
@@ -560,6 +813,7 @@ Hooks (import from `rest-pipeline-js/react`):
|
|
|
560
813
|
| `usePipelineLogsReact(orchestrator)` | `log[]` | Reactive logs |
|
|
561
814
|
| `useRerunPipelineStepReact(orchestrator)` | `function` | Bound `rerunStep` |
|
|
562
815
|
| `useRestClientReact(config)` | `RestClient` | Memoized REST client |
|
|
816
|
+
| `usePipelineStageResultReact(orchestrator, stepKey)` | `PipelineStepResult \| null` | Result of a single stage |
|
|
563
817
|
|
|
564
818
|
---
|
|
565
819
|
|
package/dist/cjs/index.js
CHANGED
|
@@ -21,3 +21,5 @@ __exportStar(require("./request-executor"), exports);
|
|
|
21
21
|
__exportStar(require("./error-handler"), exports);
|
|
22
22
|
__exportStar(require("./progress-tracker"), exports);
|
|
23
23
|
__exportStar(require("./pipeline-orchestrator"), exports);
|
|
24
|
+
__exportStar(require("./pipeline-builder"), exports);
|
|
25
|
+
__exportStar(require("./pipeline-validator"), exports);
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PipelineBuilder = void 0;
|
|
4
|
+
exports.createPipeline = createPipeline;
|
|
5
|
+
exports.pipe = pipe;
|
|
6
|
+
const pipeline_orchestrator_1 = require("./pipeline-orchestrator");
|
|
7
|
+
/**
|
|
8
|
+
* Сокращённая фабричная функция для создания PipelineOrchestrator.
|
|
9
|
+
* Избавляет от необходимости писать вложенный объект `{ config: { stages: [...] } }`.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* const orchestrator = createPipeline([
|
|
13
|
+
* { key: "fetchUser", request: async () => fetchUser() },
|
|
14
|
+
* { key: "processData", request: async ({ prev }) => process(prev) },
|
|
15
|
+
* ], {
|
|
16
|
+
* httpConfig: { baseURL: "https://api.example.com" },
|
|
17
|
+
* sharedData: { userId: 42 },
|
|
18
|
+
* });
|
|
19
|
+
*/
|
|
20
|
+
function createPipeline(stages, options = {}) {
|
|
21
|
+
return new pipeline_orchestrator_1.PipelineOrchestrator({
|
|
22
|
+
config: {
|
|
23
|
+
stages,
|
|
24
|
+
middleware: options.middleware,
|
|
25
|
+
options: options.pipelineOptions,
|
|
26
|
+
metrics: options.metrics,
|
|
27
|
+
},
|
|
28
|
+
httpConfig: options.httpConfig,
|
|
29
|
+
sharedData: options.sharedData,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
33
|
+
// 4.2 pipe() — Fluent builder API
|
|
34
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
35
|
+
/**
|
|
36
|
+
* Fluent builder для создания pipeline.
|
|
37
|
+
* Позволяет строить конвейер цепочкой вызовов вместо ручного конструирования массива stages.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* const orchestrator = pipe()
|
|
41
|
+
* .step({ key: "auth", request: async () => getToken() })
|
|
42
|
+
* .step({ key: "fetchUser", condition: ({ prev }) => !!prev, request: async ({ prev }) => fetchUser(prev) })
|
|
43
|
+
* .parallel([
|
|
44
|
+
* { key: "loadA", request: async () => loadA() },
|
|
45
|
+
* { key: "loadB", request: async () => loadB() },
|
|
46
|
+
* ])
|
|
47
|
+
* .build({ httpConfig: { baseURL: "https://api.example.com" } });
|
|
48
|
+
*/
|
|
49
|
+
class PipelineBuilder {
|
|
50
|
+
constructor() {
|
|
51
|
+
this.stages = [];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Добавить обычный (последовательный) шаг.
|
|
55
|
+
*/
|
|
56
|
+
step(stage) {
|
|
57
|
+
this.stages.push(stage);
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Добавить группу параллельных шагов.
|
|
62
|
+
* Все шаги в группе выполняются одновременно через Promise.all.
|
|
63
|
+
*/
|
|
64
|
+
parallel(stages, options) {
|
|
65
|
+
var _a;
|
|
66
|
+
const group = {
|
|
67
|
+
key: (_a = options === null || options === void 0 ? void 0 : options.key) !== null && _a !== void 0 ? _a : `parallel-${this.stages.length}`,
|
|
68
|
+
parallel: stages,
|
|
69
|
+
...((options === null || options === void 0 ? void 0 : options.continueOnError) !== undefined
|
|
70
|
+
? { continueOnError: options.continueOnError }
|
|
71
|
+
: {}),
|
|
72
|
+
};
|
|
73
|
+
this.stages.push(group);
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Добавить вложенный pipeline как шаг.
|
|
78
|
+
*/
|
|
79
|
+
subPipeline(item) {
|
|
80
|
+
this.stages.push(item);
|
|
81
|
+
return this;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Добавить stream-шаг (SSE / AsyncIterable).
|
|
85
|
+
*/
|
|
86
|
+
stream(stage) {
|
|
87
|
+
this.stages.push(stage);
|
|
88
|
+
return this;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Создать PipelineOrchestrator из накопленных шагов.
|
|
92
|
+
*/
|
|
93
|
+
build(options = {}) {
|
|
94
|
+
return createPipeline([...this.stages], options);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Получить только конфиг (без создания orchestrator).
|
|
98
|
+
* Полезно для передачи конфига в другое место.
|
|
99
|
+
*/
|
|
100
|
+
toConfig(options = {}) {
|
|
101
|
+
return {
|
|
102
|
+
stages: [...this.stages],
|
|
103
|
+
middleware: options.middleware,
|
|
104
|
+
options: options.pipelineOptions,
|
|
105
|
+
metrics: options.metrics,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
exports.PipelineBuilder = PipelineBuilder;
|
|
110
|
+
/**
|
|
111
|
+
* Создаёт новый PipelineBuilder.
|
|
112
|
+
* Точка входа для fluent API.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* const orchestrator = pipe()
|
|
116
|
+
* .step({ key: "step1", request: async () => data })
|
|
117
|
+
* .build();
|
|
118
|
+
*/
|
|
119
|
+
function pipe() {
|
|
120
|
+
return new PipelineBuilder();
|
|
121
|
+
}
|