ai.matey.middleware 0.2.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.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/caching.js +226 -0
  3. package/dist/cjs/caching.js.map +1 -0
  4. package/dist/cjs/conversation-history.js +213 -0
  5. package/dist/cjs/conversation-history.js.map +1 -0
  6. package/dist/cjs/cost-tracking.js +355 -0
  7. package/dist/cjs/cost-tracking.js.map +1 -0
  8. package/dist/cjs/index.js +37 -0
  9. package/dist/cjs/index.js.map +1 -0
  10. package/dist/cjs/logging.js +174 -0
  11. package/dist/cjs/logging.js.map +1 -0
  12. package/dist/cjs/opentelemetry.js +499 -0
  13. package/dist/cjs/opentelemetry.js.map +1 -0
  14. package/dist/cjs/retry.js +205 -0
  15. package/dist/cjs/retry.js.map +1 -0
  16. package/dist/cjs/security.js +175 -0
  17. package/dist/cjs/security.js.map +1 -0
  18. package/dist/cjs/telemetry.js +216 -0
  19. package/dist/cjs/telemetry.js.map +1 -0
  20. package/dist/cjs/transform.js +284 -0
  21. package/dist/cjs/transform.js.map +1 -0
  22. package/dist/cjs/validation.js +506 -0
  23. package/dist/cjs/validation.js.map +1 -0
  24. package/dist/esm/caching.js +221 -0
  25. package/dist/esm/caching.js.map +1 -0
  26. package/dist/esm/conversation-history.js +207 -0
  27. package/dist/esm/conversation-history.js.map +1 -0
  28. package/dist/esm/cost-tracking.js +347 -0
  29. package/dist/esm/cost-tracking.js.map +1 -0
  30. package/dist/esm/index.js +21 -0
  31. package/dist/esm/index.js.map +1 -0
  32. package/dist/esm/logging.js +171 -0
  33. package/dist/esm/logging.js.map +1 -0
  34. package/dist/esm/opentelemetry.js +458 -0
  35. package/dist/esm/opentelemetry.js.map +1 -0
  36. package/dist/esm/retry.js +198 -0
  37. package/dist/esm/retry.js.map +1 -0
  38. package/dist/esm/security.js +169 -0
  39. package/dist/esm/security.js.map +1 -0
  40. package/dist/esm/telemetry.js +210 -0
  41. package/dist/esm/telemetry.js.map +1 -0
  42. package/dist/esm/transform.js +272 -0
  43. package/dist/esm/transform.js.map +1 -0
  44. package/dist/esm/validation.js +494 -0
  45. package/dist/esm/validation.js.map +1 -0
  46. package/dist/types/caching.d.ts +98 -0
  47. package/dist/types/caching.d.ts.map +1 -0
  48. package/dist/types/conversation-history.d.ts +188 -0
  49. package/dist/types/conversation-history.d.ts.map +1 -0
  50. package/dist/types/cost-tracking.d.ts +262 -0
  51. package/dist/types/cost-tracking.d.ts.map +1 -0
  52. package/dist/types/index.d.ts +20 -0
  53. package/dist/types/index.d.ts.map +1 -0
  54. package/dist/types/logging.d.ts +82 -0
  55. package/dist/types/logging.d.ts.map +1 -0
  56. package/dist/types/opentelemetry.d.ts +219 -0
  57. package/dist/types/opentelemetry.d.ts.map +1 -0
  58. package/dist/types/retry.d.ts +86 -0
  59. package/dist/types/retry.d.ts.map +1 -0
  60. package/dist/types/security.d.ts +120 -0
  61. package/dist/types/security.d.ts.map +1 -0
  62. package/dist/types/telemetry.d.ts +120 -0
  63. package/dist/types/telemetry.d.ts.map +1 -0
  64. package/dist/types/transform.d.ts +184 -0
  65. package/dist/types/transform.d.ts.map +1 -0
  66. package/dist/types/validation.d.ts +356 -0
  67. package/dist/types/validation.d.ts.map +1 -0
  68. package/package.json +203 -0
  69. package/readme.md +103 -0
