@closeloop/sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +478 -0
- package/dist/errors-B0i1OvBd.d.mts +909 -0
- package/dist/errors-B0i1OvBd.d.ts +909 -0
- package/dist/index.d.mts +26 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +883 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +844 -0
- package/dist/index.mjs.map +1 -0
- package/dist/nextjs.d.mts +135 -0
- package/dist/nextjs.d.ts +135 -0
- package/dist/nextjs.js +955 -0
- package/dist/nextjs.js.map +1 -0
- package/dist/nextjs.mjs +920 -0
- package/dist/nextjs.mjs.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,909 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credit balance for a wallet and plan
|
|
3
|
+
*/
|
|
4
|
+
interface CreditBalance {
|
|
5
|
+
/**
|
|
6
|
+
* Unique balance ID
|
|
7
|
+
*/
|
|
8
|
+
id: string;
|
|
9
|
+
/**
|
|
10
|
+
* Wallet address of the balance owner
|
|
11
|
+
*/
|
|
12
|
+
walletAddress: string;
|
|
13
|
+
/**
|
|
14
|
+
* Plan ID this balance is for
|
|
15
|
+
*/
|
|
16
|
+
planId: string;
|
|
17
|
+
/**
|
|
18
|
+
* Plan name for display
|
|
19
|
+
*/
|
|
20
|
+
planName: string;
|
|
21
|
+
/**
|
|
22
|
+
* Total credits purchased
|
|
23
|
+
*/
|
|
24
|
+
totalCredits: number;
|
|
25
|
+
/**
|
|
26
|
+
* Credits consumed
|
|
27
|
+
*/
|
|
28
|
+
usedCredits: number;
|
|
29
|
+
/**
|
|
30
|
+
* Remaining available credits
|
|
31
|
+
*/
|
|
32
|
+
remainingCredits: number;
|
|
33
|
+
/**
|
|
34
|
+
* Whether the balance is active
|
|
35
|
+
*/
|
|
36
|
+
isActive: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* When the credits expire (if applicable)
|
|
39
|
+
*/
|
|
40
|
+
expiresAt: string | null;
|
|
41
|
+
/**
|
|
42
|
+
* When the balance was created
|
|
43
|
+
*/
|
|
44
|
+
createdAt: string;
|
|
45
|
+
/**
|
|
46
|
+
* When the balance was last updated
|
|
47
|
+
*/
|
|
48
|
+
updatedAt: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Parameters for getting a specific balance
|
|
52
|
+
*/
|
|
53
|
+
interface GetBalanceParams {
|
|
54
|
+
/**
|
|
55
|
+
* The wallet address of the user
|
|
56
|
+
*/
|
|
57
|
+
walletAddress: string;
|
|
58
|
+
/**
|
|
59
|
+
* The plan ID to get balance for
|
|
60
|
+
*/
|
|
61
|
+
planId: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Parameters for listing balances
|
|
65
|
+
*/
|
|
66
|
+
interface ListBalancesParams {
|
|
67
|
+
/**
|
|
68
|
+
* The wallet address to get all balances for
|
|
69
|
+
*/
|
|
70
|
+
walletAddress: string;
|
|
71
|
+
/**
|
|
72
|
+
* Only return active balances
|
|
73
|
+
*/
|
|
74
|
+
activeOnly?: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Maximum number of results
|
|
77
|
+
*/
|
|
78
|
+
limit?: number;
|
|
79
|
+
/**
|
|
80
|
+
* Cursor for pagination
|
|
81
|
+
*/
|
|
82
|
+
cursor?: string;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Response from listing balances
|
|
86
|
+
*/
|
|
87
|
+
interface ListBalancesResponse {
|
|
88
|
+
/**
|
|
89
|
+
* Array of credit balances
|
|
90
|
+
*/
|
|
91
|
+
balances: CreditBalance[];
|
|
92
|
+
/**
|
|
93
|
+
* Cursor for next page (null if no more)
|
|
94
|
+
*/
|
|
95
|
+
nextCursor: string | null;
|
|
96
|
+
/**
|
|
97
|
+
* Total count of balances
|
|
98
|
+
*/
|
|
99
|
+
totalCount: number;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Credit transaction record
|
|
103
|
+
*/
|
|
104
|
+
interface CreditTransaction {
|
|
105
|
+
/**
|
|
106
|
+
* Transaction ID
|
|
107
|
+
*/
|
|
108
|
+
id: string;
|
|
109
|
+
/**
|
|
110
|
+
* Balance ID this transaction belongs to
|
|
111
|
+
*/
|
|
112
|
+
balanceId: string;
|
|
113
|
+
/**
|
|
114
|
+
* Type of transaction
|
|
115
|
+
*/
|
|
116
|
+
type: "PURCHASE" | "CONSUMPTION" | "REFUND" | "EXPIRATION";
|
|
117
|
+
/**
|
|
118
|
+
* Amount (positive for additions, negative for deductions)
|
|
119
|
+
*/
|
|
120
|
+
amount: number;
|
|
121
|
+
/**
|
|
122
|
+
* Description of the transaction
|
|
123
|
+
*/
|
|
124
|
+
description: string | null;
|
|
125
|
+
/**
|
|
126
|
+
* What consumed the credits (for CONSUMPTION type)
|
|
127
|
+
*/
|
|
128
|
+
consumedBy: string | null;
|
|
129
|
+
/**
|
|
130
|
+
* Additional metadata
|
|
131
|
+
*/
|
|
132
|
+
metadata: Record<string, unknown> | null;
|
|
133
|
+
/**
|
|
134
|
+
* When the transaction occurred
|
|
135
|
+
*/
|
|
136
|
+
createdAt: string;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Parameters for listing transactions
|
|
140
|
+
*/
|
|
141
|
+
interface ListTransactionsParams {
|
|
142
|
+
/**
|
|
143
|
+
* Balance ID to get transactions for
|
|
144
|
+
*/
|
|
145
|
+
balanceId: string;
|
|
146
|
+
/**
|
|
147
|
+
* Filter by transaction type
|
|
148
|
+
*/
|
|
149
|
+
type?: "PURCHASE" | "CONSUMPTION" | "REFUND" | "EXPIRATION";
|
|
150
|
+
/**
|
|
151
|
+
* Maximum number of results
|
|
152
|
+
*/
|
|
153
|
+
limit?: number;
|
|
154
|
+
/**
|
|
155
|
+
* Cursor for pagination
|
|
156
|
+
*/
|
|
157
|
+
cursor?: string;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Response from listing transactions
|
|
161
|
+
*/
|
|
162
|
+
interface ListTransactionsResponse {
|
|
163
|
+
/**
|
|
164
|
+
* Array of transactions
|
|
165
|
+
*/
|
|
166
|
+
transactions: CreditTransaction[];
|
|
167
|
+
/**
|
|
168
|
+
* Cursor for next page
|
|
169
|
+
*/
|
|
170
|
+
nextCursor: string | null;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Aggregated stats for a wallet's credits
|
|
174
|
+
*/
|
|
175
|
+
interface CreditStats {
|
|
176
|
+
/**
|
|
177
|
+
* Total credits across all balances
|
|
178
|
+
*/
|
|
179
|
+
totalCredits: number;
|
|
180
|
+
/**
|
|
181
|
+
* Total credits used
|
|
182
|
+
*/
|
|
183
|
+
totalUsed: number;
|
|
184
|
+
/**
|
|
185
|
+
* Total remaining credits
|
|
186
|
+
*/
|
|
187
|
+
totalRemaining: number;
|
|
188
|
+
/**
|
|
189
|
+
* Number of active balances
|
|
190
|
+
*/
|
|
191
|
+
activeBalances: number;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
interface HttpClientOptions {
|
|
195
|
+
baseUrl: string;
|
|
196
|
+
apiKey: string;
|
|
197
|
+
timeout?: number;
|
|
198
|
+
}
|
|
199
|
+
interface RequestOptions {
|
|
200
|
+
method: "GET" | "POST" | "PUT" | "DELETE";
|
|
201
|
+
path: string;
|
|
202
|
+
body?: unknown;
|
|
203
|
+
headers?: Record<string, string>;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* HTTP client for making requests to the CloseLoop API
|
|
207
|
+
*/
|
|
208
|
+
declare class HttpClient {
|
|
209
|
+
private baseUrl;
|
|
210
|
+
private apiKey;
|
|
211
|
+
private timeout;
|
|
212
|
+
constructor(options: HttpClientOptions);
|
|
213
|
+
/**
|
|
214
|
+
* Make an HTTP request to the CloseLoop API
|
|
215
|
+
*/
|
|
216
|
+
request<T>(options: RequestOptions): Promise<T>;
|
|
217
|
+
private handleErrorResponse;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Resource for querying credit balances and transaction history
|
|
222
|
+
*/
|
|
223
|
+
declare class Balances {
|
|
224
|
+
private readonly http;
|
|
225
|
+
constructor(http: HttpClient);
|
|
226
|
+
/**
|
|
227
|
+
* Get a specific credit balance for a wallet and plan.
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* ```typescript
|
|
231
|
+
* const balance = await client.balances.get({
|
|
232
|
+
* walletAddress: "0x1234...",
|
|
233
|
+
* planId: "plan_abc123"
|
|
234
|
+
* })
|
|
235
|
+
*
|
|
236
|
+
* if (balance) {
|
|
237
|
+
* console.log(`Credits: ${balance.remainingCredits}/${balance.totalCredits}`)
|
|
238
|
+
* }
|
|
239
|
+
* ```
|
|
240
|
+
*
|
|
241
|
+
* @returns The credit balance, or null if not found
|
|
242
|
+
* @throws {CloseLoopError} When input validation fails
|
|
243
|
+
*/
|
|
244
|
+
get(params: GetBalanceParams): Promise<CreditBalance | null>;
|
|
245
|
+
/**
|
|
246
|
+
* List all credit balances for a wallet.
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* ```typescript
|
|
250
|
+
* const { balances, nextCursor } = await client.balances.list({
|
|
251
|
+
* walletAddress: "0x1234...",
|
|
252
|
+
* activeOnly: true,
|
|
253
|
+
* limit: 10
|
|
254
|
+
* })
|
|
255
|
+
*
|
|
256
|
+
* for (const balance of balances) {
|
|
257
|
+
* console.log(`${balance.planName}: ${balance.remainingCredits} credits`)
|
|
258
|
+
* }
|
|
259
|
+
*
|
|
260
|
+
* // Paginate if needed
|
|
261
|
+
* if (nextCursor) {
|
|
262
|
+
* const nextPage = await client.balances.list({
|
|
263
|
+
* walletAddress: "0x1234...",
|
|
264
|
+
* cursor: nextCursor
|
|
265
|
+
* })
|
|
266
|
+
* }
|
|
267
|
+
* ```
|
|
268
|
+
*
|
|
269
|
+
* @throws {CloseLoopError} When input validation fails
|
|
270
|
+
*/
|
|
271
|
+
list(params: ListBalancesParams): Promise<ListBalancesResponse>;
|
|
272
|
+
/**
|
|
273
|
+
* Get transaction history for a balance.
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* ```typescript
|
|
277
|
+
* const { transactions } = await client.balances.transactions({
|
|
278
|
+
* balanceId: "bal_xyz",
|
|
279
|
+
* type: "CONSUMPTION",
|
|
280
|
+
* limit: 50
|
|
281
|
+
* })
|
|
282
|
+
*
|
|
283
|
+
* for (const tx of transactions) {
|
|
284
|
+
* console.log(`${tx.type}: ${tx.amount} - ${tx.description}`)
|
|
285
|
+
* }
|
|
286
|
+
* ```
|
|
287
|
+
*
|
|
288
|
+
* @throws {CloseLoopError} When input validation fails
|
|
289
|
+
*/
|
|
290
|
+
transactions(params: ListTransactionsParams): Promise<ListTransactionsResponse>;
|
|
291
|
+
/**
|
|
292
|
+
* Get aggregated stats for a wallet's credits.
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* ```typescript
|
|
296
|
+
* const stats = await client.balances.stats("0x1234...")
|
|
297
|
+
* console.log(`Total: ${stats.totalCredits}, Used: ${stats.totalUsed}`)
|
|
298
|
+
* ```
|
|
299
|
+
*
|
|
300
|
+
* @throws {CloseLoopError} When input validation fails
|
|
301
|
+
*/
|
|
302
|
+
stats(walletAddress: string): Promise<CreditStats>;
|
|
303
|
+
/**
|
|
304
|
+
* Build URL query string from params, filtering out undefined values
|
|
305
|
+
*/
|
|
306
|
+
private buildQueryString;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Parameters for verifying credits
|
|
311
|
+
*/
|
|
312
|
+
interface VerifyCreditsParams {
|
|
313
|
+
/**
|
|
314
|
+
* The wallet address of the user
|
|
315
|
+
*/
|
|
316
|
+
walletAddress: string;
|
|
317
|
+
/**
|
|
318
|
+
* The plan ID to check credits for
|
|
319
|
+
*/
|
|
320
|
+
planId: string;
|
|
321
|
+
/**
|
|
322
|
+
* The number of credits required
|
|
323
|
+
*/
|
|
324
|
+
amount: number;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Response from credit verification
|
|
328
|
+
*/
|
|
329
|
+
interface VerifyCreditsResponse {
|
|
330
|
+
/**
|
|
331
|
+
* Whether the user has enough credits
|
|
332
|
+
*/
|
|
333
|
+
hasEnoughCredits: boolean;
|
|
334
|
+
/**
|
|
335
|
+
* Current remaining credits
|
|
336
|
+
*/
|
|
337
|
+
remainingCredits: number;
|
|
338
|
+
/**
|
|
339
|
+
* When the credits expire (if applicable)
|
|
340
|
+
*/
|
|
341
|
+
expiresAt: string | null;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Parameters for consuming credits
|
|
345
|
+
*/
|
|
346
|
+
interface ConsumeCreditsParams {
|
|
347
|
+
/**
|
|
348
|
+
* The wallet address of the user
|
|
349
|
+
*/
|
|
350
|
+
walletAddress: string;
|
|
351
|
+
/**
|
|
352
|
+
* The plan ID to consume credits from
|
|
353
|
+
*/
|
|
354
|
+
planId: string;
|
|
355
|
+
/**
|
|
356
|
+
* The number of credits to consume
|
|
357
|
+
*/
|
|
358
|
+
amount: number;
|
|
359
|
+
/**
|
|
360
|
+
* Optional identifier for what consumed the credits
|
|
361
|
+
* (e.g., "ai-text-generation", "image-processing")
|
|
362
|
+
*/
|
|
363
|
+
consumedBy?: string;
|
|
364
|
+
/**
|
|
365
|
+
* Optional metadata to attach to the transaction
|
|
366
|
+
*/
|
|
367
|
+
metadata?: Record<string, unknown>;
|
|
368
|
+
/**
|
|
369
|
+
* Idempotency key to prevent duplicate consumption
|
|
370
|
+
*/
|
|
371
|
+
idempotencyKey?: string;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Response from credit consumption
|
|
375
|
+
*/
|
|
376
|
+
interface ConsumeCreditsResponse {
|
|
377
|
+
/**
|
|
378
|
+
* Whether the consumption was successful
|
|
379
|
+
*/
|
|
380
|
+
success: boolean;
|
|
381
|
+
/**
|
|
382
|
+
* Remaining credits after consumption
|
|
383
|
+
*/
|
|
384
|
+
remainingCredits: number;
|
|
385
|
+
/**
|
|
386
|
+
* Total credits used
|
|
387
|
+
*/
|
|
388
|
+
usedCredits: number;
|
|
389
|
+
/**
|
|
390
|
+
* The transaction ID for this consumption
|
|
391
|
+
*/
|
|
392
|
+
transactionId: string;
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Parameters for batch credit consumption
|
|
396
|
+
*/
|
|
397
|
+
interface BatchConsumeParams {
|
|
398
|
+
/**
|
|
399
|
+
* Array of consumption operations
|
|
400
|
+
*/
|
|
401
|
+
operations: Array<{
|
|
402
|
+
walletAddress: string;
|
|
403
|
+
planId: string;
|
|
404
|
+
amount: number;
|
|
405
|
+
consumedBy?: string;
|
|
406
|
+
metadata?: Record<string, unknown>;
|
|
407
|
+
}>;
|
|
408
|
+
/**
|
|
409
|
+
* If true, fail the entire batch if any operation fails
|
|
410
|
+
*/
|
|
411
|
+
atomic?: boolean;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Response from batch credit consumption
|
|
415
|
+
*/
|
|
416
|
+
interface BatchConsumeResponse {
|
|
417
|
+
/**
|
|
418
|
+
* Results for each operation
|
|
419
|
+
*/
|
|
420
|
+
results: Array<{
|
|
421
|
+
success: boolean;
|
|
422
|
+
remainingCredits?: number;
|
|
423
|
+
error?: string;
|
|
424
|
+
}>;
|
|
425
|
+
/**
|
|
426
|
+
* Number of successful operations
|
|
427
|
+
*/
|
|
428
|
+
successCount: number;
|
|
429
|
+
/**
|
|
430
|
+
* Number of failed operations
|
|
431
|
+
*/
|
|
432
|
+
failedCount: number;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Resource for credit verification and consumption operations
|
|
437
|
+
*/
|
|
438
|
+
declare class Credits {
|
|
439
|
+
private readonly http;
|
|
440
|
+
constructor(http: HttpClient);
|
|
441
|
+
/**
|
|
442
|
+
* Verify if a user has enough credits without consuming them.
|
|
443
|
+
*
|
|
444
|
+
* @example
|
|
445
|
+
* ```typescript
|
|
446
|
+
* const result = await client.credits.verify({
|
|
447
|
+
* walletAddress: "0x1234...",
|
|
448
|
+
* planId: "plan_abc123",
|
|
449
|
+
* amount: 10
|
|
450
|
+
* })
|
|
451
|
+
*
|
|
452
|
+
* if (result.hasEnoughCredits) {
|
|
453
|
+
* // Proceed with service
|
|
454
|
+
* }
|
|
455
|
+
* ```
|
|
456
|
+
*
|
|
457
|
+
* @throws {CloseLoopError} When input validation fails
|
|
458
|
+
*/
|
|
459
|
+
verify(params: VerifyCreditsParams): Promise<VerifyCreditsResponse>;
|
|
460
|
+
/**
|
|
461
|
+
* Consume credits from a user's balance.
|
|
462
|
+
*
|
|
463
|
+
* @example
|
|
464
|
+
* ```typescript
|
|
465
|
+
* const result = await client.credits.consume({
|
|
466
|
+
* walletAddress: "0x1234...",
|
|
467
|
+
* planId: "plan_abc123",
|
|
468
|
+
* amount: 1,
|
|
469
|
+
* consumedBy: "ai-generation",
|
|
470
|
+
* metadata: { requestId: "req_xyz" }
|
|
471
|
+
* })
|
|
472
|
+
*
|
|
473
|
+
* console.log(`Remaining: ${result.remainingCredits}`)
|
|
474
|
+
* ```
|
|
475
|
+
*
|
|
476
|
+
* @throws {InsufficientCreditsError} When user doesn't have enough credits
|
|
477
|
+
* @throws {CreditsExpiredError} When credits have expired
|
|
478
|
+
* @throws {CloseLoopError} When input validation fails
|
|
479
|
+
*/
|
|
480
|
+
consume(params: ConsumeCreditsParams): Promise<ConsumeCreditsResponse>;
|
|
481
|
+
/**
|
|
482
|
+
* Verify and consume credits in a single atomic operation.
|
|
483
|
+
* This is useful when you want to ensure credits are available
|
|
484
|
+
* before consuming them, without race conditions.
|
|
485
|
+
*
|
|
486
|
+
* @example
|
|
487
|
+
* ```typescript
|
|
488
|
+
* try {
|
|
489
|
+
* const result = await client.credits.verifyAndConsume({
|
|
490
|
+
* walletAddress: "0x1234...",
|
|
491
|
+
* planId: "plan_abc123",
|
|
492
|
+
* amount: 5,
|
|
493
|
+
* consumedBy: "batch-processing"
|
|
494
|
+
* })
|
|
495
|
+
* // Credits were verified and consumed
|
|
496
|
+
* } catch (error) {
|
|
497
|
+
* if (error instanceof InsufficientCreditsError) {
|
|
498
|
+
* // Handle insufficient credits
|
|
499
|
+
* }
|
|
500
|
+
* }
|
|
501
|
+
* ```
|
|
502
|
+
*
|
|
503
|
+
* @throws {InsufficientCreditsError} When user doesn't have enough credits
|
|
504
|
+
* @throws {CreditsExpiredError} When credits have expired
|
|
505
|
+
* @throws {CloseLoopError} When input validation fails
|
|
506
|
+
*/
|
|
507
|
+
verifyAndConsume(params: ConsumeCreditsParams): Promise<ConsumeCreditsResponse>;
|
|
508
|
+
/**
|
|
509
|
+
* Consume credits in batch.
|
|
510
|
+
*
|
|
511
|
+
* @example
|
|
512
|
+
* ```typescript
|
|
513
|
+
* const result = await client.credits.batchConsume({
|
|
514
|
+
* operations: [
|
|
515
|
+
* { walletAddress: "0x1234...", planId: "plan_a", amount: 1 },
|
|
516
|
+
* { walletAddress: "0x5678...", planId: "plan_b", amount: 2 }
|
|
517
|
+
* ],
|
|
518
|
+
* atomic: false // Allow partial success
|
|
519
|
+
* })
|
|
520
|
+
*
|
|
521
|
+
* console.log(`Success: ${result.successCount}, Failed: ${result.failedCount}`)
|
|
522
|
+
* ```
|
|
523
|
+
*
|
|
524
|
+
* @throws {CloseLoopError} When input validation fails
|
|
525
|
+
*/
|
|
526
|
+
batchConsume(params: BatchConsumeParams): Promise<BatchConsumeResponse>;
|
|
527
|
+
/**
|
|
528
|
+
* Build consumption request body with sanitized metadata
|
|
529
|
+
*/
|
|
530
|
+
private buildConsumeBody;
|
|
531
|
+
/**
|
|
532
|
+
* Build idempotency headers if key is provided
|
|
533
|
+
*/
|
|
534
|
+
private buildIdempotencyHeaders;
|
|
535
|
+
/**
|
|
536
|
+
* Assert credits are available, throw typed errors if not
|
|
537
|
+
*/
|
|
538
|
+
private assertCreditsAvailable;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Webhook event types
|
|
543
|
+
*/
|
|
544
|
+
type WebhookEventType = "payment.success" | "credits.low" | "credits.expired";
|
|
545
|
+
/**
|
|
546
|
+
* Webhook event wrapper
|
|
547
|
+
*/
|
|
548
|
+
interface WebhookEvent<T = WebhookPayload> {
|
|
549
|
+
/**
|
|
550
|
+
* Event type
|
|
551
|
+
*/
|
|
552
|
+
type: WebhookEventType;
|
|
553
|
+
/**
|
|
554
|
+
* Unique event ID
|
|
555
|
+
*/
|
|
556
|
+
id: string;
|
|
557
|
+
/**
|
|
558
|
+
* When the event was created
|
|
559
|
+
*/
|
|
560
|
+
createdAt: string;
|
|
561
|
+
/**
|
|
562
|
+
* Event payload
|
|
563
|
+
*/
|
|
564
|
+
data: T;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Payload for payment.success events
|
|
568
|
+
*/
|
|
569
|
+
interface PaymentSuccessPayload {
|
|
570
|
+
/**
|
|
571
|
+
* Transaction ID
|
|
572
|
+
*/
|
|
573
|
+
transactionId: string;
|
|
574
|
+
/**
|
|
575
|
+
* Plan ID that was purchased
|
|
576
|
+
*/
|
|
577
|
+
planId: string;
|
|
578
|
+
/**
|
|
579
|
+
* Plan name
|
|
580
|
+
*/
|
|
581
|
+
planName: string;
|
|
582
|
+
/**
|
|
583
|
+
* Payment amount in USDC
|
|
584
|
+
*/
|
|
585
|
+
amount: number;
|
|
586
|
+
/**
|
|
587
|
+
* Number of API requests (for API access type)
|
|
588
|
+
*/
|
|
589
|
+
requests: number | null;
|
|
590
|
+
/**
|
|
591
|
+
* Number of credits (for CREDIT access type)
|
|
592
|
+
*/
|
|
593
|
+
creditAmount: number | null;
|
|
594
|
+
/**
|
|
595
|
+
* Blockchain transaction hash
|
|
596
|
+
*/
|
|
597
|
+
transactionHash: string;
|
|
598
|
+
/**
|
|
599
|
+
* Wallet address of the payer
|
|
600
|
+
*/
|
|
601
|
+
payerAddress: string;
|
|
602
|
+
/**
|
|
603
|
+
* Access type of the plan
|
|
604
|
+
*/
|
|
605
|
+
accessType: string;
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Payload for credits.low events
|
|
609
|
+
*/
|
|
610
|
+
interface CreditsLowPayload {
|
|
611
|
+
/**
|
|
612
|
+
* Wallet address
|
|
613
|
+
*/
|
|
614
|
+
walletAddress: string;
|
|
615
|
+
/**
|
|
616
|
+
* Plan ID
|
|
617
|
+
*/
|
|
618
|
+
planId: string;
|
|
619
|
+
/**
|
|
620
|
+
* Remaining credits
|
|
621
|
+
*/
|
|
622
|
+
remainingCredits: number;
|
|
623
|
+
/**
|
|
624
|
+
* Low balance threshold that triggered this event
|
|
625
|
+
*/
|
|
626
|
+
threshold: number;
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Payload for credits.expired events
|
|
630
|
+
*/
|
|
631
|
+
interface CreditsExpiredPayload {
|
|
632
|
+
/**
|
|
633
|
+
* Wallet address
|
|
634
|
+
*/
|
|
635
|
+
walletAddress: string;
|
|
636
|
+
/**
|
|
637
|
+
* Plan ID
|
|
638
|
+
*/
|
|
639
|
+
planId: string;
|
|
640
|
+
/**
|
|
641
|
+
* Number of credits that expired
|
|
642
|
+
*/
|
|
643
|
+
expiredCredits: number;
|
|
644
|
+
/**
|
|
645
|
+
* When the credits expired
|
|
646
|
+
*/
|
|
647
|
+
expiresAt: string;
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* Union of all webhook payloads
|
|
651
|
+
*/
|
|
652
|
+
type WebhookPayload = PaymentSuccessPayload | CreditsLowPayload | CreditsExpiredPayload;
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Parameters for verifying a webhook
|
|
656
|
+
*/
|
|
657
|
+
interface VerifyWebhookParams {
|
|
658
|
+
/**
|
|
659
|
+
* Raw request body as string or Buffer
|
|
660
|
+
*/
|
|
661
|
+
payload: string | Buffer;
|
|
662
|
+
/**
|
|
663
|
+
* X-CloseLoop-Signature header value
|
|
664
|
+
*/
|
|
665
|
+
signature: string;
|
|
666
|
+
/**
|
|
667
|
+
* Your webhook secret
|
|
668
|
+
*/
|
|
669
|
+
secret: string;
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Resource for webhook signature verification and event handling
|
|
673
|
+
*/
|
|
674
|
+
declare class Webhooks {
|
|
675
|
+
/**
|
|
676
|
+
* Verify a webhook signature and parse the event.
|
|
677
|
+
*
|
|
678
|
+
* @example
|
|
679
|
+
* ```typescript
|
|
680
|
+
* // Express handler
|
|
681
|
+
* app.post("/webhook", (req, res) => {
|
|
682
|
+
* try {
|
|
683
|
+
* const event = client.webhooks.verify({
|
|
684
|
+
* payload: req.body,
|
|
685
|
+
* signature: req.headers["x-closeloop-signature"],
|
|
686
|
+
* secret: process.env.WEBHOOK_SECRET!
|
|
687
|
+
* })
|
|
688
|
+
*
|
|
689
|
+
* if (client.webhooks.isPaymentSuccess(event)) {
|
|
690
|
+
* const { creditAmount, payerAddress } = event.data
|
|
691
|
+
* // Handle credit purchase
|
|
692
|
+
* }
|
|
693
|
+
*
|
|
694
|
+
* res.json({ received: true })
|
|
695
|
+
* } catch (error) {
|
|
696
|
+
* res.status(400).json({ error: "Invalid signature" })
|
|
697
|
+
* }
|
|
698
|
+
* })
|
|
699
|
+
* ```
|
|
700
|
+
*
|
|
701
|
+
* @example
|
|
702
|
+
* ```typescript
|
|
703
|
+
* // Next.js App Router
|
|
704
|
+
* export async function POST(request: Request) {
|
|
705
|
+
* const payload = await request.text()
|
|
706
|
+
* const signature = request.headers.get("x-closeloop-signature")!
|
|
707
|
+
*
|
|
708
|
+
* const event = client.webhooks.verify({
|
|
709
|
+
* payload,
|
|
710
|
+
* signature,
|
|
711
|
+
* secret: process.env.WEBHOOK_SECRET!
|
|
712
|
+
* })
|
|
713
|
+
*
|
|
714
|
+
* // Handle event...
|
|
715
|
+
* return Response.json({ received: true })
|
|
716
|
+
* }
|
|
717
|
+
* ```
|
|
718
|
+
*
|
|
719
|
+
* @throws {CloseLoopError} When signature is invalid or payload is malformed
|
|
720
|
+
*/
|
|
721
|
+
verify(params: VerifyWebhookParams): WebhookEvent;
|
|
722
|
+
/**
|
|
723
|
+
* Type guard for payment.success events
|
|
724
|
+
* Also validates the payload structure
|
|
725
|
+
*
|
|
726
|
+
* @example
|
|
727
|
+
* ```typescript
|
|
728
|
+
* if (client.webhooks.isPaymentSuccess(event)) {
|
|
729
|
+
* // TypeScript knows event.data is PaymentSuccessPayload
|
|
730
|
+
* console.log(event.data.creditAmount)
|
|
731
|
+
* }
|
|
732
|
+
* ```
|
|
733
|
+
*/
|
|
734
|
+
isPaymentSuccess(event: WebhookEvent<WebhookPayload>): event is WebhookEvent<PaymentSuccessPayload>;
|
|
735
|
+
/**
|
|
736
|
+
* Type guard for credits.low events
|
|
737
|
+
* Also validates the payload structure
|
|
738
|
+
*
|
|
739
|
+
* @example
|
|
740
|
+
* ```typescript
|
|
741
|
+
* if (client.webhooks.isCreditsLow(event)) {
|
|
742
|
+
* // TypeScript knows event.data is CreditsLowPayload
|
|
743
|
+
* console.log(`Low balance: ${event.data.remainingCredits}`)
|
|
744
|
+
* }
|
|
745
|
+
* ```
|
|
746
|
+
*/
|
|
747
|
+
isCreditsLow(event: WebhookEvent<WebhookPayload>): event is WebhookEvent<CreditsLowPayload>;
|
|
748
|
+
/**
|
|
749
|
+
* Type guard for credits.expired events
|
|
750
|
+
* Also validates the payload structure
|
|
751
|
+
*
|
|
752
|
+
* @example
|
|
753
|
+
* ```typescript
|
|
754
|
+
* if (client.webhooks.isCreditsExpired(event)) {
|
|
755
|
+
* // TypeScript knows event.data is CreditsExpiredPayload
|
|
756
|
+
* console.log(`Expired: ${event.data.expiredCredits} credits`)
|
|
757
|
+
* }
|
|
758
|
+
* ```
|
|
759
|
+
*/
|
|
760
|
+
isCreditsExpired(event: WebhookEvent<WebhookPayload>): event is WebhookEvent<CreditsExpiredPayload>;
|
|
761
|
+
/**
|
|
762
|
+
* Validate that all required parameters are present
|
|
763
|
+
*/
|
|
764
|
+
private validateRequiredParams;
|
|
765
|
+
/**
|
|
766
|
+
* Convert payload to string regardless of input type
|
|
767
|
+
*/
|
|
768
|
+
private normalizePayload;
|
|
769
|
+
/**
|
|
770
|
+
* Verify HMAC signature or throw error
|
|
771
|
+
*/
|
|
772
|
+
private verifySignatureOrThrow;
|
|
773
|
+
/**
|
|
774
|
+
* Parse JSON payload or throw error
|
|
775
|
+
*/
|
|
776
|
+
private parseJsonOrThrow;
|
|
777
|
+
/**
|
|
778
|
+
* Validate event structure using Zod schema
|
|
779
|
+
*/
|
|
780
|
+
private validateEventStructure;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
/**
|
|
784
|
+
* Configuration options for the CloseLoop client
|
|
785
|
+
*/
|
|
786
|
+
interface CloseLoopOptions {
|
|
787
|
+
/**
|
|
788
|
+
* Your CloseLoop API key.
|
|
789
|
+
* Get this from your CloseLoop dashboard.
|
|
790
|
+
*/
|
|
791
|
+
apiKey: string;
|
|
792
|
+
/**
|
|
793
|
+
* Base URL for the CloseLoop API.
|
|
794
|
+
* Defaults to https://closeloop.app
|
|
795
|
+
*/
|
|
796
|
+
baseUrl?: string;
|
|
797
|
+
/**
|
|
798
|
+
* Request timeout in milliseconds.
|
|
799
|
+
* Defaults to 30000 (30 seconds)
|
|
800
|
+
*/
|
|
801
|
+
timeout?: number;
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* CloseLoop SDK client for credit billing integration.
|
|
805
|
+
*
|
|
806
|
+
* @example
|
|
807
|
+
* ```typescript
|
|
808
|
+
* import { CloseLoop } from "@closeloop/sdk"
|
|
809
|
+
*
|
|
810
|
+
* const client = new CloseLoop({
|
|
811
|
+
* apiKey: process.env.CLOSELOOP_API_KEY!
|
|
812
|
+
* })
|
|
813
|
+
*
|
|
814
|
+
* // Verify credits
|
|
815
|
+
* const verification = await client.credits.verify({
|
|
816
|
+
* walletAddress: "0x1234...",
|
|
817
|
+
* planId: "plan_abc123",
|
|
818
|
+
* amount: 1
|
|
819
|
+
* })
|
|
820
|
+
*
|
|
821
|
+
* if (verification.hasEnoughCredits) {
|
|
822
|
+
* // Process request...
|
|
823
|
+
*
|
|
824
|
+
* // Consume credit
|
|
825
|
+
* await client.credits.consume({
|
|
826
|
+
* walletAddress: "0x1234...",
|
|
827
|
+
* planId: "plan_abc123",
|
|
828
|
+
* amount: 1,
|
|
829
|
+
* consumedBy: "my-service"
|
|
830
|
+
* })
|
|
831
|
+
* }
|
|
832
|
+
* ```
|
|
833
|
+
*/
|
|
834
|
+
declare class CloseLoop {
|
|
835
|
+
private httpClient;
|
|
836
|
+
/**
|
|
837
|
+
* Credit consumption and verification operations
|
|
838
|
+
*/
|
|
839
|
+
readonly credits: Credits;
|
|
840
|
+
/**
|
|
841
|
+
* Credit balance queries
|
|
842
|
+
*/
|
|
843
|
+
readonly balances: Balances;
|
|
844
|
+
/**
|
|
845
|
+
* Webhook signature verification utilities
|
|
846
|
+
*/
|
|
847
|
+
readonly webhooks: Webhooks;
|
|
848
|
+
constructor(options: CloseLoopOptions);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* Base error class for all CloseLoop SDK errors
|
|
853
|
+
*/
|
|
854
|
+
declare class CloseLoopError extends Error {
|
|
855
|
+
code: string;
|
|
856
|
+
statusCode?: number | undefined;
|
|
857
|
+
details?: Record<string, unknown> | undefined;
|
|
858
|
+
constructor(message: string, code: string, statusCode?: number | undefined, details?: Record<string, unknown> | undefined);
|
|
859
|
+
}
|
|
860
|
+
/**
|
|
861
|
+
* Thrown when a user doesn't have enough credits for an operation
|
|
862
|
+
*/
|
|
863
|
+
declare class InsufficientCreditsError extends CloseLoopError {
|
|
864
|
+
remainingCredits: number;
|
|
865
|
+
requiredCredits: number;
|
|
866
|
+
constructor(remainingCredits: number, requiredCredits: number);
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* Thrown when credits have expired
|
|
870
|
+
*/
|
|
871
|
+
declare class CreditsExpiredError extends CloseLoopError {
|
|
872
|
+
expiresAt: Date;
|
|
873
|
+
constructor(expiresAt: Date);
|
|
874
|
+
}
|
|
875
|
+
/**
|
|
876
|
+
* Thrown when authentication fails (invalid API key)
|
|
877
|
+
*/
|
|
878
|
+
declare class AuthenticationError extends CloseLoopError {
|
|
879
|
+
constructor(message?: string);
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* Thrown when rate limit is exceeded
|
|
883
|
+
*/
|
|
884
|
+
declare class RateLimitError extends CloseLoopError {
|
|
885
|
+
retryAfter?: number | undefined;
|
|
886
|
+
constructor(retryAfter?: number | undefined);
|
|
887
|
+
}
|
|
888
|
+
/**
|
|
889
|
+
* Thrown when a network error occurs
|
|
890
|
+
*/
|
|
891
|
+
declare class NetworkError extends CloseLoopError {
|
|
892
|
+
cause?: Error | undefined;
|
|
893
|
+
constructor(message: string, cause?: Error | undefined);
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* Thrown when a resource is not found
|
|
897
|
+
*/
|
|
898
|
+
declare class NotFoundError extends CloseLoopError {
|
|
899
|
+
constructor(resource: string);
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* Thrown when input validation fails
|
|
903
|
+
*/
|
|
904
|
+
declare class ValidationError extends CloseLoopError {
|
|
905
|
+
field?: string | undefined;
|
|
906
|
+
constructor(message: string, field?: string | undefined);
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
export { AuthenticationError as A, Balances as B, CloseLoop as C, type GetBalanceParams as G, InsufficientCreditsError as I, type ListBalancesParams as L, NetworkError as N, type PaymentSuccessPayload as P, RateLimitError as R, type VerifyWebhookParams as V, Webhooks as W, type CloseLoopOptions as a, Credits as b, CloseLoopError as c, CreditsExpiredError as d, NotFoundError as e, ValidationError as f, type VerifyCreditsParams as g, type VerifyCreditsResponse as h, type ConsumeCreditsParams as i, type ConsumeCreditsResponse as j, type BatchConsumeParams as k, type BatchConsumeResponse as l, type CreditBalance as m, type ListBalancesResponse as n, type CreditTransaction as o, type ListTransactionsParams as p, type ListTransactionsResponse as q, type CreditStats as r, type WebhookEventType as s, type WebhookEvent as t, type CreditsLowPayload as u, type CreditsExpiredPayload as v, type WebhookPayload as w };
|