@commet/node 4.5.0 → 5.0.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,57 +44,53 @@ __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;
47
+ // src/resources/addons.ts
48
+ var AddonsResource = class {
49
+ constructor(httpClient) {
50
+ this.httpClient = httpClient;
51
+ }
52
+ async listActive(params, options) {
53
+ return this.httpClient.get(
54
+ "/addons/active",
55
+ { customerId: params.customerId },
56
+ options
57
+ );
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);
99
94
  }
100
95
  };
101
96
 
@@ -104,18 +99,20 @@ var CreditPacksResource = class {
104
99
  constructor(httpClient) {
105
100
  this.httpClient = httpClient;
106
101
  }
107
- /**
108
- * List all active credit packs
109
- *
110
- * @example
111
- * ```typescript
112
- * const packs = await commet.creditPacks.list();
113
- * console.log(packs.data); // [{ id: "cp_xxx", name: "100 Credits", ... }]
114
- * ```
115
- */
116
102
  async list() {
117
103
  return this.httpClient.get("/credit-packs");
118
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
+ }
119
116
  };
120
117
 
121
118
  // src/resources/customers.ts
@@ -123,15 +120,13 @@ var CustomersResource = class {
123
120
  constructor(httpClient) {
124
121
  this.httpClient = httpClient;
125
122
  }
126
- /**
127
- * Create a customer (idempotent when id is provided)
128
- */
123
+ /** Idempotent when `id` is provided — returns existing customer instead of duplicating. */
129
124
  async create(params, options) {
130
125
  return this.httpClient.post(
131
126
  "/customers",
132
127
  {
133
128
  billingEmail: params.email,
134
- externalId: params.id,
129
+ id: params.id,
135
130
  fullName: params.fullName,
136
131
  domain: params.domain,
137
132
  website: params.website,
@@ -144,13 +139,10 @@ var CustomersResource = class {
144
139
  options
145
140
  );
146
141
  }
147
- /**
148
- * Create multiple customers in batch
149
- */
150
142
  async createBatch(params, options) {
151
143
  const customers = params.customers.map((c) => ({
152
144
  billingEmail: c.email,
153
- externalId: c.id,
145
+ id: c.id,
154
146
  fullName: c.fullName,
155
147
  domain: c.domain,
156
148
  website: c.website,
@@ -162,18 +154,12 @@ var CustomersResource = class {
162
154
  }));
163
155
  return this.httpClient.post("/customers/batch", { customers }, options);
164
156
  }
165
- /**
166
- * Get a customer by ID
167
- */
168
- async get(customerId) {
169
- return this.httpClient.get(`/customers/${customerId}`);
157
+ async get(params) {
158
+ return this.httpClient.get(`/customers/${params.id}`);
170
159
  }
171
- /**
172
- * Update a customer
173
- */
174
160
  async update(params, options) {
175
161
  return this.httpClient.put(
176
- `/customers/${params.customerId}`,
162
+ `/customers/${params.id}`,
177
163
  {
178
164
  billingEmail: params.email,
179
165
  fullName: params.fullName,
@@ -188,9 +174,6 @@ var CustomersResource = class {
188
174
  options
189
175
  );
190
176
  }
191
- /**
192
- * List customers with optional filters
193
- */
194
177
  async list(params) {
195
178
  return this.httpClient.get("/customers", params);
196
179
  }
@@ -208,34 +191,113 @@ var FeaturesResource = class {
208
191
  options
209
192
  );
210
193
  }
211
- async check(params, options) {
212
- 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(
213
197
  `/features/${params.code}`,
214
- { customerId: params.customerId },
198
+ { customerId: params.customerId, action: "canUse" },
215
199
  options
216
200
  );
217
- if (!result.success || !result.data) {
218
- return {
219
- success: false,
220
- code: result.code,
221
- message: result.message,
222
- details: result.details
223
- };
224
- }
225
- return {
226
- success: true,
227
- data: { allowed: result.data.allowed }
228
- };
229
201
  }
230
- async canUse(params, options) {
202
+ async list(params, options) {
231
203
  return this.httpClient.get(
232
- `/features/${params.code}`,
233
- { 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,
234
222
  options
235
223
  );
236
224
  }
237
- async list(customerId, options) {
238
- return this.httpClient.get("/features", { customerId }, options);
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,
291
+ options
292
+ );
293
+ }
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
+ );
239
301
  }
240
302
  };
241
303
 
@@ -244,33 +306,93 @@ var PlansResource = class {
244
306
  constructor(httpClient) {
245
307
  this.httpClient = httpClient;
246
308
  }
247
- /**
248
- * List all available plans
249
- *
250
- * @example
251
- * ```typescript
252
- * // List public plans
253
- * const plans = await commet.plans.list();
254
- *
255
- * // Include private plans
256
- * const allPlans = await commet.plans.list({ includePrivate: true });
257
- * ```
258
- */
259
309
  async list(params) {
260
310
  return this.httpClient.get("/plans", params);
261
311
  }
262
- /**
263
- * Get a specific plan by code
264
- *
265
- * @example
266
- * ```typescript
267
- * const plan = await commet.plans.get('pro');
268
- * console.log(plan.data.name); // "Pro"
269
- * console.log(plan.data.prices); // [{ billingInterval: 'monthly', price: 9900 }]
270
- * ```
271
- */
272
- async get(planCode) {
273
- 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
+ );
274
396
  }
275
397
  };
276
398
 
@@ -284,39 +406,63 @@ var PortalResource = class {
284
406
  }
285
407
  };
286
408
 
287
- // src/resources/seats.ts
288
- function resolveCode(params) {
289
- const code = params.featureCode ?? params.seatType;
290
- if (!code) {
291
- 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;
292
413
  }
293
- return code;
294
- }
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
295
430
  var SeatsResource = class {
296
431
  constructor(httpClient) {
297
432
  this.httpClient = httpClient;
298
433
  }
434
+ /** Prorates charges for the current billing period. */
299
435
  async add(params, options) {
300
- const code = resolveCode(params);
301
436
  return this.httpClient.post(
302
437
  "/seats",
303
- { customerId: params.customerId, seatType: code, count: params.count },
438
+ {
439
+ customerId: params.customerId,
440
+ featureCode: params.featureCode,
441
+ count: params.count ?? 1
442
+ },
304
443
  options
305
444
  );
306
445
  }
446
+ /** Removal takes effect at the end of the billing period. */
307
447
  async remove(params, options) {
308
- const code = resolveCode(params);
309
448
  return this.httpClient.delete(
310
449
  "/seats",
311
- { customerId: params.customerId, seatType: code, count: params.count },
450
+ {
451
+ customerId: params.customerId,
452
+ featureCode: params.featureCode,
453
+ count: params.count ?? 1
454
+ },
312
455
  options
313
456
  );
314
457
  }
315
458
  async set(params, options) {
316
- const code = resolveCode(params);
317
459
  return this.httpClient.put(
318
460
  "/seats",
319
- { customerId: params.customerId, seatType: code, count: params.count },
461
+ {
462
+ customerId: params.customerId,
463
+ featureCode: params.featureCode,
464
+ count: params.count
465
+ },
320
466
  options
321
467
  );
322
468
  }
@@ -324,10 +470,9 @@ var SeatsResource = class {
324
470
  return this.httpClient.put("/seats/bulk", params, options);
325
471
  }
326
472
  async getBalance(params) {
327
- const code = resolveCode(params);
328
473
  return this.httpClient.get("/seats/balance", {
329
474
  customerId: params.customerId,
330
- seatType: code
475
+ featureCode: params.featureCode
331
476
  });
332
477
  }
333
478
  async getAllBalances(params) {
@@ -342,67 +487,109 @@ var SubscriptionsResource = class {
342
487
  constructor(httpClient) {
343
488
  this.httpClient = httpClient;
344
489
  }
345
- /**
346
- * Create a subscription with a plan
347
- *
348
- * @example
349
- * ```typescript
350
- * await commet.subscriptions.create({
351
- * externalId: 'user_123',
352
- * planCode: 'pro', // autocomplete works after `commet pull`
353
- * billingInterval: 'yearly',
354
- * initialSeats: { editor: 5 }
355
- * });
356
- * ```
357
- */
490
+ /** Returns a `checkoutUrl` when payment is required before activation. */
358
491
  async create(params, options) {
359
492
  return this.httpClient.post("/subscriptions", params, options);
360
493
  }
361
- /**
362
- * Get the active subscription for a customer
363
- *
364
- * @example
365
- * ```typescript
366
- * const sub = await commet.subscriptions.get('user_123');
367
- * ```
368
- */
369
- async get(customerId) {
370
- return this.httpClient.get("/subscriptions/active", { customerId });
494
+ async getActive(params) {
495
+ return this.httpClient.get("/subscriptions/active", {
496
+ customerId: params.customerId
497
+ });
371
498
  }
372
- /**
373
- * Cancel a subscription
374
- *
375
- * @example
376
- * ```typescript
377
- * await commet.subscriptions.cancel({
378
- * subscriptionId: 'sub_xxx',
379
- * reason: 'switched_to_competitor'
380
- * });
381
- * ```
382
- */
499
+ /** Schedules cancellation at period end by default. Set `immediate: true` to cancel now. */
383
500
  async cancel(params, options) {
501
+ const { id, ...body } = params;
502
+ return this.httpClient.post(`/subscriptions/${id}/cancel`, body, options);
503
+ }
504
+ /** Only works on subscriptions with a pending cancellation — cannot revert already-canceled. */
505
+ async uncancel(params, options) {
384
506
  return this.httpClient.post(
385
- `/subscriptions/${params.subscriptionId}/cancel`,
386
- params || {},
507
+ `/subscriptions/${params.id}/uncancel`,
508
+ {},
387
509
  options
388
510
  );
389
511
  }
390
- /**
391
- * Revert a scheduled cancellation
392
- *
393
- * Only works on subscriptions with a pending cancellation (canceledAt is set
394
- * but status is not yet "canceled"). Cannot revert already-canceled subscriptions.
395
- *
396
- * @example
397
- * ```typescript
398
- * await commet.subscriptions.uncancel({
399
- * subscriptionId: 'sub_xxx',
400
- * });
401
- * ```
402
- */
403
- async uncancel(params, options) {
512
+ /** Upgrades execute immediately with proration. Downgrades are scheduled for end of period. */
513
+ async changePlan(params, options) {
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;
527
+ return this.httpClient.post(
528
+ `/subscriptions/${id}/preview-change`,
529
+ body,
530
+ options
531
+ );
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) {
404
583
  return this.httpClient.post(
405
- `/subscriptions/${params.subscriptionId}/uncancel`,
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`,
406
593
  {},
407
594
  options
408
595
  );
@@ -414,6 +601,7 @@ var UsageResource = class {
414
601
  constructor(httpClient) {
415
602
  this.httpClient = httpClient;
416
603
  }
604
+ /** Deducts from balance/credits if the plan uses consumption. Duplicate `idempotencyKey` is rejected. */
417
605
  async track(params, options) {
418
606
  const eventData = {
419
607
  feature: params.feature,
@@ -440,44 +628,19 @@ var UsageResource = class {
440
628
  }
441
629
  return this.httpClient.post("/usage/events", eventData, options);
442
630
  }
631
+ /** Dry-run: checks if a usage event would be allowed without actually tracking it. */
632
+ async check(params, options) {
633
+ return this.httpClient.post("/usage/check", params, options);
634
+ }
443
635
  };
444
636
 
445
637
  // src/resources/webhooks.ts
446
638
  var import_node_crypto = __toESM(require("crypto"));
447
639
  var Webhooks = class {
448
- /**
449
- * Verify HMAC-SHA256 webhook signature
450
- *
451
- * Use this method to verify that webhooks are authentically from Commet.
452
- * The signature is included in the `X-Commet-Signature` header.
453
- *
454
- * @param payload - Raw request body as string (IMPORTANT: Do not parse JSON first)
455
- * @param signature - Value from X-Commet-Signature header
456
- * @param secret - Your webhook secret from Commet dashboard
457
- * @returns true if signature is valid, false otherwise
458
- *
459
- * @example
460
- * ```typescript
461
- * // Next.js API route example
462
- * export async function POST(request: Request) {
463
- * const rawBody = await request.text();
464
- * const signature = request.headers.get('x-commet-signature');
465
- *
466
- * const isValid = commet.webhooks.verify(
467
- * rawBody,
468
- * signature,
469
- * process.env.COMMET_WEBHOOK_SECRET
470
- * );
471
- *
472
- * if (!isValid) {
473
- * return new Response('Invalid signature', { status: 401 });
474
- * }
475
- *
476
- * const payload = JSON.parse(rawBody);
477
- * // Handle webhook event...
478
- * }
479
- * ```
480
- */
640
+ constructor(httpClient) {
641
+ this.httpClient = httpClient;
642
+ }
643
+ /** HMAC-SHA256 verification. Payload must be the raw request body string, not parsed JSON. */
481
644
  verify(params) {
482
645
  const { payload, signature, secret } = params;
483
646
  if (!signature || !secret || !payload) {
@@ -493,35 +656,11 @@ var Webhooks = class {
493
656
  return false;
494
657
  }
495
658
  }
496
- /**
497
- * Generate HMAC-SHA256 signature (internal use)
498
- * @internal
499
- */
500
659
  generateSignature(params) {
501
660
  const { payload, secret } = params;
502
661
  return import_node_crypto.default.createHmac("sha256", secret).update(payload).digest("hex");
503
662
  }
504
- /**
505
- * Parse and verify webhook payload in one step
506
- *
507
- * @example
508
- * ```typescript
509
- * const payload = commet.webhooks.verifyAndParse({
510
- * rawBody,
511
- * signature,
512
- * secret: process.env.COMMET_WEBHOOK_SECRET
513
- * });
514
- *
515
- * if (!payload) {
516
- * return new Response('Invalid signature', { status: 401 });
517
- * }
518
- *
519
- * // payload is typed and validated
520
- * if (payload.event === 'subscription.activated') {
521
- * // Handle activation...
522
- * }
523
- * ```
524
- */
663
+ /** Verifies signature and parses JSON in one step. Returns null if invalid. */
525
664
  verifyAndParse(params) {
526
665
  const { rawBody, signature, secret } = params;
527
666
  if (!this.verify({ payload: rawBody, signature, secret })) {
@@ -533,6 +672,21 @@ var Webhooks = class {
533
672
  return null;
534
673
  }
535
674
  }
675
+ async list(params, options) {
676
+ return this.httpClient.get("/webhooks", params, options);
677
+ }
678
+ /** Response includes `secretKey` which is only returned once. */
679
+ async create(params, options) {
680
+ return this.httpClient.post("/webhooks", params, options);
681
+ }
682
+ async delete(params, options) {
683
+ const { id } = params;
684
+ return this.httpClient.delete(`/webhooks/${id}`, void 0, options);
685
+ }
686
+ async test(params, options) {
687
+ const { id } = params;
688
+ return this.httpClient.post(`/webhooks/${id}/test`, void 0, options);
689
+ }
536
690
  };
537
691
 
538
692
  // src/types/common.ts
@@ -546,12 +700,15 @@ var CommetError = class extends Error {
546
700
  }
547
701
  };
548
702
  var CommetAPIError = class extends CommetError {
549
- constructor(message, statusCode, code, details) {
703
+ constructor(message, statusCode, code, details, errorDetail) {
550
704
  super(message, code, statusCode, details);
551
705
  this.statusCode = statusCode;
552
706
  this.code = code;
553
707
  this.details = details;
554
708
  this.name = "CommetAPIError";
709
+ this.type = errorDetail?.type;
710
+ this.param = errorDetail?.param;
711
+ this.docUrl = errorDetail?.doc_url;
555
712
  }
556
713
  };
557
714
  var CommetValidationError = class extends CommetError {
@@ -563,8 +720,8 @@ var CommetValidationError = class extends CommetError {
563
720
  };
564
721
 
565
722
  // src/version.ts
566
- var API_VERSION = "2026-05-18";
567
- var SDK_VERSION = "4.5.0";
723
+ var API_VERSION = "2026-05-25";
724
+ var SDK_VERSION = "5.0.0";
568
725
 
569
726
  // src/utils/telemetry.ts
570
727
  var registeredIntegrations = /* @__PURE__ */ new Set();
@@ -628,7 +785,7 @@ var DEFAULT_RETRY_CONFIG = {
628
785
  // 8s
629
786
  retryableStatusCodes: [408, 429, 500, 502, 503, 504]
630
787
  };
631
- var CommetHTTPClient = class {
788
+ var _CommetHTTPClient = class _CommetHTTPClient {
632
789
  constructor(config) {
633
790
  this.lastRequestMetrics = null;
634
791
  this.config = config;
@@ -639,7 +796,13 @@ var CommetHTTPClient = class {
639
796
  };
640
797
  }
641
798
  async get(endpoint, params, options) {
642
- return this.request("GET", endpoint, void 0, options, params);
799
+ return this.request(
800
+ "GET",
801
+ endpoint,
802
+ void 0,
803
+ options,
804
+ params
805
+ );
643
806
  }
644
807
  async post(endpoint, data, options) {
645
808
  return this.request("POST", endpoint, data, options);
@@ -655,6 +818,9 @@ var CommetHTTPClient = class {
655
818
  }
656
819
  async request(method, endpoint, data, options, params) {
657
820
  const url = this.buildURL(endpoint, params);
821
+ if (_CommetHTTPClient.BODY_METHODS.has(method) && this.retryConfig.maxRetries > 0 && !options?.idempotencyKey) {
822
+ options = { ...options, idempotencyKey: this.generateIdempotencyKey() };
823
+ }
658
824
  return this.executeRequest(method, url, data, options);
659
825
  }
660
826
  /**
@@ -680,8 +846,6 @@ var CommetHTTPClient = class {
680
846
  }
681
847
  if (options?.idempotencyKey) {
682
848
  headers["Idempotency-Key"] = options.idempotencyKey;
683
- } else if (method === "POST" && data) {
684
- headers["Idempotency-Key"] = this.generateIdempotencyKey();
685
849
  }
686
850
  const requestConfig = {
687
851
  method,
@@ -750,26 +914,30 @@ var CommetHTTPClient = class {
750
914
  JSON.stringify(responseData, null, 2)
751
915
  );
752
916
  }
753
- const isErrorResponse = (data2) => {
754
- return typeof data2 === "object" && data2 !== null;
917
+ const parsed = typeof responseData === "object" && responseData !== null ? responseData : {};
918
+ const errorObj = typeof parsed.error === "object" && parsed.error !== null ? parsed.error : {};
919
+ const errorDetail = {
920
+ type: errorObj.type ?? "api_error",
921
+ code: errorObj.code ?? "unknown",
922
+ message: errorObj.message ?? `Request failed with status ${response.status}`,
923
+ param: errorObj.param,
924
+ details: errorObj.details,
925
+ doc_url: errorObj.doc_url
755
926
  };
756
- const errorData = isErrorResponse(responseData) ? responseData : {};
757
- if (errorData.code === "validation_error" && Array.isArray(errorData.details)) {
927
+ if (errorDetail.code === "validation_error" && Array.isArray(errorDetail.details)) {
758
928
  const errors = {};
759
- for (const detail of errorData.details) {
929
+ for (const detail of errorDetail.details) {
760
930
  if (!errors[detail.field]) errors[detail.field] = [];
761
931
  errors[detail.field].push(detail.message);
762
932
  }
763
- throw new CommetValidationError(
764
- errorData.message || "Validation failed",
765
- errors
766
- );
933
+ throw new CommetValidationError(errorDetail.message, errors);
767
934
  }
768
935
  throw new CommetAPIError(
769
- errorData.message || `Request failed with status ${response.status}`,
936
+ errorDetail.message,
770
937
  response.status,
771
- errorData.code,
772
- errorData.details
938
+ errorDetail.code,
939
+ errorDetail.details,
940
+ errorDetail
773
941
  );
774
942
  }
775
943
  if (this.config.debug) {
@@ -827,11 +995,8 @@ var CommetHTTPClient = class {
827
995
  }
828
996
  return finalUrl;
829
997
  }
830
- /**
831
- * Generate idempotency key
832
- */
833
998
  generateIdempotencyKey() {
834
- return `sdk_${Date.now()}_${Math.random().toString(36).substring(2)}`;
999
+ return `commet-node-retry-${crypto.randomUUID()}`;
835
1000
  }
836
1001
  /**
837
1002
  * Sleep for specified milliseconds
@@ -840,6 +1005,8 @@ var CommetHTTPClient = class {
840
1005
  return new Promise((resolve) => setTimeout(resolve, ms));
841
1006
  }
842
1007
  };
1008
+ _CommetHTTPClient.BODY_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH"]);
1009
+ var CommetHTTPClient = _CommetHTTPClient;
843
1010
 
844
1011
  // src/client.ts
845
1012
  var Commet = class {
@@ -853,41 +1020,21 @@ var Commet = class {
853
1020
  );
854
1021
  }
855
1022
  this.httpClient = new CommetHTTPClient(config);
856
- this.customers = new CustomersResource(this.httpClient);
1023
+ this.addons = new AddonsResource(this.httpClient);
1024
+ this.apiKeys = new ApiKeysResource(this.httpClient);
857
1025
  this.creditPacks = new CreditPacksResource(this.httpClient);
1026
+ this.customers = new CustomersResource(this.httpClient);
1027
+ this.features = new FeaturesResource(this.httpClient);
1028
+ this.invoices = new InvoicesResource(this.httpClient);
1029
+ this.planGroups = new PlanGroupsResource(this.httpClient);
858
1030
  this.plans = new PlansResource(this.httpClient);
859
- this.usage = new UsageResource(this.httpClient);
1031
+ this.portal = new PortalResource(this.httpClient);
1032
+ this.promoCodes = new PromoCodesResource(this.httpClient);
860
1033
  this.seats = new SeatsResource(this.httpClient);
861
1034
  this.subscriptions = new SubscriptionsResource(this.httpClient);
862
- this.portal = new PortalResource(this.httpClient);
863
- this.features = new FeaturesResource(this.httpClient);
864
- this.webhooks = new Webhooks();
865
- if (config.debug) {
866
- console.log("[Commet SDK] Initialized");
867
- console.log("API Key:", `${config.apiKey.substring(0, 12)}...`);
868
- }
869
- }
870
- /**
871
- * Create a customer-scoped context for cleaner API usage
872
- *
873
- * @example
874
- * ```typescript
875
- * const customer = commet.customer("user_123");
876
- *
877
- * // All operations are now scoped to this customer
878
- * const seats = await customer.features.get("team_members");
879
- * await customer.seats.add("member");
880
- * await customer.usage.track("api_call");
881
- * ```
882
- */
883
- customer(customerId) {
884
- return new CustomerContext(customerId, {
885
- features: this.features,
886
- seats: this.seats,
887
- usage: this.usage,
888
- subscriptions: this.subscriptions,
889
- portal: this.portal
890
- });
1035
+ this.transactions = new TransactionsResource(this.httpClient);
1036
+ this.usage = new UsageResource(this.httpClient);
1037
+ this.webhooks = new Webhooks(this.httpClient);
891
1038
  }
892
1039
  };
893
1040
  function createCommet(_billingConfig, options) {
@@ -908,7 +1055,6 @@ var index_default = Commet;
908
1055
  CommetAPIError,
909
1056
  CommetError,
910
1057
  CommetValidationError,
911
- CustomerContext,
912
1058
  SDK_VERSION,
913
1059
  Webhooks,
914
1060
  createCommet,