rest-pipeline-js 1.0.2 → 1.0.4

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 CHANGED
@@ -13,7 +13,7 @@ npm i rest-pipeline-js
13
13
  ## Быстрый старт (чистый JS)
14
14
 
15
15
  ```js
16
- const { createRestClient, PipelineOrchestrator } = require('pipeline-js');
16
+ const { createRestClient, PipelineOrchestrator } = require('rest-pipeline-js');
17
17
 
18
18
  // Создание REST клиента
19
19
  const client = createRestClient({ baseURL: 'https://api.example.com' });
@@ -50,8 +50,8 @@ console.log(pipeline.getProgress());
50
50
 
51
51
  ### usePipelineProgress
52
52
  ```jsx
53
- import { usePipelineProgress } from 'pipeline-js/react';
54
- import { PipelineOrchestrator } from 'pipeline-js';
53
+ import { usePipelineProgress } from 'rest-pipeline-js/react';
54
+ import { PipelineOrchestrator } from 'rest-pipeline-js';
55
55
 
56
56
  const pipeline = new PipelineOrchestrator({ stages: [...] }, { baseURL: '...' });
57
57
  const progress = usePipelineProgress(pipeline);
@@ -59,7 +59,7 @@ const progress = usePipelineProgress(pipeline);
59
59
 
60
60
  ### usePipelineRun
61
61
  ```jsx
62
- import { usePipelineRun } from 'pipeline-js/react';
62
+ import { usePipelineRun } from 'rest-pipeline-js/react';
63
63
  const [run, { running, result, error }] = usePipelineRun(pipeline);
64
64
 
65
65
  // В компоненте:
@@ -71,7 +71,7 @@ const [run, { running, result, error }] = usePipelineRun(pipeline);
71
71
 
72
72
  ### useRestClient
73
73
  ```jsx
74
- import { useRestClient } from 'pipeline-js/react';
74
+ import { useRestClient } from 'rest-pipeline-js/react';
75
75
  const api = useRestClient({ baseURL: '...' });
76
76
  ```
77
77
 
@@ -79,8 +79,8 @@ const api = useRestClient({ baseURL: '...' });
79
79
 
80
80
  ### usePipelineProgress
81
81
  ```js
82
- import { usePipelineProgress } from 'pipeline-js/vue';
83
- import { PipelineOrchestrator } from 'pipeline-js';
82
+ import { usePipelineProgress } from 'rest-pipeline-js/vue';
83
+ import { PipelineOrchestrator } from 'rest-pipeline-js';
84
84
 
85
85
  const pipeline = new PipelineOrchestrator({ stages: [...] }, { baseURL: '...' });
86
86
  const progress = usePipelineProgress(pipeline);
@@ -88,20 +88,20 @@ const progress = usePipelineProgress(pipeline);
88
88
 
89
89
  ### usePipelineRun
90
90
  ```js
91
- import { usePipelineRun } from 'pipeline-js/vue';
91
+ import { usePipelineRun } from 'rest-pipeline-js/vue';
92
92
  const { run, running, result, error } = usePipelineRun(pipeline);
93
93
  ```
94
94
 
95
95
  ### useRestClient
96
96
  ```js
97
- import { useRestClient } from 'pipeline-js/vue';
97
+ import { useRestClient } from 'rest-pipeline-js/vue';
98
98
  const api = useRestClient({ baseURL: '...' });
99
99
  ```
100
100
 
101
101
  ## Использование в Vue 3
102
102
 
