@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.mjs CHANGED
@@ -1,79 +1,51 @@
1
- // src/customer.ts
2
- var CustomerContext = class {
3
- constructor(customerId, resources) {
4
- this.features = {
5
- get: (code, options) => this.featuresResource.get({ code, customerId: this.customerId }, options),
6
- check: (code, options) => this.featuresResource.check(
7
- { code, customerId: this.customerId },
8
- options
9
- ),
10
- canUse: (code, options) => this.featuresResource.canUse(
11
- { code, customerId: this.customerId },
12
- options
13
- ),
14
- list: (options) => this.featuresResource.list(this.customerId, options)
15
- };
16
- this.seats = {
17
- add: (featureCode, count = 1, options) => this.seatsResource.add(
18
- { customerId: this.customerId, featureCode, count },
19
- options
20
- ),
21
- remove: (featureCode, count = 1, options) => this.seatsResource.remove(
22
- { customerId: this.customerId, featureCode, count },
23
- options
24
- ),
25
- set: (featureCode, count, options) => this.seatsResource.set(
26
- { customerId: this.customerId, featureCode, count },
27
- options
28
- ),
29
- getBalance: (featureCode) => this.seatsResource.getBalance({
30
- customerId: this.customerId,
31
- featureCode
32
- })
33
- };
34
- this.usage = {
35
- track: (feature, value, properties, options) => this.usageResource.track(
36
- { customerId: this.customerId, feature, value, properties },
37
- options
38
- )
39
- };
40
- this.subscription = {
41
- get: () => this.subscriptionsResource.get(this.customerId)
42
- };
43
- this.portal = {
44
- getUrl: (options) => this.portalResource.getUrl({ customerId: this.customerId }, options)
45
- };
46
- this.customerId = customerId;
47
- this.featuresResource = resources.features;
48
- this.seatsResource = resources.seats;
49
- this.usageResource = resources.usage;
50
- this.subscriptionsResource = resources.subscriptions;
51
- this.portalResource = resources.portal;
52
- }
53
- };
54
-
55
1
  // src/resources/addons.ts
