@commet/next 1.0.11 → 1.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.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
- import { BillingInterval, WebhookPayload } from '@commet/node';
2
+ import { BillingInterval, WebhookEvent, WebhookEventPayload } from '@commet/node';
3
3
  export { WebhookData, WebhookEvent, WebhookPayload } from '@commet/node';
4
4
 
5
5
  interface CustomerPortalConfig {
@@ -50,10 +50,26 @@ interface PricingMarkdownConfig {
50
50
  }
51
51
  declare const PricingMarkdown: ({ apiKey, title, description, includeCreditPacks, billingIntervals, cacheMaxAge, onError, }: PricingMarkdownConfig) => (_req: NextRequest) => Promise<NextResponse<unknown>>;
52
52
 
53
+ type PascalCaseEventSegment<S extends string> = S extends `${infer Head}_${infer Tail}` ? `${Capitalize<Head>}${PascalCaseEventSegment<Tail>}` : Capitalize<S>;
54
+ type PascalCaseEventName<S extends string> = S extends `${infer Head}.${infer Tail}` ? `${PascalCaseEventSegment<Head>}${PascalCaseEventName<Tail>}` : PascalCaseEventSegment<S>;
55
+ type WebhookPayloadFor<E extends WebhookEvent> = Extract<WebhookEventPayload, {
56
+ event: E;
57
+ }>;
58
+ type WebhookHandler<E extends WebhookEvent> = (payload: WebhookPayloadFor<E>) => Promise<void>;
59
+ type WebhookHandlerName<E extends WebhookEvent = WebhookEvent> = `on${PascalCaseEventName<E>}`;
60
+ /**
61
+ * Named callbacks for every Commet webhook event.
62
+ *
63
+ * Event names become callback names by removing dots/underscores and applying PascalCase:
64
+ * `payment_link.completed` -> `onPaymentLinkCompleted`.
65
+ */
66
+ type WebhookNamedHandlers = {
67
+ [E in WebhookEvent as WebhookHandlerName<E>]?: WebhookHandler<E>;
68
+ };
53
69
  /**
54
70
  * Configuration for the Commet webhook handler
55
71
  */
56
- interface WebhooksConfig {
72
+ interface WebhooksConfig extends WebhookNamedHandlers {
57
73
  /**
58
74
  * Webhook secret from your Commet dashboard
59
75
  * Used to verify webhook signatures
@@ -76,7 +92,7 @@ interface WebhooksConfig {
76
92
  * }
77
93
  * ```
78
94
  */
79
- onSubscriptionActivated?: (payload: WebhookPayload) => Promise<void>;
95
+ onSubscriptionActivated?: WebhookHandler<"subscription.activated">;
80
96
  /**
81
97
  * Handles the `subscription.canceled` webhook event
82
98
  *
@@ -94,7 +110,7 @@ interface WebhooksConfig {
94
110
  * }
95
111
  * ```
96
112
  */
97
- onSubscriptionCanceled?: (payload: WebhookPayload) => Promise<void>;
113
+ onSubscriptionCanceled?: WebhookHandler<"subscription.canceled">;
98
114
  /**
99
115
  * Handles the `subscription.created` webhook event
100
116
  *
@@ -110,7 +126,7 @@ interface WebhooksConfig {
110
126
  * }
111
127
  * ```
112
128
  */
113
- onSubscriptionCreated?: (payload: WebhookPayload) => Promise<void>;
129
+ onSubscriptionCreated?: WebhookHandler<"subscription.created">;
114
130
  /**
115
131
  * Handles the `subscription.updated` webhook event
116
132
  *
@@ -128,7 +144,7 @@ interface WebhooksConfig {
128
144
  * }
129
145
  * ```
130
146
  */
131
- onSubscriptionUpdated?: (payload: WebhookPayload) => Promise<void>;
147
+ onSubscriptionUpdated?: WebhookHandler<"subscription.updated">;
132
148
  /**
133
149
  * Handles the `subscription.plan_changed` webhook event
134
150
  *
@@ -146,7 +162,13 @@ interface WebhooksConfig {
146
162
  * }
147
163
  * ```
148
164
  */
149
- onSubscriptionPlanChanged?: (payload: WebhookPayload) => Promise<void>;
165
+ onSubscriptionPlanChanged?: WebhookHandler<"subscription.plan_changed">;
166
+ /**
167
+ * Handles the `customer.state_changed` webhook event
168
+ *
169
+ * Fired whenever a customer's billing state snapshot changes.
170
+ */
171
+ onCustomerStateChanged?: WebhookHandler<"customer.state_changed">;
150
172
  /**
151
173
  * Handles the `payment.received` webhook event
152
174
  *
@@ -154,7 +176,13 @@ interface WebhooksConfig {
154
176
  *
155
177
  * @param payload - The webhook payload containing payment data
156
178
  */
157
- onPaymentReceived?: (payload: WebhookPayload) => Promise<void>;
179
+ onPaymentReceived?: WebhookHandler<"payment.received">;
180
+ /**
181
+ * Handles the `payment.recovered` webhook event
182
+ *
183
+ * Fired when a previously failed payment succeeds.
184
+ */
185
+ onPaymentRecovered?: WebhookHandler<"payment.recovered">;
158
186
  /**
159
187
  * Handles the `payment.failed` webhook event
160
188
  *
@@ -163,7 +191,13 @@ interface WebhooksConfig {
163
191
  *
164
192
  * @param payload - The webhook payload containing payment data
165
193
  */
166
- onPaymentFailed?: (payload: WebhookPayload) => Promise<void>;
194
+ onPaymentFailed?: WebhookHandler<"payment.failed">;
195
+ /**
196
+ * Handles the `usage.recorded` webhook event
197
+ *
198
+ * Fired after usage is recorded for a customer feature.
199
+ */
200
+ onUsageRecorded?: WebhookHandler<"usage.recorded">;
167
201
  /**
168
202
  * Handles the `invoice.created` webhook event
169
203
  *
@@ -171,7 +205,7 @@ interface WebhooksConfig {
171
205
  *
172
206
  * @param payload - The webhook payload containing invoice data
173
207
  */
174
- onInvoiceCreated?: (payload: WebhookPayload) => Promise<void>;
208
+ onInvoiceCreated?: WebhookHandler<"invoice.created">;
175
209
  /**
176
210
  * Catch-all handler that receives all webhook events
177
211
  *
@@ -188,7 +222,7 @@ interface WebhooksConfig {
188
222
  * }
189
223
  * ```
190
224
  */
191
- onPayload?: (payload: WebhookPayload) => Promise<void>;
225
+ onPayload?: (payload: WebhookEventPayload) => Promise<void>;
192
226
  /**
193
227
  * Error handler for webhook processing failures
194
228
  *
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
- import { BillingInterval, WebhookPayload } from '@commet/node';
2
+ import { BillingInterval, WebhookEvent, WebhookEventPayload } from '@commet/node';
3
3
  export { WebhookData, WebhookEvent, WebhookPayload } from '@commet/node';
4
4
 
5
5
  interface CustomerPortalConfig {
@@ -50,10 +50,26 @@ interface PricingMarkdownConfig {
50
50
  }
51
51
  declare const PricingMarkdown: ({ apiKey, title, description, includeCreditPacks, billingIntervals, cacheMaxAge, onError, }: PricingMarkdownConfig) => (_req: NextRequest) => Promise<NextResponse<unknown>>;
52
52
 
53
+ type PascalCaseEventSegment<S extends string> = S extends `${infer Head}_${infer Tail}` ? `${Capitalize<Head>}${PascalCaseEventSegment<Tail>}` : Capitalize<S>;
54
+ type PascalCaseEventName<S extends string> = S extends `${infer Head}.${infer Tail}` ? `${PascalCaseEventSegment<Head>}${PascalCaseEventName<Tail>}` : PascalCaseEventSegment<S>;
55
+ type WebhookPayloadFor<E extends WebhookEvent> = Extract<WebhookEventPayload, {
56
+ event: E;
57
+ }>;
58
+ type WebhookHandler<E extends WebhookEvent> = (payload: WebhookPayloadFor<E>) => Promise<void>;
59
+ type WebhookHandlerName<E extends WebhookEvent = WebhookEvent> = `on${PascalCaseEventName<E>}`;
60
+ /**
61
+ * Named callbacks for every Commet webhook event.
62
+ *
63
+ * Event names become callback names by removing dots/underscores and applying PascalCase:
64
+ * `payment_link.completed` -> `onPaymentLinkCompleted`.
65
+ */
66
+ type WebhookNamedHandlers = {
67
+ [E in WebhookEvent as WebhookHandlerName<E>]?: WebhookHandler<E>;
68
+ };
53
69
  /**
54
70
  * Configuration for the Commet webhook handler
55
71
  */
56
- interface WebhooksConfig {
72
+ interface WebhooksConfig extends WebhookNamedHandlers {
57
73
  /**
58
74
  * Webhook secret from your Commet dashboard
59
75
  * Used to verify webhook signatures
@@ -76,7 +92,7 @@ interface WebhooksConfig {
76
92
  * }
77
93
  * ```
78
94
  */
79
- onSubscriptionActivated?: (payload: WebhookPayload) => Promise<void>;
95
+ onSubscriptionActivated?: WebhookHandler<"subscription.activated">;
80
96
  /**
81
97
  * Handles the `subscription.canceled` webhook event
82
98
  *
@@ -94,7 +110,7 @@ interface WebhooksConfig {
94
110
  * }
95
111
  * ```
96
112
  */
97
- onSubscriptionCanceled?: (payload: WebhookPayload) => Promise<void>;
113
+ onSubscriptionCanceled?: WebhookHandler<"subscription.canceled">;
98
114
  /**
99
115
  * Handles the `subscription.created` webhook event
100
116
  *
@@ -110,7 +126,7 @@ interface WebhooksConfig {
110
126
  * }
111
127
  * ```
112
128
  */
113
- onSubscriptionCreated?: (payload: WebhookPayload) => Promise<void>;
129
+ onSubscriptionCreated?: WebhookHandler<"subscription.created">;
114
130
  /**
115
131
  * Handles the `subscription.updated` webhook event
116
132
  *
@@ -128,7 +144,7 @@ interface WebhooksConfig {
128
144
  * }
129
145
  * ```
130
146
  */
131
- onSubscriptionUpdated?: (payload: WebhookPayload) => Promise<void>;
147
+ onSubscriptionUpdated?: WebhookHandler<"subscription.updated">;
132
148
  /**
133
149
  * Handles the `subscription.plan_changed` webhook event
134
150
  *
@@ -146,7 +162,13 @@ interface WebhooksConfig {
146
162
  * }
147
163
  * ```
148
164
  */
149
- onSubscriptionPlanChanged?: (payload: WebhookPayload) => Promise<void>;
165
+ onSubscriptionPlanChanged?: WebhookHandler<"subscription.plan_changed">;
166
+ /**
167
+ * Handles the `customer.state_changed` webhook event
168
+ *
169
+ * Fired whenever a customer's billing state snapshot changes.
170
+ */
171
+ onCustomerStateChanged?: WebhookHandler<"customer.state_changed">;
150
172
  /**
151
173
  * Handles the `payment.received` webhook event
152
174
  *
@@ -154,7 +176,13 @@ interface WebhooksConfig {
154
176
  *
155
177
  * @param payload - The webhook payload containing payment data
156
178
  */
157
- onPaymentReceived?: (payload: WebhookPayload) => Promise<void>;
179
+ onPaymentReceived?: WebhookHandler<"payment.received">;
180
+ /**
181
+ * Handles the `payment.recovered` webhook event
182
+ *
183
+ * Fired when a previously failed payment succeeds.
184
+ */
185
+ onPaymentRecovered?: WebhookHandler<"payment.recovered">;
158
186
  /**
159
187
  * Handles the `payment.failed` webhook event
160
188
  *
@@ -163,7 +191,13 @@ interface WebhooksConfig {
163
191
  *
164
192
  * @param payload - The webhook payload containing payment data
165
193
  */
166
- onPaymentFailed?: (payload: WebhookPayload) => Promise<void>;
194
+ onPaymentFailed?: WebhookHandler<"payment.failed">;
195
+ /**
196
+ * Handles the `usage.recorded` webhook event
197
+ *
198
+ * Fired after usage is recorded for a customer feature.
199
+ */
200
+ onUsageRecorded?: WebhookHandler<"usage.recorded">;
167
201
  /**
168
202
  * Handles the `invoice.created` webhook event
169
203
  *
@@ -171,7 +205,7 @@ interface WebhooksConfig {
171
205
  *
172
206
  * @param payload - The webhook payload containing invoice data
173
207
  */
174
- onInvoiceCreated?: (payload: WebhookPayload) => Promise<void>;
208
+ onInvoiceCreated?: WebhookHandler<"invoice.created">;
175
209
  /**
176
210
  * Catch-all handler that receives all webhook events
177
211
  *
@@ -188,7 +222,7 @@ interface WebhooksConfig {
188
222
  * }
189
223
  * ```
190
224
  */
191
- onPayload?: (payload: WebhookPayload) => Promise<void>;
225
+ onPayload?: (payload: WebhookEventPayload) => Promise<void>;
192
226
  /**
193
227
  * Error handler for webhook processing failures
194
228
  *
package/dist/index.js CHANGED
@@ -310,20 +310,66 @@ function formatNumber(n) {
310
310
  // src/webhooks.ts
311
311
  var import_node3 = require("@commet/node");
312
312
  var import_server3 = require("next/server");
313
+ var webhookEventHandlerNames = {
314
+ "subscription.created": "onSubscriptionCreated",
315
+ "subscription.activated": "onSubscriptionActivated",
316
+ "subscription.reactivated": "onSubscriptionReactivated",
317
+ "subscription.canceled": "onSubscriptionCanceled",
318
+ "subscription.updated": "onSubscriptionUpdated",
319
+ "subscription.plan_changed": "onSubscriptionPlanChanged",
320
+ "subscription.cancellation_scheduled": "onSubscriptionCancellationScheduled",
321
+ "subscription.cancellation_revoked": "onSubscriptionCancellationRevoked",
322
+ "subscription.plan_change_scheduled": "onSubscriptionPlanChangeScheduled",
323
+ "subscription.plan_change_revoked": "onSubscriptionPlanChangeRevoked",
324
+ "subscription.past_due": "onSubscriptionPastDue",
325
+ "trial.started": "onTrialStarted",
326
+ "trial.converted": "onTrialConverted",
327
+ "trial.expired": "onTrialExpired",
328
+ "trial.will_end": "onTrialWillEnd",
329
+ "trial.checkout_ready": "onTrialCheckoutReady",
330
+ "checkout.ready": "onCheckoutReady",
331
+ "payment.received": "onPaymentReceived",
332
+ "payment.failed": "onPaymentFailed",
333
+ "payment.recovered": "onPaymentRecovered",
334
+ "payment.retry_failed": "onPaymentRetryFailed",
335
+ "payment.refunded": "onPaymentRefunded",
336
+ "payment.disputed": "onPaymentDisputed",
337
+ "payment.dispute_resolved": "onPaymentDisputeResolved",
338
+ "payment_link.created": "onPaymentLinkCreated",
339
+ "payment_link.completed": "onPaymentLinkCompleted",
340
+ "payment_link.failed": "onPaymentLinkFailed",
341
+ "payment_link.canceled": "onPaymentLinkCanceled",
342
+ "invoice.created": "onInvoiceCreated",
343
+ "invoice.upcoming": "onInvoiceUpcoming",
344
+ "invoice.overdue": "onInvoiceOverdue",
345
+ "invoice.voided": "onInvoiceVoided",
346
+ "payment_method.attached": "onPaymentMethodAttached",
347
+ "payment_method.updated": "onPaymentMethodUpdated",
348
+ "customer.created": "onCustomerCreated",
349
+ "customer.updated": "onCustomerUpdated",
350
+ "customer.state_changed": "onCustomerStateChanged",
351
+ "credits.granted": "onCreditsGranted",
352
+ "credits.purchased": "onCreditsPurchased",
353
+ "credits.low": "onCreditsLow",
354
+ "credits.depleted": "onCreditsDepleted",
355
+ "credits.expired": "onCreditsExpired",
356
+ "balance.topped_up": "onBalanceToppedUp",
357
+ "balance.low": "onBalanceLow",
358
+ "balance.depleted": "onBalanceDepleted",
359
+ "quota.threshold_reached": "onQuotaThresholdReached",
360
+ "quota.exceeded": "onQuotaExceeded",
361
+ "usage.recorded": "onUsageRecorded",
362
+ "seats.updated": "onSeatsUpdated",
363
+ "seats.limit_reached": "onSeatsLimitReached",
364
+ "addon.activated": "onAddonActivated",
365
+ "addon.deactivated": "onAddonDeactivated",
366
+ "payout.available": "onPayoutAvailable",
367
+ "payout.created": "onPayoutCreated",
368
+ "payout.paid": "onPayoutPaid",
369
+ "payout.failed": "onPayoutFailed"
370
+ };
313
371
  var Webhooks = (config) => {
314
- const {
315
- webhookSecret,
316
- onSubscriptionActivated,
317
- onSubscriptionCanceled,
318
- onSubscriptionCreated,
319
- onSubscriptionUpdated,
320
- onSubscriptionPlanChanged,
321
- onPaymentReceived,
322
- onPaymentFailed,
323
- onInvoiceCreated,
324
- onPayload,
325
- onError
326
- } = config;
372
+ const { webhookSecret, onPayload, onError } = config;
327
373
  const webhooks = new import_node3.Webhooks();
328
374
  return async (request) => {
329
375
  try {
@@ -361,49 +407,10 @@ var Webhooks = (config) => {
361
407
  if (onPayload) {
362
408
  promises.push(onPayload(payload));
363
409
  }
364
- switch (payload.event) {
365
- case "subscription.activated":
366
- if (onSubscriptionActivated) {
367
- promises.push(onSubscriptionActivated(payload));
368
- }
369
- break;
370
- case "subscription.canceled":
371
- if (onSubscriptionCanceled) {
372
- promises.push(onSubscriptionCanceled(payload));
373
- }
374
- break;
375
- case "subscription.created":
376
- if (onSubscriptionCreated) {
377
- promises.push(onSubscriptionCreated(payload));
378
- }
379
- break;
380
- case "subscription.updated":
381
- if (onSubscriptionUpdated) {
382
- promises.push(onSubscriptionUpdated(payload));
383
- }
384
- break;
385
- case "subscription.plan_changed":
386
- if (onSubscriptionPlanChanged) {
387
- promises.push(onSubscriptionPlanChanged(payload));
388
- }
389
- break;
390
- case "payment.received":
391
- if (onPaymentReceived) {
392
- promises.push(onPaymentReceived(payload));
393
- }
394
- break;
395
- case "payment.failed":
396
- if (onPaymentFailed) {
397
- promises.push(onPaymentFailed(payload));
398
- }
399
- break;
400
- case "invoice.created":
401
- if (onInvoiceCreated) {
402
- promises.push(onInvoiceCreated(payload));
403
- }
404
- break;
405
- default:
406
- console.log(`[Commet Webhook] Unhandled event: ${payload.event}`);
410
+ const handlerName = webhookEventHandlerNames[payload.event];
411
+ const handler = config[handlerName];
412
+ if (handler) {
413
+ promises.push(handler(payload));
407
414
  }
408
415
  try {
409
416
  await Promise.all(promises);
@@ -419,8 +426,8 @@ var Webhooks = (config) => {
419
426
  );
420
427
  }
421
428
  return import_server3.NextResponse.json(
422
- { received: true, warning: "Handler failed" },
423
- { status: 200 }
429
+ { received: false, error: "Handler failed" },
430
+ { status: 500 }
424
431
  );
425
432
  }
426
433
  return import_server3.NextResponse.json({ received: true }, { status: 200 });
@@ -448,7 +455,7 @@ var Webhooks = (config) => {
448
455
  };
449
456
 
450
457
  // src/index.ts
451
- (0, import_node4.registerIntegration)("@commet/next", "1.0.11");
458
+ (0, import_node4.registerIntegration)("@commet/next", "1.1.0");
452
459
  // Annotate the CommonJS export names for ESM import in node:
453
460
  0 && (module.exports = {
454
461
  CustomerPortal,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/portal.ts","../src/pricing-markdown.ts","../src/webhooks.ts"],"sourcesContent":["/**\n * @commet/next - Next.js integration for Commet\n *\n * @example\n * Webhooks\n * ```typescript\n * import { Webhooks } from \"@commet/next\";\n *\n * export const POST = Webhooks({\n * webhookSecret: process.env.COMMET_WEBHOOK_SECRET!,\n * onSubscriptionActivated: async (payload) => {\n * // Handle activation\n * },\n * });\n * ```\n *\n * @example\n * Customer Portal\n * ```typescript\n * import { CustomerPortal } from \"@commet/next\";\n *\n * export const GET = CustomerPortal({\n * apiKey: process.env.COMMET_API_KEY!,\n * getCustomerId: async (req) => {\n * const session = await auth.api.getSession({ headers: req.headers });\n * return session?.user.id;\n * },\n * });\n * ```\n *\n * @packageDocumentation\n */\n\nimport { registerIntegration } from \"@commet/node\";\n\ndeclare const __PKG_VERSION__: string;\nregisterIntegration(\"@commet/next\", __PKG_VERSION__);\n\nexport type { CustomerPortalConfig } from \"./portal\";\nexport { CustomerPortal } from \"./portal\";\nexport type { PricingMarkdownConfig } from \"./pricing-markdown\";\nexport { PricingMarkdown } from \"./pricing-markdown\";\nexport type {\n WebhookData,\n WebhookEvent,\n WebhookPayload,\n WebhooksConfig,\n} from \"./types\";\nexport { Webhooks } from \"./webhooks\";\n","import { Commet } from \"@commet/node\";\nimport { type NextRequest, NextResponse } from \"next/server\";\n\nexport interface CustomerPortalConfig {\n apiKey: string;\n getCustomerId: (req: NextRequest) => Promise<string | null>;\n onError?: (error: Error) => void;\n}\n\n/**\n * Creates Next.js route handler for Customer Portal access\n *\n * @example\n * ```typescript\n * // app/api/commet/portal/route.ts\n * import { CustomerPortal } from \"@commet/next\";\n * import { auth } from \"@/lib/auth\";\n *\n * export const GET = CustomerPortal({\n * apiKey: process.env.COMMET_API_KEY!,\n * getCustomerId: async (req) => {\n * const session = await auth.api.getSession({ headers: req.headers });\n * return session?.user.id ?? null;\n * },\n * });\n * ```\n *\n * @example\n * ```tsx\n * // Use in component\n * export function BillingButton() {\n * return (\n * <Button asChild>\n * <Link href=\"/api/commet/portal\">Manage Billing</Link>\n * </Button>\n * );\n * }\n * ```\n */\nexport const CustomerPortal = ({\n apiKey,\n getCustomerId,\n onError,\n}: CustomerPortalConfig) => {\n const commet = new Commet({\n apiKey,\n });\n\n return async (req: NextRequest) => {\n try {\n // Get customer identifier from request\n const customerId = await getCustomerId(req);\n\n if (!customerId) {\n return NextResponse.json(\n { error: \"Customer not authenticated\" },\n { status: 401 },\n );\n }\n\n // Get portal URL from Commet\n const result = await commet.portal.getUrl({\n customerId,\n });\n\n if (!result.success || !result.data) {\n throw new Error(\n result.error?.message || \"Failed to create portal session\",\n );\n }\n\n // Redirect to customer portal\n return NextResponse.redirect(result.data.portalUrl);\n } catch (error) {\n const errorObj =\n error instanceof Error ? error : new Error(String(error));\n\n // Call custom error handler if provided\n onError?.(errorObj);\n\n // Log error\n console.error(\"[Commet Portal]\", errorObj);\n\n // Return error response\n return NextResponse.json(\n { error: \"Failed to access customer portal\" },\n { status: 500 },\n );\n }\n };\n};\n","import type { BillingInterval, CreditPack, Plan } from \"@commet/node\";\nimport { Commet } from \"@commet/node\";\nimport { type NextRequest, NextResponse } from \"next/server\";\n\ntype PlanFeature = NonNullable<Plan[\"features\"]>[number];\n\nexport interface PricingMarkdownConfig {\n apiKey: string;\n title: string;\n description?: string;\n includeCreditPacks?: boolean;\n billingIntervals?: BillingInterval[];\n cacheMaxAge?: number;\n onError?: (error: Error) => void;\n}\n\nconst INTERVAL_SHORT: Record<BillingInterval, string> = {\n weekly: \"/wk\",\n monthly: \"/mo\",\n quarterly: \"/qtr\",\n yearly: \"/yr\",\n one_time: \"\",\n};\n\nexport const PricingMarkdown = ({\n apiKey,\n title,\n description,\n includeCreditPacks = false,\n billingIntervals,\n cacheMaxAge = 3600,\n onError,\n}: PricingMarkdownConfig) => {\n const commet = new Commet({ apiKey });\n\n return async (_req: NextRequest) => {\n try {\n const plansResult = await commet.plans.list();\n\n if (!plansResult.success || !plansResult.data) {\n throw new Error(plansResult.error?.message ?? \"Failed to fetch plans\");\n }\n\n const publicPlans = plansResult.data.filter((plan) => plan.isPublic);\n\n const creditPacks = includeCreditPacks\n ? await commet.creditPacks\n .list()\n .then((result) =>\n result.success && result.data ? result.data : [],\n )\n : [];\n\n const markdown = generateMarkdown(\n title,\n description,\n publicPlans,\n creditPacks,\n billingIntervals,\n );\n\n return new NextResponse(markdown, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/markdown; charset=utf-8\",\n \"Cache-Control\": `public, s-maxage=${cacheMaxAge}, stale-while-revalidate=${cacheMaxAge * 2}`,\n },\n });\n } catch (error) {\n const errorObj =\n error instanceof Error ? error : new Error(String(error));\n\n onError?.(errorObj);\n console.error(\"[Commet PricingMarkdown]\", errorObj);\n\n return NextResponse.json(\n { error: \"Failed to generate pricing markdown\" },\n { status: 500 },\n );\n }\n };\n};\n\nfunction generateMarkdown(\n title: string,\n description: string | undefined,\n plans: Plan[],\n creditPacks: CreditPack[],\n billingIntervals?: BillingInterval[],\n): string {\n const sections: string[] = [`# ${title}`];\n\n if (description) {\n sections.push(description);\n }\n\n if (plans.length > 0) {\n sections.push(renderPlansTable(plans, billingIntervals));\n\n const featuresSection = renderFeatures(plans);\n if (featuresSection) {\n sections.push(featuresSection);\n }\n }\n\n if (creditPacks.length > 0) {\n sections.push(renderCreditPacks(creditPacks));\n }\n\n return sections.join(\"\\n\\n\");\n}\n\nfunction renderPlansTable(\n plans: Plan[],\n filterIntervals?: BillingInterval[],\n): string {\n const usageFeatures = collectUsageFeatures(plans);\n\n const headerCols = [\"Plan\", \"Price\"];\n for (const { name, unitName } of usageFeatures) {\n headerCols.push(`${name}/${unitName ?? \"unit\"}`);\n headerCols.push(\"Overage\");\n }\n\n const rows = plans.map((plan) => {\n const priceCell = renderPriceCell(plan, filterIntervals);\n const cols = [plan.name, priceCell];\n\n const featuresByCode = new Map(\n (plan.features ?? []).map((feature) => [feature.code, feature]),\n );\n\n for (const { code } of usageFeatures) {\n const feature = featuresByCode.get(code);\n\n if (!feature) {\n cols.push(\"—\", \"—\");\n continue;\n }\n\n if (feature.unlimited) {\n cols.push(\"Unlimited\", \"—\");\n continue;\n }\n\n const included = feature.includedAmount;\n cols.push(included ? formatNumber(included) : \"—\");\n\n const overagePrice =\n feature.overage?.enabled && feature.overage.unitPrice !== null\n ? formatRatePrice(feature.overage.unitPrice)\n : \"—\";\n cols.push(overagePrice);\n }\n\n return cols;\n });\n\n const separator = headerCols.map(() => \"---\");\n const lines = [\n `| ${headerCols.join(\" | \")} |`,\n `| ${separator.join(\" | \")} |`,\n ...rows.map((cols) => `| ${cols.join(\" | \")} |`),\n ];\n\n const footnotes: string[] = [];\n\n const trialPlans = plans.filter((plan) =>\n (plan.prices ?? []).some((price) => price.trialDays > 0),\n );\n for (const plan of trialPlans) {\n const trialPrice = (plan.prices ?? []).find(\n (price) => price.trialDays > 0,\n )!;\n footnotes.push(\n `*${plan.name} plan includes a ${trialPrice.trialDays}-day free trial.*`,\n );\n }\n\n if (usageFeatures.length > 0) {\n footnotes.push(\n \"The overage rate applies only to usage beyond the included volume.\",\n );\n }\n\n return footnotes.length > 0\n ? `## Plans\\n\\n${lines.join(\"\\n\")}\\n\\n${footnotes.join(\"\\n\\n\")}`\n : `## Plans\\n\\n${lines.join(\"\\n\")}`;\n}\n\nfunction renderPriceCell(\n plan: Plan,\n filterIntervals?: BillingInterval[],\n): string {\n if (plan.isFree) return \"Free\";\n\n const prices = filterIntervals\n ? (plan.prices ?? []).filter((price) =>\n filterIntervals.includes(price.billingInterval),\n )\n : (plan.prices ?? []);\n\n if (prices.length === 0) return \"—\";\n\n return prices\n .map((price) => {\n if (price.price === 0) return \"Free\";\n return `${formatSettlementPrice(price.price)}${INTERVAL_SHORT[price.billingInterval]}`;\n })\n .join(\" / \");\n}\n\nfunction renderFeatures(plans: Plan[]): string | null {\n const allBooleanCodes = new Set<string>();\n for (const plan of plans) {\n for (const feature of plan.features ?? []) {\n if (feature.type === \"boolean\") {\n allBooleanCodes.add(feature.code);\n }\n }\n }\n\n if (allBooleanCodes.size === 0) return null;\n\n const enabledOnAll = new Set<string>();\n for (const code of allBooleanCodes) {\n const enabledOnEveryPlan = plans.every((plan) => {\n const feature = (plan.features ?? []).find((f) => f.code === code);\n return feature?.enabled;\n });\n if (enabledOnEveryPlan) {\n enabledOnAll.add(code);\n }\n }\n\n const perPlanLines: string[] = [];\n for (const plan of plans) {\n const uniqueFeatures = (plan.features ?? [])\n .filter(\n (feature) =>\n feature.type === \"boolean\" &&\n feature.enabled &&\n !enabledOnAll.has(feature.code),\n )\n .map((feature) => feature.name);\n\n if (uniqueFeatures.length > 0) {\n perPlanLines.push(`- **${plan.name}**: ${uniqueFeatures.join(\", \")}`);\n }\n }\n\n const commonFeatures = (plans[0]?.features ?? [])\n .filter(\n (feature) => feature.type === \"boolean\" && enabledOnAll.has(feature.code),\n )\n .map((feature) => feature.name);\n\n const parts: string[] = [];\n\n if (perPlanLines.length > 0) {\n parts.push(perPlanLines.join(\"\\n\"));\n }\n\n if (commonFeatures && commonFeatures.length > 0) {\n parts.push(`All plans include: ${commonFeatures.join(\", \")}.`);\n }\n\n return parts.length > 0 ? `## Features\\n\\n${parts.join(\"\\n\\n\")}` : null;\n}\n\nfunction renderCreditPacks(packs: CreditPack[]): string {\n const lines = [\n \"| Pack | Credits | Price |\",\n \"| --- | --- | --- |\",\n ...packs.map(\n (pack) =>\n `| ${pack.name} | ${formatNumber(pack.credits)} credits | ${formatSettlementPrice(pack.price)} |`,\n ),\n ];\n\n return `## Credit Packs\\n\\n${lines.join(\"\\n\")}`;\n}\n\ninterface UsageFeatureColumn {\n code: string;\n name: string;\n unitName: string | null;\n}\n\nfunction collectUsageFeatures(plans: Plan[]): UsageFeatureColumn[] {\n const seen = new Map<string, UsageFeatureColumn>();\n for (const plan of plans) {\n for (const feature of plan.features ?? []) {\n if (\n (feature.type === \"usage\" || feature.type === \"seats\") &&\n !seen.has(feature.code) &&\n hasUsageData(feature)\n ) {\n seen.set(feature.code, {\n code: feature.code,\n name: feature.name,\n unitName: feature.unitName,\n });\n }\n }\n }\n return Array.from(seen.values());\n}\n\nfunction hasUsageData(feature: PlanFeature): boolean {\n return (\n feature.unlimited === true ||\n (feature.includedAmount !== null && feature.includedAmount > 0) ||\n (feature.overage?.enabled === true && feature.overage.unitPrice !== null)\n );\n}\n\nfunction formatSettlementPrice(cents: number): string {\n if (cents === 0) return \"Free\";\n const dollars = cents / 100;\n const [whole, decimal] = dollars.toFixed(2).split(\".\");\n return `$${Number(whole).toLocaleString(\"en-US\")}.${decimal}`;\n}\n\nfunction formatRatePrice(rate: number): string {\n const dollars = rate / 10000;\n\n if (dollars === Math.floor(dollars)) {\n return `$${dollars.toFixed(2)}`;\n }\n\n const formatted = dollars.toFixed(4).replace(/0+$/, \"\");\n const decimalPlaces = formatted.split(\".\")[1]?.length ?? 0;\n if (decimalPlaces < 2) {\n return `$${dollars.toFixed(2)}`;\n }\n\n return `$${formatted}`;\n}\n\nfunction formatNumber(n: number): string {\n return n.toLocaleString(\"en-US\");\n}\n","import type { WebhookPayload } from \"@commet/node\";\nimport { Webhooks as CommetWebhooks } from \"@commet/node\";\nimport { type NextRequest, NextResponse } from \"next/server\";\nimport type { WebhooksConfig } from \"./types\";\n\n/**\n * Create a Next.js webhook handler for Commet events\n *\n * Automatically verifies signatures, routes events to handlers, and returns proper responses.\n *\n * @param config - Webhook configuration with secret and event handlers\n * @returns Next.js route handler function\n *\n * @example\n * ```typescript\n * // app/api/webhooks/commet/route.ts\n * import { Webhooks } from \"@commet/next\";\n *\n * export const POST = Webhooks({\n * webhookSecret: process.env.COMMET_WEBHOOK_SECRET!,\n * onSubscriptionActivated: async (payload) => {\n * // Grant access to user\n * },\n * onSubscriptionCanceled: async (payload) => {\n * // Revoke access from user\n * },\n * });\n * ```\n */\nexport const Webhooks = (config: WebhooksConfig) => {\n const {\n webhookSecret,\n onSubscriptionActivated,\n onSubscriptionCanceled,\n onSubscriptionCreated,\n onSubscriptionUpdated,\n onSubscriptionPlanChanged,\n onPaymentReceived,\n onPaymentFailed,\n onInvoiceCreated,\n onPayload,\n onError,\n } = config;\n\n // Create webhook verifier instance\n const webhooks = new CommetWebhooks();\n\n return async (request: NextRequest) => {\n try {\n // 1. Read raw request body\n const rawBody = await request.text();\n\n // 2. Extract signature from headers\n const signature = request.headers.get(\"x-commet-signature\");\n\n // 3. Verify signature\n const isValid = webhooks.verify({\n payload: rawBody,\n signature,\n secret: webhookSecret,\n });\n\n if (!isValid) {\n console.error(\"[Commet Webhook] Invalid signature\");\n return NextResponse.json(\n { received: false, error: \"Invalid signature\" },\n { status: 403 },\n );\n }\n\n // 4. Parse payload\n let payload: WebhookPayload;\n try {\n payload = JSON.parse(rawBody) as WebhookPayload;\n } catch (parseError) {\n console.error(\"[Commet Webhook] Failed to parse payload:\", parseError);\n if (onError) {\n await onError(\n parseError instanceof Error\n ? parseError\n : new Error(\"Failed to parse webhook payload\"),\n rawBody,\n );\n }\n return NextResponse.json(\n { received: false, error: \"Invalid payload\" },\n { status: 400 },\n );\n }\n\n // 5. Collect promises for parallel execution\n const promises: Promise<void>[] = [];\n\n // Call catch-all handler if provided\n if (onPayload) {\n promises.push(onPayload(payload));\n }\n\n // 6. Route to specific event handler\n switch (payload.event) {\n case \"subscription.activated\":\n if (onSubscriptionActivated) {\n promises.push(onSubscriptionActivated(payload));\n }\n break;\n\n case \"subscription.canceled\":\n if (onSubscriptionCanceled) {\n promises.push(onSubscriptionCanceled(payload));\n }\n break;\n\n case \"subscription.created\":\n if (onSubscriptionCreated) {\n promises.push(onSubscriptionCreated(payload));\n }\n break;\n\n case \"subscription.updated\":\n if (onSubscriptionUpdated) {\n promises.push(onSubscriptionUpdated(payload));\n }\n break;\n\n case \"subscription.plan_changed\":\n if (onSubscriptionPlanChanged) {\n promises.push(onSubscriptionPlanChanged(payload));\n }\n break;\n\n case \"payment.received\":\n if (onPaymentReceived) {\n promises.push(onPaymentReceived(payload));\n }\n break;\n\n case \"payment.failed\":\n if (onPaymentFailed) {\n promises.push(onPaymentFailed(payload));\n }\n break;\n\n case \"invoice.created\":\n if (onInvoiceCreated) {\n promises.push(onInvoiceCreated(payload));\n }\n break;\n\n default:\n console.log(`[Commet Webhook] Unhandled event: ${payload.event}`);\n }\n\n // 7. Execute all handlers in parallel\n try {\n await Promise.all(promises);\n } catch (handlerError) {\n console.error(\n \"[Commet Webhook] Handler error:\",\n handlerError instanceof Error ? handlerError.message : handlerError,\n );\n if (onError) {\n await onError(\n handlerError instanceof Error\n ? handlerError\n : new Error(\"Handler execution failed\"),\n payload,\n );\n }\n // Still return 200 to prevent retries for handler errors\n return NextResponse.json(\n { received: true, warning: \"Handler failed\" },\n { status: 200 },\n );\n }\n\n // 8. Success response\n return NextResponse.json({ received: true }, { status: 200 });\n } catch (error) {\n console.error(\"[Commet Webhook] Unexpected error:\", error);\n if (onError) {\n try {\n await onError(\n error instanceof Error ? error : new Error(\"Unexpected error\"),\n undefined,\n );\n } catch (errorHandlerError) {\n console.error(\n \"[Commet Webhook] Error handler failed:\",\n errorHandlerError,\n );\n }\n }\n return NextResponse.json(\n { received: false, error: \"Internal error\" },\n { status: 500 },\n );\n }\n };\n};\n"],"mappings":"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","names":["import_node","import_node","import_server","import_node","import_server","CommetWebhooks"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/portal.ts","../src/pricing-markdown.ts","../src/webhooks.ts"],"sourcesContent":["/**\n * @commet/next - Next.js integration for Commet\n *\n * @example\n * Webhooks\n * ```typescript\n * import { Webhooks } from \"@commet/next\";\n *\n * export const POST = Webhooks({\n * webhookSecret: process.env.COMMET_WEBHOOK_SECRET!,\n * onSubscriptionActivated: async (payload) => {\n * // Handle activation\n * },\n * });\n * ```\n *\n * @example\n * Customer Portal\n * ```typescript\n * import { CustomerPortal } from \"@commet/next\";\n *\n * export const GET = CustomerPortal({\n * apiKey: process.env.COMMET_API_KEY!,\n * getCustomerId: async (req) => {\n * const session = await auth.api.getSession({ headers: req.headers });\n * return session?.user.id;\n * },\n * });\n * ```\n *\n * @packageDocumentation\n */\n\nimport { registerIntegration } from \"@commet/node\";\n\ndeclare const __PKG_VERSION__: string;\nregisterIntegration(\"@commet/next\", __PKG_VERSION__);\n\nexport type { CustomerPortalConfig } from \"./portal\";\nexport { CustomerPortal } from \"./portal\";\nexport type { PricingMarkdownConfig } from \"./pricing-markdown\";\nexport { PricingMarkdown } from \"./pricing-markdown\";\nexport type {\n WebhookData,\n WebhookEvent,\n WebhookPayload,\n WebhooksConfig,\n} from \"./types\";\nexport { Webhooks } from \"./webhooks\";\n","import { Commet } from \"@commet/node\";\nimport { type NextRequest, NextResponse } from \"next/server\";\n\nexport interface CustomerPortalConfig {\n apiKey: string;\n getCustomerId: (req: NextRequest) => Promise<string | null>;\n onError?: (error: Error) => void;\n}\n\n/**\n * Creates Next.js route handler for Customer Portal access\n *\n * @example\n * ```typescript\n * // app/api/commet/portal/route.ts\n * import { CustomerPortal } from \"@commet/next\";\n * import { auth } from \"@/lib/auth\";\n *\n * export const GET = CustomerPortal({\n * apiKey: process.env.COMMET_API_KEY!,\n * getCustomerId: async (req) => {\n * const session = await auth.api.getSession({ headers: req.headers });\n * return session?.user.id ?? null;\n * },\n * });\n * ```\n *\n * @example\n * ```tsx\n * // Use in component\n * export function BillingButton() {\n * return (\n * <Button asChild>\n * <Link href=\"/api/commet/portal\">Manage Billing</Link>\n * </Button>\n * );\n * }\n * ```\n */\nexport const CustomerPortal = ({\n apiKey,\n getCustomerId,\n onError,\n}: CustomerPortalConfig) => {\n const commet = new Commet({\n apiKey,\n });\n\n return async (req: NextRequest) => {\n try {\n // Get customer identifier from request\n const customerId = await getCustomerId(req);\n\n if (!customerId) {\n return NextResponse.json(\n { error: \"Customer not authenticated\" },\n { status: 401 },\n );\n }\n\n // Get portal URL from Commet\n const result = await commet.portal.getUrl({\n customerId,\n });\n\n if (!result.success || !result.data) {\n throw new Error(\n result.error?.message || \"Failed to create portal session\",\n );\n }\n\n // Redirect to customer portal\n return NextResponse.redirect(result.data.portalUrl);\n } catch (error) {\n const errorObj =\n error instanceof Error ? error : new Error(String(error));\n\n // Call custom error handler if provided\n onError?.(errorObj);\n\n // Log error\n console.error(\"[Commet Portal]\", errorObj);\n\n // Return error response\n return NextResponse.json(\n { error: \"Failed to access customer portal\" },\n { status: 500 },\n );\n }\n };\n};\n","import type { BillingInterval, CreditPack, Plan } from \"@commet/node\";\nimport { Commet } from \"@commet/node\";\nimport { type NextRequest, NextResponse } from \"next/server\";\n\ntype PlanFeature = NonNullable<Plan[\"features\"]>[number];\n\nexport interface PricingMarkdownConfig {\n apiKey: string;\n title: string;\n description?: string;\n includeCreditPacks?: boolean;\n billingIntervals?: BillingInterval[];\n cacheMaxAge?: number;\n onError?: (error: Error) => void;\n}\n\nconst INTERVAL_SHORT: Record<BillingInterval, string> = {\n weekly: \"/wk\",\n monthly: \"/mo\",\n quarterly: \"/qtr\",\n yearly: \"/yr\",\n one_time: \"\",\n};\n\nexport const PricingMarkdown = ({\n apiKey,\n title,\n description,\n includeCreditPacks = false,\n billingIntervals,\n cacheMaxAge = 3600,\n onError,\n}: PricingMarkdownConfig) => {\n const commet = new Commet({ apiKey });\n\n return async (_req: NextRequest) => {\n try {\n const plansResult = await commet.plans.list();\n\n if (!plansResult.success || !plansResult.data) {\n throw new Error(plansResult.error?.message ?? \"Failed to fetch plans\");\n }\n\n const publicPlans = plansResult.data.filter((plan) => plan.isPublic);\n\n const creditPacks = includeCreditPacks\n ? await commet.creditPacks\n .list()\n .then((result) =>\n result.success && result.data ? result.data : [],\n )\n : [];\n\n const markdown = generateMarkdown(\n title,\n description,\n publicPlans,\n creditPacks,\n billingIntervals,\n );\n\n return new NextResponse(markdown, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/markdown; charset=utf-8\",\n \"Cache-Control\": `public, s-maxage=${cacheMaxAge}, stale-while-revalidate=${cacheMaxAge * 2}`,\n },\n });\n } catch (error) {\n const errorObj =\n error instanceof Error ? error : new Error(String(error));\n\n onError?.(errorObj);\n console.error(\"[Commet PricingMarkdown]\", errorObj);\n\n return NextResponse.json(\n { error: \"Failed to generate pricing markdown\" },\n { status: 500 },\n );\n }\n };\n};\n\nfunction generateMarkdown(\n title: string,\n description: string | undefined,\n plans: Plan[],\n creditPacks: CreditPack[],\n billingIntervals?: BillingInterval[],\n): string {\n const sections: string[] = [`# ${title}`];\n\n if (description) {\n sections.push(description);\n }\n\n if (plans.length > 0) {\n sections.push(renderPlansTable(plans, billingIntervals));\n\n const featuresSection = renderFeatures(plans);\n if (featuresSection) {\n sections.push(featuresSection);\n }\n }\n\n if (creditPacks.length > 0) {\n sections.push(renderCreditPacks(creditPacks));\n }\n\n return sections.join(\"\\n\\n\");\n}\n\nfunction renderPlansTable(\n plans: Plan[],\n filterIntervals?: BillingInterval[],\n): string {\n const usageFeatures = collectUsageFeatures(plans);\n\n const headerCols = [\"Plan\", \"Price\"];\n for (const { name, unitName } of usageFeatures) {\n headerCols.push(`${name}/${unitName ?? \"unit\"}`);\n headerCols.push(\"Overage\");\n }\n\n const rows = plans.map((plan) => {\n const priceCell = renderPriceCell(plan, filterIntervals);\n const cols = [plan.name, priceCell];\n\n const featuresByCode = new Map(\n (plan.features ?? []).map((feature) => [feature.code, feature]),\n );\n\n for (const { code } of usageFeatures) {\n const feature = featuresByCode.get(code);\n\n if (!feature) {\n cols.push(\"—\", \"—\");\n continue;\n }\n\n if (feature.unlimited) {\n cols.push(\"Unlimited\", \"—\");\n continue;\n }\n\n const included = feature.includedAmount;\n cols.push(included ? formatNumber(included) : \"—\");\n\n const overagePrice =\n feature.overage?.enabled && feature.overage.unitPrice !== null\n ? formatRatePrice(feature.overage.unitPrice)\n : \"—\";\n cols.push(overagePrice);\n }\n\n return cols;\n });\n\n const separator = headerCols.map(() => \"---\");\n const lines = [\n `| ${headerCols.join(\" | \")} |`,\n `| ${separator.join(\" | \")} |`,\n ...rows.map((cols) => `| ${cols.join(\" | \")} |`),\n ];\n\n const footnotes: string[] = [];\n\n const trialPlans = plans.filter((plan) =>\n (plan.prices ?? []).some((price) => price.trialDays > 0),\n );\n for (const plan of trialPlans) {\n const trialPrice = (plan.prices ?? []).find(\n (price) => price.trialDays > 0,\n )!;\n footnotes.push(\n `*${plan.name} plan includes a ${trialPrice.trialDays}-day free trial.*`,\n );\n }\n\n if (usageFeatures.length > 0) {\n footnotes.push(\n \"The overage rate applies only to usage beyond the included volume.\",\n );\n }\n\n return footnotes.length > 0\n ? `## Plans\\n\\n${lines.join(\"\\n\")}\\n\\n${footnotes.join(\"\\n\\n\")}`\n : `## Plans\\n\\n${lines.join(\"\\n\")}`;\n}\n\nfunction renderPriceCell(\n plan: Plan,\n filterIntervals?: BillingInterval[],\n): string {\n if (plan.isFree) return \"Free\";\n\n const prices = filterIntervals\n ? (plan.prices ?? []).filter((price) =>\n filterIntervals.includes(price.billingInterval),\n )\n : (plan.prices ?? []);\n\n if (prices.length === 0) return \"—\";\n\n return prices\n .map((price) => {\n if (price.price === 0) return \"Free\";\n return `${formatSettlementPrice(price.price)}${INTERVAL_SHORT[price.billingInterval]}`;\n })\n .join(\" / \");\n}\n\nfunction renderFeatures(plans: Plan[]): string | null {\n const allBooleanCodes = new Set<string>();\n for (const plan of plans) {\n for (const feature of plan.features ?? []) {\n if (feature.type === \"boolean\") {\n allBooleanCodes.add(feature.code);\n }\n }\n }\n\n if (allBooleanCodes.size === 0) return null;\n\n const enabledOnAll = new Set<string>();\n for (const code of allBooleanCodes) {\n const enabledOnEveryPlan = plans.every((plan) => {\n const feature = (plan.features ?? []).find((f) => f.code === code);\n return feature?.enabled;\n });\n if (enabledOnEveryPlan) {\n enabledOnAll.add(code);\n }\n }\n\n const perPlanLines: string[] = [];\n for (const plan of plans) {\n const uniqueFeatures = (plan.features ?? [])\n .filter(\n (feature) =>\n feature.type === \"boolean\" &&\n feature.enabled &&\n !enabledOnAll.has(feature.code),\n )\n .map((feature) => feature.name);\n\n if (uniqueFeatures.length > 0) {\n perPlanLines.push(`- **${plan.name}**: ${uniqueFeatures.join(\", \")}`);\n }\n }\n\n const commonFeatures = (plans[0]?.features ?? [])\n .filter(\n (feature) => feature.type === \"boolean\" && enabledOnAll.has(feature.code),\n )\n .map((feature) => feature.name);\n\n const parts: string[] = [];\n\n if (perPlanLines.length > 0) {\n parts.push(perPlanLines.join(\"\\n\"));\n }\n\n if (commonFeatures && commonFeatures.length > 0) {\n parts.push(`All plans include: ${commonFeatures.join(\", \")}.`);\n }\n\n return parts.length > 0 ? `## Features\\n\\n${parts.join(\"\\n\\n\")}` : null;\n}\n\nfunction renderCreditPacks(packs: CreditPack[]): string {\n const lines = [\n \"| Pack | Credits | Price |\",\n \"| --- | --- | --- |\",\n ...packs.map(\n (pack) =>\n `| ${pack.name} | ${formatNumber(pack.credits)} credits | ${formatSettlementPrice(pack.price)} |`,\n ),\n ];\n\n return `## Credit Packs\\n\\n${lines.join(\"\\n\")}`;\n}\n\ninterface UsageFeatureColumn {\n code: string;\n name: string;\n unitName: string | null;\n}\n\nfunction collectUsageFeatures(plans: Plan[]): UsageFeatureColumn[] {\n const seen = new Map<string, UsageFeatureColumn>();\n for (const plan of plans) {\n for (const feature of plan.features ?? []) {\n if (\n (feature.type === \"usage\" || feature.type === \"seats\") &&\n !seen.has(feature.code) &&\n hasUsageData(feature)\n ) {\n seen.set(feature.code, {\n code: feature.code,\n name: feature.name,\n unitName: feature.unitName,\n });\n }\n }\n }\n return Array.from(seen.values());\n}\n\nfunction hasUsageData(feature: PlanFeature): boolean {\n return (\n feature.unlimited === true ||\n (feature.includedAmount !== null && feature.includedAmount > 0) ||\n (feature.overage?.enabled === true && feature.overage.unitPrice !== null)\n );\n}\n\nfunction formatSettlementPrice(cents: number): string {\n if (cents === 0) return \"Free\";\n const dollars = cents / 100;\n const [whole, decimal] = dollars.toFixed(2).split(\".\");\n return `$${Number(whole).toLocaleString(\"en-US\")}.${decimal}`;\n}\n\nfunction formatRatePrice(rate: number): string {\n const dollars = rate / 10000;\n\n if (dollars === Math.floor(dollars)) {\n return `$${dollars.toFixed(2)}`;\n }\n\n const formatted = dollars.toFixed(4).replace(/0+$/, \"\");\n const decimalPlaces = formatted.split(\".\")[1]?.length ?? 0;\n if (decimalPlaces < 2) {\n return `$${dollars.toFixed(2)}`;\n }\n\n return `$${formatted}`;\n}\n\nfunction formatNumber(n: number): string {\n return n.toLocaleString(\"en-US\");\n}\n","import type { WebhookEvent, WebhookEventPayload } from \"@commet/node\";\nimport { Webhooks as CommetWebhooks } from \"@commet/node\";\nimport { type NextRequest, NextResponse } from \"next/server\";\nimport type { WebhookHandlerName, WebhooksConfig } from \"./types\";\n\nconst webhookEventHandlerNames = {\n \"subscription.created\": \"onSubscriptionCreated\",\n \"subscription.activated\": \"onSubscriptionActivated\",\n \"subscription.reactivated\": \"onSubscriptionReactivated\",\n \"subscription.canceled\": \"onSubscriptionCanceled\",\n \"subscription.updated\": \"onSubscriptionUpdated\",\n \"subscription.plan_changed\": \"onSubscriptionPlanChanged\",\n \"subscription.cancellation_scheduled\": \"onSubscriptionCancellationScheduled\",\n \"subscription.cancellation_revoked\": \"onSubscriptionCancellationRevoked\",\n \"subscription.plan_change_scheduled\": \"onSubscriptionPlanChangeScheduled\",\n \"subscription.plan_change_revoked\": \"onSubscriptionPlanChangeRevoked\",\n \"subscription.past_due\": \"onSubscriptionPastDue\",\n \"trial.started\": \"onTrialStarted\",\n \"trial.converted\": \"onTrialConverted\",\n \"trial.expired\": \"onTrialExpired\",\n \"trial.will_end\": \"onTrialWillEnd\",\n \"trial.checkout_ready\": \"onTrialCheckoutReady\",\n \"checkout.ready\": \"onCheckoutReady\",\n \"payment.received\": \"onPaymentReceived\",\n \"payment.failed\": \"onPaymentFailed\",\n \"payment.recovered\": \"onPaymentRecovered\",\n \"payment.retry_failed\": \"onPaymentRetryFailed\",\n \"payment.refunded\": \"onPaymentRefunded\",\n \"payment.disputed\": \"onPaymentDisputed\",\n \"payment.dispute_resolved\": \"onPaymentDisputeResolved\",\n \"payment_link.created\": \"onPaymentLinkCreated\",\n \"payment_link.completed\": \"onPaymentLinkCompleted\",\n \"payment_link.failed\": \"onPaymentLinkFailed\",\n \"payment_link.canceled\": \"onPaymentLinkCanceled\",\n \"invoice.created\": \"onInvoiceCreated\",\n \"invoice.upcoming\": \"onInvoiceUpcoming\",\n \"invoice.overdue\": \"onInvoiceOverdue\",\n \"invoice.voided\": \"onInvoiceVoided\",\n \"payment_method.attached\": \"onPaymentMethodAttached\",\n \"payment_method.updated\": \"onPaymentMethodUpdated\",\n \"customer.created\": \"onCustomerCreated\",\n \"customer.updated\": \"onCustomerUpdated\",\n \"customer.state_changed\": \"onCustomerStateChanged\",\n \"credits.granted\": \"onCreditsGranted\",\n \"credits.purchased\": \"onCreditsPurchased\",\n \"credits.low\": \"onCreditsLow\",\n \"credits.depleted\": \"onCreditsDepleted\",\n \"credits.expired\": \"onCreditsExpired\",\n \"balance.topped_up\": \"onBalanceToppedUp\",\n \"balance.low\": \"onBalanceLow\",\n \"balance.depleted\": \"onBalanceDepleted\",\n \"quota.threshold_reached\": \"onQuotaThresholdReached\",\n \"quota.exceeded\": \"onQuotaExceeded\",\n \"usage.recorded\": \"onUsageRecorded\",\n \"seats.updated\": \"onSeatsUpdated\",\n \"seats.limit_reached\": \"onSeatsLimitReached\",\n \"addon.activated\": \"onAddonActivated\",\n \"addon.deactivated\": \"onAddonDeactivated\",\n \"payout.available\": \"onPayoutAvailable\",\n \"payout.created\": \"onPayoutCreated\",\n \"payout.paid\": \"onPayoutPaid\",\n \"payout.failed\": \"onPayoutFailed\",\n} as const satisfies Record<WebhookEvent, WebhookHandlerName>;\n\ntype RuntimeWebhookHandler = (payload: WebhookEventPayload) => Promise<void>;\n\n/**\n * Create a Next.js webhook handler for Commet events\n *\n * Automatically verifies signatures, routes events to handlers, and returns proper responses.\n *\n * @param config - Webhook configuration with secret and event handlers\n * @returns Next.js route handler function\n *\n * @example\n * ```typescript\n * // app/api/webhooks/commet/route.ts\n * import { Webhooks } from \"@commet/next\";\n *\n * export const POST = Webhooks({\n * webhookSecret: process.env.COMMET_WEBHOOK_SECRET!,\n * onSubscriptionActivated: async (payload) => {\n * // Grant access to user\n * },\n * onSubscriptionCanceled: async (payload) => {\n * // Revoke access from user\n * },\n * });\n * ```\n */\nexport const Webhooks = (config: WebhooksConfig) => {\n const { webhookSecret, onPayload, onError } = config;\n\n const webhooks = new CommetWebhooks();\n\n return async (request: NextRequest) => {\n try {\n const rawBody = await request.text();\n const signature = request.headers.get(\"x-commet-signature\");\n\n const isValid = webhooks.verify({\n payload: rawBody,\n signature,\n secret: webhookSecret,\n });\n\n if (!isValid) {\n console.error(\"[Commet Webhook] Invalid signature\");\n return NextResponse.json(\n { received: false, error: \"Invalid signature\" },\n { status: 403 },\n );\n }\n\n let payload: WebhookEventPayload;\n try {\n payload = JSON.parse(rawBody) as WebhookEventPayload;\n } catch (parseError) {\n console.error(\"[Commet Webhook] Failed to parse payload:\", parseError);\n if (onError) {\n await onError(\n parseError instanceof Error\n ? parseError\n : new Error(\"Failed to parse webhook payload\"),\n rawBody,\n );\n }\n return NextResponse.json(\n { received: false, error: \"Invalid payload\" },\n { status: 400 },\n );\n }\n\n const promises: Promise<void>[] = [];\n\n if (onPayload) {\n promises.push(onPayload(payload));\n }\n\n const handlerName = webhookEventHandlerNames[payload.event];\n const handler = config[handlerName] as RuntimeWebhookHandler | undefined;\n if (handler) {\n promises.push(handler(payload));\n }\n\n try {\n await Promise.all(promises);\n } catch (handlerError) {\n console.error(\n \"[Commet Webhook] Handler error:\",\n handlerError instanceof Error ? handlerError.message : handlerError,\n );\n if (onError) {\n await onError(\n handlerError instanceof Error\n ? handlerError\n : new Error(\"Handler execution failed\"),\n payload,\n );\n }\n return NextResponse.json(\n { received: false, error: \"Handler failed\" },\n { status: 500 },\n );\n }\n\n return NextResponse.json({ received: true }, { status: 200 });\n } catch (error) {\n console.error(\"[Commet Webhook] Unexpected error:\", error);\n if (onError) {\n try {\n await onError(\n error instanceof Error ? error : new Error(\"Unexpected error\"),\n undefined,\n );\n } catch (errorHandlerError) {\n console.error(\n \"[Commet Webhook] Error handler failed:\",\n errorHandlerError,\n );\n }\n }\n return NextResponse.json(\n { received: false, error: \"Internal error\" },\n { status: 500 },\n );\n }\n };\n};\n"],"mappings":"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","names":["import_node","import_node","import_server","import_node","import_server","CommetWebhooks"]}
package/dist/index.mjs CHANGED
@@ -284,20 +284,66 @@ function formatNumber(n) {
284
284
  // src/webhooks.ts
285
285
  import { Webhooks as CommetWebhooks } from "@commet/node";
286
286
  import { NextResponse as NextResponse3 } from "next/server";
287
+ var webhookEventHandlerNames = {
288
+ "subscription.created": "onSubscriptionCreated",
289
+ "subscription.activated": "onSubscriptionActivated",
290
+ "subscription.reactivated": "onSubscriptionReactivated",
291
+ "subscription.canceled": "onSubscriptionCanceled",
292
+ "subscription.updated": "onSubscriptionUpdated",
293
+ "subscription.plan_changed": "onSubscriptionPlanChanged",
294
+ "subscription.cancellation_scheduled": "onSubscriptionCancellationScheduled",
295
+ "subscription.cancellation_revoked": "onSubscriptionCancellationRevoked",
296
+ "subscription.plan_change_scheduled": "onSubscriptionPlanChangeScheduled",
297
+ "subscription.plan_change_revoked": "onSubscriptionPlanChangeRevoked",
298
+ "subscription.past_due": "onSubscriptionPastDue",
299
+ "trial.started": "onTrialStarted",
300
+ "trial.converted": "onTrialConverted",
301
+ "trial.expired": "onTrialExpired",
302
+ "trial.will_end": "onTrialWillEnd",
303
+ "trial.checkout_ready": "onTrialCheckoutReady",
304
+ "checkout.ready": "onCheckoutReady",
305
+ "payment.received": "onPaymentReceived",
306
+ "payment.failed": "onPaymentFailed",
307
+ "payment.recovered": "onPaymentRecovered",
308
+ "payment.retry_failed": "onPaymentRetryFailed",
309
+ "payment.refunded": "onPaymentRefunded",
310
+ "payment.disputed": "onPaymentDisputed",
311
+ "payment.dispute_resolved": "onPaymentDisputeResolved",
312
+ "payment_link.created": "onPaymentLinkCreated",
313
+ "payment_link.completed": "onPaymentLinkCompleted",
314
+ "payment_link.failed": "onPaymentLinkFailed",
315
+ "payment_link.canceled": "onPaymentLinkCanceled",
316
+ "invoice.created": "onInvoiceCreated",
317
+ "invoice.upcoming": "onInvoiceUpcoming",
318
+ "invoice.overdue": "onInvoiceOverdue",
319
+ "invoice.voided": "onInvoiceVoided",
320
+ "payment_method.attached": "onPaymentMethodAttached",
321
+ "payment_method.updated": "onPaymentMethodUpdated",
322
+ "customer.created": "onCustomerCreated",
323
+ "customer.updated": "onCustomerUpdated",
324
+ "customer.state_changed": "onCustomerStateChanged",
325
+ "credits.granted": "onCreditsGranted",
326
+ "credits.purchased": "onCreditsPurchased",
327
+ "credits.low": "onCreditsLow",
328
+ "credits.depleted": "onCreditsDepleted",
329
+ "credits.expired": "onCreditsExpired",
330
+ "balance.topped_up": "onBalanceToppedUp",
331
+ "balance.low": "onBalanceLow",
332
+ "balance.depleted": "onBalanceDepleted",
333
+ "quota.threshold_reached": "onQuotaThresholdReached",
334
+ "quota.exceeded": "onQuotaExceeded",
335
+ "usage.recorded": "onUsageRecorded",
336
+ "seats.updated": "onSeatsUpdated",
337
+ "seats.limit_reached": "onSeatsLimitReached",
338
+ "addon.activated": "onAddonActivated",
339
+ "addon.deactivated": "onAddonDeactivated",
340
+ "payout.available": "onPayoutAvailable",
341
+ "payout.created": "onPayoutCreated",
342
+ "payout.paid": "onPayoutPaid",
343
+ "payout.failed": "onPayoutFailed"
344
+ };
287
345
  var Webhooks = (config) => {
288
- const {
289
- webhookSecret,
290
- onSubscriptionActivated,
291
- onSubscriptionCanceled,
292
- onSubscriptionCreated,
293
- onSubscriptionUpdated,
294
- onSubscriptionPlanChanged,
295
- onPaymentReceived,
296
- onPaymentFailed,
297
- onInvoiceCreated,
298
- onPayload,
299
- onError
300
- } = config;
346
+ const { webhookSecret, onPayload, onError } = config;
301
347
  const webhooks = new CommetWebhooks();
302
348
  return async (request) => {
303
349
  try {
@@ -335,49 +381,10 @@ var Webhooks = (config) => {
335
381
  if (onPayload) {
336
382
  promises.push(onPayload(payload));
337
383
  }
338
- switch (payload.event) {
339
- case "subscription.activated":
340
- if (onSubscriptionActivated) {
341
- promises.push(onSubscriptionActivated(payload));
342
- }
343
- break;
344
- case "subscription.canceled":
345
- if (onSubscriptionCanceled) {
346
- promises.push(onSubscriptionCanceled(payload));
347
- }
348
- break;
349
- case "subscription.created":
350
- if (onSubscriptionCreated) {
351
- promises.push(onSubscriptionCreated(payload));
352
- }
353
- break;
354
- case "subscription.updated":
355
- if (onSubscriptionUpdated) {
356
- promises.push(onSubscriptionUpdated(payload));
357
- }
358
- break;
359
- case "subscription.plan_changed":
360
- if (onSubscriptionPlanChanged) {
361
- promises.push(onSubscriptionPlanChanged(payload));
362
- }
363
- break;
364
- case "payment.received":
365
- if (onPaymentReceived) {
366
- promises.push(onPaymentReceived(payload));
367
- }
368
- break;
369
- case "payment.failed":
370
- if (onPaymentFailed) {
371
- promises.push(onPaymentFailed(payload));
372
- }
373
- break;
374
- case "invoice.created":
375
- if (onInvoiceCreated) {
376
- promises.push(onInvoiceCreated(payload));
377
- }
378
- break;
379
- default:
380
- console.log(`[Commet Webhook] Unhandled event: ${payload.event}`);
384
+ const handlerName = webhookEventHandlerNames[payload.event];
385
+ const handler = config[handlerName];
386
+ if (handler) {
387
+ promises.push(handler(payload));
381
388
  }
382
389
  try {
383
390
  await Promise.all(promises);
@@ -393,8 +400,8 @@ var Webhooks = (config) => {
393
400
  );
394
401
  }
395
402
  return NextResponse3.json(
396
- { received: true, warning: "Handler failed" },
397
- { status: 200 }
403
+ { received: false, error: "Handler failed" },
404
+ { status: 500 }
398
405
  );
399
406
  }
400
407
  return NextResponse3.json({ received: true }, { status: 200 });
@@ -422,7 +429,7 @@ var Webhooks = (config) => {
422
429
  };
423
430
 
424
431
  // src/index.ts
425
- registerIntegration("@commet/next", "1.0.11");
432
+ registerIntegration("@commet/next", "1.1.0");
426
433
  export {
427
434
  CustomerPortal,
428
435
  PricingMarkdown,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/portal.ts","../src/pricing-markdown.ts","../src/webhooks.ts"],"sourcesContent":["/**\n * @commet/next - Next.js integration for Commet\n *\n * @example\n * Webhooks\n * ```typescript\n * import { Webhooks } from \"@commet/next\";\n *\n * export const POST = Webhooks({\n * webhookSecret: process.env.COMMET_WEBHOOK_SECRET!,\n * onSubscriptionActivated: async (payload) => {\n * // Handle activation\n * },\n * });\n * ```\n *\n * @example\n * Customer Portal\n * ```typescript\n * import { CustomerPortal } from \"@commet/next\";\n *\n * export const GET = CustomerPortal({\n * apiKey: process.env.COMMET_API_KEY!,\n * getCustomerId: async (req) => {\n * const session = await auth.api.getSession({ headers: req.headers });\n * return session?.user.id;\n * },\n * });\n * ```\n *\n * @packageDocumentation\n */\n\nimport { registerIntegration } from \"@commet/node\";\n\ndeclare const __PKG_VERSION__: string;\nregisterIntegration(\"@commet/next\", __PKG_VERSION__);\n\nexport type { CustomerPortalConfig } from \"./portal\";\nexport { CustomerPortal } from \"./portal\";\nexport type { PricingMarkdownConfig } from \"./pricing-markdown\";\nexport { PricingMarkdown } from \"./pricing-markdown\";\nexport type {\n WebhookData,\n WebhookEvent,\n WebhookPayload,\n WebhooksConfig,\n} from \"./types\";\nexport { Webhooks } from \"./webhooks\";\n","import { Commet } from \"@commet/node\";\nimport { type NextRequest, NextResponse } from \"next/server\";\n\nexport interface CustomerPortalConfig {\n apiKey: string;\n getCustomerId: (req: NextRequest) => Promise<string | null>;\n onError?: (error: Error) => void;\n}\n\n/**\n * Creates Next.js route handler for Customer Portal access\n *\n * @example\n * ```typescript\n * // app/api/commet/portal/route.ts\n * import { CustomerPortal } from \"@commet/next\";\n * import { auth } from \"@/lib/auth\";\n *\n * export const GET = CustomerPortal({\n * apiKey: process.env.COMMET_API_KEY!,\n * getCustomerId: async (req) => {\n * const session = await auth.api.getSession({ headers: req.headers });\n * return session?.user.id ?? null;\n * },\n * });\n * ```\n *\n * @example\n * ```tsx\n * // Use in component\n * export function BillingButton() {\n * return (\n * <Button asChild>\n * <Link href=\"/api/commet/portal\">Manage Billing</Link>\n * </Button>\n * );\n * }\n * ```\n */\nexport const CustomerPortal = ({\n apiKey,\n getCustomerId,\n onError,\n}: CustomerPortalConfig) => {\n const commet = new Commet({\n apiKey,\n });\n\n return async (req: NextRequest) => {\n try {\n // Get customer identifier from request\n const customerId = await getCustomerId(req);\n\n if (!customerId) {\n return NextResponse.json(\n { error: \"Customer not authenticated\" },\n { status: 401 },\n );\n }\n\n // Get portal URL from Commet\n const result = await commet.portal.getUrl({\n customerId,\n });\n\n if (!result.success || !result.data) {\n throw new Error(\n result.error?.message || \"Failed to create portal session\",\n );\n }\n\n // Redirect to customer portal\n return NextResponse.redirect(result.data.portalUrl);\n } catch (error) {\n const errorObj =\n error instanceof Error ? error : new Error(String(error));\n\n // Call custom error handler if provided\n onError?.(errorObj);\n\n // Log error\n console.error(\"[Commet Portal]\", errorObj);\n\n // Return error response\n return NextResponse.json(\n { error: \"Failed to access customer portal\" },\n { status: 500 },\n );\n }\n };\n};\n","import type { BillingInterval, CreditPack, Plan } from \"@commet/node\";\nimport { Commet } from \"@commet/node\";\nimport { type NextRequest, NextResponse } from \"next/server\";\n\ntype PlanFeature = NonNullable<Plan[\"features\"]>[number];\n\nexport interface PricingMarkdownConfig {\n apiKey: string;\n title: string;\n description?: string;\n includeCreditPacks?: boolean;\n billingIntervals?: BillingInterval[];\n cacheMaxAge?: number;\n onError?: (error: Error) => void;\n}\n\nconst INTERVAL_SHORT: Record<BillingInterval, string> = {\n weekly: \"/wk\",\n monthly: \"/mo\",\n quarterly: \"/qtr\",\n yearly: \"/yr\",\n one_time: \"\",\n};\n\nexport const PricingMarkdown = ({\n apiKey,\n title,\n description,\n includeCreditPacks = false,\n billingIntervals,\n cacheMaxAge = 3600,\n onError,\n}: PricingMarkdownConfig) => {\n const commet = new Commet({ apiKey });\n\n return async (_req: NextRequest) => {\n try {\n const plansResult = await commet.plans.list();\n\n if (!plansResult.success || !plansResult.data) {\n throw new Error(plansResult.error?.message ?? \"Failed to fetch plans\");\n }\n\n const publicPlans = plansResult.data.filter((plan) => plan.isPublic);\n\n const creditPacks = includeCreditPacks\n ? await commet.creditPacks\n .list()\n .then((result) =>\n result.success && result.data ? result.data : [],\n )\n : [];\n\n const markdown = generateMarkdown(\n title,\n description,\n publicPlans,\n creditPacks,\n billingIntervals,\n );\n\n return new NextResponse(markdown, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/markdown; charset=utf-8\",\n \"Cache-Control\": `public, s-maxage=${cacheMaxAge}, stale-while-revalidate=${cacheMaxAge * 2}`,\n },\n });\n } catch (error) {\n const errorObj =\n error instanceof Error ? error : new Error(String(error));\n\n onError?.(errorObj);\n console.error(\"[Commet PricingMarkdown]\", errorObj);\n\n return NextResponse.json(\n { error: \"Failed to generate pricing markdown\" },\n { status: 500 },\n );\n }\n };\n};\n\nfunction generateMarkdown(\n title: string,\n description: string | undefined,\n plans: Plan[],\n creditPacks: CreditPack[],\n billingIntervals?: BillingInterval[],\n): string {\n const sections: string[] = [`# ${title}`];\n\n if (description) {\n sections.push(description);\n }\n\n if (plans.length > 0) {\n sections.push(renderPlansTable(plans, billingIntervals));\n\n const featuresSection = renderFeatures(plans);\n if (featuresSection) {\n sections.push(featuresSection);\n }\n }\n\n if (creditPacks.length > 0) {\n sections.push(renderCreditPacks(creditPacks));\n }\n\n return sections.join(\"\\n\\n\");\n}\n\nfunction renderPlansTable(\n plans: Plan[],\n filterIntervals?: BillingInterval[],\n): string {\n const usageFeatures = collectUsageFeatures(plans);\n\n const headerCols = [\"Plan\", \"Price\"];\n for (const { name, unitName } of usageFeatures) {\n headerCols.push(`${name}/${unitName ?? \"unit\"}`);\n headerCols.push(\"Overage\");\n }\n\n const rows = plans.map((plan) => {\n const priceCell = renderPriceCell(plan, filterIntervals);\n const cols = [plan.name, priceCell];\n\n const featuresByCode = new Map(\n (plan.features ?? []).map((feature) => [feature.code, feature]),\n );\n\n for (const { code } of usageFeatures) {\n const feature = featuresByCode.get(code);\n\n if (!feature) {\n cols.push(\"—\", \"—\");\n continue;\n }\n\n if (feature.unlimited) {\n cols.push(\"Unlimited\", \"—\");\n continue;\n }\n\n const included = feature.includedAmount;\n cols.push(included ? formatNumber(included) : \"—\");\n\n const overagePrice =\n feature.overage?.enabled && feature.overage.unitPrice !== null\n ? formatRatePrice(feature.overage.unitPrice)\n : \"—\";\n cols.push(overagePrice);\n }\n\n return cols;\n });\n\n const separator = headerCols.map(() => \"---\");\n const lines = [\n `| ${headerCols.join(\" | \")} |`,\n `| ${separator.join(\" | \")} |`,\n ...rows.map((cols) => `| ${cols.join(\" | \")} |`),\n ];\n\n const footnotes: string[] = [];\n\n const trialPlans = plans.filter((plan) =>\n (plan.prices ?? []).some((price) => price.trialDays > 0),\n );\n for (const plan of trialPlans) {\n const trialPrice = (plan.prices ?? []).find(\n (price) => price.trialDays > 0,\n )!;\n footnotes.push(\n `*${plan.name} plan includes a ${trialPrice.trialDays}-day free trial.*`,\n );\n }\n\n if (usageFeatures.length > 0) {\n footnotes.push(\n \"The overage rate applies only to usage beyond the included volume.\",\n );\n }\n\n return footnotes.length > 0\n ? `## Plans\\n\\n${lines.join(\"\\n\")}\\n\\n${footnotes.join(\"\\n\\n\")}`\n : `## Plans\\n\\n${lines.join(\"\\n\")}`;\n}\n\nfunction renderPriceCell(\n plan: Plan,\n filterIntervals?: BillingInterval[],\n): string {\n if (plan.isFree) return \"Free\";\n\n const prices = filterIntervals\n ? (plan.prices ?? []).filter((price) =>\n filterIntervals.includes(price.billingInterval),\n )\n : (plan.prices ?? []);\n\n if (prices.length === 0) return \"—\";\n\n return prices\n .map((price) => {\n if (price.price === 0) return \"Free\";\n return `${formatSettlementPrice(price.price)}${INTERVAL_SHORT[price.billingInterval]}`;\n })\n .join(\" / \");\n}\n\nfunction renderFeatures(plans: Plan[]): string | null {\n const allBooleanCodes = new Set<string>();\n for (const plan of plans) {\n for (const feature of plan.features ?? []) {\n if (feature.type === \"boolean\") {\n allBooleanCodes.add(feature.code);\n }\n }\n }\n\n if (allBooleanCodes.size === 0) return null;\n\n const enabledOnAll = new Set<string>();\n for (const code of allBooleanCodes) {\n const enabledOnEveryPlan = plans.every((plan) => {\n const feature = (plan.features ?? []).find((f) => f.code === code);\n return feature?.enabled;\n });\n if (enabledOnEveryPlan) {\n enabledOnAll.add(code);\n }\n }\n\n const perPlanLines: string[] = [];\n for (const plan of plans) {\n const uniqueFeatures = (plan.features ?? [])\n .filter(\n (feature) =>\n feature.type === \"boolean\" &&\n feature.enabled &&\n !enabledOnAll.has(feature.code),\n )\n .map((feature) => feature.name);\n\n if (uniqueFeatures.length > 0) {\n perPlanLines.push(`- **${plan.name}**: ${uniqueFeatures.join(\", \")}`);\n }\n }\n\n const commonFeatures = (plans[0]?.features ?? [])\n .filter(\n (feature) => feature.type === \"boolean\" && enabledOnAll.has(feature.code),\n )\n .map((feature) => feature.name);\n\n const parts: string[] = [];\n\n if (perPlanLines.length > 0) {\n parts.push(perPlanLines.join(\"\\n\"));\n }\n\n if (commonFeatures && commonFeatures.length > 0) {\n parts.push(`All plans include: ${commonFeatures.join(\", \")}.`);\n }\n\n return parts.length > 0 ? `## Features\\n\\n${parts.join(\"\\n\\n\")}` : null;\n}\n\nfunction renderCreditPacks(packs: CreditPack[]): string {\n const lines = [\n \"| Pack | Credits | Price |\",\n \"| --- | --- | --- |\",\n ...packs.map(\n (pack) =>\n `| ${pack.name} | ${formatNumber(pack.credits)} credits | ${formatSettlementPrice(pack.price)} |`,\n ),\n ];\n\n return `## Credit Packs\\n\\n${lines.join(\"\\n\")}`;\n}\n\ninterface UsageFeatureColumn {\n code: string;\n name: string;\n unitName: string | null;\n}\n\nfunction collectUsageFeatures(plans: Plan[]): UsageFeatureColumn[] {\n const seen = new Map<string, UsageFeatureColumn>();\n for (const plan of plans) {\n for (const feature of plan.features ?? []) {\n if (\n (feature.type === \"usage\" || feature.type === \"seats\") &&\n !seen.has(feature.code) &&\n hasUsageData(feature)\n ) {\n seen.set(feature.code, {\n code: feature.code,\n name: feature.name,\n unitName: feature.unitName,\n });\n }\n }\n }\n return Array.from(seen.values());\n}\n\nfunction hasUsageData(feature: PlanFeature): boolean {\n return (\n feature.unlimited === true ||\n (feature.includedAmount !== null && feature.includedAmount > 0) ||\n (feature.overage?.enabled === true && feature.overage.unitPrice !== null)\n );\n}\n\nfunction formatSettlementPrice(cents: number): string {\n if (cents === 0) return \"Free\";\n const dollars = cents / 100;\n const [whole, decimal] = dollars.toFixed(2).split(\".\");\n return `$${Number(whole).toLocaleString(\"en-US\")}.${decimal}`;\n}\n\nfunction formatRatePrice(rate: number): string {\n const dollars = rate / 10000;\n\n if (dollars === Math.floor(dollars)) {\n return `$${dollars.toFixed(2)}`;\n }\n\n const formatted = dollars.toFixed(4).replace(/0+$/, \"\");\n const decimalPlaces = formatted.split(\".\")[1]?.length ?? 0;\n if (decimalPlaces < 2) {\n return `$${dollars.toFixed(2)}`;\n }\n\n return `$${formatted}`;\n}\n\nfunction formatNumber(n: number): string {\n return n.toLocaleString(\"en-US\");\n}\n","import type { WebhookPayload } from \"@commet/node\";\nimport { Webhooks as CommetWebhooks } from \"@commet/node\";\nimport { type NextRequest, NextResponse } from \"next/server\";\nimport type { WebhooksConfig } from \"./types\";\n\n/**\n * Create a Next.js webhook handler for Commet events\n *\n * Automatically verifies signatures, routes events to handlers, and returns proper responses.\n *\n * @param config - Webhook configuration with secret and event handlers\n * @returns Next.js route handler function\n *\n * @example\n * ```typescript\n * // app/api/webhooks/commet/route.ts\n * import { Webhooks } from \"@commet/next\";\n *\n * export const POST = Webhooks({\n * webhookSecret: process.env.COMMET_WEBHOOK_SECRET!,\n * onSubscriptionActivated: async (payload) => {\n * // Grant access to user\n * },\n * onSubscriptionCanceled: async (payload) => {\n * // Revoke access from user\n * },\n * });\n * ```\n */\nexport const Webhooks = (config: WebhooksConfig) => {\n const {\n webhookSecret,\n onSubscriptionActivated,\n onSubscriptionCanceled,\n onSubscriptionCreated,\n onSubscriptionUpdated,\n onSubscriptionPlanChanged,\n onPaymentReceived,\n onPaymentFailed,\n onInvoiceCreated,\n onPayload,\n onError,\n } = config;\n\n // Create webhook verifier instance\n const webhooks = new CommetWebhooks();\n\n return async (request: NextRequest) => {\n try {\n // 1. Read raw request body\n const rawBody = await request.text();\n\n // 2. Extract signature from headers\n const signature = request.headers.get(\"x-commet-signature\");\n\n // 3. Verify signature\n const isValid = webhooks.verify({\n payload: rawBody,\n signature,\n secret: webhookSecret,\n });\n\n if (!isValid) {\n console.error(\"[Commet Webhook] Invalid signature\");\n return NextResponse.json(\n { received: false, error: \"Invalid signature\" },\n { status: 403 },\n );\n }\n\n // 4. Parse payload\n let payload: WebhookPayload;\n try {\n payload = JSON.parse(rawBody) as WebhookPayload;\n } catch (parseError) {\n console.error(\"[Commet Webhook] Failed to parse payload:\", parseError);\n if (onError) {\n await onError(\n parseError instanceof Error\n ? parseError\n : new Error(\"Failed to parse webhook payload\"),\n rawBody,\n );\n }\n return NextResponse.json(\n { received: false, error: \"Invalid payload\" },\n { status: 400 },\n );\n }\n\n // 5. Collect promises for parallel execution\n const promises: Promise<void>[] = [];\n\n // Call catch-all handler if provided\n if (onPayload) {\n promises.push(onPayload(payload));\n }\n\n // 6. Route to specific event handler\n switch (payload.event) {\n case \"subscription.activated\":\n if (onSubscriptionActivated) {\n promises.push(onSubscriptionActivated(payload));\n }\n break;\n\n case \"subscription.canceled\":\n if (onSubscriptionCanceled) {\n promises.push(onSubscriptionCanceled(payload));\n }\n break;\n\n case \"subscription.created\":\n if (onSubscriptionCreated) {\n promises.push(onSubscriptionCreated(payload));\n }\n break;\n\n case \"subscription.updated\":\n if (onSubscriptionUpdated) {\n promises.push(onSubscriptionUpdated(payload));\n }\n break;\n\n case \"subscription.plan_changed\":\n if (onSubscriptionPlanChanged) {\n promises.push(onSubscriptionPlanChanged(payload));\n }\n break;\n\n case \"payment.received\":\n if (onPaymentReceived) {\n promises.push(onPaymentReceived(payload));\n }\n break;\n\n case \"payment.failed\":\n if (onPaymentFailed) {\n promises.push(onPaymentFailed(payload));\n }\n break;\n\n case \"invoice.created\":\n if (onInvoiceCreated) {\n promises.push(onInvoiceCreated(payload));\n }\n break;\n\n default:\n console.log(`[Commet Webhook] Unhandled event: ${payload.event}`);\n }\n\n // 7. Execute all handlers in parallel\n try {\n await Promise.all(promises);\n } catch (handlerError) {\n console.error(\n \"[Commet Webhook] Handler error:\",\n handlerError instanceof Error ? handlerError.message : handlerError,\n );\n if (onError) {\n await onError(\n handlerError instanceof Error\n ? handlerError\n : new Error(\"Handler execution failed\"),\n payload,\n );\n }\n // Still return 200 to prevent retries for handler errors\n return NextResponse.json(\n { received: true, warning: \"Handler failed\" },\n { status: 200 },\n );\n }\n\n // 8. Success response\n return NextResponse.json({ received: true }, { status: 200 });\n } catch (error) {\n console.error(\"[Commet Webhook] Unexpected error:\", error);\n if (onError) {\n try {\n await onError(\n error instanceof Error ? error : new Error(\"Unexpected error\"),\n undefined,\n );\n } catch (errorHandlerError) {\n console.error(\n \"[Commet Webhook] Error handler failed:\",\n errorHandlerError,\n );\n }\n }\n return NextResponse.json(\n { received: false, error: \"Internal error\" },\n { status: 500 },\n );\n }\n };\n};\n"],"mappings":"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","names":["Commet","NextResponse","NextResponse"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/portal.ts","../src/pricing-markdown.ts","../src/webhooks.ts"],"sourcesContent":["/**\n * @commet/next - Next.js integration for Commet\n *\n * @example\n * Webhooks\n * ```typescript\n * import { Webhooks } from \"@commet/next\";\n *\n * export const POST = Webhooks({\n * webhookSecret: process.env.COMMET_WEBHOOK_SECRET!,\n * onSubscriptionActivated: async (payload) => {\n * // Handle activation\n * },\n * });\n * ```\n *\n * @example\n * Customer Portal\n * ```typescript\n * import { CustomerPortal } from \"@commet/next\";\n *\n * export const GET = CustomerPortal({\n * apiKey: process.env.COMMET_API_KEY!,\n * getCustomerId: async (req) => {\n * const session = await auth.api.getSession({ headers: req.headers });\n * return session?.user.id;\n * },\n * });\n * ```\n *\n * @packageDocumentation\n */\n\nimport { registerIntegration } from \"@commet/node\";\n\ndeclare const __PKG_VERSION__: string;\nregisterIntegration(\"@commet/next\", __PKG_VERSION__);\n\nexport type { CustomerPortalConfig } from \"./portal\";\nexport { CustomerPortal } from \"./portal\";\nexport type { PricingMarkdownConfig } from \"./pricing-markdown\";\nexport { PricingMarkdown } from \"./pricing-markdown\";\nexport type {\n WebhookData,\n WebhookEvent,\n WebhookPayload,\n WebhooksConfig,\n} from \"./types\";\nexport { Webhooks } from \"./webhooks\";\n","import { Commet } from \"@commet/node\";\nimport { type NextRequest, NextResponse } from \"next/server\";\n\nexport interface CustomerPortalConfig {\n apiKey: string;\n getCustomerId: (req: NextRequest) => Promise<string | null>;\n onError?: (error: Error) => void;\n}\n\n/**\n * Creates Next.js route handler for Customer Portal access\n *\n * @example\n * ```typescript\n * // app/api/commet/portal/route.ts\n * import { CustomerPortal } from \"@commet/next\";\n * import { auth } from \"@/lib/auth\";\n *\n * export const GET = CustomerPortal({\n * apiKey: process.env.COMMET_API_KEY!,\n * getCustomerId: async (req) => {\n * const session = await auth.api.getSession({ headers: req.headers });\n * return session?.user.id ?? null;\n * },\n * });\n * ```\n *\n * @example\n * ```tsx\n * // Use in component\n * export function BillingButton() {\n * return (\n * <Button asChild>\n * <Link href=\"/api/commet/portal\">Manage Billing</Link>\n * </Button>\n * );\n * }\n * ```\n */\nexport const CustomerPortal = ({\n apiKey,\n getCustomerId,\n onError,\n}: CustomerPortalConfig) => {\n const commet = new Commet({\n apiKey,\n });\n\n return async (req: NextRequest) => {\n try {\n // Get customer identifier from request\n const customerId = await getCustomerId(req);\n\n if (!customerId) {\n return NextResponse.json(\n { error: \"Customer not authenticated\" },\n { status: 401 },\n );\n }\n\n // Get portal URL from Commet\n const result = await commet.portal.getUrl({\n customerId,\n });\n\n if (!result.success || !result.data) {\n throw new Error(\n result.error?.message || \"Failed to create portal session\",\n );\n }\n\n // Redirect to customer portal\n return NextResponse.redirect(result.data.portalUrl);\n } catch (error) {\n const errorObj =\n error instanceof Error ? error : new Error(String(error));\n\n // Call custom error handler if provided\n onError?.(errorObj);\n\n // Log error\n console.error(\"[Commet Portal]\", errorObj);\n\n // Return error response\n return NextResponse.json(\n { error: \"Failed to access customer portal\" },\n { status: 500 },\n );\n }\n };\n};\n","import type { BillingInterval, CreditPack, Plan } from \"@commet/node\";\nimport { Commet } from \"@commet/node\";\nimport { type NextRequest, NextResponse } from \"next/server\";\n\ntype PlanFeature = NonNullable<Plan[\"features\"]>[number];\n\nexport interface PricingMarkdownConfig {\n apiKey: string;\n title: string;\n description?: string;\n includeCreditPacks?: boolean;\n billingIntervals?: BillingInterval[];\n cacheMaxAge?: number;\n onError?: (error: Error) => void;\n}\n\nconst INTERVAL_SHORT: Record<BillingInterval, string> = {\n weekly: \"/wk\",\n monthly: \"/mo\",\n quarterly: \"/qtr\",\n yearly: \"/yr\",\n one_time: \"\",\n};\n\nexport const PricingMarkdown = ({\n apiKey,\n title,\n description,\n includeCreditPacks = false,\n billingIntervals,\n cacheMaxAge = 3600,\n onError,\n}: PricingMarkdownConfig) => {\n const commet = new Commet({ apiKey });\n\n return async (_req: NextRequest) => {\n try {\n const plansResult = await commet.plans.list();\n\n if (!plansResult.success || !plansResult.data) {\n throw new Error(plansResult.error?.message ?? \"Failed to fetch plans\");\n }\n\n const publicPlans = plansResult.data.filter((plan) => plan.isPublic);\n\n const creditPacks = includeCreditPacks\n ? await commet.creditPacks\n .list()\n .then((result) =>\n result.success && result.data ? result.data : [],\n )\n : [];\n\n const markdown = generateMarkdown(\n title,\n description,\n publicPlans,\n creditPacks,\n billingIntervals,\n );\n\n return new NextResponse(markdown, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/markdown; charset=utf-8\",\n \"Cache-Control\": `public, s-maxage=${cacheMaxAge}, stale-while-revalidate=${cacheMaxAge * 2}`,\n },\n });\n } catch (error) {\n const errorObj =\n error instanceof Error ? error : new Error(String(error));\n\n onError?.(errorObj);\n console.error(\"[Commet PricingMarkdown]\", errorObj);\n\n return NextResponse.json(\n { error: \"Failed to generate pricing markdown\" },\n { status: 500 },\n );\n }\n };\n};\n\nfunction generateMarkdown(\n title: string,\n description: string | undefined,\n plans: Plan[],\n creditPacks: CreditPack[],\n billingIntervals?: BillingInterval[],\n): string {\n const sections: string[] = [`# ${title}`];\n\n if (description) {\n sections.push(description);\n }\n\n if (plans.length > 0) {\n sections.push(renderPlansTable(plans, billingIntervals));\n\n const featuresSection = renderFeatures(plans);\n if (featuresSection) {\n sections.push(featuresSection);\n }\n }\n\n if (creditPacks.length > 0) {\n sections.push(renderCreditPacks(creditPacks));\n }\n\n return sections.join(\"\\n\\n\");\n}\n\nfunction renderPlansTable(\n plans: Plan[],\n filterIntervals?: BillingInterval[],\n): string {\n const usageFeatures = collectUsageFeatures(plans);\n\n const headerCols = [\"Plan\", \"Price\"];\n for (const { name, unitName } of usageFeatures) {\n headerCols.push(`${name}/${unitName ?? \"unit\"}`);\n headerCols.push(\"Overage\");\n }\n\n const rows = plans.map((plan) => {\n const priceCell = renderPriceCell(plan, filterIntervals);\n const cols = [plan.name, priceCell];\n\n const featuresByCode = new Map(\n (plan.features ?? []).map((feature) => [feature.code, feature]),\n );\n\n for (const { code } of usageFeatures) {\n const feature = featuresByCode.get(code);\n\n if (!feature) {\n cols.push(\"—\", \"—\");\n continue;\n }\n\n if (feature.unlimited) {\n cols.push(\"Unlimited\", \"—\");\n continue;\n }\n\n const included = feature.includedAmount;\n cols.push(included ? formatNumber(included) : \"—\");\n\n const overagePrice =\n feature.overage?.enabled && feature.overage.unitPrice !== null\n ? formatRatePrice(feature.overage.unitPrice)\n : \"—\";\n cols.push(overagePrice);\n }\n\n return cols;\n });\n\n const separator = headerCols.map(() => \"---\");\n const lines = [\n `| ${headerCols.join(\" | \")} |`,\n `| ${separator.join(\" | \")} |`,\n ...rows.map((cols) => `| ${cols.join(\" | \")} |`),\n ];\n\n const footnotes: string[] = [];\n\n const trialPlans = plans.filter((plan) =>\n (plan.prices ?? []).some((price) => price.trialDays > 0),\n );\n for (const plan of trialPlans) {\n const trialPrice = (plan.prices ?? []).find(\n (price) => price.trialDays > 0,\n )!;\n footnotes.push(\n `*${plan.name} plan includes a ${trialPrice.trialDays}-day free trial.*`,\n );\n }\n\n if (usageFeatures.length > 0) {\n footnotes.push(\n \"The overage rate applies only to usage beyond the included volume.\",\n );\n }\n\n return footnotes.length > 0\n ? `## Plans\\n\\n${lines.join(\"\\n\")}\\n\\n${footnotes.join(\"\\n\\n\")}`\n : `## Plans\\n\\n${lines.join(\"\\n\")}`;\n}\n\nfunction renderPriceCell(\n plan: Plan,\n filterIntervals?: BillingInterval[],\n): string {\n if (plan.isFree) return \"Free\";\n\n const prices = filterIntervals\n ? (plan.prices ?? []).filter((price) =>\n filterIntervals.includes(price.billingInterval),\n )\n : (plan.prices ?? []);\n\n if (prices.length === 0) return \"—\";\n\n return prices\n .map((price) => {\n if (price.price === 0) return \"Free\";\n return `${formatSettlementPrice(price.price)}${INTERVAL_SHORT[price.billingInterval]}`;\n })\n .join(\" / \");\n}\n\nfunction renderFeatures(plans: Plan[]): string | null {\n const allBooleanCodes = new Set<string>();\n for (const plan of plans) {\n for (const feature of plan.features ?? []) {\n if (feature.type === \"boolean\") {\n allBooleanCodes.add(feature.code);\n }\n }\n }\n\n if (allBooleanCodes.size === 0) return null;\n\n const enabledOnAll = new Set<string>();\n for (const code of allBooleanCodes) {\n const enabledOnEveryPlan = plans.every((plan) => {\n const feature = (plan.features ?? []).find((f) => f.code === code);\n return feature?.enabled;\n });\n if (enabledOnEveryPlan) {\n enabledOnAll.add(code);\n }\n }\n\n const perPlanLines: string[] = [];\n for (const plan of plans) {\n const uniqueFeatures = (plan.features ?? [])\n .filter(\n (feature) =>\n feature.type === \"boolean\" &&\n feature.enabled &&\n !enabledOnAll.has(feature.code),\n )\n .map((feature) => feature.name);\n\n if (uniqueFeatures.length > 0) {\n perPlanLines.push(`- **${plan.name}**: ${uniqueFeatures.join(\", \")}`);\n }\n }\n\n const commonFeatures = (plans[0]?.features ?? [])\n .filter(\n (feature) => feature.type === \"boolean\" && enabledOnAll.has(feature.code),\n )\n .map((feature) => feature.name);\n\n const parts: string[] = [];\n\n if (perPlanLines.length > 0) {\n parts.push(perPlanLines.join(\"\\n\"));\n }\n\n if (commonFeatures && commonFeatures.length > 0) {\n parts.push(`All plans include: ${commonFeatures.join(\", \")}.`);\n }\n\n return parts.length > 0 ? `## Features\\n\\n${parts.join(\"\\n\\n\")}` : null;\n}\n\nfunction renderCreditPacks(packs: CreditPack[]): string {\n const lines = [\n \"| Pack | Credits | Price |\",\n \"| --- | --- | --- |\",\n ...packs.map(\n (pack) =>\n `| ${pack.name} | ${formatNumber(pack.credits)} credits | ${formatSettlementPrice(pack.price)} |`,\n ),\n ];\n\n return `## Credit Packs\\n\\n${lines.join(\"\\n\")}`;\n}\n\ninterface UsageFeatureColumn {\n code: string;\n name: string;\n unitName: string | null;\n}\n\nfunction collectUsageFeatures(plans: Plan[]): UsageFeatureColumn[] {\n const seen = new Map<string, UsageFeatureColumn>();\n for (const plan of plans) {\n for (const feature of plan.features ?? []) {\n if (\n (feature.type === \"usage\" || feature.type === \"seats\") &&\n !seen.has(feature.code) &&\n hasUsageData(feature)\n ) {\n seen.set(feature.code, {\n code: feature.code,\n name: feature.name,\n unitName: feature.unitName,\n });\n }\n }\n }\n return Array.from(seen.values());\n}\n\nfunction hasUsageData(feature: PlanFeature): boolean {\n return (\n feature.unlimited === true ||\n (feature.includedAmount !== null && feature.includedAmount > 0) ||\n (feature.overage?.enabled === true && feature.overage.unitPrice !== null)\n );\n}\n\nfunction formatSettlementPrice(cents: number): string {\n if (cents === 0) return \"Free\";\n const dollars = cents / 100;\n const [whole, decimal] = dollars.toFixed(2).split(\".\");\n return `$${Number(whole).toLocaleString(\"en-US\")}.${decimal}`;\n}\n\nfunction formatRatePrice(rate: number): string {\n const dollars = rate / 10000;\n\n if (dollars === Math.floor(dollars)) {\n return `$${dollars.toFixed(2)}`;\n }\n\n const formatted = dollars.toFixed(4).replace(/0+$/, \"\");\n const decimalPlaces = formatted.split(\".\")[1]?.length ?? 0;\n if (decimalPlaces < 2) {\n return `$${dollars.toFixed(2)}`;\n }\n\n return `$${formatted}`;\n}\n\nfunction formatNumber(n: number): string {\n return n.toLocaleString(\"en-US\");\n}\n","import type { WebhookEvent, WebhookEventPayload } from \"@commet/node\";\nimport { Webhooks as CommetWebhooks } from \"@commet/node\";\nimport { type NextRequest, NextResponse } from \"next/server\";\nimport type { WebhookHandlerName, WebhooksConfig } from \"./types\";\n\nconst webhookEventHandlerNames = {\n \"subscription.created\": \"onSubscriptionCreated\",\n \"subscription.activated\": \"onSubscriptionActivated\",\n \"subscription.reactivated\": \"onSubscriptionReactivated\",\n \"subscription.canceled\": \"onSubscriptionCanceled\",\n \"subscription.updated\": \"onSubscriptionUpdated\",\n \"subscription.plan_changed\": \"onSubscriptionPlanChanged\",\n \"subscription.cancellation_scheduled\": \"onSubscriptionCancellationScheduled\",\n \"subscription.cancellation_revoked\": \"onSubscriptionCancellationRevoked\",\n \"subscription.plan_change_scheduled\": \"onSubscriptionPlanChangeScheduled\",\n \"subscription.plan_change_revoked\": \"onSubscriptionPlanChangeRevoked\",\n \"subscription.past_due\": \"onSubscriptionPastDue\",\n \"trial.started\": \"onTrialStarted\",\n \"trial.converted\": \"onTrialConverted\",\n \"trial.expired\": \"onTrialExpired\",\n \"trial.will_end\": \"onTrialWillEnd\",\n \"trial.checkout_ready\": \"onTrialCheckoutReady\",\n \"checkout.ready\": \"onCheckoutReady\",\n \"payment.received\": \"onPaymentReceived\",\n \"payment.failed\": \"onPaymentFailed\",\n \"payment.recovered\": \"onPaymentRecovered\",\n \"payment.retry_failed\": \"onPaymentRetryFailed\",\n \"payment.refunded\": \"onPaymentRefunded\",\n \"payment.disputed\": \"onPaymentDisputed\",\n \"payment.dispute_resolved\": \"onPaymentDisputeResolved\",\n \"payment_link.created\": \"onPaymentLinkCreated\",\n \"payment_link.completed\": \"onPaymentLinkCompleted\",\n \"payment_link.failed\": \"onPaymentLinkFailed\",\n \"payment_link.canceled\": \"onPaymentLinkCanceled\",\n \"invoice.created\": \"onInvoiceCreated\",\n \"invoice.upcoming\": \"onInvoiceUpcoming\",\n \"invoice.overdue\": \"onInvoiceOverdue\",\n \"invoice.voided\": \"onInvoiceVoided\",\n \"payment_method.attached\": \"onPaymentMethodAttached\",\n \"payment_method.updated\": \"onPaymentMethodUpdated\",\n \"customer.created\": \"onCustomerCreated\",\n \"customer.updated\": \"onCustomerUpdated\",\n \"customer.state_changed\": \"onCustomerStateChanged\",\n \"credits.granted\": \"onCreditsGranted\",\n \"credits.purchased\": \"onCreditsPurchased\",\n \"credits.low\": \"onCreditsLow\",\n \"credits.depleted\": \"onCreditsDepleted\",\n \"credits.expired\": \"onCreditsExpired\",\n \"balance.topped_up\": \"onBalanceToppedUp\",\n \"balance.low\": \"onBalanceLow\",\n \"balance.depleted\": \"onBalanceDepleted\",\n \"quota.threshold_reached\": \"onQuotaThresholdReached\",\n \"quota.exceeded\": \"onQuotaExceeded\",\n \"usage.recorded\": \"onUsageRecorded\",\n \"seats.updated\": \"onSeatsUpdated\",\n \"seats.limit_reached\": \"onSeatsLimitReached\",\n \"addon.activated\": \"onAddonActivated\",\n \"addon.deactivated\": \"onAddonDeactivated\",\n \"payout.available\": \"onPayoutAvailable\",\n \"payout.created\": \"onPayoutCreated\",\n \"payout.paid\": \"onPayoutPaid\",\n \"payout.failed\": \"onPayoutFailed\",\n} as const satisfies Record<WebhookEvent, WebhookHandlerName>;\n\ntype RuntimeWebhookHandler = (payload: WebhookEventPayload) => Promise<void>;\n\n/**\n * Create a Next.js webhook handler for Commet events\n *\n * Automatically verifies signatures, routes events to handlers, and returns proper responses.\n *\n * @param config - Webhook configuration with secret and event handlers\n * @returns Next.js route handler function\n *\n * @example\n * ```typescript\n * // app/api/webhooks/commet/route.ts\n * import { Webhooks } from \"@commet/next\";\n *\n * export const POST = Webhooks({\n * webhookSecret: process.env.COMMET_WEBHOOK_SECRET!,\n * onSubscriptionActivated: async (payload) => {\n * // Grant access to user\n * },\n * onSubscriptionCanceled: async (payload) => {\n * // Revoke access from user\n * },\n * });\n * ```\n */\nexport const Webhooks = (config: WebhooksConfig) => {\n const { webhookSecret, onPayload, onError } = config;\n\n const webhooks = new CommetWebhooks();\n\n return async (request: NextRequest) => {\n try {\n const rawBody = await request.text();\n const signature = request.headers.get(\"x-commet-signature\");\n\n const isValid = webhooks.verify({\n payload: rawBody,\n signature,\n secret: webhookSecret,\n });\n\n if (!isValid) {\n console.error(\"[Commet Webhook] Invalid signature\");\n return NextResponse.json(\n { received: false, error: \"Invalid signature\" },\n { status: 403 },\n );\n }\n\n let payload: WebhookEventPayload;\n try {\n payload = JSON.parse(rawBody) as WebhookEventPayload;\n } catch (parseError) {\n console.error(\"[Commet Webhook] Failed to parse payload:\", parseError);\n if (onError) {\n await onError(\n parseError instanceof Error\n ? parseError\n : new Error(\"Failed to parse webhook payload\"),\n rawBody,\n );\n }\n return NextResponse.json(\n { received: false, error: \"Invalid payload\" },\n { status: 400 },\n );\n }\n\n const promises: Promise<void>[] = [];\n\n if (onPayload) {\n promises.push(onPayload(payload));\n }\n\n const handlerName = webhookEventHandlerNames[payload.event];\n const handler = config[handlerName] as RuntimeWebhookHandler | undefined;\n if (handler) {\n promises.push(handler(payload));\n }\n\n try {\n await Promise.all(promises);\n } catch (handlerError) {\n console.error(\n \"[Commet Webhook] Handler error:\",\n handlerError instanceof Error ? handlerError.message : handlerError,\n );\n if (onError) {\n await onError(\n handlerError instanceof Error\n ? handlerError\n : new Error(\"Handler execution failed\"),\n payload,\n );\n }\n return NextResponse.json(\n { received: false, error: \"Handler failed\" },\n { status: 500 },\n );\n }\n\n return NextResponse.json({ received: true }, { status: 200 });\n } catch (error) {\n console.error(\"[Commet Webhook] Unexpected error:\", error);\n if (onError) {\n try {\n await onError(\n error instanceof Error ? error : new Error(\"Unexpected error\"),\n undefined,\n );\n } catch (errorHandlerError) {\n console.error(\n \"[Commet Webhook] Error handler failed:\",\n errorHandlerError,\n );\n }\n }\n return NextResponse.json(\n { received: false, error: \"Internal error\" },\n { status: 500 },\n );\n }\n };\n};\n"],"mappings":"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","names":["Commet","NextResponse","NextResponse"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@commet/next",
3
- "version": "1.0.11",
3
+ "version": "1.1.0",
4
4
  "description": "Next.js integration for Commet billing platform",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",