@drip-sdk/node 1.0.1 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +102 -3
- package/dist/express.cjs +2 -2
- package/dist/express.cjs.map +1 -1
- 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 +224 -5
- package/dist/index.d.ts +224 -5
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +2 -2
- package/dist/middleware.cjs.map +1 -1
- 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.js +2 -2
- package/dist/next.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,3 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StreamMeter - Accumulate usage locally and charge once at the end.
|
|
3
|
+
*
|
|
4
|
+
* Perfect for LLM token streaming and other high-frequency metering scenarios
|
|
5
|
+
* where you want to avoid making an API call for every small increment.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const meter = drip.createStreamMeter({
|
|
10
|
+
* customerId: 'cust_abc123',
|
|
11
|
+
* meter: 'tokens',
|
|
12
|
+
* });
|
|
13
|
+
*
|
|
14
|
+
* for await (const chunk of llmStream) {
|
|
15
|
+
* meter.add(chunk.tokens);
|
|
16
|
+
* }
|
|
17
|
+
*
|
|
18
|
+
* const result = await meter.flush();
|
|
19
|
+
* console.log(`Charged ${result.charge.amountUsdc} for ${result.quantity} tokens`);
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Options for creating a StreamMeter.
|
|
25
|
+
*/
|
|
26
|
+
interface StreamMeterOptions {
|
|
27
|
+
/**
|
|
28
|
+
* The Drip customer ID to charge.
|
|
29
|
+
*/
|
|
30
|
+
customerId: string;
|
|
31
|
+
/**
|
|
32
|
+
* The usage meter/type to record against.
|
|
33
|
+
* Must match a meter configured in your pricing plan.
|
|
34
|
+
*/
|
|
35
|
+
meter: string;
|
|
36
|
+
/**
|
|
37
|
+
* Unique key to prevent duplicate charges.
|
|
38
|
+
* If not provided, one will be generated.
|
|
39
|
+
*/
|
|
40
|
+
idempotencyKey?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Additional metadata to attach to the charge.
|
|
43
|
+
*/
|
|
44
|
+
metadata?: Record<string, unknown>;
|
|
45
|
+
/**
|
|
46
|
+
* Auto-flush when accumulated quantity reaches this threshold.
|
|
47
|
+
* Useful for long-running streams where you want periodic charges.
|
|
48
|
+
*/
|
|
49
|
+
flushThreshold?: number;
|
|
50
|
+
/**
|
|
51
|
+
* Callback invoked on each add() call.
|
|
52
|
+
* Useful for logging or progress tracking.
|
|
53
|
+
*/
|
|
54
|
+
onAdd?: (quantity: number, total: number) => void;
|
|
55
|
+
/**
|
|
56
|
+
* Callback invoked after each successful flush.
|
|
57
|
+
*/
|
|
58
|
+
onFlush?: (result: StreamMeterFlushResult) => void;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Result of flushing a StreamMeter.
|
|
62
|
+
*/
|
|
63
|
+
interface StreamMeterFlushResult {
|
|
64
|
+
/** Whether the flush was successful */
|
|
65
|
+
success: boolean;
|
|
66
|
+
/** The quantity that was charged */
|
|
67
|
+
quantity: number;
|
|
68
|
+
/** The charge result from the API (if quantity > 0) */
|
|
69
|
+
charge: ChargeResult['charge'] | null;
|
|
70
|
+
/** Whether this was an idempotent replay */
|
|
71
|
+
isReplay: boolean;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Internal charge function type (injected by Drip class).
|
|
75
|
+
*/
|
|
76
|
+
type ChargeFn = (params: ChargeParams) => Promise<ChargeResult>;
|
|
77
|
+
/**
|
|
78
|
+
* StreamMeter accumulates usage locally and charges once when flushed.
|
|
79
|
+
*
|
|
80
|
+
* This is ideal for:
|
|
81
|
+
* - LLM token streaming (charge once at end of stream)
|
|
82
|
+
* - High-frequency events (batch small increments)
|
|
83
|
+
* - Partial failure handling (charge for what was delivered)
|
|
84
|
+
*/
|
|
85
|
+
declare class StreamMeter {
|
|
86
|
+
private _total;
|
|
87
|
+
private _flushed;
|
|
88
|
+
private _flushCount;
|
|
89
|
+
private readonly _chargeFn;
|
|
90
|
+
private readonly _options;
|
|
91
|
+
/**
|
|
92
|
+
* Creates a new StreamMeter.
|
|
93
|
+
*
|
|
94
|
+
* @param chargeFn - The charge function from Drip client
|
|
95
|
+
* @param options - StreamMeter configuration
|
|
96
|
+
*/
|
|
97
|
+
constructor(chargeFn: ChargeFn, options: StreamMeterOptions);
|
|
98
|
+
/**
|
|
99
|
+
* Current accumulated quantity (not yet charged).
|
|
100
|
+
*/
|
|
101
|
+
get total(): number;
|
|
102
|
+
/**
|
|
103
|
+
* Whether this meter has been flushed at least once.
|
|
104
|
+
*/
|
|
105
|
+
get isFlushed(): boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Number of times this meter has been flushed.
|
|
108
|
+
*/
|
|
109
|
+
get flushCount(): number;
|
|
110
|
+
/**
|
|
111
|
+
* Add quantity to the accumulated total.
|
|
112
|
+
*
|
|
113
|
+
* If a flushThreshold is set and the total exceeds it,
|
|
114
|
+
* this will automatically trigger a flush.
|
|
115
|
+
*
|
|
116
|
+
* @param quantity - Amount to add (must be positive)
|
|
117
|
+
* @returns Promise that resolves when add completes (may trigger auto-flush)
|
|
118
|
+
*/
|
|
119
|
+
add(quantity: number): Promise<StreamMeterFlushResult | null>;
|
|
120
|
+
/**
|
|
121
|
+
* Synchronously add quantity without auto-flush.
|
|
122
|
+
* Use this for maximum performance when you don't need threshold-based flushing.
|
|
123
|
+
*
|
|
124
|
+
* @param quantity - Amount to add (must be positive)
|
|
125
|
+
*/
|
|
126
|
+
addSync(quantity: number): void;
|
|
127
|
+
/**
|
|
128
|
+
* Flush accumulated usage and charge the customer.
|
|
129
|
+
*
|
|
130
|
+
* If total is 0, returns a success result with no charge.
|
|
131
|
+
* After flush, the meter resets to 0 and can be reused.
|
|
132
|
+
*
|
|
133
|
+
* @returns The flush result including charge details
|
|
134
|
+
*/
|
|
135
|
+
flush(): Promise<StreamMeterFlushResult>;
|
|
136
|
+
/**
|
|
137
|
+
* Reset the meter without charging.
|
|
138
|
+
* Use this to discard accumulated usage (e.g., on error before delivery).
|
|
139
|
+
*/
|
|
140
|
+
reset(): void;
|
|
141
|
+
}
|
|
142
|
+
|
|
1
143
|
/**
|
|
2
144
|
* Drip SDK - Usage-based billing for Node.js
|
|
3
145
|
*
|
|
@@ -7,6 +149,7 @@
|
|
|
7
149
|
*
|
|
8
150
|
* @packageDocumentation
|
|
9
151
|
*/
|
|
152
|
+
|
|
10
153
|
/**
|
|
11
154
|
* Configuration options for the Drip SDK client.
|
|
12
155
|
*/
|
|
@@ -625,7 +768,7 @@ declare class DripError extends Error {
|
|
|
625
768
|
*
|
|
626
769
|
* @example
|
|
627
770
|
* ```typescript
|
|
628
|
-
* import { Drip } from '@drip-
|
|
771
|
+
* import { Drip } from '@drip-sdk/node';
|
|
629
772
|
*
|
|
630
773
|
* const drip = new Drip({
|
|
631
774
|
* apiKey: process.env.DRIP_API_KEY!,
|
|
@@ -1214,9 +1357,39 @@ declare class Drip {
|
|
|
1214
1357
|
sequence?: number;
|
|
1215
1358
|
}): string;
|
|
1216
1359
|
/**
|
|
1217
|
-
* Verifies a webhook signature.
|
|
1360
|
+
* Verifies a webhook signature using HMAC-SHA256.
|
|
1218
1361
|
*
|
|
1219
1362
|
* Call this when receiving webhook events to ensure they're authentic.
|
|
1363
|
+
* This is an async method that uses the Web Crypto API for secure verification.
|
|
1364
|
+
*
|
|
1365
|
+
* @param payload - The raw request body (string)
|
|
1366
|
+
* @param signature - The x-drip-signature header value
|
|
1367
|
+
* @param secret - Your webhook secret
|
|
1368
|
+
* @returns Promise resolving to whether the signature is valid
|
|
1369
|
+
*
|
|
1370
|
+
* @example
|
|
1371
|
+
* ```typescript
|
|
1372
|
+
* app.post('/webhooks/drip', async (req, res) => {
|
|
1373
|
+
* const isValid = await Drip.verifyWebhookSignature(
|
|
1374
|
+
* req.rawBody,
|
|
1375
|
+
* req.headers['x-drip-signature'],
|
|
1376
|
+
* process.env.DRIP_WEBHOOK_SECRET!,
|
|
1377
|
+
* );
|
|
1378
|
+
*
|
|
1379
|
+
* if (!isValid) {
|
|
1380
|
+
* return res.status(401).send('Invalid signature');
|
|
1381
|
+
* }
|
|
1382
|
+
*
|
|
1383
|
+
* // Process the webhook...
|
|
1384
|
+
* });
|
|
1385
|
+
* ```
|
|
1386
|
+
*/
|
|
1387
|
+
static verifyWebhookSignature(payload: string, signature: string, secret: string): Promise<boolean>;
|
|
1388
|
+
/**
|
|
1389
|
+
* Synchronously verifies a webhook signature using HMAC-SHA256.
|
|
1390
|
+
*
|
|
1391
|
+
* This method uses Node.js crypto module and is only available in Node.js environments.
|
|
1392
|
+
* For edge runtimes or browsers, use the async `verifyWebhookSignature` method instead.
|
|
1220
1393
|
*
|
|
1221
1394
|
* @param payload - The raw request body (string)
|
|
1222
1395
|
* @param signature - The x-drip-signature header value
|
|
@@ -1226,7 +1399,7 @@ declare class Drip {
|
|
|
1226
1399
|
* @example
|
|
1227
1400
|
* ```typescript
|
|
1228
1401
|
* app.post('/webhooks/drip', (req, res) => {
|
|
1229
|
-
* const isValid = Drip.
|
|
1402
|
+
* const isValid = Drip.verifyWebhookSignatureSync(
|
|
1230
1403
|
* req.rawBody,
|
|
1231
1404
|
* req.headers['x-drip-signature'],
|
|
1232
1405
|
* process.env.DRIP_WEBHOOK_SECRET!,
|
|
@@ -1240,9 +1413,55 @@ declare class Drip {
|
|
|
1240
1413
|
* });
|
|
1241
1414
|
* ```
|
|
1242
1415
|
*/
|
|
1243
|
-
static
|
|
1416
|
+
static verifyWebhookSignatureSync(payload: string, signature: string, secret: string): boolean;
|
|
1417
|
+
/**
|
|
1418
|
+
* Creates a StreamMeter for accumulating usage and charging once.
|
|
1419
|
+
*
|
|
1420
|
+
* Perfect for LLM token streaming where you want to:
|
|
1421
|
+
* - Accumulate tokens locally (no API call per token)
|
|
1422
|
+
* - Charge once at the end of the stream
|
|
1423
|
+
* - Handle partial failures (charge for what was delivered)
|
|
1424
|
+
*
|
|
1425
|
+
* @param options - StreamMeter configuration
|
|
1426
|
+
* @returns A new StreamMeter instance
|
|
1427
|
+
*
|
|
1428
|
+
* @example
|
|
1429
|
+
* ```typescript
|
|
1430
|
+
* const meter = drip.createStreamMeter({
|
|
1431
|
+
* customerId: 'cust_abc123',
|
|
1432
|
+
* meter: 'tokens',
|
|
1433
|
+
* });
|
|
1434
|
+
*
|
|
1435
|
+
* // Accumulate tokens as they stream
|
|
1436
|
+
* for await (const chunk of llmStream) {
|
|
1437
|
+
* meter.addSync(chunk.tokens);
|
|
1438
|
+
* yield chunk;
|
|
1439
|
+
* }
|
|
1440
|
+
*
|
|
1441
|
+
* // Single charge at end
|
|
1442
|
+
* const result = await meter.flush();
|
|
1443
|
+
* console.log(`Charged ${result.charge?.amountUsdc} for ${result.quantity} tokens`);
|
|
1444
|
+
* ```
|
|
1445
|
+
*
|
|
1446
|
+
* @example
|
|
1447
|
+
* ```typescript
|
|
1448
|
+
* // With auto-flush threshold
|
|
1449
|
+
* const meter = drip.createStreamMeter({
|
|
1450
|
+
* customerId: 'cust_abc123',
|
|
1451
|
+
* meter: 'tokens',
|
|
1452
|
+
* flushThreshold: 10000, // Charge every 10k tokens
|
|
1453
|
+
* });
|
|
1454
|
+
*
|
|
1455
|
+
* for await (const chunk of longStream) {
|
|
1456
|
+
* await meter.add(chunk.tokens); // May auto-flush
|
|
1457
|
+
* }
|
|
1458
|
+
*
|
|
1459
|
+
* await meter.flush(); // Final flush for remaining tokens
|
|
1460
|
+
* ```
|
|
1461
|
+
*/
|
|
1462
|
+
createStreamMeter(options: StreamMeterOptions): StreamMeter;
|
|
1244
1463
|
}
|
|
1245
1464
|
|
|
1246
1465
|
// @ts-ignore
|
|
1247
1466
|
export = Drip;
|
|
1248
|
-
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, type Webhook, type WebhookEventType, type Workflow };
|
|
1467
|
+
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 Webhook, type WebhookEventType, type Workflow };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StreamMeter - Accumulate usage locally and charge once at the end.
|
|
3
|
+
*
|
|
4
|
+
* Perfect for LLM token streaming and other high-frequency metering scenarios
|
|
5
|
+
* where you want to avoid making an API call for every small increment.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const meter = drip.createStreamMeter({
|
|
10
|
+
* customerId: 'cust_abc123',
|
|
11
|
+
* meter: 'tokens',
|
|
12
|
+
* });
|
|
13
|
+
*
|
|
14
|
+
* for await (const chunk of llmStream) {
|
|
15
|
+
* meter.add(chunk.tokens);
|
|
16
|
+
* }
|
|
17
|
+
*
|
|
18
|
+
* const result = await meter.flush();
|
|
19
|
+
* console.log(`Charged ${result.charge.amountUsdc} for ${result.quantity} tokens`);
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Options for creating a StreamMeter.
|
|
25
|
+
*/
|
|
26
|
+
interface StreamMeterOptions {
|
|
27
|
+
/**
|
|
28
|
+
* The Drip customer ID to charge.
|
|
29
|
+
*/
|
|
30
|
+
customerId: string;
|
|
31
|
+
/**
|
|
32
|
+
* The usage meter/type to record against.
|
|
33
|
+
* Must match a meter configured in your pricing plan.
|
|
34
|
+
*/
|
|
35
|
+
meter: string;
|
|
36
|
+
/**
|
|
37
|
+
* Unique key to prevent duplicate charges.
|
|
38
|
+
* If not provided, one will be generated.
|
|
39
|
+
*/
|
|
40
|
+
idempotencyKey?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Additional metadata to attach to the charge.
|
|
43
|
+
*/
|
|
44
|
+
metadata?: Record<string, unknown>;
|
|
45
|
+
/**
|
|
46
|
+
* Auto-flush when accumulated quantity reaches this threshold.
|
|
47
|
+
* Useful for long-running streams where you want periodic charges.
|
|
48
|
+
*/
|
|
49
|
+
flushThreshold?: number;
|
|
50
|
+
/**
|
|
51
|
+
* Callback invoked on each add() call.
|
|
52
|
+
* Useful for logging or progress tracking.
|
|
53
|
+
*/
|
|
54
|
+
onAdd?: (quantity: number, total: number) => void;
|
|
55
|
+
/**
|
|
56
|
+
* Callback invoked after each successful flush.
|
|
57
|
+
*/
|
|
58
|
+
onFlush?: (result: StreamMeterFlushResult) => void;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Result of flushing a StreamMeter.
|
|
62
|
+
*/
|
|
63
|
+
interface StreamMeterFlushResult {
|
|
64
|
+
/** Whether the flush was successful */
|
|
65
|
+
success: boolean;
|
|
66
|
+
/** The quantity that was charged */
|
|
67
|
+
quantity: number;
|
|
68
|
+
/** The charge result from the API (if quantity > 0) */
|
|
69
|
+
charge: ChargeResult['charge'] | null;
|
|
70
|
+
/** Whether this was an idempotent replay */
|
|
71
|
+
isReplay: boolean;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Internal charge function type (injected by Drip class).
|
|
75
|
+
*/
|
|
76
|
+
type ChargeFn = (params: ChargeParams) => Promise<ChargeResult>;
|
|
77
|
+
/**
|
|
78
|
+
* StreamMeter accumulates usage locally and charges once when flushed.
|
|
79
|
+
*
|
|
80
|
+
* This is ideal for:
|
|
81
|
+
* - LLM token streaming (charge once at end of stream)
|
|
82
|
+
* - High-frequency events (batch small increments)
|
|
83
|
+
* - Partial failure handling (charge for what was delivered)
|
|
84
|
+
*/
|
|
85
|
+
declare class StreamMeter {
|
|
86
|
+
private _total;
|
|
87
|
+
private _flushed;
|
|
88
|
+
private _flushCount;
|
|
89
|
+
private readonly _chargeFn;
|
|
90
|
+
private readonly _options;
|
|
91
|
+
/**
|
|
92
|
+
* Creates a new StreamMeter.
|
|
93
|
+
*
|
|
94
|
+
* @param chargeFn - The charge function from Drip client
|
|
95
|
+
* @param options - StreamMeter configuration
|
|
96
|
+
*/
|
|
97
|
+
constructor(chargeFn: ChargeFn, options: StreamMeterOptions);
|
|
98
|
+
/**
|
|
99
|
+
* Current accumulated quantity (not yet charged).
|
|
100
|
+
*/
|
|
101
|
+
get total(): number;
|
|
102
|
+
/**
|
|
103
|
+
* Whether this meter has been flushed at least once.
|
|
104
|
+
*/
|
|
105
|
+
get isFlushed(): boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Number of times this meter has been flushed.
|
|
108
|
+
*/
|
|
109
|
+
get flushCount(): number;
|
|
110
|
+
/**
|
|
111
|
+
* Add quantity to the accumulated total.
|
|
112
|
+
*
|
|
113
|
+
* If a flushThreshold is set and the total exceeds it,
|
|
114
|
+
* this will automatically trigger a flush.
|
|
115
|
+
*
|
|
116
|
+
* @param quantity - Amount to add (must be positive)
|
|
117
|
+
* @returns Promise that resolves when add completes (may trigger auto-flush)
|
|
118
|
+
*/
|
|
119
|
+
add(quantity: number): Promise<StreamMeterFlushResult | null>;
|
|
120
|
+
/**
|
|
121
|
+
* Synchronously add quantity without auto-flush.
|
|
122
|
+
* Use this for maximum performance when you don't need threshold-based flushing.
|
|
123
|
+
*
|
|
124
|
+
* @param quantity - Amount to add (must be positive)
|
|
125
|
+
*/
|
|
126
|
+
addSync(quantity: number): void;
|
|
127
|
+
/**
|
|
128
|
+
* Flush accumulated usage and charge the customer.
|
|
129
|
+
*
|
|
130
|
+
* If total is 0, returns a success result with no charge.
|
|
131
|
+
* After flush, the meter resets to 0 and can be reused.
|
|
132
|
+
*
|
|
133
|
+
* @returns The flush result including charge details
|
|
134
|
+
*/
|
|
135
|
+
flush(): Promise<StreamMeterFlushResult>;
|
|
136
|
+
/**
|
|
137
|
+
* Reset the meter without charging.
|
|
138
|
+
* Use this to discard accumulated usage (e.g., on error before delivery).
|
|
139
|
+
*/
|
|
140
|
+
reset(): void;
|
|
141
|
+
}
|
|
142
|
+
|
|
1
143
|
/**
|
|
2
144
|
* Drip SDK - Usage-based billing for Node.js
|
|
3
145
|
*
|
|
@@ -7,6 +149,7 @@
|
|
|
7
149
|
*
|
|
8
150
|
* @packageDocumentation
|
|
9
151
|
*/
|
|
152
|
+
|
|
10
153
|
/**
|
|
11
154
|
* Configuration options for the Drip SDK client.
|
|
12
155
|
*/
|
|
@@ -625,7 +768,7 @@ declare class DripError extends Error {
|
|
|
625
768
|
*
|
|
626
769
|
* @example
|
|
627
770
|
* ```typescript
|
|
628
|
-
* import { Drip } from '@drip-
|
|
771
|
+
* import { Drip } from '@drip-sdk/node';
|
|
629
772
|
*
|
|
630
773
|
* const drip = new Drip({
|
|
631
774
|
* apiKey: process.env.DRIP_API_KEY!,
|
|
@@ -1214,9 +1357,39 @@ declare class Drip {
|
|
|
1214
1357
|
sequence?: number;
|
|
1215
1358
|
}): string;
|
|
1216
1359
|
/**
|
|
1217
|
-
* Verifies a webhook signature.
|
|
1360
|
+
* Verifies a webhook signature using HMAC-SHA256.
|
|
1218
1361
|
*
|
|
1219
1362
|
* Call this when receiving webhook events to ensure they're authentic.
|
|
1363
|
+
* This is an async method that uses the Web Crypto API for secure verification.
|
|
1364
|
+
*
|
|
1365
|
+
* @param payload - The raw request body (string)
|
|
1366
|
+
* @param signature - The x-drip-signature header value
|
|
1367
|
+
* @param secret - Your webhook secret
|
|
1368
|
+
* @returns Promise resolving to whether the signature is valid
|
|
1369
|
+
*
|
|
1370
|
+
* @example
|
|
1371
|
+
* ```typescript
|
|
1372
|
+
* app.post('/webhooks/drip', async (req, res) => {
|
|
1373
|
+
* const isValid = await Drip.verifyWebhookSignature(
|
|
1374
|
+
* req.rawBody,
|
|
1375
|
+
* req.headers['x-drip-signature'],
|
|
1376
|
+
* process.env.DRIP_WEBHOOK_SECRET!,
|
|
1377
|
+
* );
|
|
1378
|
+
*
|
|
1379
|
+
* if (!isValid) {
|
|
1380
|
+
* return res.status(401).send('Invalid signature');
|
|
1381
|
+
* }
|
|
1382
|
+
*
|
|
1383
|
+
* // Process the webhook...
|
|
1384
|
+
* });
|
|
1385
|
+
* ```
|
|
1386
|
+
*/
|
|
1387
|
+
static verifyWebhookSignature(payload: string, signature: string, secret: string): Promise<boolean>;
|
|
1388
|
+
/**
|
|
1389
|
+
* Synchronously verifies a webhook signature using HMAC-SHA256.
|
|
1390
|
+
*
|
|
1391
|
+
* This method uses Node.js crypto module and is only available in Node.js environments.
|
|
1392
|
+
* For edge runtimes or browsers, use the async `verifyWebhookSignature` method instead.
|
|
1220
1393
|
*
|
|
1221
1394
|
* @param payload - The raw request body (string)
|
|
1222
1395
|
* @param signature - The x-drip-signature header value
|
|
@@ -1226,7 +1399,7 @@ declare class Drip {
|
|
|
1226
1399
|
* @example
|
|
1227
1400
|
* ```typescript
|
|
1228
1401
|
* app.post('/webhooks/drip', (req, res) => {
|
|
1229
|
-
* const isValid = Drip.
|
|
1402
|
+
* const isValid = Drip.verifyWebhookSignatureSync(
|
|
1230
1403
|
* req.rawBody,
|
|
1231
1404
|
* req.headers['x-drip-signature'],
|
|
1232
1405
|
* process.env.DRIP_WEBHOOK_SECRET!,
|
|
@@ -1240,7 +1413,53 @@ declare class Drip {
|
|
|
1240
1413
|
* });
|
|
1241
1414
|
* ```
|
|
1242
1415
|
*/
|
|
1243
|
-
static
|
|
1416
|
+
static verifyWebhookSignatureSync(payload: string, signature: string, secret: string): boolean;
|
|
1417
|
+
/**
|
|
1418
|
+
* Creates a StreamMeter for accumulating usage and charging once.
|
|
1419
|
+
*
|
|
1420
|
+
* Perfect for LLM token streaming where you want to:
|
|
1421
|
+
* - Accumulate tokens locally (no API call per token)
|
|
1422
|
+
* - Charge once at the end of the stream
|
|
1423
|
+
* - Handle partial failures (charge for what was delivered)
|
|
1424
|
+
*
|
|
1425
|
+
* @param options - StreamMeter configuration
|
|
1426
|
+
* @returns A new StreamMeter instance
|
|
1427
|
+
*
|
|
1428
|
+
* @example
|
|
1429
|
+
* ```typescript
|
|
1430
|
+
* const meter = drip.createStreamMeter({
|
|
1431
|
+
* customerId: 'cust_abc123',
|
|
1432
|
+
* meter: 'tokens',
|
|
1433
|
+
* });
|
|
1434
|
+
*
|
|
1435
|
+
* // Accumulate tokens as they stream
|
|
1436
|
+
* for await (const chunk of llmStream) {
|
|
1437
|
+
* meter.addSync(chunk.tokens);
|
|
1438
|
+
* yield chunk;
|
|
1439
|
+
* }
|
|
1440
|
+
*
|
|
1441
|
+
* // Single charge at end
|
|
1442
|
+
* const result = await meter.flush();
|
|
1443
|
+
* console.log(`Charged ${result.charge?.amountUsdc} for ${result.quantity} tokens`);
|
|
1444
|
+
* ```
|
|
1445
|
+
*
|
|
1446
|
+
* @example
|
|
1447
|
+
* ```typescript
|
|
1448
|
+
* // With auto-flush threshold
|
|
1449
|
+
* const meter = drip.createStreamMeter({
|
|
1450
|
+
* customerId: 'cust_abc123',
|
|
1451
|
+
* meter: 'tokens',
|
|
1452
|
+
* flushThreshold: 10000, // Charge every 10k tokens
|
|
1453
|
+
* });
|
|
1454
|
+
*
|
|
1455
|
+
* for await (const chunk of longStream) {
|
|
1456
|
+
* await meter.add(chunk.tokens); // May auto-flush
|
|
1457
|
+
* }
|
|
1458
|
+
*
|
|
1459
|
+
* await meter.flush(); // Final flush for remaining tokens
|
|
1460
|
+
* ```
|
|
1461
|
+
*/
|
|
1462
|
+
createStreamMeter(options: StreamMeterOptions): StreamMeter;
|
|
1244
1463
|
}
|
|
1245
1464
|
|
|
1246
|
-
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, type Webhook, type WebhookEventType, type Workflow, Drip as default };
|
|
1465
|
+
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 Webhook, type WebhookEventType, type Workflow, Drip as default };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
2
|
-
export{
|
|
1
|
+
var C=(a=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(a,{get:(t,e)=>(typeof require<"u"?require:t)[e]}):a)(function(a){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+a+'" is not supported')});var m=class{_total=0;_flushed=false;_flushCount=0;_chargeFn;_options;constructor(t,e){this._chargeFn=t,this._options=e;}get total(){return this._total}get isFlushed(){return this._flushed}get flushCount(){return this._flushCount}async add(t){return t<=0?null:(this._total+=t,this._options.onAdd?.(t,this._total),this._options.flushThreshold!==void 0&&this._total>=this._options.flushThreshold?this.flush():null)}addSync(t){t<=0||(this._total+=t,this._options.onAdd?.(t,this._total));}async flush(){let t=this._total;if(this._total=0,t===0)return {success:true,quantity:0,charge:null,isReplay:false};let e=this._options.idempotencyKey?`${this._options.idempotencyKey}_flush_${this._flushCount}`:void 0,r=await this._chargeFn({customerId:this._options.customerId,meter:this._options.meter,quantity:t,idempotencyKey:e,metadata:this._options.metadata});this._flushed=true,this._flushCount++;let n={success:r.success,quantity:t,charge:r.charge,isReplay:r.isReplay};return this._options.onFlush?.(n),n}reset(){this._total=0;}};var d=class a extends Error{constructor(e,r,n){super(e);this.statusCode=r;this.code=n;this.name="DripError",Object.setPrototypeOf(this,a.prototype);}},y=class{apiKey;baseUrl;timeout;constructor(t){if(!t.apiKey)throw new Error("Drip API key is required");this.apiKey=t.apiKey,this.baseUrl=t.baseUrl||"https://api.drip.dev/v1",this.timeout=t.timeout||3e4;}async request(t,e={}){let r=new AbortController,n=setTimeout(()=>r.abort(),this.timeout);try{let s=await fetch(`${this.baseUrl}${t}`,{...e,signal:r.signal,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,...e.headers}});if(s.status===204)return {success:!0};let i=await s.json();if(!s.ok)throw new d(i.message||i.error||"Request failed",s.status,i.code);return i}catch(s){throw s instanceof d?s:s instanceof Error&&s.name==="AbortError"?new d("Request timed out",408,"TIMEOUT"):new d(s instanceof Error?s.message:"Unknown error",0,"UNKNOWN")}finally{clearTimeout(n);}}async createCustomer(t){return this.request("/customers",{method:"POST",body:JSON.stringify(t)})}async getCustomer(t){return this.request(`/customers/${t}`)}async listCustomers(t){let e=new URLSearchParams;t?.limit&&e.set("limit",t.limit.toString()),t?.status&&e.set("status",t.status);let r=e.toString(),n=r?`/customers?${r}`:"/customers";return this.request(n)}async getBalance(t){return this.request(`/customers/${t}/balance`)}async charge(t){return this.request("/usage",{method:"POST",body:JSON.stringify({customerId:t.customerId,usageType:t.meter,quantity:t.quantity,idempotencyKey:t.idempotencyKey,metadata:t.metadata})})}async getCharge(t){return this.request(`/charges/${t}`)}async listCharges(t){let e=new URLSearchParams;t?.customerId&&e.set("customerId",t.customerId),t?.status&&e.set("status",t.status),t?.limit&&e.set("limit",t.limit.toString()),t?.offset&&e.set("offset",t.offset.toString());let r=e.toString(),n=r?`/charges?${r}`:"/charges";return this.request(n)}async getChargeStatus(t){return this.request(`/charges/${t}/status`)}async checkout(t){let e=await this.request("/checkout",{method:"POST",body:JSON.stringify({customer_id:t.customerId,external_customer_id:t.externalCustomerId,amount:t.amount,return_url:t.returnUrl,cancel_url:t.cancelUrl,metadata:t.metadata})});return {id:e.id,url:e.url,expiresAt:e.expires_at,amountUsd:e.amount_usd}}async createWebhook(t){return this.request("/webhooks",{method:"POST",body:JSON.stringify(t)})}async listWebhooks(){return this.request("/webhooks")}async getWebhook(t){return this.request(`/webhooks/${t}`)}async deleteWebhook(t){return this.request(`/webhooks/${t}`,{method:"DELETE"})}async testWebhook(t){return this.request(`/webhooks/${t}/test`,{method:"POST"})}async rotateWebhookSecret(t){return this.request(`/webhooks/${t}/rotate-secret`,{method:"POST"})}async createWorkflow(t){return this.request("/workflows",{method:"POST",body:JSON.stringify(t)})}async listWorkflows(){return this.request("/workflows")}async startRun(t){return this.request("/runs",{method:"POST",body:JSON.stringify(t)})}async endRun(t,e){return this.request(`/runs/${t}`,{method:"PATCH",body:JSON.stringify(e)})}async getRunTimeline(t){return this.request(`/runs/${t}`)}async emitEvent(t){return this.request("/events",{method:"POST",body:JSON.stringify(t)})}async emitEventsBatch(t){return this.request("/events/batch",{method:"POST",body:JSON.stringify({events:t})})}async listMeters(){let t=await this.request("/pricing-plans");return {data:t.data.map(e=>({id:e.id,name:e.name,meter:e.unitType,unitPriceUsd:e.unitPriceUsd,isActive:e.isActive})),count:t.count}}async recordRun(t){let e=Date.now(),r=t.workflow,n=t.workflow;if(!t.workflow.startsWith("wf_"))try{let l=(await this.listWorkflows()).data.find(o=>o.slug===t.workflow||o.id===t.workflow);if(l)r=l.id,n=l.name;else {let o=await this.createWorkflow({name:t.workflow.replace(/[_-]/g," ").replace(/\b\w/g,p=>p.toUpperCase()),slug:t.workflow,productSurface:"AGENT"});r=o.id,n=o.name;}}catch{r=t.workflow;}let s=await this.startRun({customerId:t.customerId,workflowId:r,externalRunId:t.externalRunId,correlationId:t.correlationId,metadata:t.metadata}),i=0,u=0;if(t.events.length>0){let b=t.events.map((o,p)=>({runId:s.id,eventType:o.eventType,quantity:o.quantity,units:o.units,description:o.description,costUnits:o.costUnits,metadata:o.metadata,idempotencyKey:t.externalRunId?`${t.externalRunId}:${o.eventType}:${p}`:void 0})),l=await this.emitEventsBatch(b);i=l.created,u=l.duplicates;}let g=await this.endRun(s.id,{status:t.status,errorMessage:t.errorMessage,errorCode:t.errorCode}),h=Date.now()-e,f=t.events.length>0?`${i} events recorded`:"no events",R=`${t.status==="COMPLETED"?"\u2713":t.status==="FAILED"?"\u2717":"\u25CB"} ${n}: ${f} (${g.durationMs??h}ms)`;return {run:{id:s.id,workflowId:r,workflowName:n,status:t.status,durationMs:g.durationMs},events:{created:i,duplicates:u},totalCostUnits:g.totalCostUnits,summary:R}}static generateIdempotencyKey(t){let e=[t.customerId,t.runId??"no_run",t.stepName,String(t.sequence??0)],r=0,n=e.join("|");for(let s=0;s<n.length;s++){let i=n.charCodeAt(s);r=(r<<5)-r+i,r=r&r;}return `drip_${Math.abs(r).toString(36)}_${t.stepName.slice(0,16)}`}static async verifyWebhookSignature(t,e,r){if(!t||!e||!r)return false;try{let n=new TextEncoder,s=n.encode(r),i=n.encode(t),u=await crypto.subtle.importKey("raw",s,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),g=await crypto.subtle.sign("HMAC",u,i),h=Array.from(new Uint8Array(g)).map(c=>c.toString(16).padStart(2,"0")).join("");if(e.length!==h.length)return !1;let f=0;for(let c=0;c<e.length;c++)f|=e.charCodeAt(c)^h.charCodeAt(c);return f===0}catch{return false}}static verifyWebhookSignatureSync(t,e,r){if(!t||!e||!r)return false;try{let n=C("crypto"),s=n.createHmac("sha256",r).update(t).digest("hex"),i=Buffer.from(e),u=Buffer.from(s);return i.length!==u.length?!1:n.timingSafeEqual(i,u)}catch{return false}}createStreamMeter(t){return new m(this.charge.bind(this),t)}},E=y;
|
|
2
|
+
export{y as Drip,d as DripError,m as StreamMeter,E as default};//# sourceMappingURL=index.js.map
|
|
3
3
|
//# sourceMappingURL=index.js.map
|