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