103
103
  ```js
104
- import { createRestClient, PipelineOrchestrator } from 'pipeline-js';
104
+ import { createRestClient, PipelineOrchestrator } from 'rest-pipeline-js';
105
105
  import { ref, onUnmounted } from 'vue';
106
106
 
107
107
  const client = createRestClient({ baseURL: 'https://api.example.com' });
@@ -0,0 +1,7 @@
1
+ export declare class ErrorHandler {
2
+ handle(error: any, stageKey: string): {
3
+ type: string;
4
+ error: any;
5
+ stageKey: string;
6
+ };
7
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ErrorHandler = void 0;
4
+ class ErrorHandler {
5
+ handle(error, stageKey) {
6
+ // TODO: реализовать классификацию и обработку ошибок
7
+ return { type: 'unknown', error, stageKey };
8
+ }
9
+ }
10
+ exports.ErrorHandler = ErrorHandler;
@@ -0,0 +1,6 @@
1
+ export * from './rest-client';
2
+ export * from './types';
3
+ export * from './request-executor';
4
+ export * from './error-handler';
5
+ export * from './progress-tracker';
6
+ export * from './pipeline-orchestrator';
package/dist/index.js ADDED
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ // Barrel file for pipeline-js module
18
+ __exportStar(require("./rest-client"), exports);
19
+ __exportStar(require("./types"), exports);
20
+ __exportStar(require("./request-executor"), exports);
21
+ __exportStar(require("./error-handler"), exports);
22
+ __exportStar(require("./progress-tracker"), exports);
23
+ __exportStar(require("./pipeline-orchestrator"), exports);
@@ -0,0 +1,31 @@
1
+ import type { PipelineConfig, PipelineResult } from './types';
2
+ export declare class PipelineOrchestrator {
3
+ private config;
4
+ private progress;
5
+ private errorHandler;
6
+ private executor;
7
+ private sharedData;
8
+ constructor(config: PipelineConfig, httpConfig: import('./types').HttpConfig, sharedData?: Record<string, unknown>);
9
+ /**
10
+ * Подписаться на изменения прогресса выполнения pipeline
11
+ * @param listener функция-обработчик изменений
12
+ * @returns функция для отписки
13
+ */
14
+ subscribeProgress(listener: (progress: import('./types').PipelineProgress) => void): () => void;
15
+ /**
16
+ * Получить текущий прогресс выполнения pipeline (snapshot, не реактивный)
17
+ */
18
+ getProgress(): {
19
+ currentStage: number;
20
+ totalStages: number;
21
+ stageStatuses: Array<"pending" | "in-progress" | "success" | "error" | "skipped">;
22
+ };
23
+ /**
24
+ * @param onStepPause
25
+ * Необязательный callback, вызывается после каждого шага (до перехода к следующему).
26
+ * Позволяет приостановить выполнение, запросить подтверждение пользователя или изменить результат шага.
27
+ * Должен вернуть (optionally изменённый) результат шага или промис с ним.
28
+ * Если не передан — пайплайн работает как раньше.
29
+ */
30
+ run(onStepPause?: (stepIndex: number, stepResult: unknown, results: unknown[]) => Promise<unknown> | unknown): Promise<PipelineResult>;
31
+ }
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PipelineOrchestrator = void 0;
4
+ const error_handler_1 = require("./error-handler");
5
+ const progress_tracker_1 = require("./progress-tracker");
6
+ const request_executor_1 = require("./request-executor");
7
+ // import { metricsBus } from '@/core/metrics/metrics-bus';
8
+ class PipelineOrchestrator {
9
+ constructor(config, httpConfig, sharedData = {}) {
10
+ this.config = config;
11
+ this.progress = new progress_tracker_1.ProgressTracker(config.stages.length);
12
+ this.errorHandler = new error_handler_1.ErrorHandler();
13
+ this.executor = new request_executor_1.RequestExecutor(httpConfig);
14
+ this.sharedData = sharedData;
15
+ }
16
+ /**
17
+ * Подписаться на изменения прогресса выполнения pipeline
18
+ * @param listener функция-обработчик изменений
19
+ * @returns функция для отписки
20
+ */
21
+ subscribeProgress(listener) {
22
+ return this.progress.subscribe(listener);
23
+ }
24
+ /**
25
+ * Получить текущий прогресс выполнения pipeline (snapshot, не реактивный)
26
+ */
27
+ getProgress() {
28
+ return this.progress.getProgress();
29
+ }
30
+ /**
31
+ * @param onStepPause
32
+ * Необязательный callback, вызывается после каждого шага (до перехода к следующему).
33
+ * Позволяет приостановить выполнение, запросить подтверждение пользователя или изменить результат шага.
34
+ * Должен вернуть (optionally изменённый) результат шага или промис с ним.
35
+ * Если не передан — пайплайн работает как раньше.
36
+ */
37
+ async run(onStepPause) {
38
+ const results = [];
39
+ const errors = [];
40
+ let success = true;
41
+ for (let i = 0; i < this.config.stages.length; i++) {
42
+ const stage = this.config.stages[i];
43
+ this.progress.updateStage(i, 'in-progress');
44
+ if (!stage) {
45
+ this.progress.updateStage(i, 'skipped');
46
+ results.push(undefined);
47
+ continue;
48
+ }
49
+ // Проверка условия выполнения этапа
50
+ if (stage.condition && !stage.condition(results[i - 1], results, this.sharedData)) {
51
+ this.progress.updateStage(i, 'skipped');
52
+ results.push(undefined);
53
+ continue;
54
+ }
55
+ try {
56
+ let stepResult;
57
+ // Всегда передаём (prev, allResults) в request — best practice для pipeline
58
+ if (typeof stage.request === 'function') {
59
+ stepResult = await stage.request(results[i - 1], results);
60
+ }
61
+ else if (stage.key) {
62
+ const res = await this.executor.execute(stage.key, undefined, stage.retryCount, stage.timeoutMs);
63
+ stepResult = res.data;
64
+ }
65
+ else {
66
+ stepResult = undefined;
67
+ }
68
+ // --- Пользовательская пауза/подтверждение/изменение результата ---
69
+ if (onStepPause) {
70
+ stepResult = await onStepPause(i, stepResult, results);
71
+ }
72
+ results.push(stepResult);
73
+ this.progress.updateStage(i, 'success');
74
+ // ...existing code...
75
+ }
76
+ catch (err) {
77
+ let handled;
78
+ if (stage && typeof stage.errorHandler === 'function') {
79
+ handled = stage.errorHandler(err, stage.key, this.sharedData);
80
+ }
81
+ else if (stage) {
82
+ handled = this.errorHandler.handle(err, stage.key);
83
+ }
84
+ else {
85
+ handled = this.errorHandler.handle(err, 'unknown');
86
+ }
87
+ if (!handled && stage) {
88
+ handled = this.errorHandler.handle(err, stage.key);
89
+ }
90
+ errors.push(handled);
91
+ this.progress.updateStage(i, 'error');
92
+ success = false;
93
+ break;
94
+ }
95
+ }
96
+ return { results, errors, success };
97
+ }
98
+ }
99
+ exports.PipelineOrchestrator = PipelineOrchestrator;
@@ -0,0 +1,16 @@
1
+ import type { PipelineProgress } from './types';
2
+ type ProgressListener = (progress: PipelineProgress) => void;
3
+ export declare class ProgressTracker {
4
+ private progress;
5
+ private listeners;
6
+ constructor(totalStages: number);
7
+ updateStage(stage: number, status: PipelineProgress['stageStatuses'][number]): void;
8
+ getProgress(): {
9
+ currentStage: number;
10
+ totalStages: number;
11
+ stageStatuses: Array<"pending" | "in-progress" | "success" | "error" | "skipped">;
12
+ };
13
+ subscribe(listener: ProgressListener): () => void;
14
+ private notify;
15
+ }
16
+ export {};
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ProgressTracker = void 0;
4
+ class ProgressTracker {
5
+ constructor(totalStages) {
6
+ this.listeners = [];
7
+ this.progress = {
8
+ currentStage: 0,
9
+ totalStages,
10
+ stageStatuses: Array(totalStages).fill('pending'),
11
+ };
12
+ }
13
+ updateStage(stage, status) {
14
+ this.progress.stageStatuses[stage] = status;
15
+ this.progress.currentStage = stage;
16
+ this.notify();
17
+ }
18
+ getProgress() {
19
+ return { ...this.progress };
20
+ }
21
+ subscribe(listener) {
22
+ this.listeners.push(listener);
23
+ // Немедленно уведомляем нового подписчика о текущем состоянии
24
+ listener({ ...this.progress });
25
+ return () => {
26
+ this.listeners = this.listeners.filter(l => l !== listener);
27
+ };
28
+ }
29
+ notify() {
30
+ for (const listener of this.listeners) {
31
+ listener({ ...this.progress });
32
+ }
33
+ }
34
+ }
35
+ exports.ProgressTracker = ProgressTracker;
@@ -0,0 +1,9 @@
1
+ import type { RestRequestConfig, HttpConfig, ApiResponse } from './types';
2
+ export declare class RequestExecutor {
3
+ private client;
4
+ constructor(httpConfig: HttpConfig);
5
+ /**
6
+ * Выполнение одного запроса с поддержкой retry и таймаута
7
+ */
8
+ execute<T = any>(command: string, reqConfig?: RestRequestConfig, retryCount?: number, timeoutMs?: number): Promise<ApiResponse<T>>;
9
+ }
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RequestExecutor = void 0;
4
+ const rest_client_1 = require("./rest-client");
5
+ class RequestExecutor {
6
+ constructor(httpConfig) {
7
+ this.client = (0, rest_client_1.getRestClient)(httpConfig);
8
+ }
9
+ /**
10
+ * Выполнение одного запроса с поддержкой retry и таймаута
11
+ */
12
+ async execute(command, reqConfig, retryCount = 0, timeoutMs = 10000) {
13
+ let attempt = 0;
14
+ let lastError = null;
15
+ while (attempt <= retryCount) {
16
+ try {
17
+ const result = await Promise.race([
18
+ this.client.request(command, reqConfig),
19
+ new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), timeoutMs)),
20
+ ]);
21
+ return result;
22
+ }
23
+ catch (err) {
24
+ lastError = err;
25
+ attempt++;
26
+ if (attempt > retryCount)
27
+ throw lastError;
28
+ }
29
+ }
30
+ throw lastError;
31
+ }
32
+ }
33
+ exports.RequestExecutor = RequestExecutor;
@@ -0,0 +1,14 @@
1
+ import type { HttpConfig, ApiError, ApiResponse, RestRequestConfig } from './types';
2
+ type RestClient = ReturnType<typeof createRestClient>;
3
+ export declare function toApiError(error: unknown): ApiError;
4
+ export declare function createRestClient(config: HttpConfig): {
5
+ request: <T = unknown>(command: string, req?: RestRequestConfig) => Promise<ApiResponse<T>>;
6
+ get: <T = unknown>(command: string, config?: Omit<RestRequestConfig, "method">) => Promise<ApiResponse<T>>;
7
+ post: <T = unknown>(command: string, data?: unknown, config?: Omit<RestRequestConfig, "method" | "data">) => Promise<ApiResponse<T>>;
8
+ put: <T = unknown>(command: string, data?: unknown, config?: Omit<RestRequestConfig, "method" | "data">) => Promise<ApiResponse<T>>;
9
+ delete: <T = unknown>(command: string, config?: Omit<RestRequestConfig, "method">) => Promise<ApiResponse<T>>;
10
+ cancellableRequest: <T = unknown>(key: string, command: string, config?: any) => Promise<ApiResponse<T>>;
11
+ cancelRequest: (key: string) => void;
12
+ };
13
+ export declare function getRestClient(config: HttpConfig): RestClient;
14
+ export {};
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.toApiError = toApiError;
7
+ exports.createRestClient = createRestClient;
8
+ exports.getRestClient = getRestClient;
9
+ const axios_1 = __importDefault(require("axios"));
10
+ function toApiError(error) {
11
+ var _a;
12
+ if (axios_1.default.isCancel(error)) {
13
+ return {
14
+ message: 'Запрос был отменен',
15
+ code: 'REQUEST_CANCELLED',
16
+ };
17
+ }
18
+ if (axios_1.default.isAxiosError(error)) {
19
+ const axiosError = error;
20
+ return {
21
+ message: axiosError.message,
22
+ code: axiosError.code,
23
+ status: (_a = axiosError.response) === null || _a === void 0 ? void 0 : _a.status,
24
+ timestamp: new Date(),
25
+ };
26
+ }
27
+ if (error instanceof Error) {
28
+ return {
29
+ message: error.message,
30
+ timestamp: new Date(),
31
+ };
32
+ }
33
+ return {
34
+ message: 'Произошла неизвестная ошибка',
35
+ timestamp: new Date(),
36
+ };
37
+ }
38
+ const restClientCache = new Map();
39
+ function createRestClient(config) {
40
+ const httpClient = axios_1.default.create({
41
+ baseURL: config.baseURL,
42
+ timeout: config.timeout,
43
+ headers: config.headers,
44
+ withCredentials: config.withCredentials,
45
+ });
46
+ // ...реализация rate limit, cache, interceptors, request, etc. (скопировать из rest.ts при необходимости)
47
+ // Для краткости: реализуйте полный функционал по мере необходимости.
48
+ async function request(command, req) {
49
+ var _a, _b, _c, _d, _e, _f, _g, _h;
50
+ const reqId = (_a = req === null || req === void 0 ? void 0 : req.requestId) !== null && _a !== void 0 ? _a : Math.random().toString(36).slice(2);
51
+ const methodUpper = ((_b = req === null || req === void 0 ? void 0 : req.method) !== null && _b !== void 0 ? _b : 'GET').toUpperCase();
52
+ const fullUrl = `${config.baseURL}${command}`;
53
+ (_d = (_c = config.metrics) === null || _c === void 0 ? void 0 : _c.onRequestStart) === null || _d === void 0 ? void 0 : _d.call(_c, {
54
+ id: reqId,
55
+ method: methodUpper,
56
+ url: fullUrl,
57
+ timestamp: Date.now(),
58
+ requestBody: req === null || req === void 0 ? void 0 : req.data,
59
+ requestParams: req === null || req === void 0 ? void 0 : req.params,
60
+ requestHeaders: req === null || req === void 0 ? void 0 : req.headers,
61
+ });
62
+ const startTs = Date.now();
63
+ try {
64
+ const response = await httpClient.request({
65
+ url: command,
66
+ ...req,
67
+ });
68
+ const payload = {
69
+ data: response.data,
70
+ status: response.status,
71
+ statusText: response.statusText,
72
+ headers: response.headers,
73
+ };
74
+ const duration = Date.now() - startTs;
75
+ // --- вычисление размера ответа ---
76
+ let responseBytes = undefined;
77
+ const headers = response.headers;
78
+ const contentLengthHeader = headers['content-length'] || headers['Content-Length'] || undefined;
79
+ const parsedLength = contentLengthHeader ? Number(contentLengthHeader) : undefined;
80
+ if (Number.isFinite(parsedLength) && parsedLength !== 0) {
81
+ responseBytes = parsedLength;
82
+ }
83
+ else {
84
+ try {
85
+ const raw = response.data;
86
+ if (typeof raw === 'string') {
87
+ responseBytes = new TextEncoder().encode(raw).length;
88
+ }
89
+ else if (raw !== undefined) {
90
+ const str = JSON.stringify(raw);
91
+ responseBytes = new TextEncoder().encode(str).length;
92
+ }
93
+ }
94
+ catch {
95
+ // ignore sizing errors
96
+ }
97
+ }
98
+ (_f = (_e = config.metrics) === null || _e === void 0 ? void 0 : _e.onRequestEnd) === null || _f === void 0 ? void 0 : _f.call(_e, {
99
+ id: reqId,
100
+ durationMs: duration,
101
+ status: response.status,
102
+ bytes: responseBytes,
103
+ responseBody: response.data,
104
+ responseHeaders: response.headers,
105
+ });
106
+ return payload;
107
+ }
108
+ catch (error) {
109
+ const duration = Date.now() - startTs;
110
+ (_h = (_g = config.metrics) === null || _g === void 0 ? void 0 : _g.onRequestEnd) === null || _h === void 0 ? void 0 : _h.call(_g, {
111
+ id: reqId,
112
+ durationMs: duration,
113
+ error: toApiError(error),
114
+ });
115
+ throw error;
116
+ }
117
+ }
118
+ // --- Реализация cancellableRequest ---
119
+ const cancelTokenSources = new Map();
120
+ function cancelRequest(key) {
121
+ const source = cancelTokenSources.get(key);
122
+ if (source) {
123
+ source.cancel(`Запрос отменен по ключу: ${key}`);
124
+ cancelTokenSources.delete(key);
125
+ }
126
+ }
127
+ async function cancellableRequest(key, command, config) {
128
+ cancelRequest(key);
129
+ const axios = await import('axios');
130
+ const source = axios.default.CancelToken.source();
131
+ cancelTokenSources.set(key, source);
132
+ try {
133
+ return await request(command, {
134
+ ...config,
135
+ cancelToken: source.token,
136
+ });
137
+ }
138
+ finally {
139
+ cancelTokenSources.delete(key);
140
+ }
141
+ }
142
+ return {
143
+ request,
144
+ get: (command, config) => request(command, { ...config, method: 'GET' }),
145
+ post: (command, data, config) => request(command, { ...config, method: 'POST', data }),
146
+ put: (command, data, config) => request(command, { ...config, method: 'PUT', data }),
147
+ delete: (command, config) => request(command, { ...config, method: 'DELETE' }),
148
+ cancellableRequest,
149
+ cancelRequest,
150
+ };
151
+ }
152
+ function getRestClient(config) {
153
+ var _a, _b;
154
+ const key = JSON.stringify({
155
+ baseURL: config.baseURL,
156
+ timeout: config.timeout,
157
+ withCredentials: config.withCredentials,
158
+ headers: (_a = config.headers) !== null && _a !== void 0 ? _a : {},
159
+ retry: (_b = config.retry) !== null && _b !== void 0 ? _b : {},
160
+ metrics: !!config.metrics,
161
+ });
162
+ const cachedClient = restClientCache.get(key);
163
+ if (cachedClient)
164
+ return cachedClient;
165
+ const client = createRestClient(config);
166
+ restClientCache.set(key, client);
167
+ return client;
168
+ }
@@ -0,0 +1,86 @@
1
+ export interface RetryConfig {
2
+ attempts: number;
3
+ delayMs: number;
4
+ backoffMultiplier: number;
5
+ retriableStatus?: number[];
6
+ }
7
+ export type RetryOptions = Partial<RetryConfig>;
8
+ export interface CacheConfig {
9
+ enabled: boolean;
10
+ ttlMs: number;
11
+ }
12
+ export interface RateLimitConfig {
13
+ maxConcurrent?: number;
14
+ maxRequestsPerInterval?: number;
15
+ intervalMs?: number;
16
+ }
17
+ export interface MetricsHandler {
18
+ onRequestStart?: (info: {
19
+ id: string;
20
+ method?: string;
21
+ url?: string;
22
+ timestamp: number;
23
+ requestBody?: unknown;
24
+ requestParams?: unknown;
25
+ requestHeaders?: Record<string, string>;
26
+ }) => void;
27
+ onRequestEnd?: (info: {
28
+ id: string;
29
+ durationMs: number;
30
+ status?: number;
31
+ error?: ApiError;
32
+ bytes?: number;
33
+ responseBody?: unknown;
34
+ responseHeaders?: Record<string, string>;
35
+ }) => void;
36
+ }
37
+ export interface HttpConfig {
38
+ baseURL: string;
39
+ timeout?: number;
40
+ headers?: Record<string, string>;
41
+ withCredentials?: boolean;
42
+ retry?: RetryOptions;
43
+ cache?: CacheConfig;
44
+ rateLimit?: RateLimitConfig;
45
+ metrics?: MetricsHandler;
46
+ }
47
+ export interface ApiError {
48
+ message: string;
49
+ code?: string | number;
50
+ status?: number;
51
+ timestamp?: Date;
52
+ }
53
+ export interface ApiResponse<T = unknown> {
54
+ data: T;
55
+ status: number;
56
+ statusText: string;
57
+ headers: Record<string, string>;
58
+ }
59
+ export type RestRequestConfig = import('axios').AxiosRequestConfig & {
60
+ useCache?: boolean;
61
+ cacheTtlMs?: number;
62
+ cacheKey?: string;
63
+ skipRateLimit?: boolean;
64
+ requestId?: string;
65
+ };
66
+ export type PipelineStageConfig<Input, Output> = {
67
+ key: string;
68
+ request: (input: Input, allResults?: any) => Promise<Output>;
69
+ condition?: (input: Input, prevResults: any, sharedData?: Record<string, any>) => boolean;
70
+ retryCount?: number;
71
+ timeoutMs?: number;
72
+ errorHandler?: (error: any, stageKey: string, sharedData?: Record<string, any>) => any;
73
+ };
74
+ export type PipelineConfig = {
75
+ stages: PipelineStageConfig<any, any>[];
76
+ };
77
+ export type PipelineProgress = {
78
+ currentStage: number;
79
+ totalStages: number;
80
+ stageStatuses: Array<'pending' | 'in-progress' | 'success' | 'error' | 'skipped'>;
81
+ };
82
+ export type PipelineResult = {
83
+ results: any[];
84
+ errors: any[];
85
+ success: boolean;
86
+ };
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "rest-pipeline-js",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Pipeline Orchestration Utilities for JavaScript REST API Clients",
5
- "main": "src/rest-client.js",
6
- "types": "src/types.ts",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
7
  "scripts": {
8
8
  "build": "tsc",
9
9
  "test": "echo \"No tests specified\" && exit 0"
@@ -39,6 +39,14 @@ export class PipelineOrchestrator {
39
39
  return this.progress.getProgress();
40
40
  }
41
41
 
42
+ /**
43
+ * Возвращает текущий снимок состояния прогресса (не реактивный).
44
+ * Для отслеживания изменений используйте subscribeProgress.
45
+ */
46
+ getProgressRef() {
47
+ return this.progress.getProgressRef();
48
+ }
49
+
42
50
  /**
43
51
  * @param onStepPause
44
52
  * Необязательный callback, вызывается после каждого шага (до перехода к следующему).
@@ -15,6 +15,14 @@ export class ProgressTracker {
15
15
  };
16
16
  }
17
17
 
18
+ /**
19
+ * Возвращает текущий снимок состояния прогресса (не реактивный).
20
+ * Для отслеживания изменений используйте subscribeProgress.
21
+ */
22
+ getProgressRef() {
23
+ return this.progress;
24
+ }
25
+
18
26
  updateStage(stage: number, status: PipelineProgress['stageStatuses'][number]) {
19
27
  this.progress.stageStatuses[stage] = status;
20
28
  this.progress.currentStage = stage;
package/tsconfig.json CHANGED
@@ -2,7 +2,8 @@
2
2
  {
3
3
  "compilerOptions": {
4
4
  "target": "ES2019",
5
- "module": "commonjs",
5
+ "module": "NodeNext",
6
+ "moduleResolution": "nodenext",
6
7
  "declaration": true,
7
8
  "outDir": "dist",
8
9
  "strict": true,