@parsrun/service 0.1.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 +375 -0
- package/dist/client.d.ts +55 -0
- package/dist/client.js +1474 -0
- package/dist/client.js.map +1 -0
- package/dist/define.d.ts +82 -0
- package/dist/define.js +120 -0
- package/dist/define.js.map +1 -0
- package/dist/events/index.d.ts +285 -0
- package/dist/events/index.js +853 -0
- package/dist/events/index.js.map +1 -0
- package/dist/handler-CmiDUWZv.d.ts +204 -0
- package/dist/index-CVOAoJjZ.d.ts +268 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.js +3589 -0
- package/dist/index.js.map +1 -0
- package/dist/resilience/index.d.ts +197 -0
- package/dist/resilience/index.js +387 -0
- package/dist/resilience/index.js.map +1 -0
- package/dist/rpc/index.d.ts +5 -0
- package/dist/rpc/index.js +1175 -0
- package/dist/rpc/index.js.map +1 -0
- package/dist/serialization/index.d.ts +37 -0
- package/dist/serialization/index.js +320 -0
- package/dist/serialization/index.js.map +1 -0
- package/dist/server-DFE8n2Sx.d.ts +106 -0
- package/dist/tracing/index.d.ts +406 -0
- package/dist/tracing/index.js +820 -0
- package/dist/tracing/index.js.map +1 -0
- package/dist/transports/cloudflare/index.d.ts +237 -0
- package/dist/transports/cloudflare/index.js +746 -0
- package/dist/transports/cloudflare/index.js.map +1 -0
- package/dist/types-n4LLSPQU.d.ts +473 -0
- package/package.json +91 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @parsrun/service - Circuit Breaker
|
|
3
|
+
* Prevents cascading failures by failing fast when a service is unhealthy
|
|
4
|
+
*/
|
|
5
|
+
interface CircuitBreakerOptions {
|
|
6
|
+
/** Number of failures before opening circuit */
|
|
7
|
+
failureThreshold: number;
|
|
8
|
+
/** Time to wait before half-open state (ms) */
|
|
9
|
+
resetTimeout: number;
|
|
10
|
+
/** Number of successes in half-open to close circuit */
|
|
11
|
+
successThreshold: number;
|
|
12
|
+
/** Optional callback on state change */
|
|
13
|
+
onStateChange?: (from: CircuitState, to: CircuitState) => void;
|
|
14
|
+
}
|
|
15
|
+
type CircuitState = "closed" | "open" | "half-open";
|
|
16
|
+
/**
|
|
17
|
+
* Circuit Breaker implementation
|
|
18
|
+
*
|
|
19
|
+
* States:
|
|
20
|
+
* - CLOSED: Normal operation, requests pass through
|
|
21
|
+
* - OPEN: Failing fast, requests are rejected immediately
|
|
22
|
+
* - HALF-OPEN: Testing if service recovered, limited requests allowed
|
|
23
|
+
*/
|
|
24
|
+
declare class CircuitBreaker {
|
|
25
|
+
private _state;
|
|
26
|
+
private failures;
|
|
27
|
+
private successes;
|
|
28
|
+
private lastFailureTime;
|
|
29
|
+
private readonly options;
|
|
30
|
+
constructor(options: CircuitBreakerOptions);
|
|
31
|
+
/**
|
|
32
|
+
* Get current state
|
|
33
|
+
*/
|
|
34
|
+
get state(): CircuitState;
|
|
35
|
+
/**
|
|
36
|
+
* Execute a function with circuit breaker protection
|
|
37
|
+
*/
|
|
38
|
+
execute<T>(fn: () => Promise<T>): Promise<T>;
|
|
39
|
+
/**
|
|
40
|
+
* Record a successful call
|
|
41
|
+
*/
|
|
42
|
+
private onSuccess;
|
|
43
|
+
/**
|
|
44
|
+
* Record a failed call
|
|
45
|
+
*/
|
|
46
|
+
private onFailure;
|
|
47
|
+
/**
|
|
48
|
+
* Transition to a new state
|
|
49
|
+
*/
|
|
50
|
+
private transitionTo;
|
|
51
|
+
/**
|
|
52
|
+
* Manually reset the circuit breaker
|
|
53
|
+
*/
|
|
54
|
+
reset(): void;
|
|
55
|
+
/**
|
|
56
|
+
* Get circuit breaker statistics
|
|
57
|
+
*/
|
|
58
|
+
getStats(): {
|
|
59
|
+
state: CircuitState;
|
|
60
|
+
failures: number;
|
|
61
|
+
successes: number;
|
|
62
|
+
lastFailureTime: number;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @parsrun/service - Bulkhead
|
|
68
|
+
* Limits concurrent requests to prevent resource exhaustion
|
|
69
|
+
*/
|
|
70
|
+
interface BulkheadOptions {
|
|
71
|
+
/** Maximum concurrent requests */
|
|
72
|
+
maxConcurrent: number;
|
|
73
|
+
/** Maximum queue size (0 = no queue) */
|
|
74
|
+
maxQueue: number;
|
|
75
|
+
/** Optional callback when request is rejected */
|
|
76
|
+
onRejected?: () => void;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Bulkhead implementation
|
|
80
|
+
*
|
|
81
|
+
* Limits the number of concurrent requests to protect resources.
|
|
82
|
+
* Excess requests can be queued up to maxQueue limit.
|
|
83
|
+
*/
|
|
84
|
+
declare class Bulkhead {
|
|
85
|
+
private _concurrent;
|
|
86
|
+
private readonly queue;
|
|
87
|
+
private readonly options;
|
|
88
|
+
constructor(options: BulkheadOptions);
|
|
89
|
+
/**
|
|
90
|
+
* Get current concurrent count
|
|
91
|
+
*/
|
|
92
|
+
get concurrent(): number;
|
|
93
|
+
/**
|
|
94
|
+
* Get current queue size
|
|
95
|
+
*/
|
|
96
|
+
get queued(): number;
|
|
97
|
+
/**
|
|
98
|
+
* Check if bulkhead is full
|
|
99
|
+
*/
|
|
100
|
+
get isFull(): boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Execute a function with bulkhead protection
|
|
103
|
+
*/
|
|
104
|
+
execute<T>(fn: () => Promise<T>): Promise<T>;
|
|
105
|
+
/**
|
|
106
|
+
* Execute immediately
|
|
107
|
+
*/
|
|
108
|
+
private doExecute;
|
|
109
|
+
/**
|
|
110
|
+
* Add to queue
|
|
111
|
+
*/
|
|
112
|
+
private enqueue;
|
|
113
|
+
/**
|
|
114
|
+
* Process queued requests
|
|
115
|
+
*/
|
|
116
|
+
private processQueue;
|
|
117
|
+
/**
|
|
118
|
+
* Get bulkhead statistics
|
|
119
|
+
*/
|
|
120
|
+
getStats(): {
|
|
121
|
+
concurrent: number;
|
|
122
|
+
queued: number;
|
|
123
|
+
maxConcurrent: number;
|
|
124
|
+
maxQueue: number;
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Clear the queue (reject all pending)
|
|
128
|
+
*/
|
|
129
|
+
clearQueue(): void;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @parsrun/service - Retry
|
|
134
|
+
* Retry failed operations with backoff
|
|
135
|
+
*/
|
|
136
|
+
interface RetryOptions {
|
|
137
|
+
/** Number of retry attempts (not including initial attempt) */
|
|
138
|
+
attempts: number;
|
|
139
|
+
/** Backoff strategy */
|
|
140
|
+
backoff: "linear" | "exponential";
|
|
141
|
+
/** Initial delay in ms */
|
|
142
|
+
initialDelay: number;
|
|
143
|
+
/** Maximum delay in ms */
|
|
144
|
+
maxDelay: number;
|
|
145
|
+
/** Jitter factor (0-1) to add randomness */
|
|
146
|
+
jitter?: number;
|
|
147
|
+
/** Should retry predicate */
|
|
148
|
+
shouldRetry?: (error: unknown, attempt: number) => boolean;
|
|
149
|
+
/** Callback on retry */
|
|
150
|
+
onRetry?: (error: unknown, attempt: number, delay: number) => void;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Wrap a function with retry logic
|
|
154
|
+
*/
|
|
155
|
+
declare function withRetry<T>(fn: () => Promise<T>, options: RetryOptions): () => Promise<T>;
|
|
156
|
+
/**
|
|
157
|
+
* Execute a function with retry
|
|
158
|
+
*/
|
|
159
|
+
declare function executeWithRetry<T>(fn: () => Promise<T>, options: RetryOptions): Promise<T>;
|
|
160
|
+
/**
|
|
161
|
+
* Create a retry wrapper with preset options
|
|
162
|
+
*/
|
|
163
|
+
declare function createRetryWrapper(defaultOptions: Partial<RetryOptions>): <T>(fn: () => Promise<T>, options?: Partial<RetryOptions>) => Promise<T>;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* @parsrun/service - Timeout
|
|
167
|
+
* Timeout wrapper for async operations
|
|
168
|
+
*/
|
|
169
|
+
/**
|
|
170
|
+
* Timeout error
|
|
171
|
+
*/
|
|
172
|
+
declare class TimeoutExceededError extends Error {
|
|
173
|
+
readonly timeout: number;
|
|
174
|
+
constructor(timeout: number);
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Wrap a function with timeout
|
|
178
|
+
*/
|
|
179
|
+
declare function withTimeout<T>(fn: () => Promise<T>, timeoutMs: number, onTimeout?: () => void | never): () => Promise<T>;
|
|
180
|
+
/**
|
|
181
|
+
* Execute a function with timeout
|
|
182
|
+
*/
|
|
183
|
+
declare function executeWithTimeout<T>(fn: () => Promise<T>, timeoutMs: number, onTimeout?: () => void | never): Promise<T>;
|
|
184
|
+
/**
|
|
185
|
+
* Create a timeout wrapper with preset duration
|
|
186
|
+
*/
|
|
187
|
+
declare function createTimeoutWrapper(defaultTimeoutMs: number): <T>(fn: () => Promise<T>, timeoutMs?: number) => Promise<T>;
|
|
188
|
+
/**
|
|
189
|
+
* Race multiple promises with a timeout
|
|
190
|
+
*/
|
|
191
|
+
declare function raceWithTimeout<T>(promises: Promise<T>[], timeoutMs: number): Promise<T>;
|
|
192
|
+
/**
|
|
193
|
+
* Execute with deadline (absolute time)
|
|
194
|
+
*/
|
|
195
|
+
declare function executeWithDeadline<T>(fn: () => Promise<T>, deadline: Date): Promise<T>;
|
|
196
|
+
|
|
197
|
+
export { Bulkhead, type BulkheadOptions, CircuitBreaker, type CircuitBreakerOptions, type CircuitState, type RetryOptions, TimeoutExceededError, createRetryWrapper, createTimeoutWrapper, executeWithDeadline, executeWithRetry, executeWithTimeout, raceWithTimeout, withRetry, withTimeout };
|
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
// src/rpc/errors.ts
|
|
2
|
+
import { ParsError } from "@parsrun/core";
|
|
3
|
+
var RpcError = class extends ParsError {
|
|
4
|
+
retryable;
|
|
5
|
+
retryAfter;
|
|
6
|
+
constructor(message, code, statusCode = 500, options) {
|
|
7
|
+
super(message, code, statusCode, options?.details);
|
|
8
|
+
this.name = "RpcError";
|
|
9
|
+
this.retryable = options?.retryable ?? false;
|
|
10
|
+
if (options?.retryAfter !== void 0) {
|
|
11
|
+
this.retryAfter = options.retryAfter;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
var CircuitOpenError = class extends RpcError {
|
|
16
|
+
constructor(serviceName, resetAfterMs) {
|
|
17
|
+
super(
|
|
18
|
+
`Circuit breaker open for ${serviceName}`,
|
|
19
|
+
"CIRCUIT_OPEN",
|
|
20
|
+
503,
|
|
21
|
+
{
|
|
22
|
+
retryable: true,
|
|
23
|
+
retryAfter: Math.ceil(resetAfterMs / 1e3),
|
|
24
|
+
details: { service: serviceName, resetAfterMs }
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
this.name = "CircuitOpenError";
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
var BulkheadRejectedError = class extends RpcError {
|
|
31
|
+
constructor(serviceName) {
|
|
32
|
+
super(
|
|
33
|
+
`Request rejected by bulkhead for ${serviceName}: too many concurrent requests`,
|
|
34
|
+
"BULKHEAD_REJECTED",
|
|
35
|
+
503,
|
|
36
|
+
{
|
|
37
|
+
retryable: true,
|
|
38
|
+
retryAfter: 1,
|
|
39
|
+
details: { service: serviceName }
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
this.name = "BulkheadRejectedError";
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// src/resilience/circuit-breaker.ts
|
|
47
|
+
var CircuitBreaker = class {
|
|
48
|
+
_state = "closed";
|
|
49
|
+
failures = 0;
|
|
50
|
+
successes = 0;
|
|
51
|
+
lastFailureTime = 0;
|
|
52
|
+
options;
|
|
53
|
+
constructor(options) {
|
|
54
|
+
this.options = options;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get current state
|
|
58
|
+
*/
|
|
59
|
+
get state() {
|
|
60
|
+
if (this._state === "open") {
|
|
61
|
+
const timeSinceFailure = Date.now() - this.lastFailureTime;
|
|
62
|
+
if (timeSinceFailure >= this.options.resetTimeout) {
|
|
63
|
+
this.transitionTo("half-open");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return this._state;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Execute a function with circuit breaker protection
|
|
70
|
+
*/
|
|
71
|
+
async execute(fn) {
|
|
72
|
+
const currentState = this.state;
|
|
73
|
+
if (currentState === "open") {
|
|
74
|
+
const resetAfter = this.options.resetTimeout - (Date.now() - this.lastFailureTime);
|
|
75
|
+
throw new CircuitOpenError("service", Math.max(0, resetAfter));
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const result = await fn();
|
|
79
|
+
this.onSuccess();
|
|
80
|
+
return result;
|
|
81
|
+
} catch (error) {
|
|
82
|
+
this.onFailure();
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Record a successful call
|
|
88
|
+
*/
|
|
89
|
+
onSuccess() {
|
|
90
|
+
if (this._state === "half-open") {
|
|
91
|
+
this.successes++;
|
|
92
|
+
if (this.successes >= this.options.successThreshold) {
|
|
93
|
+
this.transitionTo("closed");
|
|
94
|
+
}
|
|
95
|
+
} else if (this._state === "closed") {
|
|
96
|
+
this.failures = 0;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Record a failed call
|
|
101
|
+
*/
|
|
102
|
+
onFailure() {
|
|
103
|
+
this.lastFailureTime = Date.now();
|
|
104
|
+
if (this._state === "half-open") {
|
|
105
|
+
this.transitionTo("open");
|
|
106
|
+
} else if (this._state === "closed") {
|
|
107
|
+
this.failures++;
|
|
108
|
+
if (this.failures >= this.options.failureThreshold) {
|
|
109
|
+
this.transitionTo("open");
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Transition to a new state
|
|
115
|
+
*/
|
|
116
|
+
transitionTo(newState) {
|
|
117
|
+
const oldState = this._state;
|
|
118
|
+
this._state = newState;
|
|
119
|
+
if (newState === "closed") {
|
|
120
|
+
this.failures = 0;
|
|
121
|
+
this.successes = 0;
|
|
122
|
+
} else if (newState === "half-open") {
|
|
123
|
+
this.successes = 0;
|
|
124
|
+
}
|
|
125
|
+
this.options.onStateChange?.(oldState, newState);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Manually reset the circuit breaker
|
|
129
|
+
*/
|
|
130
|
+
reset() {
|
|
131
|
+
this.transitionTo("closed");
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Get circuit breaker statistics
|
|
135
|
+
*/
|
|
136
|
+
getStats() {
|
|
137
|
+
return {
|
|
138
|
+
state: this.state,
|
|
139
|
+
failures: this.failures,
|
|
140
|
+
successes: this.successes,
|
|
141
|
+
lastFailureTime: this.lastFailureTime
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// src/resilience/bulkhead.ts
|
|
147
|
+
var Bulkhead = class {
|
|
148
|
+
_concurrent = 0;
|
|
149
|
+
queue = [];
|
|
150
|
+
options;
|
|
151
|
+
constructor(options) {
|
|
152
|
+
this.options = options;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get current concurrent count
|
|
156
|
+
*/
|
|
157
|
+
get concurrent() {
|
|
158
|
+
return this._concurrent;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Get current queue size
|
|
162
|
+
*/
|
|
163
|
+
get queued() {
|
|
164
|
+
return this.queue.length;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Check if bulkhead is full
|
|
168
|
+
*/
|
|
169
|
+
get isFull() {
|
|
170
|
+
return this._concurrent >= this.options.maxConcurrent && this.queue.length >= this.options.maxQueue;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Execute a function with bulkhead protection
|
|
174
|
+
*/
|
|
175
|
+
async execute(fn) {
|
|
176
|
+
if (this._concurrent < this.options.maxConcurrent) {
|
|
177
|
+
return this.doExecute(fn);
|
|
178
|
+
}
|
|
179
|
+
if (this.queue.length < this.options.maxQueue) {
|
|
180
|
+
return this.enqueue(fn);
|
|
181
|
+
}
|
|
182
|
+
this.options.onRejected?.();
|
|
183
|
+
throw new BulkheadRejectedError("service");
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Execute immediately
|
|
187
|
+
*/
|
|
188
|
+
async doExecute(fn) {
|
|
189
|
+
this._concurrent++;
|
|
190
|
+
try {
|
|
191
|
+
return await fn();
|
|
192
|
+
} finally {
|
|
193
|
+
this._concurrent--;
|
|
194
|
+
this.processQueue();
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Add to queue
|
|
199
|
+
*/
|
|
200
|
+
enqueue(fn) {
|
|
201
|
+
return new Promise((resolve, reject) => {
|
|
202
|
+
this.queue.push({
|
|
203
|
+
fn,
|
|
204
|
+
resolve,
|
|
205
|
+
reject
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Process queued requests
|
|
211
|
+
*/
|
|
212
|
+
processQueue() {
|
|
213
|
+
if (this.queue.length === 0) return;
|
|
214
|
+
if (this._concurrent >= this.options.maxConcurrent) return;
|
|
215
|
+
const queued = this.queue.shift();
|
|
216
|
+
if (!queued) return;
|
|
217
|
+
this.doExecute(queued.fn).then(queued.resolve).catch(queued.reject);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Get bulkhead statistics
|
|
221
|
+
*/
|
|
222
|
+
getStats() {
|
|
223
|
+
return {
|
|
224
|
+
concurrent: this._concurrent,
|
|
225
|
+
queued: this.queue.length,
|
|
226
|
+
maxConcurrent: this.options.maxConcurrent,
|
|
227
|
+
maxQueue: this.options.maxQueue
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Clear the queue (reject all pending)
|
|
232
|
+
*/
|
|
233
|
+
clearQueue() {
|
|
234
|
+
const error = new BulkheadRejectedError("service");
|
|
235
|
+
while (this.queue.length > 0) {
|
|
236
|
+
const queued = this.queue.shift();
|
|
237
|
+
queued?.reject(error);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
// src/resilience/retry.ts
|
|
243
|
+
var defaultShouldRetry = (error) => {
|
|
244
|
+
if (error && typeof error === "object" && "retryable" in error) {
|
|
245
|
+
return error.retryable;
|
|
246
|
+
}
|
|
247
|
+
return false;
|
|
248
|
+
};
|
|
249
|
+
function calculateDelay(attempt, options) {
|
|
250
|
+
let delay;
|
|
251
|
+
if (options.backoff === "exponential") {
|
|
252
|
+
delay = options.initialDelay * Math.pow(2, attempt);
|
|
253
|
+
} else {
|
|
254
|
+
delay = options.initialDelay * (attempt + 1);
|
|
255
|
+
}
|
|
256
|
+
delay = Math.min(delay, options.maxDelay);
|
|
257
|
+
if (options.jitter && options.jitter > 0) {
|
|
258
|
+
const jitterRange = delay * options.jitter;
|
|
259
|
+
delay = delay - jitterRange / 2 + Math.random() * jitterRange;
|
|
260
|
+
}
|
|
261
|
+
return Math.round(delay);
|
|
262
|
+
}
|
|
263
|
+
function sleep(ms) {
|
|
264
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
265
|
+
}
|
|
266
|
+
function withRetry(fn, options) {
|
|
267
|
+
const shouldRetry = options.shouldRetry ?? defaultShouldRetry;
|
|
268
|
+
return async () => {
|
|
269
|
+
let lastError;
|
|
270
|
+
for (let attempt = 0; attempt <= options.attempts; attempt++) {
|
|
271
|
+
try {
|
|
272
|
+
return await fn();
|
|
273
|
+
} catch (error) {
|
|
274
|
+
lastError = error;
|
|
275
|
+
if (attempt >= options.attempts || !shouldRetry(error, attempt)) {
|
|
276
|
+
throw error;
|
|
277
|
+
}
|
|
278
|
+
const delay = calculateDelay(attempt, options);
|
|
279
|
+
options.onRetry?.(error, attempt + 1, delay);
|
|
280
|
+
await sleep(delay);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
throw lastError;
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
async function executeWithRetry(fn, options) {
|
|
287
|
+
return withRetry(fn, options)();
|
|
288
|
+
}
|
|
289
|
+
function createRetryWrapper(defaultOptions) {
|
|
290
|
+
const defaults = {
|
|
291
|
+
attempts: defaultOptions.attempts ?? 3,
|
|
292
|
+
backoff: defaultOptions.backoff ?? "exponential",
|
|
293
|
+
initialDelay: defaultOptions.initialDelay ?? 100,
|
|
294
|
+
maxDelay: defaultOptions.maxDelay ?? 1e4,
|
|
295
|
+
jitter: defaultOptions.jitter ?? 0.1
|
|
296
|
+
};
|
|
297
|
+
if (defaultOptions.shouldRetry) {
|
|
298
|
+
defaults.shouldRetry = defaultOptions.shouldRetry;
|
|
299
|
+
}
|
|
300
|
+
if (defaultOptions.onRetry) {
|
|
301
|
+
defaults.onRetry = defaultOptions.onRetry;
|
|
302
|
+
}
|
|
303
|
+
return async (fn, options) => {
|
|
304
|
+
return executeWithRetry(fn, { ...defaults, ...options });
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// src/resilience/timeout.ts
|
|
309
|
+
var TimeoutExceededError = class extends Error {
|
|
310
|
+
timeout;
|
|
311
|
+
constructor(timeout) {
|
|
312
|
+
super(`Operation timed out after ${timeout}ms`);
|
|
313
|
+
this.name = "TimeoutExceededError";
|
|
314
|
+
this.timeout = timeout;
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
function withTimeout(fn, timeoutMs, onTimeout) {
|
|
318
|
+
return async () => {
|
|
319
|
+
let timeoutId;
|
|
320
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
321
|
+
timeoutId = setTimeout(() => {
|
|
322
|
+
if (onTimeout) {
|
|
323
|
+
try {
|
|
324
|
+
onTimeout();
|
|
325
|
+
} catch (error) {
|
|
326
|
+
reject(error);
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
reject(new TimeoutExceededError(timeoutMs));
|
|
331
|
+
}, timeoutMs);
|
|
332
|
+
});
|
|
333
|
+
try {
|
|
334
|
+
return await Promise.race([fn(), timeoutPromise]);
|
|
335
|
+
} finally {
|
|
336
|
+
if (timeoutId !== void 0) {
|
|
337
|
+
clearTimeout(timeoutId);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
async function executeWithTimeout(fn, timeoutMs, onTimeout) {
|
|
343
|
+
return withTimeout(fn, timeoutMs, onTimeout)();
|
|
344
|
+
}
|
|
345
|
+
function createTimeoutWrapper(defaultTimeoutMs) {
|
|
346
|
+
return async (fn, timeoutMs) => {
|
|
347
|
+
return executeWithTimeout(fn, timeoutMs ?? defaultTimeoutMs);
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
async function raceWithTimeout(promises, timeoutMs) {
|
|
351
|
+
let timeoutId;
|
|
352
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
353
|
+
timeoutId = setTimeout(() => {
|
|
354
|
+
reject(new TimeoutExceededError(timeoutMs));
|
|
355
|
+
}, timeoutMs);
|
|
356
|
+
});
|
|
357
|
+
try {
|
|
358
|
+
return await Promise.race([...promises, timeoutPromise]);
|
|
359
|
+
} finally {
|
|
360
|
+
if (timeoutId !== void 0) {
|
|
361
|
+
clearTimeout(timeoutId);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
async function executeWithDeadline(fn, deadline) {
|
|
366
|
+
const now = Date.now();
|
|
367
|
+
const deadlineMs = deadline.getTime();
|
|
368
|
+
const timeoutMs = Math.max(0, deadlineMs - now);
|
|
369
|
+
if (timeoutMs === 0) {
|
|
370
|
+
throw new TimeoutExceededError(0);
|
|
371
|
+
}
|
|
372
|
+
return executeWithTimeout(fn, timeoutMs);
|
|
373
|
+
}
|
|
374
|
+
export {
|
|
375
|
+
Bulkhead,
|
|
376
|
+
CircuitBreaker,
|
|
377
|
+
TimeoutExceededError,
|
|
378
|
+
createRetryWrapper,
|
|
379
|
+
createTimeoutWrapper,
|
|
380
|
+
executeWithDeadline,
|
|
381
|
+
executeWithRetry,
|
|
382
|
+
executeWithTimeout,
|
|
383
|
+
raceWithTimeout,
|
|
384
|
+
withRetry,
|
|
385
|
+
withTimeout
|
|
386
|
+
};
|
|
387
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/rpc/errors.ts","../../src/resilience/circuit-breaker.ts","../../src/resilience/bulkhead.ts","../../src/resilience/retry.ts","../../src/resilience/timeout.ts"],"sourcesContent":["/**\n * @parsrun/service - RPC Errors\n */\n\nimport { ParsError } from \"@parsrun/core\";\n\n/**\n * Base RPC error\n */\nexport class RpcError extends ParsError {\n public readonly retryable: boolean;\n public readonly retryAfter?: number;\n\n constructor(\n message: string,\n code: string,\n statusCode: number = 500,\n options?: {\n retryable?: boolean;\n retryAfter?: number;\n details?: Record<string, unknown>;\n }\n ) {\n super(message, code, statusCode, options?.details);\n this.name = \"RpcError\";\n this.retryable = options?.retryable ?? false;\n if (options?.retryAfter !== undefined) {\n this.retryAfter = options.retryAfter;\n }\n }\n}\n\n/**\n * Service not found error\n */\nexport class ServiceNotFoundError extends RpcError {\n constructor(serviceName: string) {\n super(`Service not found: ${serviceName}`, \"SERVICE_NOT_FOUND\", 404, {\n retryable: false,\n details: { service: serviceName },\n });\n this.name = \"ServiceNotFoundError\";\n }\n}\n\n/**\n * Method not found error\n */\nexport class MethodNotFoundError extends RpcError {\n constructor(serviceName: string, methodName: string) {\n super(\n `Method not found: ${serviceName}.${methodName}`,\n \"METHOD_NOT_FOUND\",\n 404,\n {\n retryable: false,\n details: { service: serviceName, method: methodName },\n }\n );\n this.name = \"MethodNotFoundError\";\n }\n}\n\n/**\n * Version mismatch error\n */\nexport class VersionMismatchError extends RpcError {\n constructor(serviceName: string, requested: string, available: string) {\n super(\n `Version mismatch for ${serviceName}: requested ${requested}, available ${available}`,\n \"VERSION_MISMATCH\",\n 400,\n {\n retryable: false,\n details: { service: serviceName, requested, available },\n }\n );\n this.name = \"VersionMismatchError\";\n }\n}\n\n/**\n * Timeout error\n */\nexport class TimeoutError extends RpcError {\n constructor(serviceName: string, methodName: string, timeoutMs: number) {\n super(\n `Request to ${serviceName}.${methodName} timed out after ${timeoutMs}ms`,\n \"TIMEOUT\",\n 504,\n {\n retryable: true,\n details: { service: serviceName, method: methodName, timeout: timeoutMs },\n }\n );\n this.name = \"TimeoutError\";\n }\n}\n\n/**\n * Circuit breaker open error\n */\nexport class CircuitOpenError extends RpcError {\n constructor(serviceName: string, resetAfterMs: number) {\n super(\n `Circuit breaker open for ${serviceName}`,\n \"CIRCUIT_OPEN\",\n 503,\n {\n retryable: true,\n retryAfter: Math.ceil(resetAfterMs / 1000),\n details: { service: serviceName, resetAfterMs },\n }\n );\n this.name = \"CircuitOpenError\";\n }\n}\n\n/**\n * Bulkhead rejected error\n */\nexport class BulkheadRejectedError extends RpcError {\n constructor(serviceName: string) {\n super(\n `Request rejected by bulkhead for ${serviceName}: too many concurrent requests`,\n \"BULKHEAD_REJECTED\",\n 503,\n {\n retryable: true,\n retryAfter: 1,\n details: { service: serviceName },\n }\n );\n this.name = \"BulkheadRejectedError\";\n }\n}\n\n/**\n * Transport error\n */\nexport class TransportError extends RpcError {\n constructor(message: string, cause?: Error) {\n const options: { retryable: boolean; details?: Record<string, unknown> } = {\n retryable: true,\n };\n if (cause) {\n options.details = { cause: cause.message };\n }\n super(message, \"TRANSPORT_ERROR\", 502, options);\n this.name = \"TransportError\";\n }\n}\n\n/**\n * Serialization error\n */\nexport class SerializationError extends RpcError {\n constructor(message: string, cause?: Error) {\n const options: { retryable: boolean; details?: Record<string, unknown> } = {\n retryable: false,\n };\n if (cause) {\n options.details = { cause: cause.message };\n }\n super(message, \"SERIALIZATION_ERROR\", 400, options);\n this.name = \"SerializationError\";\n }\n}\n\n/**\n * Convert unknown error to RpcError\n */\nexport function toRpcError(error: unknown): RpcError {\n if (error instanceof RpcError) {\n return error;\n }\n\n if (error instanceof Error) {\n return new RpcError(error.message, \"INTERNAL_ERROR\", 500, {\n retryable: false,\n details: { originalError: error.name },\n });\n }\n\n return new RpcError(String(error), \"UNKNOWN_ERROR\", 500, {\n retryable: false,\n });\n}\n","/**\n * @parsrun/service - Circuit Breaker\n * Prevents cascading failures by failing fast when a service is unhealthy\n */\n\nimport { CircuitOpenError } from \"../rpc/errors.js\";\n\n// ============================================================================\n// CIRCUIT BREAKER\n// ============================================================================\n\nexport interface CircuitBreakerOptions {\n /** Number of failures before opening circuit */\n failureThreshold: number;\n /** Time to wait before half-open state (ms) */\n resetTimeout: number;\n /** Number of successes in half-open to close circuit */\n successThreshold: number;\n /** Optional callback on state change */\n onStateChange?: (from: CircuitState, to: CircuitState) => void;\n}\n\nexport type CircuitState = \"closed\" | \"open\" | \"half-open\";\n\n/**\n * Circuit Breaker implementation\n *\n * States:\n * - CLOSED: Normal operation, requests pass through\n * - OPEN: Failing fast, requests are rejected immediately\n * - HALF-OPEN: Testing if service recovered, limited requests allowed\n */\nexport class CircuitBreaker {\n private _state: CircuitState = \"closed\";\n private failures = 0;\n private successes = 0;\n private lastFailureTime = 0;\n private readonly options: CircuitBreakerOptions;\n\n constructor(options: CircuitBreakerOptions) {\n this.options = options;\n }\n\n /**\n * Get current state\n */\n get state(): CircuitState {\n // Check if we should transition from open to half-open\n if (this._state === \"open\") {\n const timeSinceFailure = Date.now() - this.lastFailureTime;\n if (timeSinceFailure >= this.options.resetTimeout) {\n this.transitionTo(\"half-open\");\n }\n }\n return this._state;\n }\n\n /**\n * Execute a function with circuit breaker protection\n */\n async execute<T>(fn: () => Promise<T>): Promise<T> {\n // Check state (this may transition from open to half-open)\n const currentState = this.state;\n\n if (currentState === \"open\") {\n const resetAfter = this.options.resetTimeout - (Date.now() - this.lastFailureTime);\n throw new CircuitOpenError(\"service\", Math.max(0, resetAfter));\n }\n\n try {\n const result = await fn();\n this.onSuccess();\n return result;\n } catch (error) {\n this.onFailure();\n throw error;\n }\n }\n\n /**\n * Record a successful call\n */\n private onSuccess(): void {\n if (this._state === \"half-open\") {\n this.successes++;\n if (this.successes >= this.options.successThreshold) {\n this.transitionTo(\"closed\");\n }\n } else if (this._state === \"closed\") {\n // Reset failure count on success\n this.failures = 0;\n }\n }\n\n /**\n * Record a failed call\n */\n private onFailure(): void {\n this.lastFailureTime = Date.now();\n\n if (this._state === \"half-open\") {\n // Any failure in half-open goes back to open\n this.transitionTo(\"open\");\n } else if (this._state === \"closed\") {\n this.failures++;\n if (this.failures >= this.options.failureThreshold) {\n this.transitionTo(\"open\");\n }\n }\n }\n\n /**\n * Transition to a new state\n */\n private transitionTo(newState: CircuitState): void {\n const oldState = this._state;\n this._state = newState;\n\n // Reset counters on state change\n if (newState === \"closed\") {\n this.failures = 0;\n this.successes = 0;\n } else if (newState === \"half-open\") {\n this.successes = 0;\n }\n\n this.options.onStateChange?.(oldState, newState);\n }\n\n /**\n * Manually reset the circuit breaker\n */\n reset(): void {\n this.transitionTo(\"closed\");\n }\n\n /**\n * Get circuit breaker statistics\n */\n getStats(): {\n state: CircuitState;\n failures: number;\n successes: number;\n lastFailureTime: number;\n } {\n return {\n state: this.state,\n failures: this.failures,\n successes: this.successes,\n lastFailureTime: this.lastFailureTime,\n };\n }\n}\n","/**\n * @parsrun/service - Bulkhead\n * Limits concurrent requests to prevent resource exhaustion\n */\n\nimport { BulkheadRejectedError } from \"../rpc/errors.js\";\n\n// ============================================================================\n// BULKHEAD\n// ============================================================================\n\nexport interface BulkheadOptions {\n /** Maximum concurrent requests */\n maxConcurrent: number;\n /** Maximum queue size (0 = no queue) */\n maxQueue: number;\n /** Optional callback when request is rejected */\n onRejected?: () => void;\n}\n\ninterface QueuedRequest<T> {\n fn: () => Promise<T>;\n resolve: (value: T) => void;\n reject: (error: Error) => void;\n}\n\n/**\n * Bulkhead implementation\n *\n * Limits the number of concurrent requests to protect resources.\n * Excess requests can be queued up to maxQueue limit.\n */\nexport class Bulkhead {\n private _concurrent = 0;\n private readonly queue: QueuedRequest<unknown>[] = [];\n private readonly options: BulkheadOptions;\n\n constructor(options: BulkheadOptions) {\n this.options = options;\n }\n\n /**\n * Get current concurrent count\n */\n get concurrent(): number {\n return this._concurrent;\n }\n\n /**\n * Get current queue size\n */\n get queued(): number {\n return this.queue.length;\n }\n\n /**\n * Check if bulkhead is full\n */\n get isFull(): boolean {\n return (\n this._concurrent >= this.options.maxConcurrent &&\n this.queue.length >= this.options.maxQueue\n );\n }\n\n /**\n * Execute a function with bulkhead protection\n */\n async execute<T>(fn: () => Promise<T>): Promise<T> {\n // Check if we can execute immediately\n if (this._concurrent < this.options.maxConcurrent) {\n return this.doExecute(fn);\n }\n\n // Check if we can queue\n if (this.queue.length < this.options.maxQueue) {\n return this.enqueue(fn);\n }\n\n // Reject\n this.options.onRejected?.();\n throw new BulkheadRejectedError(\"service\");\n }\n\n /**\n * Execute immediately\n */\n private async doExecute<T>(fn: () => Promise<T>): Promise<T> {\n this._concurrent++;\n try {\n return await fn();\n } finally {\n this._concurrent--;\n this.processQueue();\n }\n }\n\n /**\n * Add to queue\n */\n private enqueue<T>(fn: () => Promise<T>): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n this.queue.push({\n fn,\n resolve: resolve as (value: unknown) => void,\n reject,\n });\n });\n }\n\n /**\n * Process queued requests\n */\n private processQueue(): void {\n if (this.queue.length === 0) return;\n if (this._concurrent >= this.options.maxConcurrent) return;\n\n const queued = this.queue.shift();\n if (!queued) return;\n\n this.doExecute(queued.fn)\n .then(queued.resolve)\n .catch(queued.reject);\n }\n\n /**\n * Get bulkhead statistics\n */\n getStats(): {\n concurrent: number;\n queued: number;\n maxConcurrent: number;\n maxQueue: number;\n } {\n return {\n concurrent: this._concurrent,\n queued: this.queue.length,\n maxConcurrent: this.options.maxConcurrent,\n maxQueue: this.options.maxQueue,\n };\n }\n\n /**\n * Clear the queue (reject all pending)\n */\n clearQueue(): void {\n const error = new BulkheadRejectedError(\"service\");\n while (this.queue.length > 0) {\n const queued = this.queue.shift();\n queued?.reject(error);\n }\n }\n}\n","/**\n * @parsrun/service - Retry\n * Retry failed operations with backoff\n */\n\n// ============================================================================\n// RETRY\n// ============================================================================\n\nexport interface RetryOptions {\n /** Number of retry attempts (not including initial attempt) */\n attempts: number;\n /** Backoff strategy */\n backoff: \"linear\" | \"exponential\";\n /** Initial delay in ms */\n initialDelay: number;\n /** Maximum delay in ms */\n maxDelay: number;\n /** Jitter factor (0-1) to add randomness */\n jitter?: number;\n /** Should retry predicate */\n shouldRetry?: (error: unknown, attempt: number) => boolean;\n /** Callback on retry */\n onRetry?: (error: unknown, attempt: number, delay: number) => void;\n}\n\n/**\n * Default retry predicate - retry on retryable errors\n */\nconst defaultShouldRetry = (error: unknown): boolean => {\n if (error && typeof error === \"object\" && \"retryable\" in error) {\n return (error as { retryable: boolean }).retryable;\n }\n return false;\n};\n\n/**\n * Calculate delay for retry attempt\n */\nfunction calculateDelay(\n attempt: number,\n options: RetryOptions\n): number {\n let delay: number;\n\n if (options.backoff === \"exponential\") {\n // Exponential backoff: initialDelay * 2^attempt\n delay = options.initialDelay * Math.pow(2, attempt);\n } else {\n // Linear backoff: initialDelay * (attempt + 1)\n delay = options.initialDelay * (attempt + 1);\n }\n\n // Apply max delay\n delay = Math.min(delay, options.maxDelay);\n\n // Apply jitter\n if (options.jitter && options.jitter > 0) {\n const jitterRange = delay * options.jitter;\n delay = delay - jitterRange / 2 + Math.random() * jitterRange;\n }\n\n return Math.round(delay);\n}\n\n/**\n * Sleep for a given duration\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Wrap a function with retry logic\n */\nexport function withRetry<T>(\n fn: () => Promise<T>,\n options: RetryOptions\n): () => Promise<T> {\n const shouldRetry = options.shouldRetry ?? defaultShouldRetry;\n\n return async (): Promise<T> => {\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= options.attempts; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error;\n\n // Check if we should retry\n if (attempt >= options.attempts || !shouldRetry(error, attempt)) {\n throw error;\n }\n\n // Calculate delay\n const delay = calculateDelay(attempt, options);\n\n // Callback\n options.onRetry?.(error, attempt + 1, delay);\n\n // Wait before retry\n await sleep(delay);\n }\n }\n\n throw lastError;\n };\n}\n\n/**\n * Execute a function with retry\n */\nexport async function executeWithRetry<T>(\n fn: () => Promise<T>,\n options: RetryOptions\n): Promise<T> {\n return withRetry(fn, options)();\n}\n\n/**\n * Create a retry wrapper with preset options\n */\nexport function createRetryWrapper(\n defaultOptions: Partial<RetryOptions>\n): <T>(fn: () => Promise<T>, options?: Partial<RetryOptions>) => Promise<T> {\n const defaults: RetryOptions = {\n attempts: defaultOptions.attempts ?? 3,\n backoff: defaultOptions.backoff ?? \"exponential\",\n initialDelay: defaultOptions.initialDelay ?? 100,\n maxDelay: defaultOptions.maxDelay ?? 10_000,\n jitter: defaultOptions.jitter ?? 0.1,\n };\n\n if (defaultOptions.shouldRetry) {\n defaults.shouldRetry = defaultOptions.shouldRetry;\n }\n if (defaultOptions.onRetry) {\n defaults.onRetry = defaultOptions.onRetry;\n }\n\n return async <T>(\n fn: () => Promise<T>,\n options?: Partial<RetryOptions>\n ): Promise<T> => {\n return executeWithRetry(fn, { ...defaults, ...options });\n };\n}\n","/**\n * @parsrun/service - Timeout\n * Timeout wrapper for async operations\n */\n\n// ============================================================================\n// TIMEOUT\n// ============================================================================\n\n/**\n * Timeout error\n */\nexport class TimeoutExceededError extends Error {\n readonly timeout: number;\n\n constructor(timeout: number) {\n super(`Operation timed out after ${timeout}ms`);\n this.name = \"TimeoutExceededError\";\n this.timeout = timeout;\n }\n}\n\n/**\n * Wrap a function with timeout\n */\nexport function withTimeout<T>(\n fn: () => Promise<T>,\n timeoutMs: number,\n onTimeout?: () => void | never\n): () => Promise<T> {\n return async (): Promise<T> => {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n if (onTimeout) {\n try {\n onTimeout();\n } catch (error) {\n reject(error);\n return;\n }\n }\n reject(new TimeoutExceededError(timeoutMs));\n }, timeoutMs);\n });\n\n try {\n return await Promise.race([fn(), timeoutPromise]);\n } finally {\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId);\n }\n }\n };\n}\n\n/**\n * Execute a function with timeout\n */\nexport async function executeWithTimeout<T>(\n fn: () => Promise<T>,\n timeoutMs: number,\n onTimeout?: () => void | never\n): Promise<T> {\n return withTimeout(fn, timeoutMs, onTimeout)();\n}\n\n/**\n * Create a timeout wrapper with preset duration\n */\nexport function createTimeoutWrapper(\n defaultTimeoutMs: number\n): <T>(fn: () => Promise<T>, timeoutMs?: number) => Promise<T> {\n return async <T>(fn: () => Promise<T>, timeoutMs?: number): Promise<T> => {\n return executeWithTimeout(fn, timeoutMs ?? defaultTimeoutMs);\n };\n}\n\n/**\n * Race multiple promises with a timeout\n */\nexport async function raceWithTimeout<T>(\n promises: Promise<T>[],\n timeoutMs: number\n): Promise<T> {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(new TimeoutExceededError(timeoutMs));\n }, timeoutMs);\n });\n\n try {\n return await Promise.race([...promises, timeoutPromise]);\n } finally {\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId);\n }\n }\n}\n\n/**\n * Execute with deadline (absolute time)\n */\nexport async function executeWithDeadline<T>(\n fn: () => Promise<T>,\n deadline: Date\n): Promise<T> {\n const now = Date.now();\n const deadlineMs = deadline.getTime();\n const timeoutMs = Math.max(0, deadlineMs - now);\n\n if (timeoutMs === 0) {\n throw new TimeoutExceededError(0);\n }\n\n return executeWithTimeout(fn, timeoutMs);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { B as BulkheadRejectedError, C as CallOptions, i as CircuitOpenError, b as EmbeddedRegistry, E as EmbeddedTransport, H as HttpTransport, f as HttpTransportOptions, M as MethodNotFoundError, R as RpcClient, h as RpcError, k as SerializationError, S as ServiceNotFoundError, T as TimeoutError, j as TransportError, V as VersionMismatchError, a as createEmbeddedTransport, e as createHttpHandler, d as createHttpTransport, c as createRpcClient, g as getEmbeddedRegistry, t as toRpcError } from '../index-CVOAoJjZ.js';
|
|
2
|
+
export { a as RpcHandler, e as RpcHandlerContext, b as RpcHandlers, d as RpcMiddleware, R as RpcServer, c as createRpcServer, l as loggingMiddleware, t as tenantMiddleware, v as validationMiddleware } from '../server-DFE8n2Sx.js';
|
|
3
|
+
import '../types-n4LLSPQU.js';
|
|
4
|
+
import '../serialization/index.js';
|
|
5
|
+
import '@parsrun/core';
|