@drip-sdk/node 1.0.9 → 1.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 +245 -549
- package/dist/core.cjs +3 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.cts +640 -0
- package/dist/core.d.ts +638 -0
- package/dist/core.js +3 -0
- package/dist/core.js.map +1 -0
- package/dist/express.cjs +2 -2
- package/dist/express.cjs.map +1 -1
- package/dist/express.d.cts +3 -3
- package/dist/express.d.ts +3 -3
- package/dist/express.js +2 -2
- package/dist/express.js.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +736 -3
- package/dist/index.d.ts +736 -3
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/langchain.cjs +3 -0
- package/dist/langchain.cjs.map +1 -0
- package/dist/langchain.d.cts +290 -0
- package/dist/langchain.d.ts +290 -0
- package/dist/langchain.js +3 -0
- package/dist/langchain.js.map +1 -0
- package/dist/middleware.cjs +2 -2
- package/dist/middleware.cjs.map +1 -1
- package/dist/middleware.d.cts +3 -3
- package/dist/middleware.d.ts +3 -3
- package/dist/middleware.js +2 -2
- package/dist/middleware.js.map +1 -1
- package/dist/next.cjs +2 -2
- package/dist/next.cjs.map +1 -1
- package/dist/next.d.cts +3 -3
- package/dist/next.d.ts +3 -3
- package/dist/next.js +2 -2
- package/dist/next.js.map +1 -1
- package/dist/{types-D8mMON4v.d.ts → types-B2qwDadD.d.ts} +1 -1
- package/dist/{types-92iVqLtE.d.cts → types-Bo8SiUdl.d.cts} +1 -1
- package/package.json +23 -1
package/dist/index.d.ts
CHANGED
|
@@ -140,6 +140,327 @@ declare class StreamMeter {
|
|
|
140
140
|
reset(): void;
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Production-grade resilience patterns for the Drip SDK.
|
|
145
|
+
*
|
|
146
|
+
* This module provides:
|
|
147
|
+
* - Rate limiting (token bucket algorithm)
|
|
148
|
+
* - Retry with exponential backoff
|
|
149
|
+
* - Circuit breaker pattern
|
|
150
|
+
* - Request metrics and observability
|
|
151
|
+
*/
|
|
152
|
+
/**
|
|
153
|
+
* Configuration for rate limiting.
|
|
154
|
+
*/
|
|
155
|
+
interface RateLimiterConfig {
|
|
156
|
+
/**
|
|
157
|
+
* Maximum requests per second.
|
|
158
|
+
* @default 100
|
|
159
|
+
*/
|
|
160
|
+
requestsPerSecond: number;
|
|
161
|
+
/**
|
|
162
|
+
* Maximum burst size (bucket capacity).
|
|
163
|
+
* @default 200
|
|
164
|
+
*/
|
|
165
|
+
burstSize: number;
|
|
166
|
+
/**
|
|
167
|
+
* Whether rate limiting is enabled.
|
|
168
|
+
* @default true
|
|
169
|
+
*/
|
|
170
|
+
enabled: boolean;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Thread-safe token bucket rate limiter.
|
|
174
|
+
*
|
|
175
|
+
* Allows bursting up to `burstSize` requests, then limits to
|
|
176
|
+
* `requestsPerSecond` sustained rate.
|
|
177
|
+
*/
|
|
178
|
+
declare class RateLimiter {
|
|
179
|
+
private readonly config;
|
|
180
|
+
private tokens;
|
|
181
|
+
private lastRefill;
|
|
182
|
+
constructor(config?: Partial<RateLimiterConfig>);
|
|
183
|
+
/**
|
|
184
|
+
* Refill tokens based on elapsed time.
|
|
185
|
+
*/
|
|
186
|
+
private refill;
|
|
187
|
+
/**
|
|
188
|
+
* Acquire a token, blocking if necessary.
|
|
189
|
+
*
|
|
190
|
+
* @param timeout - Maximum time to wait for a token in ms (undefined = wait forever)
|
|
191
|
+
* @returns Promise that resolves to true if token acquired, false if timeout
|
|
192
|
+
*/
|
|
193
|
+
acquire(timeout?: number): Promise<boolean>;
|
|
194
|
+
/**
|
|
195
|
+
* Try to acquire a token without waiting.
|
|
196
|
+
*
|
|
197
|
+
* @returns true if token acquired, false otherwise
|
|
198
|
+
*/
|
|
199
|
+
tryAcquire(): boolean;
|
|
200
|
+
/**
|
|
201
|
+
* Get current number of available tokens.
|
|
202
|
+
*/
|
|
203
|
+
get availableTokens(): number;
|
|
204
|
+
private sleep;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Configuration for retry behavior.
|
|
208
|
+
*/
|
|
209
|
+
interface RetryConfig {
|
|
210
|
+
/**
|
|
211
|
+
* Maximum number of retry attempts.
|
|
212
|
+
* @default 3
|
|
213
|
+
*/
|
|
214
|
+
maxRetries: number;
|
|
215
|
+
/**
|
|
216
|
+
* Base delay in milliseconds.
|
|
217
|
+
* @default 100
|
|
218
|
+
*/
|
|
219
|
+
baseDelayMs: number;
|
|
220
|
+
/**
|
|
221
|
+
* Maximum delay in milliseconds.
|
|
222
|
+
* @default 10000
|
|
223
|
+
*/
|
|
224
|
+
maxDelayMs: number;
|
|
225
|
+
/**
|
|
226
|
+
* Exponential backoff base.
|
|
227
|
+
* @default 2
|
|
228
|
+
*/
|
|
229
|
+
exponentialBase: number;
|
|
230
|
+
/**
|
|
231
|
+
* Random jitter factor (0-1).
|
|
232
|
+
* @default 0.1
|
|
233
|
+
*/
|
|
234
|
+
jitter: number;
|
|
235
|
+
/**
|
|
236
|
+
* HTTP status codes that should trigger retry.
|
|
237
|
+
* @default [429, 500, 502, 503, 504]
|
|
238
|
+
*/
|
|
239
|
+
retryableStatusCodes: number[];
|
|
240
|
+
/**
|
|
241
|
+
* Whether retry is enabled.
|
|
242
|
+
* @default true
|
|
243
|
+
*/
|
|
244
|
+
enabled: boolean;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Error thrown when all retry attempts have been exhausted.
|
|
248
|
+
*/
|
|
249
|
+
declare class RetryExhaustedError extends Error {
|
|
250
|
+
readonly attempts: number;
|
|
251
|
+
readonly lastError: Error;
|
|
252
|
+
constructor(attempts: number, lastError: Error);
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Calculate backoff delay for a given attempt.
|
|
256
|
+
*/
|
|
257
|
+
declare function calculateBackoff(attempt: number, config: RetryConfig): number;
|
|
258
|
+
/**
|
|
259
|
+
* Check if an error is retryable based on configuration.
|
|
260
|
+
*/
|
|
261
|
+
declare function isRetryableError(error: unknown, config: RetryConfig): boolean;
|
|
262
|
+
/**
|
|
263
|
+
* Circuit breaker states.
|
|
264
|
+
*/
|
|
265
|
+
type CircuitState = 'closed' | 'open' | 'half_open';
|
|
266
|
+
/**
|
|
267
|
+
* Configuration for circuit breaker.
|
|
268
|
+
*/
|
|
269
|
+
interface CircuitBreakerConfig {
|
|
270
|
+
/**
|
|
271
|
+
* Number of failures before opening circuit.
|
|
272
|
+
* @default 5
|
|
273
|
+
*/
|
|
274
|
+
failureThreshold: number;
|
|
275
|
+
/**
|
|
276
|
+
* Number of successes in half-open to close circuit.
|
|
277
|
+
* @default 2
|
|
278
|
+
*/
|
|
279
|
+
successThreshold: number;
|
|
280
|
+
/**
|
|
281
|
+
* Milliseconds to wait before transitioning from open to half-open.
|
|
282
|
+
* @default 30000
|
|
283
|
+
*/
|
|
284
|
+
timeoutMs: number;
|
|
285
|
+
/**
|
|
286
|
+
* Whether circuit breaker is enabled.
|
|
287
|
+
* @default true
|
|
288
|
+
*/
|
|
289
|
+
enabled: boolean;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Error thrown when circuit breaker is open.
|
|
293
|
+
*/
|
|
294
|
+
declare class CircuitBreakerOpenError extends Error {
|
|
295
|
+
readonly circuitName: string;
|
|
296
|
+
readonly timeUntilRetryMs: number;
|
|
297
|
+
constructor(circuitName: string, timeUntilRetryMs: number);
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Circuit breaker pattern implementation.
|
|
301
|
+
*
|
|
302
|
+
* Prevents cascading failures by failing fast when a service is unhealthy.
|
|
303
|
+
*/
|
|
304
|
+
declare class CircuitBreaker {
|
|
305
|
+
readonly name: string;
|
|
306
|
+
private readonly config;
|
|
307
|
+
private state;
|
|
308
|
+
private failureCount;
|
|
309
|
+
private successCount;
|
|
310
|
+
private lastFailureTime;
|
|
311
|
+
constructor(name: string, config?: Partial<CircuitBreakerConfig>);
|
|
312
|
+
/**
|
|
313
|
+
* Get current circuit state.
|
|
314
|
+
*/
|
|
315
|
+
getState(): CircuitState;
|
|
316
|
+
/**
|
|
317
|
+
* Check if state should transition based on timeout.
|
|
318
|
+
*/
|
|
319
|
+
private checkStateTransition;
|
|
320
|
+
/**
|
|
321
|
+
* Record a successful call.
|
|
322
|
+
*/
|
|
323
|
+
recordSuccess(): void;
|
|
324
|
+
/**
|
|
325
|
+
* Record a failed call.
|
|
326
|
+
*/
|
|
327
|
+
recordFailure(): void;
|
|
328
|
+
/**
|
|
329
|
+
* Check if a request should be allowed.
|
|
330
|
+
*/
|
|
331
|
+
allowRequest(): boolean;
|
|
332
|
+
/**
|
|
333
|
+
* Get milliseconds until circuit transitions to half-open.
|
|
334
|
+
*/
|
|
335
|
+
getTimeUntilRetry(): number;
|
|
336
|
+
/**
|
|
337
|
+
* Reset the circuit breaker to initial state.
|
|
338
|
+
*/
|
|
339
|
+
reset(): void;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Metrics for a single request.
|
|
343
|
+
*/
|
|
344
|
+
interface RequestMetrics {
|
|
345
|
+
method: string;
|
|
346
|
+
endpoint: string;
|
|
347
|
+
statusCode: number | null;
|
|
348
|
+
durationMs: number;
|
|
349
|
+
success: boolean;
|
|
350
|
+
timestamp: number;
|
|
351
|
+
error?: string;
|
|
352
|
+
retryCount: number;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Aggregated metrics summary.
|
|
356
|
+
*/
|
|
357
|
+
interface MetricsSummary {
|
|
358
|
+
windowSize: number;
|
|
359
|
+
totalRequests: number;
|
|
360
|
+
totalSuccesses: number;
|
|
361
|
+
totalFailures: number;
|
|
362
|
+
successRate: number;
|
|
363
|
+
avgLatencyMs: number;
|
|
364
|
+
minLatencyMs: number;
|
|
365
|
+
maxLatencyMs: number;
|
|
366
|
+
p50LatencyMs: number;
|
|
367
|
+
p95LatencyMs: number;
|
|
368
|
+
p99LatencyMs: number;
|
|
369
|
+
requestsByEndpoint: Record<string, number>;
|
|
370
|
+
errorsByType: Record<string, number>;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Collects and aggregates request metrics.
|
|
374
|
+
*
|
|
375
|
+
* Thread-safe metrics collection with windowed aggregation.
|
|
376
|
+
*/
|
|
377
|
+
declare class MetricsCollector {
|
|
378
|
+
private readonly windowSize;
|
|
379
|
+
private readonly metrics;
|
|
380
|
+
private totalRequests;
|
|
381
|
+
private totalSuccesses;
|
|
382
|
+
private totalFailures;
|
|
383
|
+
constructor(windowSize?: number);
|
|
384
|
+
/**
|
|
385
|
+
* Record a request's metrics.
|
|
386
|
+
*/
|
|
387
|
+
record(metrics: RequestMetrics): void;
|
|
388
|
+
/**
|
|
389
|
+
* Get aggregated metrics summary.
|
|
390
|
+
*/
|
|
391
|
+
getSummary(): MetricsSummary;
|
|
392
|
+
/**
|
|
393
|
+
* Reset all metrics.
|
|
394
|
+
*/
|
|
395
|
+
reset(): void;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Combined configuration for all resilience features.
|
|
399
|
+
*/
|
|
400
|
+
interface ResilienceConfig {
|
|
401
|
+
rateLimiter: RateLimiterConfig;
|
|
402
|
+
retry: RetryConfig;
|
|
403
|
+
circuitBreaker: CircuitBreakerConfig;
|
|
404
|
+
collectMetrics: boolean;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Create default production configuration.
|
|
408
|
+
*/
|
|
409
|
+
declare function createDefaultResilienceConfig(): ResilienceConfig;
|
|
410
|
+
/**
|
|
411
|
+
* Create configuration with all features disabled.
|
|
412
|
+
*/
|
|
413
|
+
declare function createDisabledResilienceConfig(): ResilienceConfig;
|
|
414
|
+
/**
|
|
415
|
+
* Create configuration optimized for high throughput.
|
|
416
|
+
*/
|
|
417
|
+
declare function createHighThroughputResilienceConfig(): ResilienceConfig;
|
|
418
|
+
/**
|
|
419
|
+
* Health status of resilience components.
|
|
420
|
+
*/
|
|
421
|
+
interface ResilienceHealth {
|
|
422
|
+
circuitBreaker: {
|
|
423
|
+
state: CircuitState;
|
|
424
|
+
timeUntilRetryMs: number;
|
|
425
|
+
};
|
|
426
|
+
rateLimiter: {
|
|
427
|
+
availableTokens: number;
|
|
428
|
+
requestsPerSecond: number;
|
|
429
|
+
};
|
|
430
|
+
metrics: MetricsSummary | null;
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Manages all resilience features for the SDK.
|
|
434
|
+
*
|
|
435
|
+
* Provides a unified interface for rate limiting, retry, circuit breaker,
|
|
436
|
+
* and metrics collection.
|
|
437
|
+
*/
|
|
438
|
+
declare class ResilienceManager {
|
|
439
|
+
readonly config: ResilienceConfig;
|
|
440
|
+
readonly rateLimiter: RateLimiter;
|
|
441
|
+
readonly circuitBreaker: CircuitBreaker;
|
|
442
|
+
readonly metrics: MetricsCollector | null;
|
|
443
|
+
constructor(config?: Partial<ResilienceConfig>);
|
|
444
|
+
/**
|
|
445
|
+
* Execute a function with all resilience features.
|
|
446
|
+
*
|
|
447
|
+
* @param fn - The function to execute
|
|
448
|
+
* @param method - HTTP method for metrics
|
|
449
|
+
* @param endpoint - Endpoint for metrics
|
|
450
|
+
* @returns Result of the function
|
|
451
|
+
*/
|
|
452
|
+
execute<T>(fn: () => Promise<T>, method?: string, endpoint?: string): Promise<T>;
|
|
453
|
+
/**
|
|
454
|
+
* Get current metrics summary.
|
|
455
|
+
*/
|
|
456
|
+
getMetrics(): MetricsSummary | null;
|
|
457
|
+
/**
|
|
458
|
+
* Get health status of all resilience components.
|
|
459
|
+
*/
|
|
460
|
+
getHealth(): ResilienceHealth;
|
|
461
|
+
private sleep;
|
|
462
|
+
}
|
|
463
|
+
|
|
143
464
|
/**
|
|
144
465
|
* Drip SDK - Usage-based billing for Node.js
|
|
145
466
|
*
|
|
@@ -150,6 +471,31 @@ declare class StreamMeter {
|
|
|
150
471
|
* @packageDocumentation
|
|
151
472
|
*/
|
|
152
473
|
|
|
474
|
+
/**
|
|
475
|
+
* Retry options for API calls.
|
|
476
|
+
*/
|
|
477
|
+
interface RetryOptions {
|
|
478
|
+
/**
|
|
479
|
+
* Maximum number of retry attempts.
|
|
480
|
+
* @default 3
|
|
481
|
+
*/
|
|
482
|
+
maxAttempts?: number;
|
|
483
|
+
/**
|
|
484
|
+
* Base delay between retries in milliseconds (exponential backoff).
|
|
485
|
+
* @default 100
|
|
486
|
+
*/
|
|
487
|
+
baseDelayMs?: number;
|
|
488
|
+
/**
|
|
489
|
+
* Maximum delay between retries in milliseconds.
|
|
490
|
+
* @default 5000
|
|
491
|
+
*/
|
|
492
|
+
maxDelayMs?: number;
|
|
493
|
+
/**
|
|
494
|
+
* Custom function to determine if an error is retryable.
|
|
495
|
+
* By default, retries on network errors and 5xx status codes.
|
|
496
|
+
*/
|
|
497
|
+
isRetryable?: (error: unknown) => boolean;
|
|
498
|
+
}
|
|
153
499
|
/**
|
|
154
500
|
* Configuration options for the Drip SDK client.
|
|
155
501
|
*/
|
|
@@ -170,6 +516,36 @@ interface DripConfig {
|
|
|
170
516
|
* @default 30000
|
|
171
517
|
*/
|
|
172
518
|
timeout?: number;
|
|
519
|
+
/**
|
|
520
|
+
* Enable production resilience features (rate limiting, retry with backoff,
|
|
521
|
+
* circuit breaker, metrics).
|
|
522
|
+
*
|
|
523
|
+
* - `true`: Use default production settings (100 req/s, 3 retries)
|
|
524
|
+
* - `'high-throughput'`: Optimized for high throughput (1000 req/s, 2 retries)
|
|
525
|
+
* - `ResilienceConfig`: Custom configuration object
|
|
526
|
+
* - `undefined`/`false`: Disabled (default for backward compatibility)
|
|
527
|
+
*
|
|
528
|
+
* @example
|
|
529
|
+
* ```typescript
|
|
530
|
+
* // Enable with defaults
|
|
531
|
+
* const drip = new Drip({ apiKey: '...', resilience: true });
|
|
532
|
+
*
|
|
533
|
+
* // High throughput mode
|
|
534
|
+
* const drip = new Drip({ apiKey: '...', resilience: 'high-throughput' });
|
|
535
|
+
*
|
|
536
|
+
* // Custom config
|
|
537
|
+
* const drip = new Drip({
|
|
538
|
+
* apiKey: '...',
|
|
539
|
+
* resilience: {
|
|
540
|
+
* rateLimiter: { requestsPerSecond: 500, burstSize: 1000, enabled: true },
|
|
541
|
+
* retry: { maxRetries: 5, enabled: true },
|
|
542
|
+
* circuitBreaker: { failureThreshold: 10, enabled: true },
|
|
543
|
+
* collectMetrics: true,
|
|
544
|
+
* },
|
|
545
|
+
* });
|
|
546
|
+
* ```
|
|
547
|
+
*/
|
|
548
|
+
resilience?: boolean | 'high-throughput' | Partial<ResilienceConfig>;
|
|
173
549
|
}
|
|
174
550
|
/**
|
|
175
551
|
* Parameters for creating a new customer.
|
|
@@ -196,8 +572,8 @@ interface CreateCustomerParams {
|
|
|
196
572
|
interface Customer {
|
|
197
573
|
/** Unique customer ID in Drip */
|
|
198
574
|
id: string;
|
|
199
|
-
/** Your business ID */
|
|
200
|
-
businessId
|
|
575
|
+
/** Your business ID (optional - may not be returned by all endpoints) */
|
|
576
|
+
businessId?: string;
|
|
201
577
|
/** Your external customer ID (if provided) */
|
|
202
578
|
externalCustomerId: string | null;
|
|
203
579
|
/** Customer's on-chain address */
|
|
@@ -697,6 +1073,96 @@ interface ListMetersResponse {
|
|
|
697
1073
|
/** Total count */
|
|
698
1074
|
count: number;
|
|
699
1075
|
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Custom pricing map for cost estimation.
|
|
1078
|
+
* Maps usage type to unit price (e.g., { "api_call": "0.005", "token": "0.0001" })
|
|
1079
|
+
*/
|
|
1080
|
+
type CustomPricing = Record<string, string>;
|
|
1081
|
+
/**
|
|
1082
|
+
* Parameters for estimating costs from historical usage events.
|
|
1083
|
+
*/
|
|
1084
|
+
interface EstimateFromUsageParams {
|
|
1085
|
+
/** Filter to a specific customer (optional) */
|
|
1086
|
+
customerId?: string;
|
|
1087
|
+
/** Start of the period to estimate */
|
|
1088
|
+
periodStart: Date | string;
|
|
1089
|
+
/** End of the period to estimate */
|
|
1090
|
+
periodEnd: Date | string;
|
|
1091
|
+
/** Default price for usage types without pricing plans */
|
|
1092
|
+
defaultUnitPrice?: string;
|
|
1093
|
+
/** Include events that already have charges (default: true) */
|
|
1094
|
+
includeChargedEvents?: boolean;
|
|
1095
|
+
/** Filter to specific usage types */
|
|
1096
|
+
usageTypes?: string[];
|
|
1097
|
+
/** Custom pricing overrides (takes precedence over DB pricing) */
|
|
1098
|
+
customPricing?: CustomPricing;
|
|
1099
|
+
}
|
|
1100
|
+
/**
|
|
1101
|
+
* A usage item for hypothetical cost estimation.
|
|
1102
|
+
*/
|
|
1103
|
+
interface HypotheticalUsageItem {
|
|
1104
|
+
/** The usage type (e.g., "api_call", "token") */
|
|
1105
|
+
usageType: string;
|
|
1106
|
+
/** The quantity of usage */
|
|
1107
|
+
quantity: number;
|
|
1108
|
+
/** Override unit price for this specific item */
|
|
1109
|
+
unitPriceOverride?: string;
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* Parameters for estimating costs from hypothetical usage.
|
|
1113
|
+
*/
|
|
1114
|
+
interface EstimateFromHypotheticalParams {
|
|
1115
|
+
/** List of usage items to estimate */
|
|
1116
|
+
items: HypotheticalUsageItem[];
|
|
1117
|
+
/** Default price for usage types without pricing plans */
|
|
1118
|
+
defaultUnitPrice?: string;
|
|
1119
|
+
/** Custom pricing overrides (takes precedence over DB pricing) */
|
|
1120
|
+
customPricing?: CustomPricing;
|
|
1121
|
+
}
|
|
1122
|
+
/**
|
|
1123
|
+
* A line item in the cost estimate.
|
|
1124
|
+
*/
|
|
1125
|
+
interface CostEstimateLineItem {
|
|
1126
|
+
/** The usage type */
|
|
1127
|
+
usageType: string;
|
|
1128
|
+
/** Total quantity */
|
|
1129
|
+
quantity: string;
|
|
1130
|
+
/** Unit price used */
|
|
1131
|
+
unitPrice: string;
|
|
1132
|
+
/** Estimated cost in USDC */
|
|
1133
|
+
estimatedCostUsdc: string;
|
|
1134
|
+
/** Number of events (for usage-based estimates) */
|
|
1135
|
+
eventCount?: number;
|
|
1136
|
+
/** Whether a pricing plan was found for this usage type */
|
|
1137
|
+
hasPricingPlan: boolean;
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* Response from cost estimation.
|
|
1141
|
+
*/
|
|
1142
|
+
interface CostEstimateResponse {
|
|
1143
|
+
/** Business ID (optional - may not be returned by all endpoints) */
|
|
1144
|
+
businessId?: string;
|
|
1145
|
+
/** Customer ID (if filtered) */
|
|
1146
|
+
customerId?: string;
|
|
1147
|
+
/** Period start (for usage-based estimates) */
|
|
1148
|
+
periodStart?: string;
|
|
1149
|
+
/** Period end (for usage-based estimates) */
|
|
1150
|
+
periodEnd?: string;
|
|
1151
|
+
/** Breakdown by usage type */
|
|
1152
|
+
lineItems: CostEstimateLineItem[];
|
|
1153
|
+
/** Subtotal in USDC */
|
|
1154
|
+
subtotalUsdc: string;
|
|
1155
|
+
/** Total estimated cost in USDC */
|
|
1156
|
+
estimatedTotalUsdc: string;
|
|
1157
|
+
/** Currency (always USDC) */
|
|
1158
|
+
currency: 'USDC';
|
|
1159
|
+
/** Indicates this is an estimate, not a charge */
|
|
1160
|
+
isEstimate: true;
|
|
1161
|
+
/** When the estimate was generated */
|
|
1162
|
+
generatedAt: string;
|
|
1163
|
+
/** Notes about the estimate (e.g., missing pricing plans, custom pricing applied) */
|
|
1164
|
+
notes: string[];
|
|
1165
|
+
}
|
|
700
1166
|
/**
|
|
701
1167
|
* A single event to record in a run.
|
|
702
1168
|
*/
|
|
@@ -807,6 +1273,63 @@ interface RunTimeline {
|
|
|
807
1273
|
};
|
|
808
1274
|
summary: string;
|
|
809
1275
|
}
|
|
1276
|
+
/**
|
|
1277
|
+
* Parameters for wrapping an external API call with usage tracking.
|
|
1278
|
+
* This ensures usage is recorded even if there's a crash/failure after the API call.
|
|
1279
|
+
*/
|
|
1280
|
+
interface WrapApiCallParams<T> {
|
|
1281
|
+
/**
|
|
1282
|
+
* The Drip customer ID to charge.
|
|
1283
|
+
*/
|
|
1284
|
+
customerId: string;
|
|
1285
|
+
/**
|
|
1286
|
+
* The usage meter/type to record against.
|
|
1287
|
+
* Must match a meter configured in your pricing plan.
|
|
1288
|
+
*/
|
|
1289
|
+
meter: string;
|
|
1290
|
+
/**
|
|
1291
|
+
* The async function that makes the external API call.
|
|
1292
|
+
* This is the call you want to track (e.g., OpenAI, Anthropic, etc.)
|
|
1293
|
+
*/
|
|
1294
|
+
call: () => Promise<T>;
|
|
1295
|
+
/**
|
|
1296
|
+
* Function to extract the usage quantity from the API call result.
|
|
1297
|
+
* @example (result) => result.usage.total_tokens
|
|
1298
|
+
*/
|
|
1299
|
+
extractUsage: (result: T) => number;
|
|
1300
|
+
/**
|
|
1301
|
+
* Custom idempotency key prefix.
|
|
1302
|
+
* If not provided, a unique key is generated.
|
|
1303
|
+
* The key ensures retries don't double-charge.
|
|
1304
|
+
*/
|
|
1305
|
+
idempotencyKey?: string;
|
|
1306
|
+
/**
|
|
1307
|
+
* Additional metadata to attach to this usage event.
|
|
1308
|
+
*/
|
|
1309
|
+
metadata?: Record<string, unknown>;
|
|
1310
|
+
/**
|
|
1311
|
+
* Retry configuration for the Drip charge call.
|
|
1312
|
+
* The external API call is NOT retried (only called once).
|
|
1313
|
+
*/
|
|
1314
|
+
retryOptions?: RetryOptions;
|
|
1315
|
+
}
|
|
1316
|
+
/**
|
|
1317
|
+
* Result of a wrapped API call.
|
|
1318
|
+
*/
|
|
1319
|
+
interface WrapApiCallResult<T> {
|
|
1320
|
+
/**
|
|
1321
|
+
* The result from the external API call.
|
|
1322
|
+
*/
|
|
1323
|
+
result: T;
|
|
1324
|
+
/**
|
|
1325
|
+
* The charge result from Drip.
|
|
1326
|
+
*/
|
|
1327
|
+
charge: ChargeResult;
|
|
1328
|
+
/**
|
|
1329
|
+
* The idempotency key used (useful for debugging).
|
|
1330
|
+
*/
|
|
1331
|
+
idempotencyKey: string;
|
|
1332
|
+
}
|
|
810
1333
|
/**
|
|
811
1334
|
* Error thrown by Drip SDK operations.
|
|
812
1335
|
*/
|
|
@@ -852,6 +1375,7 @@ declare class Drip {
|
|
|
852
1375
|
private readonly apiKey;
|
|
853
1376
|
private readonly baseUrl;
|
|
854
1377
|
private readonly timeout;
|
|
1378
|
+
private readonly resilience;
|
|
855
1379
|
/**
|
|
856
1380
|
* Creates a new Drip SDK client.
|
|
857
1381
|
*
|
|
@@ -860,8 +1384,21 @@ declare class Drip {
|
|
|
860
1384
|
*
|
|
861
1385
|
* @example
|
|
862
1386
|
* ```typescript
|
|
1387
|
+
* // Basic usage
|
|
1388
|
+
* const drip = new Drip({
|
|
1389
|
+
* apiKey: 'drip_live_abc123...',
|
|
1390
|
+
* });
|
|
1391
|
+
*
|
|
1392
|
+
* // With production resilience (recommended)
|
|
1393
|
+
* const drip = new Drip({
|
|
1394
|
+
* apiKey: 'drip_live_abc123...',
|
|
1395
|
+
* resilience: true,
|
|
1396
|
+
* });
|
|
1397
|
+
*
|
|
1398
|
+
* // High throughput mode
|
|
863
1399
|
* const drip = new Drip({
|
|
864
1400
|
* apiKey: 'drip_live_abc123...',
|
|
1401
|
+
* resilience: 'high-throughput',
|
|
865
1402
|
* });
|
|
866
1403
|
* ```
|
|
867
1404
|
*/
|
|
@@ -871,6 +1408,11 @@ declare class Drip {
|
|
|
871
1408
|
* @internal
|
|
872
1409
|
*/
|
|
873
1410
|
private request;
|
|
1411
|
+
/**
|
|
1412
|
+
* Execute the actual HTTP request (internal).
|
|
1413
|
+
* @internal
|
|
1414
|
+
*/
|
|
1415
|
+
private rawRequest;
|
|
874
1416
|
/**
|
|
875
1417
|
* Pings the Drip API to check connectivity and measure latency.
|
|
876
1418
|
*
|
|
@@ -891,6 +1433,45 @@ declare class Drip {
|
|
|
891
1433
|
latencyMs: number;
|
|
892
1434
|
timestamp: number;
|
|
893
1435
|
}>;
|
|
1436
|
+
/**
|
|
1437
|
+
* Get SDK metrics (requires resilience to be enabled).
|
|
1438
|
+
*
|
|
1439
|
+
* Returns aggregated metrics including success rates, latencies, and errors.
|
|
1440
|
+
*
|
|
1441
|
+
* @returns Metrics summary or null if resilience is not enabled
|
|
1442
|
+
*
|
|
1443
|
+
* @example
|
|
1444
|
+
* ```typescript
|
|
1445
|
+
* const drip = new Drip({ apiKey: '...', resilience: true });
|
|
1446
|
+
* // ... make some requests ...
|
|
1447
|
+
*
|
|
1448
|
+
* const metrics = drip.getMetrics();
|
|
1449
|
+
* if (metrics) {
|
|
1450
|
+
* console.log(`Success rate: ${metrics.successRate.toFixed(1)}%`);
|
|
1451
|
+
* console.log(`P95 latency: ${metrics.p95LatencyMs.toFixed(0)}ms`);
|
|
1452
|
+
* }
|
|
1453
|
+
* ```
|
|
1454
|
+
*/
|
|
1455
|
+
getMetrics(): MetricsSummary | null;
|
|
1456
|
+
/**
|
|
1457
|
+
* Get SDK health status (requires resilience to be enabled).
|
|
1458
|
+
*
|
|
1459
|
+
* Returns health status including circuit breaker state and rate limiter status.
|
|
1460
|
+
*
|
|
1461
|
+
* @returns Health status or null if resilience is not enabled
|
|
1462
|
+
*
|
|
1463
|
+
* @example
|
|
1464
|
+
* ```typescript
|
|
1465
|
+
* const drip = new Drip({ apiKey: '...', resilience: true });
|
|
1466
|
+
*
|
|
1467
|
+
* const health = drip.getHealth();
|
|
1468
|
+
* if (health) {
|
|
1469
|
+
* console.log(`Circuit: ${health.circuitBreaker.state}`);
|
|
1470
|
+
* console.log(`Available tokens: ${health.rateLimiter.availableTokens}`);
|
|
1471
|
+
* }
|
|
1472
|
+
* ```
|
|
1473
|
+
*/
|
|
1474
|
+
getHealth(): ResilienceHealth | null;
|
|
894
1475
|
/**
|
|
895
1476
|
* Creates a new customer in your Drip account.
|
|
896
1477
|
*
|
|
@@ -982,6 +1563,82 @@ declare class Drip {
|
|
|
982
1563
|
* ```
|
|
983
1564
|
*/
|
|
984
1565
|
charge(params: ChargeParams): Promise<ChargeResult>;
|
|
1566
|
+
/**
|
|
1567
|
+
* Wraps an external API call with guaranteed usage recording.
|
|
1568
|
+
*
|
|
1569
|
+
* **This solves the crash-before-record problem:**
|
|
1570
|
+
* ```typescript
|
|
1571
|
+
* // DANGEROUS - usage lost if crash between lines 1 and 2:
|
|
1572
|
+
* const response = await openai.chat.completions.create({...}); // line 1
|
|
1573
|
+
* await drip.charge({ tokens: response.usage.total_tokens }); // line 2
|
|
1574
|
+
*
|
|
1575
|
+
* // SAFE - wrapApiCall guarantees recording with retry:
|
|
1576
|
+
* const { result } = await drip.wrapApiCall({
|
|
1577
|
+
* call: () => openai.chat.completions.create({...}),
|
|
1578
|
+
* extractUsage: (r) => r.usage.total_tokens,
|
|
1579
|
+
* ...
|
|
1580
|
+
* });
|
|
1581
|
+
* ```
|
|
1582
|
+
*
|
|
1583
|
+
* How it works:
|
|
1584
|
+
* 1. Generates idempotency key BEFORE the API call
|
|
1585
|
+
* 2. Makes the external API call (once, no retry)
|
|
1586
|
+
* 3. Records usage in Drip with retry + idempotency
|
|
1587
|
+
* 4. If recording fails transiently, retries are safe (no double-charge)
|
|
1588
|
+
*
|
|
1589
|
+
* @param params - Wrap parameters including the call and usage extractor
|
|
1590
|
+
* @returns The API result and charge details
|
|
1591
|
+
* @throws {DripError} If the Drip charge fails after retries
|
|
1592
|
+
* @throws {Error} If the external API call fails
|
|
1593
|
+
*
|
|
1594
|
+
* @example
|
|
1595
|
+
* ```typescript
|
|
1596
|
+
* // OpenAI example
|
|
1597
|
+
* const { result, charge } = await drip.wrapApiCall({
|
|
1598
|
+
* customerId: 'cust_abc123',
|
|
1599
|
+
* meter: 'tokens',
|
|
1600
|
+
* call: () => openai.chat.completions.create({
|
|
1601
|
+
* model: 'gpt-4',
|
|
1602
|
+
* messages: [{ role: 'user', content: 'Hello!' }],
|
|
1603
|
+
* }),
|
|
1604
|
+
* extractUsage: (r) => r.usage?.total_tokens ?? 0,
|
|
1605
|
+
* });
|
|
1606
|
+
*
|
|
1607
|
+
* console.log(result.choices[0].message.content);
|
|
1608
|
+
* console.log(`Charged: ${charge.charge.amountUsdc} USDC`);
|
|
1609
|
+
* ```
|
|
1610
|
+
*
|
|
1611
|
+
* @example
|
|
1612
|
+
* ```typescript
|
|
1613
|
+
* // Anthropic example
|
|
1614
|
+
* const { result, charge } = await drip.wrapApiCall({
|
|
1615
|
+
* customerId: 'cust_abc123',
|
|
1616
|
+
* meter: 'tokens',
|
|
1617
|
+
* call: () => anthropic.messages.create({
|
|
1618
|
+
* model: 'claude-3-opus-20240229',
|
|
1619
|
+
* max_tokens: 1024,
|
|
1620
|
+
* messages: [{ role: 'user', content: 'Hello!' }],
|
|
1621
|
+
* }),
|
|
1622
|
+
* extractUsage: (r) => r.usage.input_tokens + r.usage.output_tokens,
|
|
1623
|
+
* });
|
|
1624
|
+
* ```
|
|
1625
|
+
*
|
|
1626
|
+
* @example
|
|
1627
|
+
* ```typescript
|
|
1628
|
+
* // With custom retry options
|
|
1629
|
+
* const { result } = await drip.wrapApiCall({
|
|
1630
|
+
* customerId: 'cust_abc123',
|
|
1631
|
+
* meter: 'api_calls',
|
|
1632
|
+
* call: () => fetch('https://api.example.com/expensive'),
|
|
1633
|
+
* extractUsage: () => 1, // Fixed cost per call
|
|
1634
|
+
* retryOptions: {
|
|
1635
|
+
* maxAttempts: 5,
|
|
1636
|
+
* baseDelayMs: 200,
|
|
1637
|
+
* },
|
|
1638
|
+
* });
|
|
1639
|
+
* ```
|
|
1640
|
+
*/
|
|
1641
|
+
wrapApiCall<T>(params: WrapApiCallParams<T>): Promise<WrapApiCallResult<T>>;
|
|
985
1642
|
/**
|
|
986
1643
|
* Records usage for internal visibility WITHOUT billing.
|
|
987
1644
|
*
|
|
@@ -1382,6 +2039,82 @@ declare class Drip {
|
|
|
1382
2039
|
* ```
|
|
1383
2040
|
*/
|
|
1384
2041
|
listMeters(): Promise<ListMetersResponse>;
|
|
2042
|
+
/**
|
|
2043
|
+
* Estimates costs from historical usage events.
|
|
2044
|
+
*
|
|
2045
|
+
* Use this to preview what existing usage would cost before creating charges,
|
|
2046
|
+
* or to run "what-if" scenarios with custom pricing.
|
|
2047
|
+
*
|
|
2048
|
+
* @param params - Parameters for the estimate
|
|
2049
|
+
* @returns Cost estimate with line item breakdown
|
|
2050
|
+
*
|
|
2051
|
+
* @example
|
|
2052
|
+
* ```typescript
|
|
2053
|
+
* // Estimate costs for last month's usage
|
|
2054
|
+
* const estimate = await drip.estimateFromUsage({
|
|
2055
|
+
* periodStart: new Date('2024-01-01'),
|
|
2056
|
+
* periodEnd: new Date('2024-01-31'),
|
|
2057
|
+
* });
|
|
2058
|
+
*
|
|
2059
|
+
* console.log(`Estimated total: $${estimate.estimatedTotalUsdc}`);
|
|
2060
|
+
* ```
|
|
2061
|
+
*
|
|
2062
|
+
* @example
|
|
2063
|
+
* ```typescript
|
|
2064
|
+
* // "What-if" scenario with custom pricing
|
|
2065
|
+
* const estimate = await drip.estimateFromUsage({
|
|
2066
|
+
* periodStart: new Date('2024-01-01'),
|
|
2067
|
+
* periodEnd: new Date('2024-01-31'),
|
|
2068
|
+
* customPricing: {
|
|
2069
|
+
* 'api_call': '0.005', // What if we charged $0.005 per call?
|
|
2070
|
+
* 'token': '0.0001', // What if we charged $0.0001 per token?
|
|
2071
|
+
* },
|
|
2072
|
+
* });
|
|
2073
|
+
* ```
|
|
2074
|
+
*/
|
|
2075
|
+
estimateFromUsage(params: EstimateFromUsageParams): Promise<CostEstimateResponse>;
|
|
2076
|
+
/**
|
|
2077
|
+
* Estimates costs from hypothetical usage.
|
|
2078
|
+
*
|
|
2079
|
+
* Use this for "what-if" scenarios, budget planning, or to preview
|
|
2080
|
+
* costs before usage occurs.
|
|
2081
|
+
*
|
|
2082
|
+
* @param params - Parameters for the estimate
|
|
2083
|
+
* @returns Cost estimate with line item breakdown
|
|
2084
|
+
*
|
|
2085
|
+
* @example
|
|
2086
|
+
* ```typescript
|
|
2087
|
+
* // Estimate what 10,000 API calls and 1M tokens would cost
|
|
2088
|
+
* const estimate = await drip.estimateFromHypothetical({
|
|
2089
|
+
* items: [
|
|
2090
|
+
* { usageType: 'api_call', quantity: 10000 },
|
|
2091
|
+
* { usageType: 'token', quantity: 1000000 },
|
|
2092
|
+
* ],
|
|
2093
|
+
* });
|
|
2094
|
+
*
|
|
2095
|
+
* console.log(`Estimated total: $${estimate.estimatedTotalUsdc}`);
|
|
2096
|
+
* for (const item of estimate.lineItems) {
|
|
2097
|
+
* console.log(` ${item.usageType}: ${item.quantity} × $${item.unitPrice} = $${item.estimatedCostUsdc}`);
|
|
2098
|
+
* }
|
|
2099
|
+
* ```
|
|
2100
|
+
*
|
|
2101
|
+
* @example
|
|
2102
|
+
* ```typescript
|
|
2103
|
+
* // Compare different pricing scenarios
|
|
2104
|
+
* const currentPricing = await drip.estimateFromHypothetical({
|
|
2105
|
+
* items: [{ usageType: 'api_call', quantity: 100000 }],
|
|
2106
|
+
* });
|
|
2107
|
+
*
|
|
2108
|
+
* const newPricing = await drip.estimateFromHypothetical({
|
|
2109
|
+
* items: [{ usageType: 'api_call', quantity: 100000 }],
|
|
2110
|
+
* customPricing: { 'api_call': '0.0005' }, // 50% discount
|
|
2111
|
+
* });
|
|
2112
|
+
*
|
|
2113
|
+
* console.log(`Current: $${currentPricing.estimatedTotalUsdc}`);
|
|
2114
|
+
* console.log(`With 50% discount: $${newPricing.estimatedTotalUsdc}`);
|
|
2115
|
+
* ```
|
|
2116
|
+
*/
|
|
2117
|
+
estimateFromHypothetical(params: EstimateFromHypotheticalParams): Promise<CostEstimateResponse>;
|
|
1385
2118
|
/**
|
|
1386
2119
|
* Records a complete agent run in a single call.
|
|
1387
2120
|
*
|
|
@@ -1593,4 +2326,4 @@ declare class Drip {
|
|
|
1593
2326
|
createStreamMeter(options: StreamMeterOptions): StreamMeter;
|
|
1594
2327
|
}
|
|
1595
2328
|
|
|
1596
|
-
export { type BalanceResult, type Charge, type ChargeParams, type ChargeResult, type ChargeStatus, type CheckoutParams, type CheckoutResult, type CreateCustomerParams, type CreateWebhookParams, type CreateWebhookResponse, type CreateWorkflowParams, type Customer, type DeleteWebhookResponse, Drip, type DripConfig, DripError, type EmitEventParams, type EndRunParams, type EventResult, type ListChargesOptions, type ListChargesResponse, type ListCustomersOptions, type ListCustomersResponse, type ListMetersResponse, type ListWebhooksResponse, type Meter, type RecordRunEvent, type RecordRunParams, type RecordRunResult, type RunResult, type RunStatus, type RunTimeline, type StartRunParams, StreamMeter, type StreamMeterFlushResult, type StreamMeterOptions, type TrackUsageParams, type TrackUsageResult, type Webhook, type WebhookEventType, type Workflow, Drip as default };
|
|
2329
|
+
export { type BalanceResult, type Charge, type ChargeParams, type ChargeResult, type ChargeStatus, type CheckoutParams, type CheckoutResult, CircuitBreaker, type CircuitBreakerConfig, CircuitBreakerOpenError, type CircuitState, type CostEstimateLineItem, type CostEstimateResponse, type CreateCustomerParams, type CreateWebhookParams, type CreateWebhookResponse, type CreateWorkflowParams, type CustomPricing, type Customer, type DeleteWebhookResponse, Drip, type DripConfig, DripError, type EmitEventParams, type EndRunParams, type EstimateFromHypotheticalParams, type EstimateFromUsageParams, type EventResult, type HypotheticalUsageItem, type ListChargesOptions, type ListChargesResponse, type ListCustomersOptions, type ListCustomersResponse, type ListMetersResponse, type ListWebhooksResponse, type Meter, MetricsCollector, type MetricsSummary, RateLimiter, type RateLimiterConfig, type RecordRunEvent, type RecordRunParams, type RecordRunResult, type RequestMetrics, type ResilienceConfig, type ResilienceHealth, ResilienceManager, type RetryConfig, RetryExhaustedError, type RetryOptions, type RunResult, type RunStatus, type RunTimeline, type StartRunParams, StreamMeter, type StreamMeterFlushResult, type StreamMeterOptions, type TrackUsageParams, type TrackUsageResult, type Webhook, type WebhookEventType, type Workflow, type WrapApiCallParams, type WrapApiCallResult, calculateBackoff, createDefaultResilienceConfig, createDisabledResilienceConfig, createHighThroughputResilienceConfig, Drip as default, isRetryableError };
|