@commet/node 4.6.0 → 5.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/dist/index.js CHANGED
@@ -35,7 +35,6 @@ __export(index_exports, {
35
35
  CommetAPIError: () => CommetAPIError,
36
36
  CommetError: () => CommetError,
37
37
  CommetValidationError: () => CommetValidationError,
38
- CustomerContext: () => CustomerContext,
39
38
  SDK_VERSION: () => SDK_VERSION,
40
39
  Webhooks: () => Webhooks,
41
40
  createCommet: () => createCommet,
@@ -45,82 +44,54 @@ __export(index_exports, {
45
44
  });
46
45
  module.exports = __toCommonJS(index_exports);
47
46
 
48
- // src/customer.ts
49
- var CustomerContext = class {
50
- constructor(customerId, resources) {
51
- this.features = {
52
- get: (code, options) => this.featuresResource.get({ code, customerId: this.customerId }, options),
53
- check: (code, options) => this.featuresResource.check(
54
- { code, customerId: this.customerId },
55
- options
56
- ),
57
- canUse: (code, options) => this.featuresResource.canUse(
58
- { code, customerId: this.customerId },
59
- options
60
- ),
61
- list: (options) => this.featuresResource.list(this.customerId, options)
62
- };
63
- this.seats = {
64
- add: (featureCode, count = 1, options) => this.seatsResource.add(
65
- { customerId: this.customerId, featureCode, count },
66
- options
67
- ),
68
- remove: (featureCode, count = 1, options) => this.seatsResource.remove(
69
- { customerId: this.customerId, featureCode, count },
70
- options
71
- ),
72
- set: (featureCode, count, options) => this.seatsResource.set(
73
- { customerId: this.customerId, featureCode, count },
74
- options
75
- ),
76
- getBalance: (featureCode) => this.seatsResource.getBalance({
77
- customerId: this.customerId,
78
- featureCode
79
- })
80
- };
81
- this.usage = {
82
- track: (feature, value, properties, options) => this.usageResource.track(
83
- { customerId: this.customerId, feature, value, properties },
84
- options
85
- )
86
- };
87
- this.subscription = {
88
- get: () => this.subscriptionsResource.get(this.customerId)
89
- };
90
- this.portal = {
91
- getUrl: (options) => this.portalResource.getUrl({ customerId: this.customerId }, options)
92
- };
93
- this.customerId = customerId;
94
- this.featuresResource = resources.features;
95
- this.seatsResource = resources.seats;
96
- this.usageResource = resources.usage;
97
- this.subscriptionsResource = resources.subscriptions;
98
- this.portalResource = resources.portal;
99
- }
100
- };
101
-
102
47
  // src/resources/addons.ts
103
48
  var AddonsResource = class {
104
49
  constructor(httpClient) {
105
50
  this.httpClient = httpClient;
106
51
  }
107
- /**
108
- * Get active addons for a customer's subscription
109
- *
110
- * @example
111
- * ```typescript
112
- * const { data } = await commet.addons.getActive({
113
- * customerId: 'cus_xxx',
114
- * });
115
- * ```
116
- */
117
- async getActive(params, options) {
52
+ async listActive(params, options) {
118
53
  return this.httpClient.get(
119
54
  "/addons/active",
120
55
  { customerId: params.customerId },
121
56
  options
122
57
  );
123
58
  }
59
+ async list(params, options) {
60
+ return this.httpClient.get("/addons", params, options);
61
+ }
62
+ async get(params, options) {
63
+ const { id } = params;
64
+ return this.httpClient.get(`/addons/${id}`, void 0, options);
65
+ }
66
+ async create(params, options) {
67
+ return this.httpClient.post("/addons", params, options);
68
+ }
69
+ async update(params, options) {
70
+ const { id, ...body } = params;
71
+ return this.httpClient.put(`/addons/${id}`, body, options);
72
+ }
73
+ /** Fails if addon has active subscriptions. */
74
+ async delete(params, options) {
75
+ const { id } = params;
76
+ return this.httpClient.delete(`/addons/${id}`, void 0, options);
77
+ }
78
+ };
79
+
80
+ // src/resources/api-keys.ts
81
+ var ApiKeysResource = class {
82
+ constructor(httpClient) {
83
+ this.httpClient = httpClient;
84
+ }
85
+ async list(params) {
86
+ return this.httpClient.get("/api-keys", params);
87
+ }
88
+ /** Response includes full `apiKey` which is only returned once. */
89
+ async create(params, options) {
90
+ return this.httpClient.post("/api-keys", params, options);
91
+ }
92
+ async delete(params, options) {
93
+ return this.httpClient.delete(`/api-keys/${params.id}`, void 0, options);
94
+ }
124
95
  };
125
96
 
126
97
  // src/resources/credit-packs.ts
@@ -128,18 +99,20 @@ var CreditPacksResource = class {
128
99
  constructor(httpClient) {
129
100
  this.httpClient = httpClient;
130
101
  }
131
- /**
132
- * List all active credit packs
133
- *
134
- * @example
135
- * ```typescript
136
- * const packs = await commet.creditPacks.list();
137
- * console.log(packs.data); // [{ id: "cp_xxx", name: "100 Credits", ... }]
138
- * ```
139
- */
140
102
  async list() {
141
103
  return this.httpClient.get("/credit-packs");
142
104
  }
105
+ async create(params, options) {
106
+ return this.httpClient.post("/credit-packs/manage", params, options);
107
+ }
108
+ async update(params, options) {
109
+ const { id, ...body } = params;
110
+ return this.httpClient.put(`/credit-packs/${id}`, body, options);
111
+ }
112
+ async delete(params, options) {
113
+ const { id } = params;
114
+ return this.httpClient.delete(`/credit-packs/${id}`, void 0, options);
115
+ }
143
116
  };
144
117
 
145
118
  // src/resources/customers.ts
@@ -147,15 +120,13 @@ var CustomersResource = class {
147
120
  constructor(httpClient) {
148
121
  this.httpClient = httpClient;
149
122
  }
150
- /**
151
- * Create a customer (idempotent when id is provided)
152
- */
123
+ /** Idempotent when `id` is provided — returns existing customer instead of duplicating. */
153
124
  async create(params, options) {
154
125
  return this.httpClient.post(
155
126
  "/customers",
156
127
  {
157
128
  billingEmail: params.email,
158
- externalId: params.id,
129
+ id: params.id,
159
130
  fullName: params.fullName,
160
131
  domain: params.domain,
161
132
  website: params.website,
@@ -168,13 +139,10 @@ var CustomersResource = class {
168
139
  options
169
140
  );
170
141
  }
171
- /**
172
- * Create multiple customers in batch
173
- */
174
142
  async createBatch(params, options) {
175
143
  const customers = params.customers.map((c) => ({
176
144
  billingEmail: c.email,
177
- externalId: c.id,
145
+ id: c.id,
178
146
  fullName: c.fullName,
179
147
  domain: c.domain,
180
148
  website: c.website,
@@ -186,18 +154,12 @@ var CustomersResource = class {
186
154
  }));
187
155
  return this.httpClient.post("/customers/batch", { customers }, options);
188
156
  }
189
- /**
190
- * Get a customer by ID
191
- */
192
- async get(customerId) {
193
- return this.httpClient.get(`/customers/${customerId}`);
157
+ async get(params) {
158
+ return this.httpClient.get(`/customers/${params.id}`);
194
159
  }
195
- /**
196
- * Update a customer
197
- */
198
160
  async update(params, options) {
199
161
  return this.httpClient.put(
200
- `/customers/${params.customerId}`,
162
+ `/customers/${params.id}`,
201
163
  {
202
164
  billingEmail: params.email,
203
165
  fullName: params.fullName,
@@ -212,9 +174,6 @@ var CustomersResource = class {
212
174
  options
213
175
  );
214
176
  }
215
- /**
216
- * List customers with optional filters
217
- */
218
177
  async list(params) {
219
178
  return this.httpClient.get("/customers", params);
220
179
  }
@@ -232,34 +191,113 @@ var FeaturesResource = class {
232
191
  options
233
192
  );
234
193
  }
235
- async check(params, options) {
236
- const result = await this.httpClient.get(
194
+ /** Checks if the customer can consume one more unit — returns billing impact and reason if blocked. */
195
+ async canUse(params, options) {
196
+ return this.httpClient.get(
237
197
  `/features/${params.code}`,
238
- { customerId: params.customerId },
198
+ { customerId: params.customerId, action: "canUse" },
239
199
  options
240
200
  );
241
- if (!result.success || !result.data) {
242
- return {
243
- success: false,
244
- code: result.code,
245
- message: result.message,
246
- details: result.details
247
- };
248
- }
249
- return {
250
- success: true,
251
- data: { allowed: result.data.allowed }
252
- };
253
201
  }
254
- async canUse(params, options) {
202
+ async list(params, options) {
255
203
  return this.httpClient.get(
256
- `/features/${params.code}`,
257
- { customerId: params.customerId, action: "canUse" },
204
+ "/features",
205
+ { customerId: params.customerId },
206
+ options
207
+ );
208
+ }
209
+ async create(params, options) {
210
+ return this.httpClient.post("/features/manage", params, options);
211
+ }
212
+ async update(params, options) {
213
+ const { code, ...body } = params;
214
+ return this.httpClient.put(`/features/${code}/manage`, body, options);
215
+ }
216
+ /** Fails if feature is attached to active plans or has an active addon. */
217
+ async delete(params, options) {
218
+ const { code } = params;
219
+ return this.httpClient.delete(
220
+ `/features/${code}/manage`,
221
+ void 0,
222
+ options
223
+ );
224
+ }
225
+ };
226
+
227
+ // src/resources/invoices.ts
228
+ var InvoicesResource = class {
229
+ constructor(httpClient) {
230
+ this.httpClient = httpClient;
231
+ }
232
+ async list(params) {
233
+ return this.httpClient.get("/invoices", params);
234
+ }
235
+ async get(params) {
236
+ return this.httpClient.get(`/invoices/${params.id}`);
237
+ }
238
+ /** Negative amount creates a credit. */
239
+ async createAdjustment(params, options) {
240
+ return this.httpClient.post("/invoices", params, options);
241
+ }
242
+ /** Signed URL, expires after 7 days. */
243
+ async getDownloadUrl(params) {
244
+ return this.httpClient.get(`/invoices/${params.id}/download`);
245
+ }
246
+ async send(params, options) {
247
+ return this.httpClient.post(`/invoices/${params.id}/send`, {}, options);
248
+ }
249
+ /** Only outstanding invoices can be changed to paid or void. */
250
+ async updateStatus(params, options) {
251
+ const { id, ...body } = params;
252
+ return this.httpClient.put(`/invoices/${id}/status`, body, options);
253
+ }
254
+ };
255
+
256
+ // src/resources/plan-groups.ts
257
+ var PlanGroupsResource = class {
258
+ constructor(httpClient) {
259
+ this.httpClient = httpClient;
260
+ }
261
+ async list(params) {
262
+ return this.httpClient.get("/plan-groups", params);
263
+ }
264
+ async get(params) {
265
+ return this.httpClient.get(`/plan-groups/${params.id}`);
266
+ }
267
+ async create(params, options) {
268
+ return this.httpClient.post("/plan-groups", params, options);
269
+ }
270
+ async update(params, options) {
271
+ const { id, ...body } = params;
272
+ return this.httpClient.put(`/plan-groups/${id}`, body, options);
273
+ }
274
+ /** Plans in the group are unlinked, not deleted. */
275
+ async delete(params, options) {
276
+ return this.httpClient.delete(
277
+ `/plan-groups/${params.id}`,
278
+ void 0,
279
+ options
280
+ );
281
+ }
282
+ async addPlan(params, options) {
283
+ const { id, ...body } = params;
284
+ return this.httpClient.post(`/plan-groups/${id}/plans`, body, options);
285
+ }
286
+ async removePlan(params, options) {
287
+ const { id, planId } = params;
288
+ return this.httpClient.delete(
289
+ `/plan-groups/${id}/plans/${planId}`,
290
+ void 0,
258
291
  options
259
292
  );
260
293
  }
261
- async list(customerId, options) {
262
- return this.httpClient.get("/features", { customerId }, options);
294
+ async reorderPlans(params, options) {
295
+ const { id, ...body } = params;
296
+ return this.httpClient.put(
297
+ `/plan-groups/${id}/plans/reorder`,
298
+ body,
299
+ options
300
+ );
263
301
  }
264
302
  };
265
303
 
@@ -268,33 +306,93 @@ var PlansResource = class {
268
306
  constructor(httpClient) {
269
307
  this.httpClient = httpClient;
270
308
  }
271
- /**
272
- * List all available plans
273
- *
274
- * @example
275
- * ```typescript
276
- * // List public plans
277
- * const plans = await commet.plans.list();
278
- *
279
- * // Include private plans
280
- * const allPlans = await commet.plans.list({ includePrivate: true });
281
- * ```
282
- */
283
309
  async list(params) {
284
310
  return this.httpClient.get("/plans", params);
285
311
  }
286
- /**
287
- * Get a specific plan by code
288
- *
289
- * @example
290
- * ```typescript
291
- * const plan = await commet.plans.get('pro');
292
- * console.log(plan.data.name); // "Pro"
293
- * console.log(plan.data.prices); // [{ billingInterval: 'monthly', price: 9900 }]
294
- * ```
295
- */
296
- async get(planCode) {
297
- return this.httpClient.get(`/plans/${planCode}`);
312
+ async get(params) {
313
+ return this.httpClient.get(`/plans/${params.id}`);
314
+ }
315
+ async create(params, options) {
316
+ return this.httpClient.post("/plans/manage", params, options);
317
+ }
318
+ async update(params, options) {
319
+ const { id, ...body } = params;
320
+ return this.httpClient.put(`/plans/${id}/manage`, body, options);
321
+ }
322
+ async delete(params, options) {
323
+ return this.httpClient.delete(
324
+ `/plans/${params.id}/manage`,
325
+ void 0,
326
+ options
327
+ );
328
+ }
329
+ async setVisibility(params, options) {
330
+ const { id, ...body } = params;
331
+ return this.httpClient.put(`/plans/${id}/visibility`, body, options);
332
+ }
333
+ async addFeature(params, options) {
334
+ const { planId, ...body } = params;
335
+ return this.httpClient.post(`/plans/${planId}/features`, body, options);
336
+ }
337
+ async updateFeature(params, options) {
338
+ const { planId, featureId, ...body } = params;
339
+ return this.httpClient.put(
340
+ `/plans/${planId}/features/${featureId}`,
341
+ body,
342
+ options
343
+ );
344
+ }
345
+ async removeFeature(params, options) {
346
+ const { planId, featureId } = params;
347
+ return this.httpClient.delete(
348
+ `/plans/${planId}/features/${featureId}`,
349
+ void 0,
350
+ options
351
+ );
352
+ }
353
+ async addPrice(params, options) {
354
+ const { planId, ...body } = params;
355
+ return this.httpClient.post(`/plans/${planId}/prices`, body, options);
356
+ }
357
+ async updatePrice(params, options) {
358
+ const { planId, priceId, ...body } = params;
359
+ return this.httpClient.put(
360
+ `/plans/${planId}/prices/${priceId}`,
361
+ body,
362
+ options
363
+ );
364
+ }
365
+ async deletePrice(params, options) {
366
+ const { planId, priceId } = params;
367
+ return this.httpClient.delete(
368
+ `/plans/${planId}/prices/${priceId}`,
369
+ void 0,
370
+ options
371
+ );
372
+ }
373
+ async setDefaultPrice(params, options) {
374
+ const { planId, priceId } = params;
375
+ return this.httpClient.put(
376
+ `/plans/${planId}/prices/${priceId}/default`,
377
+ {},
378
+ options
379
+ );
380
+ }
381
+ async setRegionalPrices(params, options) {
382
+ const { planId, priceId, ...body } = params;
383
+ return this.httpClient.put(
384
+ `/plans/${planId}/prices/${priceId}/regional`,
385
+ body,
386
+ options
387
+ );
388
+ }
389
+ async deleteRegionalPrices(params, options) {
390
+ const { planId, priceId } = params;
391
+ return this.httpClient.delete(
392
+ `/plans/${planId}/prices/${priceId}/regional`,
393
+ void 0,
394
+ options
395
+ );
298
396
  }
299
397
  };
300
398
 
@@ -308,39 +406,63 @@ var PortalResource = class {
308
406
  }
309
407
  };
310
408
 
311
- // src/resources/seats.ts
312
- function resolveCode(params) {
313
- const code = params.featureCode ?? params.seatType;
314
- if (!code) {
315
- throw new Error("Either featureCode or seatType must be provided");
409
+ // src/resources/promo-codes.ts
410
+ var PromoCodesResource = class {
411
+ constructor(httpClient) {
412
+ this.httpClient = httpClient;
316
413
  }
317
- return code;
318
- }
414
+ async list(params) {
415
+ return this.httpClient.get("/promo-codes", params);
416
+ }
417
+ async get(params) {
418
+ return this.httpClient.get(`/promo-codes/${params.id}`);
419
+ }
420
+ async create(params, options) {
421
+ return this.httpClient.post("/promo-codes", params, options);
422
+ }
423
+ async update(params, options) {
424
+ const { id, ...body } = params;
425
+ return this.httpClient.put(`/promo-codes/${id}`, body, options);
426
+ }
427
+ };
428
+
429
+ // src/resources/seats.ts
319
430
  var SeatsResource = class {
320
431
  constructor(httpClient) {
321
432
  this.httpClient = httpClient;
322
433
  }
434
+ /** Prorates charges for the current billing period. */
323
435
  async add(params, options) {
324
- const code = resolveCode(params);
325
436
  return this.httpClient.post(
326
437
  "/seats",
327
- { customerId: params.customerId, seatType: code, count: params.count },
438
+ {
439
+ customerId: params.customerId,
440
+ featureCode: params.featureCode,
441
+ count: params.count ?? 1
442
+ },
328
443
  options
329
444
  );
330
445
  }
446
+ /** Removal takes effect at the end of the billing period. */
331
447
  async remove(params, options) {
332
- const code = resolveCode(params);
333
448
  return this.httpClient.delete(
334
449
  "/seats",
335
- { customerId: params.customerId, seatType: code, count: params.count },
450
+ {
451
+ customerId: params.customerId,
452
+ featureCode: params.featureCode,
453
+ count: params.count ?? 1
454
+ },
336
455
  options
337
456
  );
338
457
  }
339
458
  async set(params, options) {
340
- const code = resolveCode(params);
341
459
  return this.httpClient.put(
342
460
  "/seats",
343
- { customerId: params.customerId, seatType: code, count: params.count },
461
+ {
462
+ customerId: params.customerId,
463
+ featureCode: params.featureCode,
464
+ count: params.count
465
+ },
344
466
  options
345
467
  );
346
468
  }
@@ -348,10 +470,9 @@ var SeatsResource = class {
348
470
  return this.httpClient.put("/seats/bulk", params, options);
349
471
  }
350
472
  async getBalance(params) {
351
- const code = resolveCode(params);
352
473
  return this.httpClient.get("/seats/balance", {
353
474
  customerId: params.customerId,
354
- seatType: code
475
+ featureCode: params.featureCode
355
476
  });
356
477
  }
357
478
  async getAllBalances(params) {
@@ -366,92 +487,113 @@ var SubscriptionsResource = class {
366
487
  constructor(httpClient) {
367
488
  this.httpClient = httpClient;
368
489
  }
369
- /**
370
- * Create a subscription with a plan
371
- *
372
- * @example
373
- * ```typescript
374
- * await commet.subscriptions.create({
375
- * externalId: 'user_123',
376
- * planCode: 'pro', // autocomplete works after `commet pull`
377
- * billingInterval: 'yearly',
378
- * initialSeats: { editor: 5 }
379
- * });
380
- * ```
381
- */
490
+ /** Returns a `checkoutUrl` when payment is required before activation. */
382
491
  async create(params, options) {
383
492
  return this.httpClient.post("/subscriptions", params, options);
384
493
  }
385
- /**
386
- * Get the active subscription for a customer
387
- *
388
- * @example
389
- * ```typescript
390
- * const sub = await commet.subscriptions.get('user_123');
391
- * ```
392
- */
393
- async get(customerId) {
394
- return this.httpClient.get("/subscriptions/active", { customerId });
494
+ async getActive(params) {
495
+ return this.httpClient.get("/subscriptions/active", {
496
+ customerId: params.customerId
497
+ });
395
498
  }
396
- /**
397
- * Cancel a subscription
398
- *
399
- * @example
400
- * ```typescript
401
- * await commet.subscriptions.cancel({
402
- * subscriptionId: 'sub_xxx',
403
- * reason: 'switched_to_competitor'
404
- * });
405
- * ```
406
- */
499
+ /** Schedules cancellation at period end by default. Set `immediate: true` to cancel now. */
407
500
  async cancel(params, options) {
408
- return this.httpClient.post(
409
- `/subscriptions/${params.subscriptionId}/cancel`,
410
- params || {},
411
- options
412
- );
501
+ const { id, ...body } = params;
502
+ return this.httpClient.post(`/subscriptions/${id}/cancel`, body, options);
413
503
  }
414
- /**
415
- * Revert a scheduled cancellation
416
- *
417
- * Only works on subscriptions with a pending cancellation (canceledAt is set
418
- * but status is not yet "canceled"). Cannot revert already-canceled subscriptions.
419
- *
420
- * @example
421
- * ```typescript
422
- * await commet.subscriptions.uncancel({
423
- * subscriptionId: 'sub_xxx',
424
- * });
425
- * ```
426
- */
504
+ /** Only works on subscriptions with a pending cancellation — cannot revert already-canceled. */
427
505
  async uncancel(params, options) {
428
506
  return this.httpClient.post(
429
- `/subscriptions/${params.subscriptionId}/uncancel`,
507
+ `/subscriptions/${params.id}/uncancel`,
430
508
  {},
431
509
  options
432
510
  );
433
511
  }
434
- /**
435
- * Change the plan of a subscription (upgrade/downgrade)
436
- *
437
- * Upgrades execute immediately. Downgrades are scheduled for end of period.
438
- *
439
- * @example
440
- * ```typescript
441
- * await commet.subscriptions.changePlan({
442
- * subscriptionId: 'sub_xxx',
443
- * newPlanId: 'pln_xxx',
444
- * });
445
- * ```
446
- */
512
+ /** Upgrades execute immediately with proration. Downgrades are scheduled for end of period. */
447
513
  async changePlan(params, options) {
448
- const { subscriptionId, ...body } = params;
514
+ const { id, ...body } = params;
515
+ return this.httpClient.post(
516
+ `/subscriptions/${id}/change-plan`,
517
+ body,
518
+ options
519
+ );
520
+ }
521
+ async list(params) {
522
+ return this.httpClient.get("/subscriptions", params);
523
+ }
524
+ /** Dry-run: returns proration details without applying the change. */
525
+ async previewChange(params, options) {
526
+ const { id, ...body } = params;
449
527
  return this.httpClient.post(
450
- `/subscriptions/${subscriptionId}/change-plan`,
528
+ `/subscriptions/${id}/preview-change`,
451
529
  body,
452
530
  options
453
531
  );
454
532
  }
533
+ /** Prorated charge for the current billing period. */
534
+ async activateAddon(params, options) {
535
+ const { id, ...body } = params;
536
+ return this.httpClient.post(`/subscriptions/${id}/addons`, body, options);
537
+ }
538
+ async deactivateAddon(params, options) {
539
+ const { id, addonId } = params;
540
+ return this.httpClient.delete(
541
+ `/subscriptions/${id}/addons/${addonId}`,
542
+ void 0,
543
+ options
544
+ );
545
+ }
546
+ /** Positive amount adds, negative subtracts. */
547
+ async adjustBalance(params, options) {
548
+ const { id, ...body } = params;
549
+ return this.httpClient.post(
550
+ `/subscriptions/${id}/balance/adjust`,
551
+ body,
552
+ options
553
+ );
554
+ }
555
+ /** Charges the customer's payment method. */
556
+ async topupBalance(params, options) {
557
+ const { id, ...body } = params;
558
+ return this.httpClient.post(
559
+ `/subscriptions/${id}/balance/topup`,
560
+ body,
561
+ options
562
+ );
563
+ }
564
+ async purchaseCredits(params, options) {
565
+ const { id, ...body } = params;
566
+ return this.httpClient.post(`/subscriptions/${id}/credits`, body, options);
567
+ }
568
+ };
569
+
570
+ // src/resources/transactions.ts
571
+ var TransactionsResource = class {
572
+ constructor(httpClient) {
573
+ this.httpClient = httpClient;
574
+ }
575
+ async list(params) {
576
+ return this.httpClient.get("/transactions", params);
577
+ }
578
+ async get(params) {
579
+ return this.httpClient.get(`/transactions/${params.id}`);
580
+ }
581
+ /** Full refund only. */
582
+ async refund(params, options) {
583
+ return this.httpClient.post(
584
+ `/transactions/${params.id}/refund`,
585
+ {},
586
+ options
587
+ );
588
+ }
589
+ /** Creates a new invoice and initiates a new payment attempt. */
590
+ async retry(params, options) {
591
+ return this.httpClient.post(
592
+ `/transactions/${params.id}/retry`,
593
+ {},
594
+ options
595
+ );
596
+ }
455
597
  };
456
598
 
457
599
  // src/resources/usage.ts
@@ -459,6 +601,7 @@ var UsageResource = class {
459
601
  constructor(httpClient) {
460
602
  this.httpClient = httpClient;
461
603
  }
604
+ /** Deducts from balance/credits if the plan uses consumption. Duplicate `idempotencyKey` is rejected. */
462
605
  async track(params, options) {
463
606
  const eventData = {
464
607
  feature: params.feature,
@@ -485,21 +628,7 @@ var UsageResource = class {
485
628
  }
486
629
  return this.httpClient.post("/usage/events", eventData, options);
487
630
  }
488
- /**
489
- * Check if a usage event would be allowed before tracking it
490
- *
491
- * @example
492
- * ```typescript
493
- * const { data } = await commet.usage.check({
494
- * customerId: 'cus_xxx',
495
- * featureCode: 'api_calls',
496
- * quantity: 1,
497
- * });
498
- * if (data.allowed) {
499
- * // proceed with the operation
500
- * }
501
- * ```
502
- */
631
+ /** Dry-run: checks if a usage event would be allowed without actually tracking it. */
503
632
  async check(params, options) {
504
633
  return this.httpClient.post("/usage/check", params, options);
505
634
  }
@@ -508,39 +637,10 @@ var UsageResource = class {
508
637
  // src/resources/webhooks.ts
509
638
  var import_node_crypto = __toESM(require("crypto"));
510
639
  var Webhooks = class {
511
- /**
512
- * Verify HMAC-SHA256 webhook signature
513
- *
514
- * Use this method to verify that webhooks are authentically from Commet.
515
- * The signature is included in the `X-Commet-Signature` header.
516
- *
517
- * @param payload - Raw request body as string (IMPORTANT: Do not parse JSON first)
518
- * @param signature - Value from X-Commet-Signature header
519
- * @param secret - Your webhook secret from Commet dashboard
520
- * @returns true if signature is valid, false otherwise
521
- *
522
- * @example
523
- * ```typescript
524
- * // Next.js API route example
525
- * export async function POST(request: Request) {
526
- * const rawBody = await request.text();
527
- * const signature = request.headers.get('x-commet-signature');
528
- *
529
- * const isValid = commet.webhooks.verify(
530
- * rawBody,
531
- * signature,
532
- * process.env.COMMET_WEBHOOK_SECRET
533
- * );
534
- *
535
- * if (!isValid) {
536
- * return new Response('Invalid signature', { status: 401 });
537
- * }
538
- *
539
- * const payload = JSON.parse(rawBody);
540
- * // Handle webhook event...
541
- * }
542
- * ```
543
- */
640
+ constructor(httpClient) {
641
+ this.httpClient = httpClient;
642
+ }
643
+ /** HMAC-SHA256 verification. Payload must be the raw request body string, not parsed JSON. */
544
644
  verify(params) {
545
645
  const { payload, signature, secret } = params;
546
646
  if (!signature || !secret || !payload) {
@@ -556,35 +656,11 @@ var Webhooks = class {
556
656
  return false;
557
657
  }
558
658
  }
559
- /**
560
- * Generate HMAC-SHA256 signature (internal use)
561
- * @internal
562
- */
563
659
  generateSignature(params) {
564
660
  const { payload, secret } = params;
565
661
  return import_node_crypto.default.createHmac("sha256", secret).update(payload).digest("hex");
566
662
  }
567
- /**
568
- * Parse and verify webhook payload in one step
569
- *
570
- * @example
571
- * ```typescript
572
- * const payload = commet.webhooks.verifyAndParse({
573
- * rawBody,
574
- * signature,
575
- * secret: process.env.COMMET_WEBHOOK_SECRET
576
- * });
577
- *
578
- * if (!payload) {
579
- * return new Response('Invalid signature', { status: 401 });
580
- * }
581
- *
582
- * // payload is typed and validated
583
- * if (payload.event === 'subscription.activated') {
584
- * // Handle activation...
585
- * }
586
- * ```
587
- */
663
+ /** Verifies signature and parses JSON in one step. Returns null if invalid. */
588
664
  verifyAndParse(params) {
589
665
  const { rawBody, signature, secret } = params;
590
666
  if (!this.verify({ payload: rawBody, signature, secret })) {
@@ -596,6 +672,28 @@ var Webhooks = class {
596
672
  return null;
597
673
  }
598
674
  }
675
+ async list(params, options) {
676
+ return this.httpClient.get("/webhooks", params, options);
677
+ }
678
+ async create(params, options) {
679
+ return this.httpClient.post("/webhooks", params, options);
680
+ }
681
+ async get(params, options) {
682
+ const { id } = params;
683
+ return this.httpClient.get(`/webhooks/${id}`, void 0, options);
684
+ }
685
+ async update(params, options) {
686
+ const { id, ...body } = params;
687
+ return this.httpClient.put(`/webhooks/${id}`, body, options);
688
+ }
689
+ async delete(params, options) {
690
+ const { id } = params;
691
+ return this.httpClient.delete(`/webhooks/${id}`, void 0, options);
692
+ }
693
+ async test(params, options) {
694
+ const { id } = params;
695
+ return this.httpClient.post(`/webhooks/${id}/test`, void 0, options);
696
+ }
599
697
  };
600
698
 
601
699
  // src/types/common.ts
@@ -609,12 +707,15 @@ var CommetError = class extends Error {
609
707
  }
610
708
  };
611
709
  var CommetAPIError = class extends CommetError {
612
- constructor(message, statusCode, code, details) {
710
+ constructor(message, statusCode, code, details, errorDetail) {
613
711
  super(message, code, statusCode, details);
614
712
  this.statusCode = statusCode;
615
713
  this.code = code;
616
714
  this.details = details;
617
715
  this.name = "CommetAPIError";
716
+ this.type = errorDetail?.type;
717
+ this.param = errorDetail?.param;
718
+ this.docUrl = errorDetail?.doc_url;
618
719
  }
619
720
  };
620
721
  var CommetValidationError = class extends CommetError {
@@ -626,8 +727,8 @@ var CommetValidationError = class extends CommetError {
626
727
  };
627
728
 
628
729
  // src/version.ts
629
- var API_VERSION = "2026-05-18";
630
- var SDK_VERSION = "4.6.0";
730
+ var API_VERSION = "2026-05-25";
731
+ var SDK_VERSION = "5.1.0";
631
732
 
632
733
  // src/utils/telemetry.ts
633
734
  var registeredIntegrations = /* @__PURE__ */ new Set();
@@ -691,7 +792,7 @@ var DEFAULT_RETRY_CONFIG = {
691
792
  // 8s
692
793
  retryableStatusCodes: [408, 429, 500, 502, 503, 504]
693
794
  };
694
- var CommetHTTPClient = class {
795
+ var _CommetHTTPClient = class _CommetHTTPClient {
695
796
  constructor(config) {
696
797
  this.lastRequestMetrics = null;
697
798
  this.config = config;
@@ -702,7 +803,13 @@ var CommetHTTPClient = class {
702
803
  };
703
804
  }
704
805
  async get(endpoint, params, options) {
705
- return this.request("GET", endpoint, void 0, options, params);
806
+ return this.request(
807
+ "GET",
808
+ endpoint,
809
+ void 0,
810
+ options,
811
+ params
812
+ );
706
813
  }
707
814
  async post(endpoint, data, options) {
708
815
  return this.request("POST", endpoint, data, options);
@@ -718,6 +825,9 @@ var CommetHTTPClient = class {
718
825
  }
719
826
  async request(method, endpoint, data, options, params) {
720
827
  const url = this.buildURL(endpoint, params);
828
+ if (_CommetHTTPClient.BODY_METHODS.has(method) && this.retryConfig.maxRetries > 0 && !options?.idempotencyKey) {
829
+ options = { ...options, idempotencyKey: this.generateIdempotencyKey() };
830
+ }
721
831
  return this.executeRequest(method, url, data, options);
722
832
  }
723
833
  /**
@@ -743,8 +853,6 @@ var CommetHTTPClient = class {
743
853
  }
744
854
  if (options?.idempotencyKey) {
745
855
  headers["Idempotency-Key"] = options.idempotencyKey;
746
- } else if (method === "POST" && data) {
747
- headers["Idempotency-Key"] = this.generateIdempotencyKey();
748
856
  }
749
857
  const requestConfig = {
750
858
  method,
@@ -813,26 +921,30 @@ var CommetHTTPClient = class {
813
921
  JSON.stringify(responseData, null, 2)
814
922
  );
815
923
  }
816
- const isErrorResponse = (data2) => {
817
- return typeof data2 === "object" && data2 !== null;
924
+ const parsed = typeof responseData === "object" && responseData !== null ? responseData : {};
925
+ const errorObj = typeof parsed.error === "object" && parsed.error !== null ? parsed.error : {};
926
+ const errorDetail = {
927
+ type: errorObj.type ?? "api_error",
928
+ code: errorObj.code ?? "unknown",
929
+ message: errorObj.message ?? `Request failed with status ${response.status}`,
930
+ param: errorObj.param,
931
+ details: errorObj.details,
932
+ doc_url: errorObj.doc_url
818
933
  };
819
- const errorData = isErrorResponse(responseData) ? responseData : {};
820
- if (errorData.code === "validation_error" && Array.isArray(errorData.details)) {
934
+ if (errorDetail.code === "validation_error" && Array.isArray(errorDetail.details)) {
821
935
  const errors = {};
822
- for (const detail of errorData.details) {
936
+ for (const detail of errorDetail.details) {
823
937
  if (!errors[detail.field]) errors[detail.field] = [];
824
938
  errors[detail.field].push(detail.message);
825
939
  }
826
- throw new CommetValidationError(
827
- errorData.message || "Validation failed",
828
- errors
829
- );
940
+ throw new CommetValidationError(errorDetail.message, errors);
830
941
  }
831
942
  throw new CommetAPIError(
832
- errorData.message || `Request failed with status ${response.status}`,
943
+ errorDetail.message,
833
944
  response.status,
834
- errorData.code,
835
- errorData.details
945
+ errorDetail.code,
946
+ errorDetail.details,
947
+ errorDetail
836
948
  );
837
949
  }
838
950
  if (this.config.debug) {
@@ -890,11 +1002,8 @@ var CommetHTTPClient = class {
890
1002
  }
891
1003
  return finalUrl;
892
1004
  }
893
- /**
894
- * Generate idempotency key
895
- */
896
1005
  generateIdempotencyKey() {
897
- return `sdk_${Date.now()}_${Math.random().toString(36).substring(2)}`;
1006
+ return `commet-node-retry-${crypto.randomUUID()}`;
898
1007
  }
899
1008
  /**
900
1009
  * Sleep for specified milliseconds
@@ -903,6 +1012,8 @@ var CommetHTTPClient = class {
903
1012
  return new Promise((resolve) => setTimeout(resolve, ms));
904
1013
  }
905
1014
  };
1015
+ _CommetHTTPClient.BODY_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH"]);
1016
+ var CommetHTTPClient = _CommetHTTPClient;
906
1017
 
907
1018
  // src/client.ts
908
1019
  var Commet = class {
@@ -917,41 +1028,20 @@ var Commet = class {
917
1028
  }
918
1029
  this.httpClient = new CommetHTTPClient(config);
919
1030
  this.addons = new AddonsResource(this.httpClient);
920
- this.customers = new CustomersResource(this.httpClient);
1031
+ this.apiKeys = new ApiKeysResource(this.httpClient);
921
1032
  this.creditPacks = new CreditPacksResource(this.httpClient);
1033
+ this.customers = new CustomersResource(this.httpClient);
1034
+ this.features = new FeaturesResource(this.httpClient);
1035
+ this.invoices = new InvoicesResource(this.httpClient);
1036
+ this.planGroups = new PlanGroupsResource(this.httpClient);
922
1037
  this.plans = new PlansResource(this.httpClient);
923
- this.usage = new UsageResource(this.httpClient);
1038
+ this.portal = new PortalResource(this.httpClient);
1039
+ this.promoCodes = new PromoCodesResource(this.httpClient);
924
1040
  this.seats = new SeatsResource(this.httpClient);
925
1041
  this.subscriptions = new SubscriptionsResource(this.httpClient);
926
- this.portal = new PortalResource(this.httpClient);
927
- this.features = new FeaturesResource(this.httpClient);
928
- this.webhooks = new Webhooks();
929
- if (config.debug) {
930
- console.log("[Commet SDK] Initialized");
931
- console.log("API Key:", `${config.apiKey.substring(0, 12)}...`);
932
- }
933
- }
934
- /**
935
- * Create a customer-scoped context for cleaner API usage
936
- *
937
- * @example
938
- * ```typescript
939
- * const customer = commet.customer("user_123");
940
- *
941
- * // All operations are now scoped to this customer
942
- * const seats = await customer.features.get("team_members");
943
- * await customer.seats.add("member");
944
- * await customer.usage.track("api_call");
945
- * ```
946
- */
947
- customer(customerId) {
948
- return new CustomerContext(customerId, {
949
- features: this.features,
950
- seats: this.seats,
951
- usage: this.usage,
952
- subscriptions: this.subscriptions,
953
- portal: this.portal
954
- });
1042
+ this.transactions = new TransactionsResource(this.httpClient);
1043
+ this.usage = new UsageResource(this.httpClient);
1044
+ this.webhooks = new Webhooks(this.httpClient);
955
1045
  }
956
1046
  };
957
1047
  function createCommet(_billingConfig, options) {
@@ -972,7 +1062,6 @@ var index_default = Commet;
972
1062
  CommetAPIError,
973
1063
  CommetError,
974
1064
  CommetValidationError,
975
- CustomerContext,
976
1065
  SDK_VERSION,
977
1066
  Webhooks,
978
1067
  createCommet,