@@ -0,0 +1,458 @@
1
+ /**
2
+ * OpenTelemetry Middleware
3
+ *
4
+ * Provides distributed tracing and metrics export using OpenTelemetry.
5
+ * OpenTelemetry packages are optional peer dependencies - this middleware
6
+ * will check for their availability at runtime.
7
+ *
8
+ * @module
9
+ */
10
+ // ============================================================================
11
+ // Runtime Availability Check
12
+ // ============================================================================
13
+ let otelAvailable = false;
14
+ let api = null;
15
+ let TracerProvider = null;
16
+ let OTLPTraceExporter = null;
17
+ let Resource = null;
18
+ let SEMRESATTRS_SERVICE_NAME = null;
19
+ let SEMRESATTRS_SERVICE_VERSION = null;
20
+ let BatchSpanProcessor = null;
21
+ /**
22
+ * Check if OpenTelemetry packages are available and load them.
23
+ */
24
+ async function checkOpenTelemetryAvailability() {
25
+ if (otelAvailable) {
26
+ return true;
27
+ }
28
+ try {
29
+ // Use dynamic import() for ESM/CJS compatibility
30
+ const [apiModule, sdkTraceBase, otlpExporter, resources, semanticConventions] = await Promise.all([
31
+ import('@opentelemetry/api'),
32
+ import('@opentelemetry/sdk-trace-base'),
33
+ import('@opentelemetry/exporter-trace-otlp-http'),
34
+ import('@opentelemetry/resources'),
35
+ import('@opentelemetry/semantic-conventions'),
36
+ ]);
37
+ api = apiModule;
38
+ TracerProvider = sdkTraceBase.BasicTracerProvider;
39
+ BatchSpanProcessor = sdkTraceBase.BatchSpanProcessor;
40
+ OTLPTraceExporter = otlpExporter.OTLPTraceExporter;
41
+ Resource = resources.Resource;
42
+ SEMRESATTRS_SERVICE_NAME = semanticConventions.SEMRESATTRS_SERVICE_NAME;
43
+ SEMRESATTRS_SERVICE_VERSION = semanticConventions.SEMRESATTRS_SERVICE_VERSION;
44
+ otelAvailable = true;
45
+ return true;
46
+ }
47
+ catch {
48
+ return false;
49
+ }
50
+ }
51
+ /**
52
+ * Synchronous check if OpenTelemetry is already loaded.
53
+ * Use checkOpenTelemetryAvailability() for the full check.
54
+ */
55
+ function isOtelLoaded() {
56
+ return otelAvailable;
57
+ }
58
+ /**
59
+ * OpenTelemetry span attribute names.
60
+ */
61
+ export const OpenTelemetryAttributes = {
62
+ // Request attributes
63
+ REQUEST_ID: 'ai.request.id',
64
+ REQUEST_MODEL: 'ai.request.model',
65
+ REQUEST_STREAM: 'ai.request.stream',
66
+ REQUEST_MESSAGE_COUNT: 'ai.request.message_count',
67
+ REQUEST_MAX_TOKENS: 'ai.request.max_tokens',
68
+ // Response attributes
69
+ RESPONSE_BACKEND: 'ai.response.backend',
70
+ RESPONSE_FINISH_REASON: 'ai.response.finish_reason',
71
+ RESPONSE_MODEL: 'ai.response.model',
72
+ // Token usage attributes
73
+ TOKENS_PROMPT: 'ai.tokens.prompt',
74
+ TOKENS_COMPLETION: 'ai.tokens.completion',
75
+ TOKENS_TOTAL: 'ai.tokens.total',
76
+ // Provenance attributes
77
+ FRONTEND: 'ai.frontend',
78
+ BACKEND: 'ai.backend',
79
+ // Performance attributes
80
+ DURATION_MS: 'ai.duration.ms',
81
+ };
82
+ // ============================================================================
83
+ // Tracer Provider Singleton
84
+ // ============================================================================
85
+ let globalTracerProvider = null;
86
+ let globalTracerProviderConfig = null;
87
+ let providerInitializationPromise = null;
88
+ /**
89
+ * Get or create the global tracer provider.
90
+ *
91
+ * WARNING: This uses a singleton pattern. If you call this multiple times
92
+ * with different configs, only the first config will be used. To reset,
93
+ * call shutdownOpenTelemetry() first.
94
+ *
95
+ * This function is NOT thread-safe for concurrent calls, but uses a promise
96
+ * to prevent race conditions during initialization.
97
+ */
98
+ async function getOrCreateTracerProvider(config) {
99
+ // Create a config hash to detect configuration changes
100
+ const configHash = JSON.stringify({
101
+ serviceName: config.serviceName,
102
+ serviceVersion: config.serviceVersion,
103
+ endpoint: config.endpoint,
104
+ exportSpans: config.exportSpans,
105
+ });
106
+ if (globalTracerProvider) {
107
+ // Warn if trying to create with different config
108
+ if (globalTracerProviderConfig && globalTracerProviderConfig !== configHash) {
109
+ console.warn('[OpenTelemetry] Tracer provider already initialized with different config. ' +
110
+ 'Call shutdownOpenTelemetry() to reset before creating with new config.');
111
+ }
112
+ return globalTracerProvider;
113
+ }
114
+ // If initialization is in progress, wait for it
115
+ if (providerInitializationPromise) {
116
+ return providerInitializationPromise;
117
+ }
118
+ // Start initialization
119
+ providerInitializationPromise = (() => {
120
+ try {
121
+ const { serviceName = 'ai-matey', serviceVersion = '0.1.0', endpoint = 'http://localhost:4318/v1/traces', headers = {}, resourceAttributes = {}, exportSpans = true, batchSpanProcessorConfig = {}, exporterTimeoutMillis = 10000, } = config;
122
+ // Create resource with service information
123
+ const resource = new Resource({
124
+ [SEMRESATTRS_SERVICE_NAME]: serviceName,
125
+ [SEMRESATTRS_SERVICE_VERSION]: serviceVersion,
126
+ ...resourceAttributes,
127
+ });
128
+ // Create tracer provider
129
+ const provider = new TracerProvider({
130
+ resource,
131
+ });
132
+ // Add span processor with OTLP exporter if spans should be exported
133
+ if (exportSpans) {
134
+ const exporter = new OTLPTraceExporter({
135
+ url: endpoint,
136
+ headers,
137
+ timeoutMillis: exporterTimeoutMillis,
138
+ });
139
+ const processorConfig = {
140
+ maxQueueSize: batchSpanProcessorConfig.maxQueueSize,
141
+ maxExportBatchSize: batchSpanProcessorConfig.maxExportBatchSize,
142
+ scheduledDelayMillis: batchSpanProcessorConfig.scheduledDelayMillis,
143
+ exportTimeoutMillis: batchSpanProcessorConfig.exportTimeoutMillis,
144
+ };
145
+ provider.addSpanProcessor(new BatchSpanProcessor(exporter, processorConfig));
146
+ }
147
+ // Register the provider
148
+ api.trace.setGlobalTracerProvider(provider);
149
+ globalTracerProvider = provider;
150
+ globalTracerProviderConfig = configHash;
151
+ return Promise.resolve(provider);
152
+ }
153
+ finally {
154
+ // Clear the initialization promise whether success or failure
155
+ providerInitializationPromise = null;
156
+ }
157
+ })();
158
+ return providerInitializationPromise;
159
+ }
160
+ // ============================================================================
161
+ // Sampling
162
+ // ============================================================================
163
+ /**
164
+ * Determine if this request should be sampled.
165
+ */
166
+ function shouldSample(samplingRate) {
167
+ return Math.random() < samplingRate;
168
+ }
169
+ // ============================================================================
170
+ // Middleware Factory
171
+ // ============================================================================
172
+ /**
173
+ * Create OpenTelemetry middleware.
174
+ *
175
+ * Provides distributed tracing with span creation, context propagation,
176
+ * and metrics export via OpenTelemetry.
177
+ *
178
+ * **Note:** This middleware requires optional OpenTelemetry packages to be installed:
179
+ * - `@opentelemetry/api`
180
+ * - `@opentelemetry/sdk-trace-base`
181
+ * - `@opentelemetry/exporter-trace-otlp-http`
182
+ * - `@opentelemetry/resources`
183
+ * - `@opentelemetry/semantic-conventions`
184
+ *
185
+ * Install with:
186
+ * ```bash
187
+ * npm install @opentelemetry/api @opentelemetry/sdk-trace-base \
188
+ * @opentelemetry/exporter-trace-otlp-http @opentelemetry/resources \
189
+ * @opentelemetry/semantic-conventions
190
+ * ```
191
+ *
192
+ * @param config OpenTelemetry configuration
193
+ * @returns Promise that resolves to OpenTelemetry middleware
194
+ * @throws Error if OpenTelemetry packages are not installed
195
+ *
196
+ * @example
197
+ * ```typescript
198
+ * import { createOpenTelemetryMiddleware } from 'ai.matey.middleware';
199
+ *
200
+ * const otel = await createOpenTelemetryMiddleware({
201
+ * serviceName: 'my-ai-service',
202
+ * endpoint: 'http://localhost:4318/v1/traces',
203
+ * samplingRate: 1.0
204
+ * });
205
+ *
206
+ * bridge.use(otel);
207
+ * ```
208
+ */
209
+ export async function createOpenTelemetryMiddleware(config = {}) {
210
+ // Check if OpenTelemetry is available
211
+ const available = await checkOpenTelemetryAvailability();
212
+ if (!available) {
213
+ throw new Error('OpenTelemetry packages are not installed. Please install:\n' +
214
+ 'npm install @opentelemetry/api @opentelemetry/sdk-trace-base ' +
215
+ '@opentelemetry/exporter-trace-otlp-http @opentelemetry/resources ' +
216
+ '@opentelemetry/semantic-conventions');
217
+ }
218
+ const { samplingRate = 1.0, tracerName = 'ai-matey-tracer' } = config;
219
+ // Initialize tracer provider (async to handle race conditions)
220
+ const provider = await getOrCreateTracerProvider(config);
221
+ const tracer = provider.getTracer(tracerName);
222
+ return async (context, next) => {
223
+ // Check if we should sample this request
224
+ const sampled = shouldSample(samplingRate);
225
+ if (!sampled) {
226
+ // Skip tracing for this request
227
+ return next();
228
+ }
229
+ const requestId = context.request.metadata.requestId;
230
+ // Create span for the request
231
+ const span = tracer.startSpan('ai.matey.request', {
232
+ attributes: {
233
+ [OpenTelemetryAttributes.REQUEST_ID]: requestId,
234
+ [OpenTelemetryAttributes.REQUEST_MODEL]: context.request.parameters?.model ?? 'unknown',
235
+ [OpenTelemetryAttributes.REQUEST_STREAM]: String(context.request.stream ?? false),
236
+ [OpenTelemetryAttributes.REQUEST_MESSAGE_COUNT]: context.request.messages.length,
237
+ [OpenTelemetryAttributes.FRONTEND]: context.request.metadata.provenance?.frontend ?? 'unknown',
238
+ },
239
+ });
240
+ // Add max_tokens if present
241
+ if (context.request.parameters?.maxTokens) {
242
+ span.setAttribute(OpenTelemetryAttributes.REQUEST_MAX_TOKENS, context.request.parameters.maxTokens);
243
+ }
244
+ const startTime = Date.now();
245
+ try {
246
+ // Execute within span context
247
+ const spanContext = api.trace.setSpan(api.context.active(), span);
248
+ // Call next middleware/handler in the span context
249
+ const response = await api.context.with(spanContext, async () => {
250
+ return await next();
251
+ });
252
+ const duration = Date.now() - startTime;
253
+ // Add response attributes to span
254
+ span.setAttribute(OpenTelemetryAttributes.RESPONSE_BACKEND, response.metadata.provenance?.backend ?? 'unknown');
255
+ span.setAttribute(OpenTelemetryAttributes.RESPONSE_FINISH_REASON, response.finishReason);
256
+ span.setAttribute(OpenTelemetryAttributes.DURATION_MS, duration);
257
+ if (response.metadata.provenance?.backendModel) {
258
+ span.setAttribute(OpenTelemetryAttributes.RESPONSE_MODEL, response.metadata.provenance.backendModel);
259
+ }
260
+ // Add token usage if present
261
+ if (response.usage) {
262
+ if (response.usage.promptTokens) {
263
+ span.setAttribute(OpenTelemetryAttributes.TOKENS_PROMPT, response.usage.promptTokens);
264
+ }
265
+ if (response.usage.completionTokens) {
266
+ span.setAttribute(OpenTelemetryAttributes.TOKENS_COMPLETION, response.usage.completionTokens);
267
+ }
268
+ if (response.usage.totalTokens) {
269
+ span.setAttribute(OpenTelemetryAttributes.TOKENS_TOTAL, response.usage.totalTokens);
270
+ }
271
+ }
272
+ // Mark span as successful
273
+ span.setStatus({ code: api.SpanStatusCode.OK });
274
+ span.end();
275
+ return response;
276
+ }
277
+ catch (error) {
278
+ const duration = Date.now() - startTime;
279
+ // Safely add error information to span
280
+ // Wrap in try-catch to prevent span operations from masking the original error
281
+ try {
282
+ span.setAttribute(OpenTelemetryAttributes.DURATION_MS, duration);
283
+ span.setAttribute('error', true);
284
+ span.setAttribute('error.type', error instanceof Error ? error.name : 'unknown');
285
+ if (error instanceof Error) {
286
+ span.recordException(error);
287
+ span.setStatus({
288
+ code: api.SpanStatusCode.ERROR,
289
+ message: error.message,
290
+ });
291
+ }
292
+ else {
293
+ span.setStatus({
294
+ code: api.SpanStatusCode.ERROR,
295
+ message: String(error),
296
+ });
297
+ }
298
+ span.end();
299
+ }
300
+ catch (spanError) {
301
+ // If span operations fail, log but don't mask the original error
302
+ console.error('[OpenTelemetry] Failed to record error in span:', spanError);
303
+ // Try to end the span anyway to prevent memory leak
304
+ try {
305
+ span.end();
306
+ }
307
+ catch {
308
+ // Ignore - best effort to clean up
309
+ }
310
+ }
311
+ // Always re-throw the original error
312
+ throw error;
313
+ }
314
+ };
315
+ }
316
+ // ============================================================================
317
+ // OpenTelemetry Telemetry Sink
318
+ // ============================================================================
319
+ /**
320
+ * OpenTelemetry-based telemetry sink.
321
+ *
322
+ * Implements the TelemetrySink interface using OpenTelemetry metrics.
323
+ * This allows you to use the existing telemetry middleware with OpenTelemetry.
324
+ *
325
+ * **Note:** Currently uses spans for metrics as the OpenTelemetry metrics API
326
+ * is still evolving. Consider using createOpenTelemetryMiddleware for full
327
+ * tracing support.
328
+ */
329
+ export class OpenTelemetryTelemetrySink {
330
+ tracer;
331
+ constructor(tracer) {
332
+ this.tracer = tracer;
333
+ }
334
+ /**
335
+ * Create a new OpenTelemetryTelemetrySink instance.
336
+ *
337
+ * @param config OpenTelemetry configuration
338
+ * @returns Promise that resolves to a new sink instance
339
+ * @throws Error if OpenTelemetry packages are not installed
340
+ */
341
+ static async create(config = {}) {
342
+ // Check if OpenTelemetry is available
343
+ const available = await checkOpenTelemetryAvailability();
344
+ if (!available) {
345
+ throw new Error('OpenTelemetry packages are not installed. Please install:\n' +
346
+ 'npm install @opentelemetry/api @opentelemetry/sdk-trace-base ' +
347
+ '@opentelemetry/exporter-trace-otlp-http @opentelemetry/resources ' +
348
+ '@opentelemetry/semantic-conventions');
349
+ }
350
+ const { tracerName = 'ai-matey-telemetry-sink' } = config;
351
+ // Initialize tracer provider (async to handle race conditions)
352
+ const provider = await getOrCreateTracerProvider(config);
353
+ const tracer = provider.getTracer(tracerName);
354
+ return new OpenTelemetryTelemetrySink(tracer);
355
+ }
356
+ recordMetric(name, value, tags) {
357
+ // Create a span for the metric (simplified approach)
358
+ const span = this.tracer.startSpan(`metric.${name}`, {
359
+ attributes: {
360
+ 'metric.name': name,
361
+ 'metric.value': value,
362
+ ...tags,
363
+ },
364
+ });
365
+ span.end();
366
+ }
367
+ recordEvent(name, data) {
368
+ // Create a span for the event
369
+ // Flatten and sanitize data to only include primitive types
370
+ const attributes = {
371
+ 'event.name': name,
372
+ };
373
+ if (data) {
374
+ for (const [key, value] of Object.entries(data)) {
375
+ // Only include primitive types that OpenTelemetry supports
376
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
377
+ attributes[key] = value;
378
+ }
379
+ else if (value === null || value === undefined) {
380
+ attributes[key] = String(value);
381
+ }
382
+ else {
383
+ // For complex objects, stringify them
384
+ attributes[key] = JSON.stringify(value);
385
+ }
386
+ }
387
+ }
388
+ const span = this.tracer.startSpan(`event.${name}`, {
389
+ attributes,
390
+ });
391
+ span.end();
392
+ }
393
+ }
394
+ // ============================================================================
395
+ // Utility Functions
396
+ // ============================================================================
397
+ /**
398
+ * Check if OpenTelemetry packages are installed and available.
399
+ *
400
+ * @returns Promise that resolves to true if OpenTelemetry is available
401
+ *
402
+ * @example
403
+ * ```typescript
404
+ * import { isOpenTelemetryAvailable } from 'ai.matey.middleware';
405
+ *
406
+ * if (await isOpenTelemetryAvailable()) {
407
+ * console.log('OpenTelemetry is available!');
408
+ * } else {
409
+ * console.log('OpenTelemetry packages not installed.');
410
+ * }
411
+ * ```
412
+ */
413
+ export async function isOpenTelemetryAvailable() {
414
+ return checkOpenTelemetryAvailability();
415
+ }
416
+ /**
417
+ * Synchronously check if OpenTelemetry is already loaded.
418
+ * Use isOpenTelemetryAvailable() for async check with dynamic import.
419
+ *
420
+ * @returns True if OpenTelemetry is already loaded
421
+ *
422
+ * @example
423
+ * ```typescript
424
+ * import { isOpenTelemetryLoaded } from 'ai.matey.middleware';
425
+ *
426
+ * if (isOpenTelemetryLoaded()) {
427
+ * console.log('OpenTelemetry is already loaded!');
428
+ * }
429
+ * ```
430
+ */
431
+ export function isOpenTelemetryLoaded() {
432
+ return isOtelLoaded();
433
+ }
434
+ /**
435
+ * Force shutdown of the global tracer provider.
436
+ * Useful for graceful shutdown in server applications.
437
+ *
438
+ * @returns Promise that resolves when shutdown is complete
439
+ *
440
+ * @example
441
+ * ```typescript
442
+ * import { shutdownOpenTelemetry } from 'ai.matey.middleware';
443
+ *
444
+ * process.on('SIGTERM', async () => {
445
+ * await shutdownOpenTelemetry();
446
+ * process.exit(0);
447
+ * });
448
+ * ```
449
+ */
450
+ export async function shutdownOpenTelemetry() {
451
+ if (globalTracerProvider) {
452
+ await globalTracerProvider.shutdown();
453
+ globalTracerProvider = null;
454
+ globalTracerProviderConfig = null;
455
+ providerInitializationPromise = null;
456
+ }
457
+ }
458
+ //# sourceMappingURL=opentelemetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opentelemetry.js","sourceRoot":"","sources":["../../src/opentelemetry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Retry Middleware
3
+ *
4
+ * Retries failed requests with exponential backoff.
5
+ *
6
+ * @module
7
+ */
8
+ import { AdapterError } from 'ai.matey.errors';
9
+ // ============================================================================
10
+ // Retry Logic
11
+ // ============================================================================
12
+ /**
13
+ * Default retry condition.
14
+ *
15
+ * Only retry transient errors (network issues, rate limits, server errors).
16
+ * Note: maxAttempts is enforced by the middleware loop, not this function.
17
+ */
18
+ function defaultShouldRetry(error, _attempt) {
19
+ // Check if error has isRetryable property
20
+ if (error && typeof error === 'object' && 'isRetryable' in error) {
21
+ return error.isRetryable === true;
22
+ }
23
+ // For AdapterError, check isRetryable
24
+ if (error instanceof AdapterError) {
25
+ return error.isRetryable;
26
+ }
27
+ // Default: don't retry unknown errors
28
+ return false;
29
+ }
30
+ /**
31
+ * Calculate retry delay with exponential backoff.
32
+ */
33
+ function calculateDelay(attempt, initialDelay, backoffMultiplier, maxDelay, useJitter) {
34
+ // Calculate exponential backoff
35
+ let delay = initialDelay * Math.pow(backoffMultiplier, attempt);
36
+ // Cap at max delay
37
+ delay = Math.min(delay, maxDelay);
38
+ // Add jitter if enabled (random value between 0 and delay)
39
+ if (useJitter) {
40
+ delay = Math.random() * delay;
41
+ }
42
+ return Math.floor(delay);
43
+ }
44
+ /**
45
+ * Sleep for specified duration.
46
+ */
47
+ function sleep(ms) {
48
+ return new Promise((resolve) => setTimeout(resolve, ms));
49
+ }
50
+ // ============================================================================
51
+ // Middleware Factory
52
+ // ============================================================================
53
+ /**
54
+ * Create retry middleware.
55
+ *
56
+ * Retries failed requests with exponential backoff.
57
+ *
58
+ * @param config Retry configuration
59
+ * @returns Retry middleware
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * const retry = createRetryMiddleware({
64
+ * maxAttempts: 3,
65
+ * initialDelay: 1000,
66
+ * backoffMultiplier: 2,
67
+ * maxDelay: 30000
68
+ * });
69
+ *
70
+ * bridge.use(retry);
71
+ * ```
72
+ */
73
+ export function createRetryMiddleware(config = {}) {
74
+ const { maxAttempts = 3, initialDelay = 1000, backoffMultiplier = 2, maxDelay = 30000, useJitter = true, shouldRetry = defaultShouldRetry, onRetry, } = config;
75
+ return async (context, next) => {
76
+ let lastError;
77
+ let attempt = 0;
78
+ while (attempt < maxAttempts) {
79
+ try {
80
+ // Call next middleware/handler
81
+ const response = await next();
82
+ // Success - add retry metadata if we retried
83
+ if (attempt > 0) {
84
+ return {
85
+ ...response,
86
+ metadata: {
87
+ ...response.metadata,
88
+ custom: {
89
+ ...response.metadata.custom,
90
+ retryAttempts: attempt,
91
+ retrySuccess: true,
92
+ },
93
+ },
94
+ };
95
+ }
96
+ return response;
97
+ }
98
+ catch (error) {
99
+ lastError = error;
100
+ attempt++;
101
+ // Check if we should retry
102
+ const willRetry = attempt < maxAttempts && shouldRetry(error, attempt);
103
+ if (!willRetry) {
104
+ // No more retries - add metadata and throw
105
+ if (error instanceof AdapterError) {
106
+ throw new AdapterError({
107
+ ...error,
108
+ details: {
109
+ ...error.details,
110
+ retryAttempts: attempt,
111
+ retrySuccess: false,
112
+ },
113
+ });
114
+ }
115
+ throw error;
116
+ }
117
+ // Calculate retry delay
118
+ const delay = calculateDelay(attempt - 1, // 0-indexed for delay calculation
119
+ initialDelay, backoffMultiplier, maxDelay, useJitter);
120
+ // Call retry callback if provided
121
+ if (onRetry) {
122
+ onRetry(error, attempt, delay);
123
+ }
124
+ // Check if request was aborted
125
+ if (context.signal?.aborted) {
126
+ throw error;
127
+ }
128
+ // Wait before retrying
129
+ await sleep(delay);
130
+ // Check again if request was aborted during sleep
131
+ if (context.signal?.aborted) {
132
+ throw error;
133
+ }
134
+ }
135
+ }
136
+ // Should never reach here, but just in case
137
+ throw lastError;
138
+ };
139
+ }
140
+ // ============================================================================
141
+ // Retry Utilities
142
+ // ============================================================================
143
+ /**
144
+ * Check if an error is a rate limit error.
145
+ */
146
+ export function isRateLimitError(error) {
147
+ if (error instanceof AdapterError) {
148
+ return error.code === 'RATE_LIMIT_EXCEEDED';
149
+ }
150
+ return false;
151
+ }
152
+ /**
153
+ * Check if an error is a network error.
154
+ */
155
+ export function isNetworkError(error) {
156
+ if (error instanceof AdapterError) {
157
+ return error.code === 'NETWORK_ERROR';
158
+ }
159
+ return false;
160
+ }
161
+ /**
162
+ * Check if an error is a server error (5xx).
163
+ */
164
+ export function isServerError(error) {
165
+ if (error instanceof AdapterError) {
166
+ return error.code === 'PROVIDER_ERROR' || error.code === 'INTERNAL_ERROR';
167
+ }
168
+ return false;
169
+ }
170
+ /**
171
+ * Create a retry predicate that only retries specific error types.
172
+ * Note: maxAttempts is enforced by the middleware loop, not this function.
173
+ */
174
+ export function createRetryPredicate(errorTypes) {
175
+ return (error, _attempt) => {
176
+ for (const type of errorTypes) {
177
+ switch (type) {
178
+ case 'rate_limit':
179
+ if (isRateLimitError(error)) {
180
+ return true;
181
+ }
182
+ break;
183
+ case 'network':
184
+ if (isNetworkError(error)) {
185
+ return true;
186
+ }
187
+ break;
188
+ case 'server':
189
+ if (isServerError(error)) {
190
+ return true;
191
+ }
192
+ break;
193
+ }
194
+ }
195
+ return false;
196
+ };
197
+ }
198
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/retry.ts"],"names":[],"mappings":"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"}