56
2
  var AddonsResource = class {
57
3
  constructor(httpClient) {
58
4
  this.httpClient = httpClient;
59
5
  }
60
- /**
61
- * Get active addons for a customer's subscription
62
- *
63
- * @example
64
- * ```typescript
65
- * const { data } = await commet.addons.getActive({
66
- * customerId: 'cus_xxx',
67
- * });
68
- * ```
69
- */
70
- async getActive(params, options) {
6
+ async listActive(params, options) {
71
7
  return this.httpClient.get(
72
8
  "/addons/active",
73
9
  { customerId: params.customerId },
74
10
  options
75
11
  );
76
12
  }
13
+ async list(params, options) {
14
+ return this.httpClient.get("/addons", params, options);
15
+ }
16
+ async get(params, options) {
17
+ const { id } = params;
18
+ return this.httpClient.get(`/addons/${id}`, void 0, options);
19
+ }
20
+ async create(params, options) {
21
+ return this.httpClient.post("/addons", params, options);
22
+ }
23
+ async update(params, options) {
24
+ const { id, ...body } = params;
25
+ return this.httpClient.put(`/addons/${id}`, body, options);
26
+ }
27
+ /** Fails if addon has active subscriptions. */
28
+ async delete(params, options) {
29
+ const { id } = params;
30
+ return this.httpClient.delete(`/addons/${id}`, void 0, options);
31
+ }
32
+ };
33
+
34
+ // src/resources/api-keys.ts
35
+ var ApiKeysResource = class {
36
+ constructor(httpClient) {
37
+ this.httpClient = httpClient;
38
+ }
39
+ async list(params) {
40
+ return this.httpClient.get("/api-keys", params);
41
+ }
42
+ /** Response includes full `apiKey` which is only returned once. */
43
+ async create(params, options) {
44
+ return this.httpClient.post("/api-keys", params, options);
45
+ }
46
+ async delete(params, options) {
47
+ return this.httpClient.delete(`/api-keys/${params.id}`, void 0, options);
48
+ }
77
49
  };
78
50
 
79
51
  // src/resources/credit-packs.ts
@@ -81,18 +53,20 @@ var CreditPacksResource = class {
81
53
  constructor(httpClient) {
82
54
  this.httpClient = httpClient;
83
55
  }
84
- /**
85
- * List all active credit packs
86
- *
87
- * @example
88
- * ```typescript
89
- * const packs = await commet.creditPacks.list();
90
- * console.log(packs.data); // [{ id: "cp_xxx", name: "100 Credits", ... }]
91
- * ```
92
- */
93
56
  async list() {
94
57
  return this.httpClient.get("/credit-packs");
95
58
  }
59
+ async create(params, options) {
60
+ return this.httpClient.post("/credit-packs/manage", params, options);
61
+ }
62
+ async update(params, options) {
63
+ const { id, ...body } = params;
64
+ return this.httpClient.put(`/credit-packs/${id}`, body, options);
65
+ }
66
+ async delete(params, options) {
67
+ const { id } = params;
68
+ return this.httpClient.delete(`/credit-packs/${id}`, void 0, options);
69
+ }
96
70
  };
97
71
 
98
72
  // src/resources/customers.ts
@@ -100,15 +74,13 @@ var CustomersResource = class {
100
74
  constructor(httpClient) {
101
75
  this.httpClient = httpClient;
102
76
  }
103
- /**
104
- * Create a customer (idempotent when id is provided)
105
- */
77
+ /** Idempotent when `id` is provided — returns existing customer instead of duplicating. */
106
78
  async create(params, options) {
107
79
  return this.httpClient.post(
108
80
  "/customers",
109
81
  {
110
82
  billingEmail: params.email,
111
- externalId: params.id,
83
+ id: params.id,
112
84
  fullName: params.fullName,
113
85
  domain: params.domain,
114
86
  website: params.website,
@@ -121,13 +93,10 @@ var CustomersResource = class {
121
93
  options
122
94
  );
123
95
  }
124
- /**
125
- * Create multiple customers in batch
126
- */
127
96
  async createBatch(params, options) {
128
97
  const customers = params.customers.map((c) => ({
129
98
  billingEmail: c.email,
130
- externalId: c.id,
99
+ id: c.id,
131
100
  fullName: c.fullName,
132
101
  domain: c.domain,
133
102
  website: c.website,
@@ -139,18 +108,12 @@ var CustomersResource = class {
139
108
  }));
140
109
  return this.httpClient.post("/customers/batch", { customers }, options);
141
110
  }
142
- /**
143
- * Get a customer by ID
144
- */
145
- async get(customerId) {
146
- return this.httpClient.get(`/customers/${customerId}`);
111
+ async get(params) {
112
+ return this.httpClient.get(`/customers/${params.id}`);
147
113
  }
148
- /**
149
- * Update a customer
150
- */
151
114
  async update(params, options) {
152
115
  return this.httpClient.put(
153
- `/customers/${params.customerId}`,
116
+ `/customers/${params.id}`,
154
117
  {
155
118
  billingEmail: params.email,
156
119
  fullName: params.fullName,
@@ -165,9 +128,6 @@ var CustomersResource = class {
165
128
  options
166
129
  );
167
130
  }
168
- /**
169
- * List customers with optional filters
170
- */
171
131
  async list(params) {
172
132
  return this.httpClient.get("/customers", params);
173
133
  }
@@ -185,34 +145,113 @@ var FeaturesResource = class {
185
145
  options
186
146
  );
187
147
  }
188
- async check(params, options) {
189
- const result = await this.httpClient.get(
148
+ /** Checks if the customer can consume one more unit — returns billing impact and reason if blocked. */
149
+ async canUse(params, options) {
150
+ return this.httpClient.get(
190
151
  `/features/${params.code}`,
191
- { customerId: params.customerId },
152
+ { customerId: params.customerId, action: "canUse" },
192
153
  options
193
154
  );
194
- if (!result.success || !result.data) {
195
- return {
196
- success: false,
197
- code: result.code,
198
- message: result.message,
199
- details: result.details
200
- };
201
- }
202
- return {
203
- success: true,
204
- data: { allowed: result.data.allowed }
205
- };
206
155
  }
207
- async canUse(params, options) {
156
+ async list(params, options) {
208
157
  return this.httpClient.get(
209
- `/features/${params.code}`,
210
- { customerId: params.customerId, action: "canUse" },
158
+ "/features",
159
+ { customerId: params.customerId },
160
+ options
161
+ );
162
+ }
163
+ async create(params, options) {
164
+ return this.httpClient.post("/features/manage", params, options);
165
+ }
166
+ async update(params, options) {
167
+ const { code, ...body } = params;
168
+ return this.httpClient.put(`/features/${code}/manage`, body, options);
169
+ }
170
+ /** Fails if feature is attached to active plans or has an active addon. */
171
+ async delete(params, options) {
172
+ const { code } = params;
173
+ return this.httpClient.delete(
174
+ `/features/${code}/manage`,
175
+ void 0,
176
+ options
177
+ );
178
+ }
179
+ };
180
+
181
+ // src/resources/invoices.ts
182
+ var InvoicesResource = class {
183
+ constructor(httpClient) {
184
+ this.httpClient = httpClient;
185
+ }
186
+ async list(params) {
187
+ return this.httpClient.get("/invoices", params);
188
+ }
189
+ async get(params) {
190
+ return this.httpClient.get(`/invoices/${params.id}`);
191
+ }
192
+ /** Negative amount creates a credit. */
193
+ async createAdjustment(params, options) {
194
+ return this.httpClient.post("/invoices", params, options);
195
+ }
196
+ /** Signed URL, expires after 7 days. */
197
+ async getDownloadUrl(params) {
198
+ return this.httpClient.get(`/invoices/${params.id}/download`);
199
+ }
200
+ async send(params, options) {
201
+ return this.httpClient.post(`/invoices/${params.id}/send`, {}, options);
202
+ }
203
+ /** Only outstanding invoices can be changed to paid or void. */
204
+ async updateStatus(params, options) {
205
+ const { id, ...body } = params;
206
+ return this.httpClient.put(`/invoices/${id}/status`, body, options);
207
+ }
208
+ };
209
+
210
+ // src/resources/plan-groups.ts
211
+ var PlanGroupsResource = class {
212
+ constructor(httpClient) {
213
+ this.httpClient = httpClient;
214
+ }
215
+ async list(params) {
216
+ return this.httpClient.get("/plan-groups", params);
217
+ }
218
+ async get(params) {
219
+ return this.httpClient.get(`/plan-groups/${params.id}`);
220
+ }
221
+ async create(params, options) {
222
+ return this.httpClient.post("/plan-groups", params, options);
223
+ }
224
+ async update(params, options) {
225
+ const { id, ...body } = params;
226
+ return this.httpClient.put(`/plan-groups/${id}`, body, options);
227
+ }
228
+ /** Plans in the group are unlinked, not deleted. */
229
+ async delete(params, options) {
230
+ return this.httpClient.delete(
231
+ `/plan-groups/${params.id}`,
232
+ void 0,
233
+ options
234
+ );
235
+ }
236
+ async addPlan(params, options) {
237
+ const { id, ...body } = params;
238
+ return this.httpClient.post(`/plan-groups/${id}/plans`, body, options);
239
+ }
240
+ async removePlan(params, options) {
241
+ const { id, planId } = params;
242
+ return this.httpClient.delete(
243
+ `/plan-groups/${id}/plans/${planId}`,
244
+ void 0,
211
245
  options
212
246
  );
213
247
  }
214
- async list(customerId, options) {
215
- return this.httpClient.get("/features", { customerId }, options);
248
+ async reorderPlans(params, options) {
249
+ const { id, ...body } = params;
250
+ return this.httpClient.put(
251
+ `/plan-groups/${id}/plans/reorder`,
252
+ body,
253
+ options
254
+ );
216
255
  }
217
256
  };
218
257
 
@@ -221,33 +260,93 @@ var PlansResource = class {
221
260
  constructor(httpClient) {
222
261
  this.httpClient = httpClient;
223
262
  }
224
- /**
225
- * List all available plans
226
- *
227
- * @example
228
- * ```typescript
229
- * // List public plans
230
- * const plans = await commet.plans.list();
231
- *
232
- * // Include private plans
233
- * const allPlans = await commet.plans.list({ includePrivate: true });
234
- * ```
235
- */
236
263
  async list(params) {
237
264
  return this.httpClient.get("/plans", params);
238
265
  }
239
- /**
240
- * Get a specific plan by code
241
- *
242
- * @example
243
- * ```typescript
244
- * const plan = await commet.plans.get('pro');
245
- * console.log(plan.data.name); // "Pro"
246
- * console.log(plan.data.prices); // [{ billingInterval: 'monthly', price: 9900 }]
247
- * ```
248
- */
249
- async get(planCode) {
250
- return this.httpClient.get(`/plans/${planCode}`);
266
+ async get(params) {
267
+ return this.httpClient.get(`/plans/${params.id}`);
268
+ }
269
+ async create(params, options) {
270
+ return this.httpClient.post("/plans/manage", params, options);
271
+ }
272
+ async update(params, options) {
273
+ const { id, ...body } = params;
274
+ return this.httpClient.put(`/plans/${id}/manage`, body, options);
275
+ }
276
+ async delete(params, options) {
277
+ return this.httpClient.delete(
278
+ `/plans/${params.id}/manage`,
279
+ void 0,
280
+ options
281
+ );
282
+ }
283
+ async setVisibility(params, options) {
284
+ const { id, ...body } = params;
285
+ return this.httpClient.put(`/plans/${id}/visibility`, body, options);
286
+ }
287
+ async addFeature(params, options) {
288
+ const { planId, ...body } = params;
289
+ return this.httpClient.post(`/plans/${planId}/features`, body, options);
290
+ }
291
+ async updateFeature(params, options) {
292
+ const { planId, featureId, ...body } = params;
293
+ return this.httpClient.put(
294
+ `/plans/${planId}/features/${featureId}`,
295
+ body,
296
+ options
297
+ );
298
+ }
299
+ async removeFeature(params, options) {
300
+ const { planId, featureId } = params;
301
+ return this.httpClient.delete(
302
+ `/plans/${planId}/features/${featureId}`,
303
+ void 0,
304
+ options
305
+ );
306
+ }
307
+ async addPrice(params, options) {
308
+ const { planId, ...body } = params;
309
+ return this.httpClient.post(`/plans/${planId}/prices`, body, options);
310
+ }
311
+ async updatePrice(params, options) {
312
+ const { planId, priceId, ...body } = params;
313
+ return this.httpClient.put(
314
+ `/plans/${planId}/prices/${priceId}`,
315
+ body,
316
+ options
317
+ );
318
+ }
319
+ async deletePrice(params, options) {
320
+ const { planId, priceId } = params;
321
+ return this.httpClient.delete(
322
+ `/plans/${planId}/prices/${priceId}`,
323
+ void 0,
324
+ options
325
+ );
326
+ }
327
+ async setDefaultPrice(params, options) {
328
+ const { planId, priceId } = params;
329
+ return this.httpClient.put(
330
+ `/plans/${planId}/prices/${priceId}/default`,
331
+ {},
332
+ options
333
+ );
334
+ }
335
+ async setRegionalPrices(params, options) {
336
+ const { planId, priceId, ...body } = params;
337
+ return this.httpClient.put(
338
+ `/plans/${planId}/prices/${priceId}/regional`,
339
+ body,
340
+ options
341
+ );
342
+ }
343
+ async deleteRegionalPrices(params, options) {
344
+ const { planId, priceId } = params;
345
+ return this.httpClient.delete(
346
+ `/plans/${planId}/prices/${priceId}/regional`,
347
+ void 0,
348
+ options
349
+ );
251
350
  }
252
351
  };
253
352
 
@@ -261,39 +360,63 @@ var PortalResource = class {
261
360
  }
262
361
  };
263
362
 
264
- // src/resources/seats.ts
265
- function resolveCode(params) {
266
- const code = params.featureCode ?? params.seatType;
267
- if (!code) {
268
- throw new Error("Either featureCode or seatType must be provided");
363
+ // src/resources/promo-codes.ts
364
+ var PromoCodesResource = class {
365
+ constructor(httpClient) {
366
+ this.httpClient = httpClient;
269
367
  }
270
- return code;
271
- }
368
+ async list(params) {
369
+ return this.httpClient.get("/promo-codes", params);
370
+ }
371
+ async get(params) {
372
+ return this.httpClient.get(`/promo-codes/${params.id}`);
373
+ }
374
+ async create(params, options) {
375
+ return this.httpClient.post("/promo-codes", params, options);
376
+ }
377
+ async update(params, options) {
378
+ const { id, ...body } = params;
379
+ return this.httpClient.put(`/promo-codes/${id}`, body, options);
380
+ }
381
+ };
382
+
383
+ // src/resources/seats.ts
272
384
  var SeatsResource = class {
273
385
  constructor(httpClient) {
274
386
  this.httpClient = httpClient;
275
387
  }
388
+ /** Prorates charges for the current billing period. */
276
389
  async add(params, options) {
277
- const code = resolveCode(params);
278
390
  return this.httpClient.post(
279
391
  "/seats",
280
- { customerId: params.customerId, seatType: code, count: params.count },
392
+ {
393
+ customerId: params.customerId,
394
+ featureCode: params.featureCode,
395
+ count: params.count ?? 1
396
+ },
281
397
  options
282
398
  );
283
399
  }
400
+ /** Removal takes effect at the end of the billing period. */
284
401
  async remove(params, options) {
285
- const code = resolveCode(params);
286
402
  return this.httpClient.delete(
287
403
  "/seats",
288
- { customerId: params.customerId, seatType: code, count: params.count },
404
+ {
405
+ customerId: params.customerId,
406
+ featureCode: params.featureCode,
407
+ count: params.count ?? 1
408
+ },
289
409
  options
290
410
  );
291
411
  }
292
412
  async set(params, options) {
293
- const code = resolveCode(params);
294
413
  return this.httpClient.put(
295
414
  "/seats",
296
- { customerId: params.customerId, seatType: code, count: params.count },
415
+ {
416
+ customerId: params.customerId,
417
+ featureCode: params.featureCode,
418
+ count: params.count
419
+ },
297
420
  options
298
421
  );
299
422
  }
@@ -301,10 +424,9 @@ var SeatsResource = class {
301
424
  return this.httpClient.put("/seats/bulk", params, options);
302
425
  }
303
426
  async getBalance(params) {
304
- const code = resolveCode(params);
305
427
  return this.httpClient.get("/seats/balance", {
306
428
  customerId: params.customerId,
307
- seatType: code
429
+ featureCode: params.featureCode
308
430
  });
309
431
  }
310
432
  async getAllBalances(params) {
@@ -319,92 +441,113 @@ var SubscriptionsResource = class {
319
441
  constructor(httpClient) {
320
442
  this.httpClient = httpClient;
321
443
  }
322
- /**
323
- * Create a subscription with a plan
324
- *
325
- * @example
326
- * ```typescript
327
- * await commet.subscriptions.create({
328
- * externalId: 'user_123',
329
- * planCode: 'pro', // autocomplete works after `commet pull`
330
- * billingInterval: 'yearly',
331
- * initialSeats: { editor: 5 }
332
- * });
333
- * ```
334
- */
444
+ /** Returns a `checkoutUrl` when payment is required before activation. */
335
445
  async create(params, options) {
336
446
  return this.httpClient.post("/subscriptions", params, options);
337
447
  }
338
- /**
339
- * Get the active subscription for a customer
340
- *
341
- * @example
342
- * ```typescript
343
- * const sub = await commet.subscriptions.get('user_123');
344
- * ```
345
- */
346
- async get(customerId) {
347
- return this.httpClient.get("/subscriptions/active", { customerId });
448
+ async getActive(params) {
449
+ return this.httpClient.get("/subscriptions/active", {
450
+ customerId: params.customerId
451
+ });
348
452
  }
349
- /**
350
- * Cancel a subscription
351
- *
352
- * @example
353
- * ```typescript
354
- * await commet.subscriptions.cancel({
355
- * subscriptionId: 'sub_xxx',
356
- * reason: 'switched_to_competitor'
357
- * });
358
- * ```
359
- */
453
+ /** Schedules cancellation at period end by default. Set `immediate: true` to cancel now. */
360
454
  async cancel(params, options) {
361
- return this.httpClient.post(
362
- `/subscriptions/${params.subscriptionId}/cancel`,
363
- params || {},
364
- options
365
- );
455
+ const { id, ...body } = params;
456
+ return this.httpClient.post(`/subscriptions/${id}/cancel`, body, options);
366
457
  }
367
- /**
368
- * Revert a scheduled cancellation
369
- *
370
- * Only works on subscriptions with a pending cancellation (canceledAt is set
371
- * but status is not yet "canceled"). Cannot revert already-canceled subscriptions.
372
- *
373
- * @example
374
- * ```typescript
375
- * await commet.subscriptions.uncancel({
376
- * subscriptionId: 'sub_xxx',
377
- * });
378
- * ```
379
- */
458
+ /** Only works on subscriptions with a pending cancellation — cannot revert already-canceled. */
380
459
  async uncancel(params, options) {
381
460
  return this.httpClient.post(
382
- `/subscriptions/${params.subscriptionId}/uncancel`,
461
+ `/subscriptions/${params.id}/uncancel`,
383
462
  {},
384
463
  options
385
464
  );
386
465
  }
387
- /**
388
- * Change the plan of a subscription (upgrade/downgrade)
389
- *
390
- * Upgrades execute immediately. Downgrades are scheduled for end of period.
391
- *
392
- * @example
393
- * ```typescript
394
- * await commet.subscriptions.changePlan({
395
- * subscriptionId: 'sub_xxx',
396
- * newPlanId: 'pln_xxx',
397
- * });
398
- * ```
399
- */
466
+ /** Upgrades execute immediately with proration. Downgrades are scheduled for end of period. */
400
467
  async changePlan(params, options) {
401
- const { subscriptionId, ...body } = params;
468
+ const { id, ...body } = params;
469
+ return this.httpClient.post(
470
+ `/subscriptions/${id}/change-plan`,
471
+ body,
472
+ options
473
+ );
474
+ }
475
+ async list(params) {
476
+ return this.httpClient.get("/subscriptions", params);
477
+ }
478
+ /** Dry-run: returns proration details without applying the change. */
479
+ async previewChange(params, options) {
480
+ const { id, ...body } = params;
402
481
  return this.httpClient.post(
403
- `/subscriptions/${subscriptionId}/change-plan`,
482
+ `/subscriptions/${id}/preview-change`,
404
483
  body,
405
484
  options
406
485
  );
407
486
  }
487
+ /** Prorated charge for the current billing period. */
488
+ async activateAddon(params, options) {
489
+ const { id, ...body } = params;
490
+ return this.httpClient.post(`/subscriptions/${id}/addons`, body, options);
491
+ }
492
+ async deactivateAddon(params, options) {
493
+ const { id, addonId } = params;
494
+ return this.httpClient.delete(
495
+ `/subscriptions/${id}/addons/${addonId}`,
496
+ void 0,
497
+ options
498
+ );
499
+ }
500
+ /** Positive amount adds, negative subtracts. */
501
+ async adjustBalance(params, options) {
502
+ const { id, ...body } = params;
503
+ return this.httpClient.post(
504
+ `/subscriptions/${id}/balance/adjust`,
505
+ body,
506
+ options
507
+ );
508
+ }
509
+ /** Charges the customer's payment method. */
510
+ async topupBalance(params, options) {
511
+ const { id, ...body } = params;
512
+ return this.httpClient.post(
513
+ `/subscriptions/${id}/balance/topup`,
514
+ body,
515
+ options
516
+ );
517
+ }
518
+ async purchaseCredits(params, options) {
519
+ const { id, ...body } = params;
520
+ return this.httpClient.post(`/subscriptions/${id}/credits`, body, options);
521
+ }
522
+ };
523
+
524
+ // src/resources/transactions.ts
525
+ var TransactionsResource = class {
526
+ constructor(httpClient) {
527
+ this.httpClient = httpClient;
528
+ }
529
+ async list(params) {
530
+ return this.httpClient.get("/transactions", params);
531
+ }
532
+ async get(params) {
533
+ return this.httpClient.get(`/transactions/${params.id}`);
534
+ }
535
+ /** Full refund only. */
536
+ async refund(params, options) {
537
+ return this.httpClient.post(
538
+ `/transactions/${params.id}/refund`,
539
+ {},
540
+ options
541
+ );
542
+ }
543
+ /** Creates a new invoice and initiates a new payment attempt. */
544
+ async retry(params, options) {
545
+ return this.httpClient.post(
546
+ `/transactions/${params.id}/retry`,
547
+ {},
548
+ options
549
+ );
550
+ }
408
551
  };
409
552
 
410
553
  // src/resources/usage.ts
@@ -412,6 +555,7 @@ var UsageResource = class {
412
555
  constructor(httpClient) {
413
556
  this.httpClient = httpClient;
414
557
  }
558
+ /** Deducts from balance/credits if the plan uses consumption. Duplicate `idempotencyKey` is rejected. */
415
559
  async track(params, options) {
416
560
  const eventData = {
417
561
  feature: params.feature,
@@ -438,62 +582,19 @@ var UsageResource = class {
438
582
  }
439
583
  return this.httpClient.post("/usage/events", eventData, options);
440
584
  }
441
- /**
442
- * Check if a usage event would be allowed before tracking it
443
- *
444
- * @example
445
- * ```typescript
446
- * const { data } = await commet.usage.check({
447
- * customerId: 'cus_xxx',
448
- * featureCode: 'api_calls',
449
- * quantity: 1,
450
- * });
451
- * if (data.allowed) {
452
- * // proceed with the operation
453
- * }
454
- * ```
455
- */
585
+ /** Dry-run: checks if a usage event would be allowed without actually tracking it. */
456
586
  async check(params, options) {
457
587
  return this.httpClient.post("/usage/check", params, options);
458
588
  }
459
589
  };
460
590
 
461
591
  // src/resources/webhooks.ts
462
- import crypto from "crypto";
592
+ import crypto2 from "crypto";
463
593
  var Webhooks = class {
464
- /**
465
- * Verify HMAC-SHA256 webhook signature
466
- *
467
- * Use this method to verify that webhooks are authentically from Commet.
468
- * The signature is included in the `X-Commet-Signature` header.
469
- *
470
- * @param payload - Raw request body as string (IMPORTANT: Do not parse JSON first)
471
- * @param signature - Value from X-Commet-Signature header
472
- * @param secret - Your webhook secret from Commet dashboard
473
- * @returns true if signature is valid, false otherwise
474
- *
475
- * @example
476
- * ```typescript
477
- * // Next.js API route example
478
- * export async function POST(request: Request) {
479
- * const rawBody = await request.text();
480
- * const signature = request.headers.get('x-commet-signature');
481
- *
482
- * const isValid = commet.webhooks.verify(
483
- * rawBody,
484
- * signature,
485
- * process.env.COMMET_WEBHOOK_SECRET
486
- * );
487
- *
488
- * if (!isValid) {
489
- * return new Response('Invalid signature', { status: 401 });
490
- * }
491
- *
492
- * const payload = JSON.parse(rawBody);
493
- * // Handle webhook event...
494
- * }
495
- * ```
496
- */
594
+ constructor(httpClient) {
595
+ this.httpClient = httpClient;
596
+ }
597
+ /** HMAC-SHA256 verification. Payload must be the raw request body string, not parsed JSON. */
497
598
  verify(params) {
498
599
  const { payload, signature, secret } = params;
499
600
  if (!signature || !secret || !payload) {
@@ -501,7 +602,7 @@ var Webhooks = class {
501
602
  }
502
603
  try {
503
604
  const expectedSignature = this.generateSignature({ payload, secret });
504
- return crypto.timingSafeEqual(
605
+ return crypto2.timingSafeEqual(
505
606
  Buffer.from(signature, "hex"),
506
607
  Buffer.from(expectedSignature, "hex")
507
608
  );
@@ -509,35 +610,11 @@ var Webhooks = class {
509
610
  return false;
510
611
  }
511
612
  }
512
- /**
513
- * Generate HMAC-SHA256 signature (internal use)
514
- * @internal
515
- */
516
613
  generateSignature(params) {
517
614
  const { payload, secret } = params;
518
- return crypto.createHmac("sha256", secret).update(payload).digest("hex");
615
+ return crypto2.createHmac("sha256", secret).update(payload).digest("hex");
519
616
  }
520
- /**
521
- * Parse and verify webhook payload in one step
522
- *
523
- * @example
524
- * ```typescript
525
- * const payload = commet.webhooks.verifyAndParse({
526
- * rawBody,
527
- * signature,
528
- * secret: process.env.COMMET_WEBHOOK_SECRET
529
- * });
530
- *
531
- * if (!payload) {
532
- * return new Response('Invalid signature', { status: 401 });
533
- * }
534
- *
535
- * // payload is typed and validated
536
- * if (payload.event === 'subscription.activated') {
537
- * // Handle activation...
538
- * }
539
- * ```
540
- */
617
+ /** Verifies signature and parses JSON in one step. Returns null if invalid. */
541
618
  verifyAndParse(params) {
542
619
  const { rawBody, signature, secret } = params;
543
620
  if (!this.verify({ payload: rawBody, signature, secret })) {
@@ -549,6 +626,28 @@ var Webhooks = class {
549
626
  return null;
550
627
  }
551
628
  }
629
+ async list(params, options) {
630
+ return this.httpClient.get("/webhooks", params, options);
631
+ }
632
+ async create(params, options) {
633
+ return this.httpClient.post("/webhooks", params, options);
634
+ }
635
+ async get(params, options) {
636
+ const { id } = params;
637
+ return this.httpClient.get(`/webhooks/${id}`, void 0, options);
638
+ }
639
+ async update(params, options) {
640
+ const { id, ...body } = params;
641
+ return this.httpClient.put(`/webhooks/${id}`, body, options);
642
+ }
643
+ async delete(params, options) {
644
+ const { id } = params;
645
+ return this.httpClient.delete(`/webhooks/${id}`, void 0, options);
646
+ }
647
+ async test(params, options) {
648
+ const { id } = params;
649
+ return this.httpClient.post(`/webhooks/${id}/test`, void 0, options);
650
+ }
552
651
  };
553
652
 
554
653
  // src/types/common.ts
@@ -562,12 +661,15 @@ var CommetError = class extends Error {
562
661
  }
563
662
  };
564
663
  var CommetAPIError = class extends CommetError {
565
- constructor(message, statusCode, code, details) {
664
+ constructor(message, statusCode, code, details, errorDetail) {
566
665
  super(message, code, statusCode, details);
567
666
  this.statusCode = statusCode;
568
667
  this.code = code;
569
668
  this.details = details;
570
669
  this.name = "CommetAPIError";
670
+ this.type = errorDetail?.type;
671
+ this.param = errorDetail?.param;
672
+ this.docUrl = errorDetail?.doc_url;
571
673
  }
572
674
  };
573
675
  var CommetValidationError = class extends CommetError {
@@ -579,8 +681,8 @@ var CommetValidationError = class extends CommetError {
579
681
  };
580
682
 
581
683
  // src/version.ts
582
- var API_VERSION = "2026-05-18";
583
- var SDK_VERSION = "4.6.0";
684
+ var API_VERSION = "2026-05-25";
685
+ var SDK_VERSION = "5.1.0";
584
686
 
585
687
  // src/utils/telemetry.ts
586
688
  var registeredIntegrations = /* @__PURE__ */ new Set();
@@ -644,7 +746,7 @@ var DEFAULT_RETRY_CONFIG = {
644
746
  // 8s
645
747
  retryableStatusCodes: [408, 429, 500, 502, 503, 504]
646
748
  };
647
- var CommetHTTPClient = class {
749
+ var _CommetHTTPClient = class _CommetHTTPClient {
648
750
  constructor(config) {
649
751
  this.lastRequestMetrics = null;
650
752
  this.config = config;
@@ -655,7 +757,13 @@ var CommetHTTPClient = class {
655
757
  };
656
758
  }
657
759
  async get(endpoint, params, options) {
658
- return this.request("GET", endpoint, void 0, options, params);
760
+ return this.request(
761
+ "GET",
762
+ endpoint,
763
+ void 0,
764
+ options,
765
+ params
766
+ );
659
767
  }
660
768
  async post(endpoint, data, options) {
661
769
  return this.request("POST", endpoint, data, options);
@@ -671,6 +779,9 @@ var CommetHTTPClient = class {
671
779
  }
672
780
  async request(method, endpoint, data, options, params) {
673
781
  const url = this.buildURL(endpoint, params);
782
+ if (_CommetHTTPClient.BODY_METHODS.has(method) && this.retryConfig.maxRetries > 0 && !options?.idempotencyKey) {
783
+ options = { ...options, idempotencyKey: this.generateIdempotencyKey() };
784
+ }
674
785
  return this.executeRequest(method, url, data, options);
675
786
  }
676
787
  /**
@@ -696,8 +807,6 @@ var CommetHTTPClient = class {
696
807
  }
697
808
  if (options?.idempotencyKey) {
698
809
  headers["Idempotency-Key"] = options.idempotencyKey;
699
- } else if (method === "POST" && data) {
700
- headers["Idempotency-Key"] = this.generateIdempotencyKey();
701
810
  }
702
811
  const requestConfig = {
703
812
  method,
@@ -766,26 +875,30 @@ var CommetHTTPClient = class {
766
875
  JSON.stringify(responseData, null, 2)
767
876
  );
768
877
  }
769
- const isErrorResponse = (data2) => {
770
- return typeof data2 === "object" && data2 !== null;
878
+ const parsed = typeof responseData === "object" && responseData !== null ? responseData : {};
879
+ const errorObj = typeof parsed.error === "object" && parsed.error !== null ? parsed.error : {};
880
+ const errorDetail = {
881
+ type: errorObj.type ?? "api_error",
882
+ code: errorObj.code ?? "unknown",
883
+ message: errorObj.message ?? `Request failed with status ${response.status}`,
884
+ param: errorObj.param,
885
+ details: errorObj.details,
886
+ doc_url: errorObj.doc_url
771
887
  };
772
- const errorData = isErrorResponse(responseData) ? responseData : {};
773
- if (errorData.code === "validation_error" && Array.isArray(errorData.details)) {
888
+ if (errorDetail.code === "validation_error" && Array.isArray(errorDetail.details)) {
774
889
  const errors = {};
775
- for (const detail of errorData.details) {
890
+ for (const detail of errorDetail.details) {
776
891
  if (!errors[detail.field]) errors[detail.field] = [];
777
892
  errors[detail.field].push(detail.message);
778
893
  }
779
- throw new CommetValidationError(
780
- errorData.message || "Validation failed",
781
- errors
782
- );
894
+ throw new CommetValidationError(errorDetail.message, errors);
783
895
  }
784
896
  throw new CommetAPIError(
785
- errorData.message || `Request failed with status ${response.status}`,
897
+ errorDetail.message,
786
898
  response.status,
787
- errorData.code,
788
- errorData.details
899
+ errorDetail.code,
900
+ errorDetail.details,
901
+ errorDetail
789
902
  );
790
903
  }
791
904
  if (this.config.debug) {
@@ -843,11 +956,8 @@ var CommetHTTPClient = class {
843
956
  }
844
957
  return finalUrl;
845
958
  }
846
- /**
847
- * Generate idempotency key
848
- */
849
959
  generateIdempotencyKey() {
850
- return `sdk_${Date.now()}_${Math.random().toString(36).substring(2)}`;
960
+ return `commet-node-retry-${crypto.randomUUID()}`;
851
961
  }
852
962
  /**
853
963
  * Sleep for specified milliseconds
@@ -856,6 +966,8 @@ var CommetHTTPClient = class {
856
966
  return new Promise((resolve) => setTimeout(resolve, ms));
857
967
  }
858
968
  };
969
+ _CommetHTTPClient.BODY_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH"]);
970
+ var CommetHTTPClient = _CommetHTTPClient;
859
971
 
860
972
  // src/client.ts
861
973
  var Commet = class {
@@ -870,41 +982,20 @@ var Commet = class {
870
982
  }
871
983
  this.httpClient = new CommetHTTPClient(config);
872
984
  this.addons = new AddonsResource(this.httpClient);
873
- this.customers = new CustomersResource(this.httpClient);
985
+ this.apiKeys = new ApiKeysResource(this.httpClient);
874
986
  this.creditPacks = new CreditPacksResource(this.httpClient);
987
+ this.customers = new CustomersResource(this.httpClient);
988
+ this.features = new FeaturesResource(this.httpClient);
989
+ this.invoices = new InvoicesResource(this.httpClient);
990
+ this.planGroups = new PlanGroupsResource(this.httpClient);
875
991
  this.plans = new PlansResource(this.httpClient);
876
- this.usage = new UsageResource(this.httpClient);
992
+ this.portal = new PortalResource(this.httpClient);
993
+ this.promoCodes = new PromoCodesResource(this.httpClient);
877
994
  this.seats = new SeatsResource(this.httpClient);
878
995
  this.subscriptions = new SubscriptionsResource(this.httpClient);
879
- this.portal = new PortalResource(this.httpClient);
880
- this.features = new FeaturesResource(this.httpClient);
881
- this.webhooks = new Webhooks();
882
- if (config.debug) {
883
- console.log("[Commet SDK] Initialized");
884
- console.log("API Key:", `${config.apiKey.substring(0, 12)}...`);
885
- }
886
- }
887
- /**
888
- * Create a customer-scoped context for cleaner API usage
889
- *
890
- * @example
891
- * ```typescript
892
- * const customer = commet.customer("user_123");
893
- *
894
- * // All operations are now scoped to this customer
895
- * const seats = await customer.features.get("team_members");
896
- * await customer.seats.add("member");
897
- * await customer.usage.track("api_call");
898
- * ```
899
- */
900
- customer(customerId) {
901
- return new CustomerContext(customerId, {
902
- features: this.features,
903
- seats: this.seats,
904
- usage: this.usage,
905
- subscriptions: this.subscriptions,
906
- portal: this.portal
907
- });
996
+ this.transactions = new TransactionsResource(this.httpClient);
997
+ this.usage = new UsageResource(this.httpClient);
998
+ this.webhooks = new Webhooks(this.httpClient);
908
999
  }
909
1000
  };
910
1001
  function createCommet(_billingConfig, options) {
@@ -924,7 +1015,6 @@ export {
924
1015
  CommetAPIError,
925
1016
  CommetError,
926
1017
  CommetValidationError,
927
- CustomerContext,
928
1018
  SDK_VERSION,
929
1019
  Webhooks,
930
1020
  createCommet,