@commet/node 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/customer.ts","../src/resources/customers.ts","../src/resources/features.ts","../src/resources/plans.ts","../src/resources/portal.ts","../src/resources/seats.ts","../src/resources/subscriptions.ts","../src/resources/usage.ts","../src/resources/webhooks.ts","../src/types/common.ts","../src/utils/http.ts","../src/client.ts","../src/utils/environment.ts"],"sourcesContent":["/**\n * Commet SDK - Billing and usage tracking for SaaS\n */\nexport { Commet } from \"./client\";\nexport { CustomerContext } from \"./customer\";\n\n// Type exports\nexport type {\n CommetConfig,\n CommetGeneratedTypes,\n GeneratedEventType,\n GeneratedSeatType,\n GeneratedPlanCode,\n GeneratedFeatureCode,\n Environment,\n ApiResponse,\n PaginatedResponse,\n PaginatedList,\n Currency,\n CustomerID,\n EventID,\n RequestOptions,\n} from \"./types/common\";\n\n// Error exports\nexport {\n CommetError,\n CommetAPIError,\n CommetValidationError,\n} from \"./types/common\";\n\n// Customers\nexport type {\n Customer,\n CustomerAddress,\n CreateParams as CreateCustomerParams,\n UpdateParams as UpdateCustomerParams,\n ListCustomersParams,\n BatchResult as CustomersBatchResult,\n} from \"./resources/customers\";\n\n// Usage\nexport type {\n UsageEvent,\n UsageEventProperty,\n TrackParams,\n BatchResult as UsageBatchResult,\n} from \"./resources/usage\";\n\n// Seats\nexport type {\n SeatEvent,\n SeatBalance,\n AddParams as AddSeatsParams,\n RemoveParams as RemoveSeatsParams,\n SetParams as SetSeatsParams,\n SetAllParams as SetAllSeatsParams,\n GetBalanceParams,\n GetAllBalancesParams,\n} from \"./resources/seats\";\n\n// Plans\nexport type {\n Plan,\n PlanDetail,\n PlanPrice,\n PlanFeature,\n PlanID,\n BillingInterval,\n FeatureType,\n ListPlansParams,\n} from \"./resources/plans\";\n\n// Subscriptions\nexport type {\n Subscription,\n ActiveSubscription,\n SubscriptionStatus,\n FeatureSummary,\n CreateSubscriptionParams,\n ChangePlanParams,\n CancelParams,\n GetSubscriptionParams,\n} from \"./resources/subscriptions\";\n\n// Portal\nexport type { PortalAccess, GetUrlParams } from \"./resources/portal\";\n\n// Features\nexport type {\n FeatureAccess,\n CanUseResult,\n CheckResult,\n} from \"./resources/features\";\n\n// Webhooks\nexport { Webhooks } from \"./resources/webhooks\";\nexport type {\n WebhookPayload,\n WebhookData,\n WebhookEvent,\n} from \"./resources/webhooks\";\n\n// Utility exports\nexport { isSandbox, isProduction } from \"./utils/environment\";\n\n// Default export\nimport { Commet } from \"./client\";\nexport default Commet;\n","import type { RequestOptions } from \"./types/common\";\nimport type { FeaturesResource } from \"./resources/features\";\nimport type { SeatsResource } from \"./resources/seats\";\nimport type { UsageResource } from \"./resources/usage\";\nimport type { SubscriptionsResource } from \"./resources/subscriptions\";\nimport type { PortalResource } from \"./resources/portal\";\n\n/**\n * Customer-scoped API context\n *\n * Provides a cleaner API where you don't have to pass externalId\n * on every call. All operations are scoped to a specific customer.\n *\n * @example\n * ```typescript\n * const customer = commet.customer(\"user_123\");\n *\n * // All operations are now scoped to this customer\n * const seats = await customer.features.get(\"team_members\");\n * await customer.seats.add(\"member\");\n * await customer.usage.track(\"api_call\");\n * ```\n */\nexport class CustomerContext {\n private readonly externalId: string;\n private readonly featuresResource: FeaturesResource;\n private readonly seatsResource: SeatsResource;\n private readonly usageResource: UsageResource;\n private readonly subscriptionsResource: SubscriptionsResource;\n private readonly portalResource: PortalResource;\n\n constructor(\n externalId: string,\n resources: {\n features: FeaturesResource;\n seats: SeatsResource;\n usage: UsageResource;\n subscriptions: SubscriptionsResource;\n portal: PortalResource;\n },\n ) {\n this.externalId = externalId;\n this.featuresResource = resources.features;\n this.seatsResource = resources.seats;\n this.usageResource = resources.usage;\n this.subscriptionsResource = resources.subscriptions;\n this.portalResource = resources.portal;\n }\n\n /**\n * Feature access methods - delegates to FeaturesResource\n */\n features = {\n get: (code: string, options?: RequestOptions) =>\n this.featuresResource.get(code, this.externalId, options),\n\n check: (code: string, options?: RequestOptions) =>\n this.featuresResource.check(code, this.externalId, options),\n\n canUse: (code: string, options?: RequestOptions) =>\n this.featuresResource.canUse(code, this.externalId, options),\n\n list: (options?: RequestOptions) =>\n this.featuresResource.list(this.externalId, options),\n };\n\n /**\n * Seat management methods - delegates to SeatsResource\n */\n seats = {\n add: (seatType: string, count = 1, options?: RequestOptions) =>\n this.seatsResource.add(\n { externalId: this.externalId, seatType, count },\n options,\n ),\n\n remove: (seatType: string, count = 1, options?: RequestOptions) =>\n this.seatsResource.remove(\n { externalId: this.externalId, seatType, count },\n options,\n ),\n\n set: (seatType: string, count: number, options?: RequestOptions) =>\n this.seatsResource.set(\n { externalId: this.externalId, seatType, count },\n options,\n ),\n\n getBalance: (seatType: string) =>\n this.seatsResource.getBalance({ externalId: this.externalId, seatType }),\n };\n\n /**\n * Usage tracking methods - delegates to UsageResource\n */\n usage = {\n track: (\n eventType: string,\n properties?: Record<string, string>,\n options?: RequestOptions,\n ) =>\n this.usageResource.track(\n { externalId: this.externalId, eventType, properties },\n options,\n ),\n };\n\n /**\n * Subscription methods - delegates to SubscriptionsResource\n */\n subscription = {\n get: () => this.subscriptionsResource.get({ externalId: this.externalId }),\n };\n\n /**\n * Portal methods - delegates to PortalResource\n */\n portal = {\n getUrl: (options?: RequestOptions) =>\n this.portalResource.getUrl({ externalId: this.externalId }, options),\n };\n}\n","import type {\n ApiResponse,\n ListParams as BaseListParams,\n CustomerID,\n RequestOptions,\n} from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\n\nexport interface Customer {\n id: CustomerID;\n organizationId: string;\n externalId?: string;\n legalName?: string;\n displayName?: string;\n domain?: string;\n website?: string;\n billingEmail: string;\n timezone?: string;\n language?: string;\n industry?: string;\n employeeCount?: string;\n metadata?: Record<string, unknown>;\n isActive: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CustomerAddress {\n line1: string;\n line2?: string;\n city: string;\n state?: string;\n postalCode: string;\n country: string; // ISO-2\n}\n\nexport interface CreateParams {\n email: string; // billingEmail - the only required field\n externalId?: string;\n legalName?: string;\n displayName?: string;\n domain?: string;\n website?: string;\n timezone?: string;\n language?: string;\n industry?: string;\n metadata?: Record<string, unknown>;\n address?: CustomerAddress;\n}\n\nexport interface UpdateParams {\n externalId?: string;\n email?: string;\n legalName?: string;\n displayName?: string;\n domain?: string;\n website?: string;\n timezone?: string;\n language?: string;\n industry?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface ListCustomersParams extends BaseListParams {\n externalId?: string;\n isActive?: boolean;\n search?: string;\n}\n\nexport interface BatchResult {\n successful: Customer[];\n failed: Array<{\n index: number;\n error: string;\n data: CreateParams;\n }>;\n}\n\n/**\n * Customers resource - Manage your customers\n */\nexport class CustomersResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n /**\n * Create a customer (idempotent with externalId)\n */\n async create(\n params: CreateParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<Customer>> {\n return this.httpClient.post(\n \"/customers\",\n {\n billingEmail: params.email,\n externalId: params.externalId,\n legalName: params.legalName,\n displayName: params.displayName,\n domain: params.domain,\n website: params.website,\n timezone: params.timezone,\n language: params.language,\n industry: params.industry,\n metadata: params.metadata,\n address: params.address,\n },\n options,\n );\n }\n\n /**\n * Create multiple customers in batch\n */\n async createBatch(\n params: { customers: CreateParams[] },\n options?: RequestOptions,\n ): Promise<ApiResponse<BatchResult>> {\n const customers = params.customers.map((c) => ({\n billingEmail: c.email,\n externalId: c.externalId,\n legalName: c.legalName,\n displayName: c.displayName,\n domain: c.domain,\n website: c.website,\n timezone: c.timezone,\n language: c.language,\n industry: c.industry,\n metadata: c.metadata,\n address: c.address,\n }));\n return this.httpClient.post(\"/customers/batch\", { customers }, options);\n }\n\n /**\n * Get a customer by ID\n */\n async get(customerId: CustomerID): Promise<ApiResponse<Customer>> {\n return this.httpClient.get(`/customers/${customerId}`);\n }\n\n /**\n * Update a customer\n */\n async update(\n customerId: CustomerID,\n params: UpdateParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<Customer>> {\n return this.httpClient.put(\n `/customers/${customerId}`,\n {\n billingEmail: params.email,\n externalId: params.externalId,\n legalName: params.legalName,\n displayName: params.displayName,\n domain: params.domain,\n website: params.website,\n timezone: params.timezone,\n language: params.language,\n industry: params.industry,\n metadata: params.metadata,\n },\n options,\n );\n }\n\n /**\n * List customers with optional filters\n */\n async list(params?: ListCustomersParams): Promise<ApiResponse<Customer[]>> {\n return this.httpClient.get(\"/customers\", params as Record<string, unknown>);\n }\n\n /**\n * Archive a customer\n */\n async archive(\n customerId: CustomerID,\n options?: RequestOptions,\n ): Promise<ApiResponse<Customer>> {\n return this.httpClient.put(\n `/customers/${customerId}`,\n { isActive: false },\n options,\n );\n }\n}\n","import type {\n ApiResponse,\n GeneratedFeatureCode,\n RequestOptions,\n} from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\n\nexport interface FeatureAccess {\n code: string;\n name: string;\n type: \"boolean\" | \"metered\" | \"seats\";\n allowed: boolean;\n // For boolean features\n enabled?: boolean;\n // For metered/seats features\n current?: number;\n included?: number;\n remaining?: number;\n overage?: number;\n overageUnitPrice?: number;\n unlimited?: boolean;\n overageEnabled?: boolean;\n}\n\nexport interface CanUseResult {\n allowed: boolean;\n willBeCharged: boolean;\n reason?: string;\n}\n\nexport interface CheckResult {\n allowed: boolean;\n}\n\n/**\n * Features resource for checking feature access and usage\n *\n * Provides a clean API to check if a customer can use a feature\n * without having to manually parse subscription data.\n */\nexport class FeaturesResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n /**\n * Get detailed feature access/usage for a customer\n *\n * @example\n * ```typescript\n * const seats = await commet.features.get(\"team_members\", \"user_123\");\n * console.log(seats.current, seats.included, seats.remaining);\n * ```\n */\n async get(\n code: GeneratedFeatureCode,\n externalId: string,\n options?: RequestOptions,\n ): Promise<ApiResponse<FeatureAccess>> {\n return this.httpClient.get(\n `/features/${code}`,\n { externalId },\n options,\n );\n }\n\n /**\n * Check if a boolean feature is enabled for a customer\n *\n * @example\n * ```typescript\n * const { allowed } = await commet.features.check(\"custom_branding\", \"user_123\");\n * if (!allowed) redirect(\"/upgrade\");\n * ```\n */\n async check(\n code: GeneratedFeatureCode,\n externalId: string,\n options?: RequestOptions,\n ): Promise<ApiResponse<CheckResult>> {\n const result = await this.httpClient.get<FeatureAccess>(\n `/features/${code}`,\n { externalId },\n options,\n );\n\n if (!result.success || !result.data) {\n return {\n success: false,\n data: { allowed: false },\n message: result.message,\n };\n }\n\n return {\n success: true,\n data: { allowed: result.data.allowed },\n message: result.message,\n };\n }\n\n /**\n * Check if customer can use one more unit of a feature\n *\n * Returns whether the customer can add one more (allowed)\n * and whether they'll be charged extra (willBeCharged).\n *\n * @example\n * ```typescript\n * const { allowed, willBeCharged } = await commet.features.canUse(\"team_members\", \"user_123\");\n *\n * if (!allowed) {\n * return { error: \"Upgrade to add more members\" };\n * }\n *\n * if (willBeCharged) {\n * // Show confirmation: \"This will cost $10/month extra\"\n * }\n * ```\n */\n async canUse(\n code: GeneratedFeatureCode,\n externalId: string,\n options?: RequestOptions,\n ): Promise<ApiResponse<CanUseResult>> {\n return this.httpClient.get(\n `/features/${code}`,\n { externalId, action: \"canUse\" },\n options,\n );\n }\n\n /**\n * List all features for a customer's active subscription\n *\n * @example\n * ```typescript\n * const features = await commet.features.list(\"user_123\");\n * for (const feature of features) {\n * console.log(feature.code, feature.allowed);\n * }\n * ```\n */\n async list(\n externalId: string,\n options?: RequestOptions,\n ): Promise<ApiResponse<FeatureAccess[]>> {\n return this.httpClient.get(\"/features\", { externalId }, options);\n }\n}\n\n","import type {\n ApiResponse,\n GeneratedPlanCode,\n ListParams,\n} from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\n\nexport type PlanID = `plan_${string}`;\nexport type BillingInterval = \"monthly\" | \"quarterly\" | \"yearly\";\nexport type FeatureType = \"boolean\" | \"metered\" | \"seats\";\n\nexport interface PlanPrice {\n billingInterval: BillingInterval;\n price: number; // in cents\n isDefault: boolean;\n}\n\nexport interface PlanFeature {\n code: string;\n name: string;\n type: FeatureType;\n enabled?: boolean;\n includedAmount?: number;\n unlimited?: boolean;\n overageEnabled?: boolean;\n overageUnitPrice?: number;\n}\n\nexport interface Plan {\n id: PlanID;\n name: string;\n description?: string;\n isPublic: boolean;\n isDefault: boolean;\n trialDays: number;\n sortOrder: number;\n prices: PlanPrice[];\n features: PlanFeature[];\n createdAt: string;\n}\n\nexport interface PlanDetail extends Plan {\n features: Array<\n PlanFeature & {\n unitName?: string;\n overage?: {\n enabled: boolean;\n model: \"per_unit\" | \"tiered\";\n unitPrice: number;\n tiers?: Array<{\n order: number;\n upTo: number | null;\n unitAmount: number;\n flatFee: number;\n }>;\n } | null;\n }\n >;\n updatedAt: string;\n}\n\nexport interface ListPlansParams extends ListParams {\n includePrivate?: boolean;\n}\n\n/**\n * Plans resource for listing available plans\n */\nexport class PlansResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n /**\n * List all available plans\n *\n * @example\n * ```typescript\n * // List public plans\n * const plans = await commet.plans.list();\n *\n * // Include private plans\n * const allPlans = await commet.plans.list({ includePrivate: true });\n * ```\n */\n async list(params?: ListPlansParams): Promise<ApiResponse<Plan[]>> {\n return this.httpClient.get(\"/plans\", params);\n }\n\n /**\n * Get a specific plan by code\n *\n * @example\n * ```typescript\n * const plan = await commet.plans.get('pro');\n * console.log(plan.data.name); // \"Pro\"\n * console.log(plan.data.prices); // [{ billingInterval: 'monthly', price: 9900 }]\n * ```\n */\n async get(planCode: GeneratedPlanCode): Promise<ApiResponse<PlanDetail>> {\n return this.httpClient.get(`/plans/${planCode}`);\n }\n}\n","import type { ApiResponse, CustomerID, RequestOptions } from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\n\nexport interface PortalAccess {\n success: boolean;\n message: string;\n portalUrl: string;\n}\n\ninterface GetUrlByCustomerId {\n customerId: CustomerID;\n email?: never;\n externalId?: never;\n}\n\ninterface GetUrlByExternalId {\n externalId: string;\n email?: never;\n customerId?: never;\n}\n\ninterface GetUrlByEmail {\n email: string;\n customerId?: never;\n externalId?: never;\n}\n\nexport type GetUrlParams =\n | GetUrlByCustomerId\n | GetUrlByExternalId\n | GetUrlByEmail;\n\n/**\n * Portal resource - Generate customer portal access\n */\nexport class PortalResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n /**\n * Get a portal URL\n *\n * @example\n * ```typescript\n * const portal = await commet.portal.getUrl({ externalId: 'user_123' });\n * ```\n */\n async getUrl(\n params: GetUrlParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<PortalAccess>> {\n return this.httpClient.post(\"/portal/request-access\", params, options);\n }\n}\n","import type {\n ApiResponse,\n CustomerID,\n GeneratedSeatType,\n RequestOptions,\n} from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\n\nexport interface SeatEvent {\n id: string;\n organizationId: string;\n customerId: CustomerID;\n seatType: GeneratedSeatType;\n eventType: \"add\" | \"remove\" | \"set\";\n quantity: number;\n previousBalance?: number;\n newBalance: number;\n ts: string;\n createdAt: string;\n}\n\nexport interface SeatBalance {\n current: number;\n asOf: string;\n}\n\nexport interface AddParams {\n customerId?: CustomerID;\n externalId?: string;\n seatType: GeneratedSeatType;\n count: number;\n}\n\nexport interface RemoveParams {\n customerId?: CustomerID;\n externalId?: string;\n seatType: GeneratedSeatType;\n count: number;\n}\n\nexport interface SetParams {\n customerId?: CustomerID;\n externalId?: string;\n seatType: GeneratedSeatType;\n count: number;\n}\n\nexport interface SetAllParams {\n customerId?: CustomerID;\n externalId?: string;\n seats: Record<string, number>;\n}\n\nexport interface GetBalanceParams {\n customerId?: CustomerID;\n externalId?: string;\n seatType: GeneratedSeatType;\n}\n\nexport interface GetAllBalancesParams {\n customerId?: CustomerID;\n externalId?: string;\n}\n\n/**\n * Seats resource - Manage seat-based licenses\n */\nexport class SeatsResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n /**\n * Add seats\n *\n * @example\n * ```typescript\n * await commet.seats.add({\n * externalId: 'user_123',\n * seatType: 'editor',\n * count: 5\n * });\n * ```\n */\n async add(\n params: AddParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<SeatEvent>> {\n return this.httpClient.post(\"/seats\", params, options);\n }\n\n /**\n * Remove seats\n *\n * @example\n * ```typescript\n * await commet.seats.remove({\n * externalId: 'user_123',\n * seatType: 'editor',\n * count: 2\n * });\n * ```\n */\n async remove(\n params: RemoveParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<SeatEvent>> {\n return this.httpClient.delete(\"/seats\", params, options);\n }\n\n /**\n * Set seats to a specific count\n *\n * @example\n * ```typescript\n * await commet.seats.set({\n * externalId: 'user_123',\n * seatType: 'editor',\n * count: 10\n * });\n * ```\n */\n async set(\n params: SetParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<SeatEvent>> {\n return this.httpClient.put(\"/seats\", params, options);\n }\n\n /**\n * Set all seat types\n *\n * @example\n * ```typescript\n * await commet.seats.setAll({\n * externalId: 'user_123',\n * seats: { editor: 10, viewer: 50 }\n * });\n * ```\n */\n async setAll(\n params: SetAllParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<SeatEvent[]>> {\n return this.httpClient.put(\"/seats/bulk\", params, options);\n }\n\n /**\n * Get balance for a seat type\n *\n * @example\n * ```typescript\n * const balance = await commet.seats.getBalance({\n * externalId: 'user_123',\n * seatType: 'editor'\n * });\n * ```\n */\n async getBalance(\n params: GetBalanceParams,\n ): Promise<ApiResponse<SeatBalance>> {\n return this.httpClient.get(\"/seats/balance\", {\n customerId: params.customerId,\n externalId: params.externalId,\n seatType: params.seatType,\n });\n }\n\n /**\n * Get all seat balances\n *\n * @example\n * ```typescript\n * const balances = await commet.seats.getAllBalances({\n * externalId: 'user_123'\n * });\n * ```\n */\n async getAllBalances(\n params: GetAllBalancesParams,\n ): Promise<ApiResponse<Record<string, SeatBalance>>> {\n return this.httpClient.get(\"/seats/balances\", {\n customerId: params.customerId,\n externalId: params.externalId,\n });\n }\n}\n","import type {\n ApiResponse,\n GeneratedPlanCode,\n RequestOptions,\n} from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\nimport type { BillingInterval } from \"./plans\";\n\nexport type SubscriptionStatus =\n | \"draft\"\n | \"pending_payment\"\n | \"trialing\"\n | \"active\"\n | \"paused\"\n | \"past_due\"\n | \"canceled\"\n | \"expired\";\n\nexport interface FeatureSummary {\n code: string;\n name: string;\n type: \"boolean\" | \"metered\" | \"seats\";\n enabled?: boolean;\n usage?: {\n current: number;\n included: number;\n overage: number;\n overageUnitPrice?: number;\n };\n}\n\nexport interface ActiveSubscription {\n id: string;\n customerId: string;\n plan: {\n id: string;\n name: string;\n basePrice: number;\n billingInterval: BillingInterval;\n };\n name: string;\n description?: string;\n status: SubscriptionStatus;\n trialEndsAt?: string;\n currentPeriod: {\n start: string;\n end: string;\n daysRemaining: number;\n };\n features: FeatureSummary[];\n startDate: string;\n endDate?: string;\n billingDayOfMonth: number;\n nextBillingDate: string;\n checkoutUrl?: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface Subscription {\n id: string;\n customerId: string;\n planId: string;\n planName: string;\n name: string;\n description?: string;\n status: SubscriptionStatus;\n billingInterval: BillingInterval;\n trialEndsAt?: string;\n startDate: string;\n endDate?: string;\n currentPeriodStart?: string;\n currentPeriodEnd?: string;\n billingDayOfMonth: number;\n checkoutUrl?: string;\n createdAt: string;\n updatedAt: string;\n}\n\n// Customer identifier: mutually exclusive customerId or externalId\ntype CustomerIdentifier =\n | { customerId: string; externalId?: never }\n | { customerId?: never; externalId: string };\n\n// Plan identifier: use planCode (with autocomplete) or planId (legacy)\ntype PlanIdentifier =\n | { planCode: GeneratedPlanCode; planId?: never }\n | { planCode?: never; planId: string };\n\nexport type CreateSubscriptionParams = CustomerIdentifier &\n PlanIdentifier & {\n billingInterval?: BillingInterval;\n initialSeats?: Record<string, number>;\n skipTrial?: boolean;\n name?: string;\n startDate?: string;\n };\n\nexport type ChangePlanParams = PlanIdentifier & {\n billingInterval?: BillingInterval;\n};\n\nexport interface CancelParams {\n reason?: string;\n immediate?: boolean;\n}\n\nexport type GetSubscriptionParams = CustomerIdentifier;\n\n/**\n * Subscription resource for managing subscriptions (plan-first model)\n *\n * Each customer can only have ONE active subscription at a time.\n */\nexport class SubscriptionsResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n /**\n * Create a subscription with a plan\n *\n * @example\n * ```typescript\n * await commet.subscriptions.create({\n * externalId: 'user_123',\n * planCode: 'pro', // autocomplete works after `commet pull`\n * billingInterval: 'yearly',\n * initialSeats: { editor: 5 }\n * });\n * ```\n */\n async create(\n params: CreateSubscriptionParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<Subscription>> {\n return this.httpClient.post(\"/subscriptions\", params, options);\n }\n\n /**\n * Get the active subscription for a customer\n *\n * @example\n * ```typescript\n * const sub = await commet.subscriptions.get({ externalId: 'user_123' });\n * ```\n */\n async get(\n params: GetSubscriptionParams,\n ): Promise<ApiResponse<ActiveSubscription | null>> {\n return this.httpClient.get(\"/subscriptions/active\", params);\n }\n\n /**\n * Change the plan of a subscription (upgrade/downgrade)\n *\n * @example\n * ```typescript\n * await commet.subscriptions.changePlan('sub_xxx', {\n * planCode: 'enterprise' // autocomplete works after `commet pull`\n * });\n * ```\n */\n async changePlan(\n subscriptionId: string,\n params: ChangePlanParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<Subscription>> {\n return this.httpClient.post(\n `/subscriptions/${subscriptionId}/change-plan`,\n params,\n options,\n );\n }\n\n /**\n * Cancel a subscription\n *\n * @example\n * ```typescript\n * await commet.subscriptions.cancel('sub_xxx', {\n * reason: 'switched_to_competitor'\n * });\n * ```\n */\n async cancel(\n subscriptionId: string,\n params?: CancelParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<Subscription>> {\n return this.httpClient.post(\n `/subscriptions/${subscriptionId}/cancel`,\n params || {},\n options,\n );\n }\n}\n","import type {\n ApiResponse,\n CustomerID,\n EventID,\n GeneratedEventType,\n RequestOptions,\n} from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\n\nexport interface UsageEvent {\n id: EventID;\n organizationId: string;\n customerId: CustomerID;\n eventType: GeneratedEventType;\n idempotencyKey?: string;\n ts: string;\n properties?: UsageEventProperty[];\n createdAt: string;\n}\n\nexport interface UsageEventProperty {\n id: string;\n usageEventId: EventID;\n property: string;\n value: string;\n createdAt: string;\n}\n\nexport interface BatchResult<T> {\n successful: T[];\n failed: Array<{\n index: number;\n error: string;\n data: TrackParams;\n }>;\n}\n\nexport interface TrackParams {\n eventType: GeneratedEventType;\n customerId?: CustomerID;\n externalId?: string;\n idempotencyKey?: string;\n value?: number;\n timestamp?: string;\n properties?: Record<string, string>;\n}\n\n/**\n * Usage resource - Track consumption events for usage-based billing\n */\nexport class UsageResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n /**\n * Track a usage event\n *\n * @example\n * ```typescript\n * await commet.usage.track({\n * externalId: 'user_123',\n * eventType: 'api_call',\n * idempotencyKey: `evt_${requestId}`,\n * properties: { endpoint: '/users', method: 'GET' }\n * });\n * ```\n */\n async track(\n params: TrackParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<UsageEvent>> {\n const eventData = {\n eventType: params.eventType,\n customerId: params.customerId,\n externalId: params.externalId,\n idempotencyKey: params.idempotencyKey,\n ts: params.timestamp || new Date().toISOString(),\n properties: params.properties\n ? Object.entries(params.properties).map(([property, value]) => ({\n property,\n value,\n }))\n : undefined,\n };\n\n return this.httpClient.post(\"/usage/events\", eventData, options);\n }\n\n /**\n * Track multiple usage events in a batch\n *\n * @example\n * ```typescript\n * await commet.usage.trackBatch({\n * events: [\n * { externalId: 'user_123', eventType: 'api_call', idempotencyKey: 'evt_1' },\n * { externalId: 'user_456', eventType: 'api_call', idempotencyKey: 'evt_2' }\n * ]\n * });\n * ```\n */\n async trackBatch(\n params: { events: TrackParams[] },\n options?: RequestOptions,\n ): Promise<ApiResponse<BatchResult<UsageEvent>>> {\n const events = params.events.map((event) => ({\n eventType: event.eventType,\n customerId: event.customerId,\n externalId: event.externalId,\n idempotencyKey: event.idempotencyKey,\n ts: event.timestamp || new Date().toISOString(),\n properties: event.properties\n ? Object.entries(event.properties).map(([property, value]) => ({\n property,\n value,\n }))\n : undefined,\n }));\n\n return this.httpClient.post(\"/usage/events/batch\", { events }, options);\n }\n}\n","import crypto from \"node:crypto\";\n\n/**\n * Webhook payload structure from Commet\n */\nexport interface WebhookPayload {\n event: WebhookEvent;\n timestamp: string;\n organizationId: string;\n data: WebhookData;\n}\n\n/**\n * Webhook data structure (subscription-related fields)\n */\nexport interface WebhookData {\n id?: string;\n publicId?: string;\n subscriptionId?: string;\n customerId?: string;\n externalId?: string;\n status?: string;\n name?: string;\n canceledAt?: string;\n [key: string]: unknown;\n}\n\n/**\n * Supported webhook events\n */\nexport type WebhookEvent =\n | \"subscription.created\"\n | \"subscription.activated\"\n | \"subscription.canceled\"\n | \"subscription.updated\";\n\n/**\n * Webhooks resource for signature verification\n */\nexport class Webhooks {\n /**\n * Verify HMAC-SHA256 webhook signature\n *\n * Use this method to verify that webhooks are authentically from Commet.\n * The signature is included in the `X-Commet-Signature` header.\n *\n * @param payload - Raw request body as string (IMPORTANT: Do not parse JSON first)\n * @param signature - Value from X-Commet-Signature header\n * @param secret - Your webhook secret from Commet dashboard\n * @returns true if signature is valid, false otherwise\n *\n * @example\n * ```typescript\n * // Next.js API route example\n * export async function POST(request: Request) {\n * const rawBody = await request.text();\n * const signature = request.headers.get('x-commet-signature');\n *\n * const isValid = commet.webhooks.verify(\n * rawBody,\n * signature,\n * process.env.COMMET_WEBHOOK_SECRET\n * );\n *\n * if (!isValid) {\n * return new Response('Invalid signature', { status: 401 });\n * }\n *\n * const payload = JSON.parse(rawBody);\n * // Handle webhook event...\n * }\n * ```\n */\n verify(payload: string, signature: string | null, secret: string): boolean {\n if (!signature || !secret || !payload) {\n return false;\n }\n\n try {\n const expectedSignature = this.generateSignature(payload, secret);\n\n // Use timing-safe comparison to prevent timing attacks\n return crypto.timingSafeEqual(\n Buffer.from(signature, \"hex\"),\n Buffer.from(expectedSignature, \"hex\"),\n );\n } catch (error) {\n // timingSafeEqual throws if lengths don't match\n return false;\n }\n }\n\n /**\n * Generate HMAC-SHA256 signature (internal use)\n * @internal\n */\n private generateSignature(payload: string, secret: string): string {\n return crypto.createHmac(\"sha256\", secret).update(payload).digest(\"hex\");\n }\n\n /**\n * Parse and verify webhook payload in one step\n *\n * @param rawBody - Raw request body as string\n * @param signature - Value from X-Commet-Signature header\n * @param secret - Your webhook secret from Commet dashboard\n * @returns Parsed payload if valid, null if invalid\n *\n * @example\n * ```typescript\n * const payload = commet.webhooks.verifyAndParse(\n * rawBody,\n * signature,\n * process.env.COMMET_WEBHOOK_SECRET\n * );\n *\n * if (!payload) {\n * return new Response('Invalid signature', { status: 401 });\n * }\n *\n * // payload is typed and validated\n * if (payload.event === 'subscription.activated') {\n * // Handle activation...\n * }\n * ```\n */\n verifyAndParse(\n rawBody: string,\n signature: string | null,\n secret: string,\n ): WebhookPayload | null {\n if (!this.verify(rawBody, signature, secret)) {\n return null;\n }\n\n try {\n return JSON.parse(rawBody) as WebhookPayload;\n } catch {\n return null;\n }\n }\n}\n","export type Environment = \"sandbox\" | \"production\";\n\nexport type CommetConfig = {\n apiKey: string;\n environment?: Environment;\n debug?: boolean;\n timeout?: number;\n retries?: number;\n};\n\n// API Response types\nexport interface ApiResponse<T = unknown> {\n success: boolean;\n data?: T;\n error?: string;\n message?: string;\n // Pagination fields (optional, included for list endpoints)\n hasMore?: boolean;\n nextCursor?: string;\n}\n\nexport interface PaginatedResponse<T> {\n data: T[];\n hasMore: boolean;\n nextCursor?: string;\n totalCount?: number;\n}\n\nexport interface PaginatedList<T> extends PaginatedResponse<T> {\n next(): Promise<PaginatedList<T>>;\n all(): Promise<T[]>;\n}\n\n// Error types\nexport class CommetError extends Error {\n constructor(\n message: string,\n public code?: string,\n public statusCode?: number,\n public details?: unknown,\n ) {\n super(message);\n this.name = \"CommetError\";\n }\n}\n\nexport class CommetAPIError extends CommetError {\n constructor(\n message: string,\n public statusCode: number,\n public code?: string,\n public details?: unknown,\n ) {\n super(message, code, statusCode, details);\n this.name = \"CommetAPIError\";\n }\n}\n\nexport class CommetValidationError extends CommetError {\n constructor(\n message: string,\n public validationErrors: Record<string, string[]>,\n ) {\n super(message);\n this.name = \"CommetValidationError\";\n }\n}\n\nexport type CustomerID = `cus_${string}`;\nexport type AgreementID = `agr_${string}`;\nexport type InvoiceID = `inv_${string}`;\nexport type PhaseID = `phs_${string}`;\nexport type ItemID = `itm_${string}`;\nexport type ProductID = `prd_${string}`;\nexport type EventID = `evt_${string}`;\nexport type WebhookID = `wh_${string}`;\n\n// Currency enum\nexport type Currency =\n | \"USD\"\n | \"EUR\"\n | \"GBP\"\n | \"CAD\"\n | \"AUD\"\n | \"JPY\"\n | \"ARS\"\n | \"BRL\"\n | \"MXN\"\n | \"CLP\";\n\n// Common parameters\nexport interface ListParams extends Record<string, unknown> {\n limit?: number;\n cursor?: string;\n startDate?: string;\n endDate?: string;\n}\n\nexport interface RetrieveOptions {\n expand?: string[];\n}\n\n// Request options\nexport interface RequestOptions {\n idempotencyKey?: string;\n timeout?: number;\n}\n\n/**\n * Generated types interface - augmented by CLI after 'commet pull'\n *\n * This interface gets filled by module augmentation when you run `commet pull`.\n * The CLI generates a .commet.d.ts file that augments this interface with your\n * organization's specific event and seat types.\n *\n * @example\n * // After running `commet pull`, TypeScript will automatically know your types:\n * await commet.usage.events.create({\n * eventType: 'api_call', // Autocomplete works!\n * customerId: 'cus_123'\n * });\n */\n\n// biome-ignore lint/suspicious/noEmptyInterface: <explanation>\nexport interface CommetGeneratedTypes {}\n\n/**\n * Helper type that provides fallback to string if types are not generated\n */\nexport type GeneratedEventType = CommetGeneratedTypes extends {\n eventType: infer T;\n}\n ? T\n : string;\n\n/**\n * Helper type that provides fallback to string if types are not generated\n */\nexport type GeneratedSeatType = CommetGeneratedTypes extends {\n seatType: infer T;\n}\n ? T\n : string;\n\n/**\n * Helper type that provides fallback to string if types are not generated\n * @deprecated Use GeneratedPlanCode instead\n */\nexport type GeneratedProductId = CommetGeneratedTypes extends {\n productId: infer T;\n}\n ? T\n : string;\n\n/**\n * Helper type that provides fallback to string if types are not generated\n */\nexport type GeneratedPlanCode = CommetGeneratedTypes extends {\n planCode: infer T;\n}\n ? T\n : string;\n\n/**\n * Helper type that provides fallback to string if types are not generated\n */\nexport type GeneratedFeatureCode = CommetGeneratedTypes extends {\n featureCode: infer T;\n}\n ? T\n : string;\n","import type {\n ApiResponse,\n CommetConfig,\n Environment,\n RequestOptions,\n} from \"../types/common\";\nimport { CommetAPIError, CommetValidationError } from \"../types/common\";\n\nexport interface RetryConfig {\n maxRetries: number;\n baseDelay: number;\n maxDelay: number;\n retryableStatusCodes: number[];\n}\n\nconst DEFAULT_RETRY_CONFIG: RetryConfig = {\n maxRetries: 3,\n baseDelay: 1000, // 1s\n maxDelay: 8000, // 8s\n retryableStatusCodes: [408, 429, 500, 502, 503, 504],\n};\n\nexport class CommetHTTPClient {\n private config: CommetConfig;\n private environment: Environment;\n private retryConfig: RetryConfig;\n\n constructor(config: CommetConfig, environment: Environment) {\n this.config = config;\n this.environment = environment;\n this.retryConfig = {\n ...DEFAULT_RETRY_CONFIG,\n maxRetries: config.retries ?? DEFAULT_RETRY_CONFIG.maxRetries,\n };\n }\n\n async get<T = unknown>(\n endpoint: string,\n params?: Record<string, unknown>,\n options?: RequestOptions,\n ): Promise<ApiResponse<T>> {\n return this.request(\"GET\", endpoint, undefined, options, params);\n }\n\n async post<T = unknown>(\n endpoint: string,\n data?: unknown,\n options?: RequestOptions,\n ): Promise<ApiResponse<T>> {\n return this.request(\"POST\", endpoint, data, options);\n }\n\n async put<T = unknown>(\n endpoint: string,\n data?: unknown,\n options?: RequestOptions,\n ): Promise<ApiResponse<T>> {\n return this.request(\"PUT\", endpoint, data, options);\n }\n\n async delete<T = unknown>(\n endpoint: string,\n data?: unknown,\n options?: RequestOptions,\n ): Promise<ApiResponse<T>> {\n return this.request(\"DELETE\", endpoint, data, options);\n }\n\n /**\n * Core request method with retry logic\n */\n private async request<T = unknown>(\n method: string,\n endpoint: string,\n data?: unknown,\n options?: RequestOptions,\n params?: Record<string, unknown>,\n ): Promise<ApiResponse<T>> {\n const url = this.buildURL(endpoint, params);\n return this.executeRequest(method, url, data, options);\n }\n\n /**\n * Execute real API request with retry logic\n */\n private async executeRequest<T = unknown>(\n method: string,\n url: string,\n data?: unknown,\n options?: RequestOptions,\n attempt = 1,\n ): Promise<ApiResponse<T>> {\n try {\n const headers: Record<string, string> = {\n \"x-api-key\": this.config.apiKey,\n \"Content-Type\": \"application/json\",\n \"User-Agent\": \"commet/0.1.0\",\n };\n\n if (options?.idempotencyKey) {\n headers[\"Idempotency-Key\"] = options.idempotencyKey;\n } else if (method === \"POST\" && data) {\n headers[\"Idempotency-Key\"] = this.generateIdempotencyKey();\n }\n\n const requestConfig: RequestInit = {\n method,\n headers,\n signal: AbortSignal.timeout(\n options?.timeout ?? this.config.timeout ?? 30000,\n ),\n };\n\n if (data) {\n requestConfig.body = JSON.stringify(data);\n }\n\n if (this.config.debug) {\n console.log(`[Commet SDK] ${method} ${url}`);\n if (data) {\n console.log(\"Request data:\", JSON.stringify(data, null, 2));\n }\n }\n\n const response = await fetch(url, requestConfig);\n\n if (this.config.debug) {\n console.log(\n `[Commet SDK] Response status: ${response.status} ${response.statusText}`,\n );\n }\n\n let responseData: unknown;\n let responseText: string;\n\n try {\n responseData = await response.json();\n responseText = \"\";\n } catch (jsonError) {\n try {\n responseText = await response.text();\n } catch (textError) {\n responseText = \"Failed to read response body\";\n }\n if (this.config.debug) {\n console.log(\n \"[Commet SDK] Failed to parse JSON response:\",\n responseText,\n );\n }\n\n // For 404 errors with invalid JSON, return a graceful response\n // This handles cases like HTML error pages or empty responses\n if (response.status === 404) {\n return {\n success: false,\n error: \"Resource not found\",\n } as ApiResponse<T>;\n }\n\n throw new CommetAPIError(\n `Invalid JSON response: ${response.status} ${response.statusText}`,\n response.status,\n \"INVALID_JSON\",\n { responseText },\n );\n }\n\n if (!response.ok) {\n // Check if we should retry\n if (\n attempt <= this.retryConfig.maxRetries &&\n this.retryConfig.retryableStatusCodes.includes(response.status)\n ) {\n const delay = Math.min(\n this.retryConfig.baseDelay * 2 ** (attempt - 1),\n this.retryConfig.maxDelay,\n );\n\n if (this.config.debug) {\n console.log(\n `[Commet SDK] Retrying in ${delay}ms (attempt ${attempt}/${this.retryConfig.maxRetries})`,\n );\n }\n\n await this.sleep(delay);\n return this.executeRequest(method, url, data, options, attempt + 1);\n }\n\n // Log error response for debugging\n if (this.config.debug) {\n console.log(\n \"[Commet SDK] Error response:\",\n JSON.stringify(responseData, null, 2),\n );\n }\n\n // Type guard for error response\n const isErrorResponse = (\n data: unknown,\n ): data is {\n message?: string;\n errors?: Record<string, string[]>;\n code?: string;\n details?: unknown;\n } => {\n return typeof data === \"object\" && data !== null;\n };\n\n const errorData = isErrorResponse(responseData) ? responseData : {};\n\n // Handle different error types\n if (response.status === 400 && errorData.errors) {\n throw new CommetValidationError(\n errorData.message || \"Validation failed\",\n errorData.errors,\n );\n }\n\n throw new CommetAPIError(\n errorData.message || `Request failed with status ${response.status}`,\n response.status,\n errorData.code,\n errorData.details,\n );\n }\n\n if (this.config.debug) {\n console.log(\"[Commet SDK] Response:\", responseData);\n }\n\n return responseData as ApiResponse<T>;\n } catch (error) {\n // Handle network errors and timeouts\n if (error instanceof TypeError && error.message.includes(\"fetch\")) {\n if (attempt <= this.retryConfig.maxRetries) {\n const delay = Math.min(\n this.retryConfig.baseDelay * 2 ** (attempt - 1),\n this.retryConfig.maxDelay,\n );\n\n if (this.config.debug) {\n console.log(`[Commet SDK] Network error, retrying in ${delay}ms`);\n }\n\n await this.sleep(delay);\n return this.executeRequest(method, url, data, options, attempt + 1);\n }\n }\n\n throw error;\n }\n }\n\n /**\n * Get base URL based on environment\n */\n private getBaseURL(): string {\n return this.environment === \"production\"\n ? \"https://commet.co\"\n : \"https://sandbox.commet.co\";\n }\n\n /**\n * Build full URL from endpoint and params\n */\n private buildURL(endpoint: string, params?: Record<string, unknown>): string {\n const baseURL = this.getBaseURL();\n\n // Construct full path with /api prefix\n const normalizedEndpoint = endpoint.startsWith(\"/\")\n ? endpoint\n : `/${endpoint}`;\n const fullPath = `/api${normalizedEndpoint}`;\n\n // Debug logging\n if (this.config.debug) {\n console.log(\n `[Commet SDK] Building URL - baseURL: ${baseURL}, endpoint: ${endpoint}, fullPath: ${fullPath}`,\n );\n }\n\n const url = new URL(fullPath, baseURL);\n\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.append(key, String(value));\n }\n }\n }\n\n const finalUrl = url.toString();\n\n // Debug final URL\n if (this.config.debug) {\n console.log(`[Commet SDK] Final URL: ${finalUrl}`);\n }\n\n return finalUrl;\n }\n\n /**\n * Generate idempotency key\n */\n private generateIdempotencyKey(): string {\n // Generate UUID-like key for idempotency\n return `sdk_${Date.now()}_${Math.random().toString(36).substring(2)}`;\n }\n\n /**\n * Sleep for specified milliseconds\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","import { CustomerContext } from \"./customer\";\nimport { CustomersResource } from \"./resources/customers\";\nimport { FeaturesResource } from \"./resources/features\";\nimport { PlansResource } from \"./resources/plans\";\nimport { PortalResource } from \"./resources/portal\";\nimport { SeatsResource } from \"./resources/seats\";\nimport { SubscriptionsResource } from \"./resources/subscriptions\";\nimport { UsageResource } from \"./resources/usage\";\nimport { Webhooks } from \"./resources/webhooks\";\nimport type { CommetConfig, Environment } from \"./types/common\";\nimport { CommetHTTPClient } from \"./utils/http\";\n\n/**\n * Main Commet SDK client\n */\nexport class Commet {\n private httpClient: CommetHTTPClient;\n private environment: Environment;\n\n public readonly customers: CustomersResource;\n public readonly plans: PlansResource;\n public readonly usage: UsageResource;\n public readonly seats: SeatsResource;\n public readonly subscriptions: SubscriptionsResource;\n public readonly portal: PortalResource;\n public readonly features: FeaturesResource;\n public readonly webhooks: Webhooks;\n\n constructor(config: CommetConfig) {\n if (!config.apiKey) {\n throw new Error(\"Commet SDK: API key is required\");\n }\n\n if (!config.apiKey.startsWith(\"ck_\")) {\n throw new Error(\n \"Commet SDK: Invalid API key format. Expected format: ck_xxx...\",\n );\n }\n\n // Default to sandbox for safety\n this.environment = config.environment || \"sandbox\";\n\n this.httpClient = new CommetHTTPClient(config, this.environment);\n this.customers = new CustomersResource(this.httpClient);\n this.plans = new PlansResource(this.httpClient);\n this.usage = new UsageResource(this.httpClient);\n this.seats = new SeatsResource(this.httpClient);\n this.subscriptions = new SubscriptionsResource(this.httpClient);\n this.portal = new PortalResource(this.httpClient);\n this.features = new FeaturesResource(this.httpClient);\n this.webhooks = new Webhooks();\n\n if (config.debug) {\n console.log(`[Commet SDK] Initialized in ${this.environment} mode`);\n console.log(\"API Key:\", `${config.apiKey.substring(0, 12)}...`);\n const baseURL =\n this.environment === \"production\"\n ? \"https://commet.co\"\n : \"https://sandbox.commet.co\";\n console.log(\"Base URL:\", baseURL);\n }\n }\n\n /**\n * Create a customer-scoped context for cleaner API usage\n *\n * @example\n * ```typescript\n * const customer = commet.customer(\"user_123\");\n *\n * // All operations are now scoped to this customer\n * const seats = await customer.features.get(\"team_members\");\n * await customer.seats.add(\"member\");\n * await customer.usage.track(\"api_call\");\n * ```\n */\n customer(externalId: string): CustomerContext {\n return new CustomerContext(externalId, {\n features: this.features,\n seats: this.seats,\n usage: this.usage,\n subscriptions: this.subscriptions,\n portal: this.portal,\n });\n }\n\n getEnvironment(): Environment {\n return this.environment;\n }\n\n isSandbox(): boolean {\n return this.environment === \"sandbox\";\n }\n\n isProduction(): boolean {\n return this.environment === \"production\";\n }\n}\n","import type { Environment } from \"../types/common\";\n\n/**\n * Check if environment is sandbox\n */\nexport function isSandbox(environment: Environment): boolean {\n return environment === \"sandbox\";\n}\n\n/**\n * Check if environment is production\n */\nexport function isProduction(environment: Environment): boolean {\n return environment === \"production\";\n}\n"],"mappings":"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","names":["crypto","data"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/customer.ts","../src/resources/customers.ts","../src/resources/features.ts","../src/resources/plans.ts","../src/resources/portal.ts","../src/resources/seats.ts","../src/resources/subscriptions.ts","../src/resources/usage.ts","../src/resources/webhooks.ts","../src/types/common.ts","../src/utils/http.ts","../src/client.ts","../src/utils/environment.ts"],"sourcesContent":["/**\n * Commet SDK - Billing and usage tracking for SaaS\n */\nexport { Commet } from \"./client\";\nexport { CustomerContext } from \"./customer\";\n\n// Type exports\nexport type {\n CommetConfig,\n CommetGeneratedTypes,\n GeneratedEventType,\n GeneratedSeatType,\n GeneratedPlanCode,\n GeneratedFeatureCode,\n Environment,\n ApiResponse,\n PaginatedResponse,\n PaginatedList,\n Currency,\n CustomerID,\n EventID,\n RequestOptions,\n} from \"./types/common\";\n\n// Error exports\nexport {\n CommetError,\n CommetAPIError,\n CommetValidationError,\n} from \"./types/common\";\n\n// Customers\nexport type {\n Customer,\n CustomerAddress,\n CreateParams as CreateCustomerParams,\n UpdateParams as UpdateCustomerParams,\n ListCustomersParams,\n BatchResult as CustomersBatchResult,\n} from \"./resources/customers\";\n\n// Usage\nexport type {\n UsageEvent,\n UsageEventProperty,\n TrackParams,\n BatchResult as UsageBatchResult,\n} from \"./resources/usage\";\n\n// Seats\nexport type {\n SeatEvent,\n SeatBalance,\n AddParams as AddSeatsParams,\n RemoveParams as RemoveSeatsParams,\n SetParams as SetSeatsParams,\n SetAllParams as SetAllSeatsParams,\n GetBalanceParams,\n GetAllBalancesParams,\n} from \"./resources/seats\";\n\n// Plans\nexport type {\n Plan,\n PlanDetail,\n PlanPrice,\n PlanFeature,\n PlanID,\n BillingInterval,\n FeatureType,\n ListPlansParams,\n} from \"./resources/plans\";\n\n// Subscriptions\nexport type {\n Subscription,\n ActiveSubscription,\n SubscriptionStatus,\n FeatureSummary,\n CreateSubscriptionParams,\n ChangePlanParams,\n CancelParams,\n} from \"./resources/subscriptions\";\n\n// Portal\nexport type { PortalAccess, GetUrlParams } from \"./resources/portal\";\n\n// Features\nexport type {\n FeatureAccess,\n CanUseResult,\n CheckResult,\n GetFeatureParams,\n CheckFeatureParams,\n CanUseFeatureParams,\n} from \"./resources/features\";\n\n// Webhooks\nexport { Webhooks } from \"./resources/webhooks\";\nexport type {\n WebhookPayload,\n WebhookData,\n WebhookEvent,\n} from \"./resources/webhooks\";\n\n// Utility exports\nexport { isSandbox, isProduction } from \"./utils/environment\";\n\n// Default export\nimport { Commet } from \"./client\";\nexport default Commet;\n","import type { FeaturesResource } from \"./resources/features\";\nimport type { PortalResource } from \"./resources/portal\";\nimport type { SeatsResource } from \"./resources/seats\";\nimport type { SubscriptionsResource } from \"./resources/subscriptions\";\nimport type { UsageResource } from \"./resources/usage\";\nimport type { RequestOptions } from \"./types/common\";\n\n/**\n * Customer-scoped API context\n *\n * Provides a cleaner API where you don't have to pass externalId\n * on every call. All operations are scoped to a specific customer.\n *\n * @example\n * ```typescript\n * const customer = commet.customer(\"user_123\");\n *\n * // All operations are now scoped to this customer\n * const seats = await customer.features.get(\"team_members\");\n * await customer.seats.add(\"member\");\n * await customer.usage.track(\"api_call\");\n * ```\n */\nexport class CustomerContext {\n private readonly externalId: string;\n private readonly featuresResource: FeaturesResource;\n private readonly seatsResource: SeatsResource;\n private readonly usageResource: UsageResource;\n private readonly subscriptionsResource: SubscriptionsResource;\n private readonly portalResource: PortalResource;\n\n constructor(\n externalId: string,\n resources: {\n features: FeaturesResource;\n seats: SeatsResource;\n usage: UsageResource;\n subscriptions: SubscriptionsResource;\n portal: PortalResource;\n },\n ) {\n this.externalId = externalId;\n this.featuresResource = resources.features;\n this.seatsResource = resources.seats;\n this.usageResource = resources.usage;\n this.subscriptionsResource = resources.subscriptions;\n this.portalResource = resources.portal;\n }\n\n /**\n * Feature access methods - delegates to FeaturesResource\n */\n features = {\n get: (code: string, options?: RequestOptions) =>\n this.featuresResource.get({ code, externalId: this.externalId }, options),\n\n check: (code: string, options?: RequestOptions) =>\n this.featuresResource.check(\n { code, externalId: this.externalId },\n options,\n ),\n\n canUse: (code: string, options?: RequestOptions) =>\n this.featuresResource.canUse(\n { code, externalId: this.externalId },\n options,\n ),\n\n list: (options?: RequestOptions) =>\n this.featuresResource.list(this.externalId, options),\n };\n\n /**\n * Seat management methods - delegates to SeatsResource\n */\n seats = {\n add: (seatType: string, count = 1, options?: RequestOptions) =>\n this.seatsResource.add(\n { externalId: this.externalId, seatType, count },\n options,\n ),\n\n remove: (seatType: string, count = 1, options?: RequestOptions) =>\n this.seatsResource.remove(\n { externalId: this.externalId, seatType, count },\n options,\n ),\n\n set: (seatType: string, count: number, options?: RequestOptions) =>\n this.seatsResource.set(\n { externalId: this.externalId, seatType, count },\n options,\n ),\n\n getBalance: (seatType: string) =>\n this.seatsResource.getBalance({ externalId: this.externalId, seatType }),\n };\n\n /**\n * Usage tracking methods - delegates to UsageResource\n */\n usage = {\n track: (\n eventType: string,\n properties?: Record<string, string>,\n options?: RequestOptions,\n ) =>\n this.usageResource.track(\n { externalId: this.externalId, eventType, properties },\n options,\n ),\n };\n\n /**\n * Subscription methods - delegates to SubscriptionsResource\n */\n subscription = {\n get: () => this.subscriptionsResource.get(this.externalId),\n };\n\n /**\n * Portal methods - delegates to PortalResource\n */\n portal = {\n getUrl: (options?: RequestOptions) =>\n this.portalResource.getUrl({ externalId: this.externalId }, options),\n };\n}\n","import type {\n ApiResponse,\n ListParams as BaseListParams,\n CustomerID,\n RequestOptions,\n} from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\n\nexport interface Customer {\n id: CustomerID;\n organizationId: string;\n externalId?: string;\n legalName?: string;\n displayName?: string;\n domain?: string;\n website?: string;\n billingEmail: string;\n timezone?: string;\n language?: string;\n industry?: string;\n employeeCount?: string;\n metadata?: Record<string, unknown>;\n isActive: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CustomerAddress {\n line1: string;\n line2?: string;\n city: string;\n state?: string;\n postalCode: string;\n country: string; // ISO-2\n}\n\nexport interface CreateParams {\n email: string; // billingEmail - the only required field\n externalId?: string;\n legalName?: string;\n displayName?: string;\n domain?: string;\n website?: string;\n timezone?: string;\n language?: string;\n industry?: string;\n metadata?: Record<string, unknown>;\n address?: CustomerAddress;\n}\n\nexport interface UpdateParams {\n customerId: CustomerID;\n externalId?: string;\n email?: string;\n legalName?: string;\n displayName?: string;\n domain?: string;\n website?: string;\n timezone?: string;\n language?: string;\n industry?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface ListCustomersParams extends BaseListParams {\n externalId?: string;\n isActive?: boolean;\n search?: string;\n}\n\nexport interface BatchResult {\n successful: Customer[];\n failed: Array<{\n index: number;\n error: string;\n data: CreateParams;\n }>;\n}\n\n/**\n * Customers resource - Manage your customers\n */\nexport class CustomersResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n /**\n * Create a customer (idempotent with externalId)\n */\n async create(\n params: CreateParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<Customer>> {\n return this.httpClient.post(\n \"/customers\",\n {\n billingEmail: params.email,\n externalId: params.externalId,\n legalName: params.legalName,\n displayName: params.displayName,\n domain: params.domain,\n website: params.website,\n timezone: params.timezone,\n language: params.language,\n industry: params.industry,\n metadata: params.metadata,\n address: params.address,\n },\n options,\n );\n }\n\n /**\n * Create multiple customers in batch\n */\n async createBatch(\n params: { customers: CreateParams[] },\n options?: RequestOptions,\n ): Promise<ApiResponse<BatchResult>> {\n const customers = params.customers.map((c) => ({\n billingEmail: c.email,\n externalId: c.externalId,\n legalName: c.legalName,\n displayName: c.displayName,\n domain: c.domain,\n website: c.website,\n timezone: c.timezone,\n language: c.language,\n industry: c.industry,\n metadata: c.metadata,\n address: c.address,\n }));\n return this.httpClient.post(\"/customers/batch\", { customers }, options);\n }\n\n /**\n * Get a customer by ID\n */\n async get(customerId: CustomerID): Promise<ApiResponse<Customer>> {\n return this.httpClient.get(`/customers/${customerId}`);\n }\n\n /**\n * Update a customer\n */\n async update(\n params: UpdateParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<Customer>> {\n return this.httpClient.put(\n `/customers/${params.customerId}`,\n {\n billingEmail: params.email,\n externalId: params.externalId,\n legalName: params.legalName,\n displayName: params.displayName,\n domain: params.domain,\n website: params.website,\n timezone: params.timezone,\n language: params.language,\n industry: params.industry,\n metadata: params.metadata,\n },\n options,\n );\n }\n\n /**\n * List customers with optional filters\n */\n async list(params?: ListCustomersParams): Promise<ApiResponse<Customer[]>> {\n return this.httpClient.get(\"/customers\", params as Record<string, unknown>);\n }\n\n /**\n * Archive a customer\n */\n async archive(\n customerId: CustomerID,\n options?: RequestOptions,\n ): Promise<ApiResponse<Customer>> {\n return this.httpClient.put(\n `/customers/${customerId}`,\n { isActive: false },\n options,\n );\n }\n}\n","import type {\n ApiResponse,\n GeneratedFeatureCode,\n RequestOptions,\n} from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\n\nexport interface FeatureParams {\n externalId: string;\n code: GeneratedFeatureCode;\n}\n\nexport type GetFeatureParams = FeatureParams;\nexport type CheckFeatureParams = FeatureParams;\nexport type CanUseFeatureParams = FeatureParams;\n\nexport interface FeatureAccess {\n code: string;\n name: string;\n type: \"boolean\" | \"metered\" | \"seats\";\n allowed: boolean;\n // For boolean features\n enabled?: boolean;\n // For metered/seats features\n current?: number;\n included?: number;\n remaining?: number;\n overage?: number;\n overageUnitPrice?: number;\n unlimited?: boolean;\n overageEnabled?: boolean;\n}\n\nexport interface CanUseResult {\n allowed: boolean;\n willBeCharged: boolean;\n reason?: string;\n}\n\nexport interface CheckResult {\n allowed: boolean;\n}\n\n/**\n * Features resource for checking feature access and usage\n *\n * Provides a clean API to check if a customer can use a feature\n * without having to manually parse subscription data.\n */\nexport class FeaturesResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n /**\n * Get detailed feature access/usage for a customer\n *\n * @example\n * ```typescript\n * const seats = await commet.features.get({ code: \"team_members\", externalId: \"user_123\" });\n * console.log(seats.current, seats.included, seats.remaining);\n * ```\n */\n async get(\n params: GetFeatureParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<FeatureAccess>> {\n const { code, externalId } = params;\n\n return this.httpClient.get(\n `/features/${code}`,\n { externalId: externalId },\n options,\n );\n }\n\n /**\n * Check if a boolean feature is enabled for a customer\n *\n * @example\n * ```typescript\n * const { allowed } = await commet.features.check({\n * code: \"custom_branding\",\n * externalId: \"user_123\"\n * });\n * if (!allowed) redirect(\"/upgrade\");\n * ```\n */\n async check(\n params: CheckFeatureParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<CheckResult>> {\n const { code, externalId } = params;\n\n const result = await this.httpClient.get<FeatureAccess>(\n `/features/${code}`,\n { externalId: externalId },\n options,\n );\n\n if (!result.success || !result.data) {\n return {\n success: false,\n data: { allowed: false },\n message: result.message,\n };\n }\n\n return {\n success: true,\n data: { allowed: result.data.allowed },\n message: result.message,\n };\n }\n\n /**\n * Check if customer can use one more unit of a feature\n *\n * Returns whether the customer can add one more (allowed)\n * and whether they'll be charged extra (willBeCharged).\n *\n * @example\n * ```typescript\n * const { allowed, willBeCharged } = await commet.features.canUse({\n * code: \"team_members\",\n * externalId: \"user_123\"\n * });\n *\n * if (!allowed) {\n * return { error: \"Upgrade to add more members\" };\n * }\n *\n * if (willBeCharged) {\n * // Show confirmation: \"This will cost $10/month extra\"\n * }\n * ```\n */\n async canUse(\n params: CanUseFeatureParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<CanUseResult>> {\n const { code, externalId } = params;\n\n return this.httpClient.get(\n `/features/${code}`,\n { externalId: externalId, action: \"canUse\" },\n options,\n );\n }\n\n /**\n * List all features for a customer's active subscription\n *\n * @example\n * ```typescript\n * const features = await commet.features.list({ externalId: \"user_123\" });\n * for (const feature of features) {\n * console.log(feature.code, feature.allowed);\n * }\n * ```\n */\n async list(\n externalId: string,\n options?: RequestOptions,\n ): Promise<ApiResponse<FeatureAccess[]>> {\n return this.httpClient.get(\"/features\", { externalId }, options);\n }\n}\n","import type {\n ApiResponse,\n GeneratedPlanCode,\n ListParams,\n} from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\n\nexport type PlanID = `plan_${string}`;\nexport type BillingInterval = \"monthly\" | \"quarterly\" | \"yearly\";\nexport type FeatureType = \"boolean\" | \"metered\" | \"seats\";\n\nexport interface PlanPrice {\n billingInterval: BillingInterval;\n price: number; // in cents\n isDefault: boolean;\n}\n\nexport interface PlanFeature {\n code: string;\n name: string;\n type: FeatureType;\n enabled?: boolean;\n includedAmount?: number;\n unlimited?: boolean;\n overageEnabled?: boolean;\n overageUnitPrice?: number;\n}\n\nexport interface Plan {\n id: PlanID;\n name: string;\n description?: string;\n isPublic: boolean;\n isDefault: boolean;\n trialDays: number;\n sortOrder: number;\n prices: PlanPrice[];\n features: PlanFeature[];\n createdAt: string;\n}\n\nexport interface PlanDetail extends Plan {\n features: Array<\n PlanFeature & {\n unitName?: string;\n overage?: {\n enabled: boolean;\n model: \"per_unit\" | \"tiered\";\n unitPrice: number;\n tiers?: Array<{\n order: number;\n upTo: number | null;\n unitAmount: number;\n flatFee: number;\n }>;\n } | null;\n }\n >;\n updatedAt: string;\n}\n\nexport interface ListPlansParams extends ListParams {\n includePrivate?: boolean;\n}\n\n/**\n * Plans resource for listing available plans\n */\nexport class PlansResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n /**\n * List all available plans\n *\n * @example\n * ```typescript\n * // List public plans\n * const plans = await commet.plans.list();\n *\n * // Include private plans\n * const allPlans = await commet.plans.list({ includePrivate: true });\n * ```\n */\n async list(params?: ListPlansParams): Promise<ApiResponse<Plan[]>> {\n return this.httpClient.get(\"/plans\", params);\n }\n\n /**\n * Get a specific plan by code\n *\n * @example\n * ```typescript\n * const plan = await commet.plans.get('pro');\n * console.log(plan.data.name); // \"Pro\"\n * console.log(plan.data.prices); // [{ billingInterval: 'monthly', price: 9900 }]\n * ```\n */\n async get(planCode: GeneratedPlanCode): Promise<ApiResponse<PlanDetail>> {\n return this.httpClient.get(`/plans/${planCode}`);\n }\n}\n","import type { ApiResponse, CustomerID, RequestOptions } from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\n\nexport interface PortalAccess {\n success: boolean;\n message: string;\n portalUrl: string;\n}\n\ninterface GetUrlByCustomerId {\n customerId: CustomerID;\n email?: never;\n externalId?: never;\n}\n\ninterface GetUrlByExternalId {\n externalId: string;\n email?: never;\n customerId?: never;\n}\n\ninterface GetUrlByEmail {\n email: string;\n customerId?: never;\n externalId?: never;\n}\n\nexport type GetUrlParams =\n | GetUrlByCustomerId\n | GetUrlByExternalId\n | GetUrlByEmail;\n\n/**\n * Portal resource - Generate customer portal access\n */\nexport class PortalResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n /**\n * Get a portal URL\n *\n * @example\n * ```typescript\n * const portal = await commet.portal.getUrl({ externalId: 'user_123' });\n * ```\n */\n async getUrl(\n params: GetUrlParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<PortalAccess>> {\n return this.httpClient.post(\"/portal/request-access\", params, options);\n }\n}\n","import type {\n ApiResponse,\n CustomerID,\n GeneratedSeatType,\n RequestOptions,\n} from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\n\nexport interface SeatEvent {\n id: string;\n organizationId: string;\n customerId: CustomerID;\n seatType: GeneratedSeatType;\n eventType: \"add\" | \"remove\" | \"set\";\n quantity: number;\n previousBalance?: number;\n newBalance: number;\n ts: string;\n createdAt: string;\n}\n\nexport interface SeatBalance {\n current: number;\n asOf: string;\n}\n\nexport interface AddParams {\n customerId?: CustomerID;\n externalId?: string;\n seatType: GeneratedSeatType;\n count: number;\n}\n\nexport interface RemoveParams {\n customerId?: CustomerID;\n externalId?: string;\n seatType: GeneratedSeatType;\n count: number;\n}\n\nexport interface SetParams {\n customerId?: CustomerID;\n externalId?: string;\n seatType: GeneratedSeatType;\n count: number;\n}\n\nexport interface SetAllParams {\n customerId?: CustomerID;\n externalId?: string;\n seats: Record<string, number>;\n}\n\nexport interface GetBalanceParams {\n customerId?: CustomerID;\n externalId?: string;\n seatType: GeneratedSeatType;\n}\n\nexport interface GetAllBalancesParams {\n customerId?: CustomerID;\n externalId?: string;\n}\n\n/**\n * Seats resource - Manage seat-based licenses\n */\nexport class SeatsResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n /**\n * Add seats\n *\n * @example\n * ```typescript\n * await commet.seats.add({\n * externalId: 'user_123',\n * seatType: 'editor',\n * count: 5\n * });\n * ```\n */\n async add(\n params: AddParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<SeatEvent>> {\n return this.httpClient.post(\"/seats\", params, options);\n }\n\n /**\n * Remove seats\n *\n * @example\n * ```typescript\n * await commet.seats.remove({\n * externalId: 'user_123',\n * seatType: 'editor',\n * count: 2\n * });\n * ```\n */\n async remove(\n params: RemoveParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<SeatEvent>> {\n return this.httpClient.delete(\"/seats\", params, options);\n }\n\n /**\n * Set seats to a specific count\n *\n * @example\n * ```typescript\n * await commet.seats.set({\n * externalId: 'user_123',\n * seatType: 'editor',\n * count: 10\n * });\n * ```\n */\n async set(\n params: SetParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<SeatEvent>> {\n return this.httpClient.put(\"/seats\", params, options);\n }\n\n /**\n * Set all seat types\n *\n * @example\n * ```typescript\n * await commet.seats.setAll({\n * externalId: 'user_123',\n * seats: { editor: 10, viewer: 50 }\n * });\n * ```\n */\n async setAll(\n params: SetAllParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<SeatEvent[]>> {\n return this.httpClient.put(\"/seats/bulk\", params, options);\n }\n\n /**\n * Get balance for a seat type\n *\n * @example\n * ```typescript\n * const balance = await commet.seats.getBalance({\n * externalId: 'user_123',\n * seatType: 'editor'\n * });\n * ```\n */\n async getBalance(\n params: GetBalanceParams,\n ): Promise<ApiResponse<SeatBalance>> {\n const { customerId, externalId, seatType } = params;\n\n return this.httpClient.get(\"/seats/balance\", {\n customerId: customerId,\n externalId: externalId,\n seatType: seatType,\n });\n }\n\n /**\n * Get all seat balances\n *\n * @example\n * ```typescript\n * const balances = await commet.seats.getAllBalances({\n * externalId: 'user_123'\n * });\n * ```\n */\n async getAllBalances(\n params: GetAllBalancesParams,\n ): Promise<ApiResponse<Record<string, SeatBalance>>> {\n const { customerId, externalId } = params;\n\n return this.httpClient.get(\"/seats/balances\", {\n customerId: customerId,\n externalId: externalId,\n });\n }\n}\n","import type {\n ApiResponse,\n GeneratedPlanCode,\n RequestOptions,\n} from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\nimport type { BillingInterval } from \"./plans\";\n\nexport type SubscriptionStatus =\n | \"draft\"\n | \"pending_payment\"\n | \"trialing\"\n | \"active\"\n | \"paused\"\n | \"past_due\"\n | \"canceled\"\n | \"expired\";\n\nexport interface FeatureSummary {\n code: string;\n name: string;\n type: \"boolean\" | \"metered\" | \"seats\";\n enabled?: boolean;\n usage?: {\n current: number;\n included: number;\n overage: number;\n overageUnitPrice?: number;\n };\n}\n\nexport interface ActiveSubscription {\n id: string;\n customerId: string;\n plan: {\n id: string;\n name: string;\n basePrice: number;\n billingInterval: BillingInterval;\n };\n name: string;\n description?: string;\n status: SubscriptionStatus;\n trialEndsAt?: string;\n currentPeriod: {\n start: string;\n end: string;\n daysRemaining: number;\n };\n features: FeatureSummary[];\n startDate: string;\n endDate?: string;\n billingDayOfMonth: number;\n nextBillingDate: string;\n checkoutUrl?: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface Subscription {\n id: string;\n customerId: string;\n planId: string;\n planName: string;\n name: string;\n description?: string;\n status: SubscriptionStatus;\n billingInterval: BillingInterval;\n trialEndsAt?: string;\n startDate: string;\n endDate?: string;\n currentPeriodStart?: string;\n currentPeriodEnd?: string;\n billingDayOfMonth: number;\n checkoutUrl?: string;\n createdAt: string;\n updatedAt: string;\n}\n\n// Customer identifier: mutually exclusive customerId or externalId\ntype CustomerIdentifier =\n | { customerId: string; externalId?: never }\n | { customerId?: never; externalId: string };\n\n// Plan identifier: use planCode (with autocomplete) or planId (legacy)\ntype PlanIdentifier =\n | { planCode: GeneratedPlanCode; planId?: never }\n | { planCode?: never; planId: string };\n\nexport type CreateSubscriptionParams = CustomerIdentifier &\n PlanIdentifier & {\n billingInterval?: BillingInterval;\n initialSeats?: Record<string, number>;\n skipTrial?: boolean;\n name?: string;\n startDate?: string;\n };\n\nexport type ChangePlanParams = PlanIdentifier & {\n subscriptionId: string;\n billingInterval?: BillingInterval;\n};\n\nexport interface CancelParams {\n subscriptionId: string;\n reason?: string;\n immediate?: boolean;\n}\n\n/**\n * Subscription resource for managing subscriptions (plan-first model)\n *\n * Each customer can only have ONE active subscription at a time.\n */\nexport class SubscriptionsResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n /**\n * Create a subscription with a plan\n *\n * @example\n * ```typescript\n * await commet.subscriptions.create({\n * externalId: 'user_123',\n * planCode: 'pro', // autocomplete works after `commet pull`\n * billingInterval: 'yearly',\n * initialSeats: { editor: 5 }\n * });\n * ```\n */\n async create(\n params: CreateSubscriptionParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<Subscription>> {\n return this.httpClient.post(\"/subscriptions\", params, options);\n }\n\n /**\n * Get the active subscription for a customer\n *\n * @example\n * ```typescript\n * const sub = await commet.subscriptions.get('user_123');\n * ```\n */\n async get(\n externalId: string,\n ): Promise<ApiResponse<ActiveSubscription | null>> {\n return this.httpClient.get(\"/subscriptions/active\", { externalId });\n }\n\n /**\n * Change the plan of a subscription (upgrade/downgrade)\n *\n * @example\n * ```typescript\n * await commet.subscriptions.changePlan({\n * subscriptionId: 'sub_xxx',\n * planCode: 'enterprise' // autocomplete works after `commet pull`\n * });\n * ```\n */\n async changePlan(\n params: ChangePlanParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<Subscription>> {\n return this.httpClient.post(\n `/subscriptions/${params.subscriptionId}/change-plan`,\n params,\n options,\n );\n }\n\n /**\n * Cancel a subscription\n *\n * @example\n * ```typescript\n * await commet.subscriptions.cancel({\n * subscriptionId: 'sub_xxx',\n * reason: 'switched_to_competitor'\n * });\n * ```\n */\n async cancel(\n params: CancelParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<Subscription>> {\n return this.httpClient.post(\n `/subscriptions/${params.subscriptionId}/cancel`,\n params || {},\n options,\n );\n }\n}\n","import type {\n ApiResponse,\n CustomerID,\n EventID,\n GeneratedEventType,\n RequestOptions,\n} from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\n\nexport interface UsageEvent {\n id: EventID;\n organizationId: string;\n customerId: CustomerID;\n eventType: GeneratedEventType;\n idempotencyKey?: string;\n ts: string;\n properties?: UsageEventProperty[];\n createdAt: string;\n}\n\nexport interface UsageEventProperty {\n id: string;\n usageEventId: EventID;\n property: string;\n value: string;\n createdAt: string;\n}\n\nexport interface BatchResult<T> {\n successful: T[];\n failed: Array<{\n index: number;\n error: string;\n data: TrackParams;\n }>;\n}\n\nexport interface TrackParams {\n eventType: GeneratedEventType;\n customerId?: CustomerID;\n externalId?: string;\n idempotencyKey?: string;\n value?: number;\n timestamp?: string;\n properties?: Record<string, string>;\n}\n\n/**\n * Usage resource - Track consumption events for usage-based billing\n */\nexport class UsageResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n /**\n * Track a usage event\n *\n * @example\n * ```typescript\n * await commet.usage.track({\n * externalId: 'user_123',\n * eventType: 'api_call',\n * idempotencyKey: `evt_${requestId}`,\n * properties: { endpoint: '/users', method: 'GET' }\n * });\n * ```\n */\n async track(\n params: TrackParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<UsageEvent>> {\n const eventData = {\n eventType: params.eventType,\n customerId: params.customerId,\n externalId: params.externalId,\n idempotencyKey: params.idempotencyKey,\n ts: params.timestamp || new Date().toISOString(),\n properties: params.properties\n ? Object.entries(params.properties).map(([property, value]) => ({\n property,\n value,\n }))\n : undefined,\n };\n\n return this.httpClient.post(\"/usage/events\", eventData, options);\n }\n\n /**\n * Track multiple usage events in a batch\n *\n * @example\n * ```typescript\n * await commet.usage.trackBatch({\n * events: [\n * { externalId: 'user_123', eventType: 'api_call', idempotencyKey: 'evt_1' },\n * { externalId: 'user_456', eventType: 'api_call', idempotencyKey: 'evt_2' }\n * ]\n * });\n * ```\n */\n async trackBatch(\n params: { events: TrackParams[] },\n options?: RequestOptions,\n ): Promise<ApiResponse<BatchResult<UsageEvent>>> {\n const events = params.events.map((event) => ({\n eventType: event.eventType,\n customerId: event.customerId,\n externalId: event.externalId,\n idempotencyKey: event.idempotencyKey,\n ts: event.timestamp || new Date().toISOString(),\n properties: event.properties\n ? Object.entries(event.properties).map(([property, value]) => ({\n property,\n value,\n }))\n : undefined,\n }));\n\n return this.httpClient.post(\"/usage/events/batch\", { events }, options);\n }\n}\n","import crypto from \"node:crypto\";\n\n/**\n * Webhook payload structure from Commet\n */\nexport interface WebhookPayload {\n event: WebhookEvent;\n timestamp: string;\n organizationId: string;\n data: WebhookData;\n}\n\n/**\n * Webhook data structure (subscription-related fields)\n */\nexport interface WebhookData {\n id?: string;\n publicId?: string;\n subscriptionId?: string;\n customerId?: string;\n externalId?: string;\n status?: string;\n name?: string;\n canceledAt?: string;\n [key: string]: unknown;\n}\n\n/**\n * Supported webhook events\n */\nexport type WebhookEvent =\n | \"subscription.created\"\n | \"subscription.activated\"\n | \"subscription.canceled\"\n | \"subscription.updated\";\n\nexport interface VerifyParams {\n payload: string;\n signature: string | null;\n secret: string;\n}\n\nexport interface GenerateSignatureParams {\n payload: string;\n secret: string;\n}\n\nexport interface VerifyAndParseParams {\n rawBody: string;\n signature: string | null;\n secret: string;\n}\n\n/**\n * Webhooks resource for signature verification\n */\nexport class Webhooks {\n /**\n * Verify HMAC-SHA256 webhook signature\n *\n * Use this method to verify that webhooks are authentically from Commet.\n * The signature is included in the `X-Commet-Signature` header.\n *\n * @param payload - Raw request body as string (IMPORTANT: Do not parse JSON first)\n * @param signature - Value from X-Commet-Signature header\n * @param secret - Your webhook secret from Commet dashboard\n * @returns true if signature is valid, false otherwise\n *\n * @example\n * ```typescript\n * // Next.js API route example\n * export async function POST(request: Request) {\n * const rawBody = await request.text();\n * const signature = request.headers.get('x-commet-signature');\n *\n * const isValid = commet.webhooks.verify(\n * rawBody,\n * signature,\n * process.env.COMMET_WEBHOOK_SECRET\n * );\n *\n * if (!isValid) {\n * return new Response('Invalid signature', { status: 401 });\n * }\n *\n * const payload = JSON.parse(rawBody);\n * // Handle webhook event...\n * }\n * ```\n */\n verify(params: VerifyParams): boolean {\n const { payload, signature, secret } = params;\n\n if (!signature || !secret || !payload) {\n return false;\n }\n\n try {\n const expectedSignature = this.generateSignature({ payload, secret });\n\n // Use timing-safe comparison to prevent timing attacks\n return crypto.timingSafeEqual(\n Buffer.from(signature, \"hex\"),\n Buffer.from(expectedSignature, \"hex\"),\n );\n } catch (error) {\n // timingSafeEqual throws if lengths don't match\n return false;\n }\n }\n\n /**\n * Generate HMAC-SHA256 signature (internal use)\n * @internal\n */\n private generateSignature(params: GenerateSignatureParams): string {\n const { payload, secret } = params;\n return crypto.createHmac(\"sha256\", secret).update(payload).digest(\"hex\");\n }\n\n /**\n * Parse and verify webhook payload in one step\n *\n * @example\n * ```typescript\n * const payload = commet.webhooks.verifyAndParse({\n * rawBody,\n * signature,\n * secret: process.env.COMMET_WEBHOOK_SECRET\n * });\n *\n * if (!payload) {\n * return new Response('Invalid signature', { status: 401 });\n * }\n *\n * // payload is typed and validated\n * if (payload.event === 'subscription.activated') {\n * // Handle activation...\n * }\n * ```\n */\n verifyAndParse(params: VerifyAndParseParams): WebhookPayload | null {\n const { rawBody, signature, secret } = params;\n\n if (!this.verify({ payload: rawBody, signature, secret })) {\n return null;\n }\n\n try {\n return JSON.parse(params.rawBody) as WebhookPayload;\n } catch {\n return null;\n }\n }\n}\n","export type Environment = \"sandbox\" | \"production\";\n\nexport type CommetConfig = {\n apiKey: string;\n environment?: Environment;\n debug?: boolean;\n timeout?: number;\n retries?: number;\n};\n\n// API Response types\nexport interface ApiResponse<T = unknown> {\n success: boolean;\n data?: T;\n error?: string;\n message?: string;\n // Pagination fields (optional, included for list endpoints)\n hasMore?: boolean;\n nextCursor?: string;\n}\n\nexport interface PaginatedResponse<T> {\n data: T[];\n hasMore: boolean;\n nextCursor?: string;\n totalCount?: number;\n}\n\nexport interface PaginatedList<T> extends PaginatedResponse<T> {\n next(): Promise<PaginatedList<T>>;\n all(): Promise<T[]>;\n}\n\n// Error types\nexport class CommetError extends Error {\n constructor(\n message: string,\n public code?: string,\n public statusCode?: number,\n public details?: unknown,\n ) {\n super(message);\n this.name = \"CommetError\";\n }\n}\n\nexport class CommetAPIError extends CommetError {\n constructor(\n message: string,\n public statusCode: number,\n public code?: string,\n public details?: unknown,\n ) {\n super(message, code, statusCode, details);\n this.name = \"CommetAPIError\";\n }\n}\n\nexport class CommetValidationError extends CommetError {\n constructor(\n message: string,\n public validationErrors: Record<string, string[]>,\n ) {\n super(message);\n this.name = \"CommetValidationError\";\n }\n}\n\nexport type CustomerID = `cus_${string}`;\nexport type AgreementID = `agr_${string}`;\nexport type InvoiceID = `inv_${string}`;\nexport type PhaseID = `phs_${string}`;\nexport type ItemID = `itm_${string}`;\nexport type ProductID = `prd_${string}`;\nexport type EventID = `evt_${string}`;\nexport type WebhookID = `wh_${string}`;\n\n// Currency enum\nexport type Currency =\n | \"USD\"\n | \"EUR\"\n | \"GBP\"\n | \"CAD\"\n | \"AUD\"\n | \"JPY\"\n | \"ARS\"\n | \"BRL\"\n | \"MXN\"\n | \"CLP\";\n\n// Common parameters\nexport interface ListParams extends Record<string, unknown> {\n limit?: number;\n cursor?: string;\n startDate?: string;\n endDate?: string;\n}\n\nexport interface RetrieveOptions {\n expand?: string[];\n}\n\n// Request options\nexport interface RequestOptions {\n idempotencyKey?: string;\n timeout?: number;\n}\n\n/**\n * Generated types interface - augmented by CLI after 'commet pull'\n *\n * This interface gets filled by module augmentation when you run `commet pull`.\n * The CLI generates a .commet.d.ts file that augments this interface with your\n * organization's specific event and seat types.\n *\n * @example\n * // After running `commet pull`, TypeScript will automatically know your types:\n * await commet.usage.events.create({\n * eventType: 'api_call', // Autocomplete works!\n * customerId: 'cus_123'\n * });\n */\n\n// biome-ignore lint/suspicious/noEmptyInterface: <explanation>\nexport interface CommetGeneratedTypes {}\n\n/**\n * Helper type that provides fallback to string if types are not generated\n */\nexport type GeneratedEventType = CommetGeneratedTypes extends {\n eventType: infer T;\n}\n ? T\n : string;\n\n/**\n * Helper type that provides fallback to string if types are not generated\n */\nexport type GeneratedSeatType = CommetGeneratedTypes extends {\n seatType: infer T;\n}\n ? T\n : string;\n\n/**\n * Helper type that provides fallback to string if types are not generated\n * @deprecated Use GeneratedPlanCode instead\n */\nexport type GeneratedProductId = CommetGeneratedTypes extends {\n productId: infer T;\n}\n ? T\n : string;\n\n/**\n * Helper type that provides fallback to string if types are not generated\n */\nexport type GeneratedPlanCode = CommetGeneratedTypes extends {\n planCode: infer T;\n}\n ? T\n : string;\n\n/**\n * Helper type that provides fallback to string if types are not generated\n */\nexport type GeneratedFeatureCode = CommetGeneratedTypes extends {\n featureCode: infer T;\n}\n ? T\n : string;\n","import type {\n ApiResponse,\n CommetConfig,\n Environment,\n RequestOptions,\n} from \"../types/common\";\nimport { CommetAPIError, CommetValidationError } from \"../types/common\";\n\nexport interface RetryConfig {\n maxRetries: number;\n baseDelay: number;\n maxDelay: number;\n retryableStatusCodes: number[];\n}\n\nconst DEFAULT_RETRY_CONFIG: RetryConfig = {\n maxRetries: 3,\n baseDelay: 1000, // 1s\n maxDelay: 8000, // 8s\n retryableStatusCodes: [408, 429, 500, 502, 503, 504],\n};\n\nexport class CommetHTTPClient {\n private config: CommetConfig;\n private environment: Environment;\n private retryConfig: RetryConfig;\n\n constructor(config: CommetConfig, environment: Environment) {\n this.config = config;\n this.environment = environment;\n this.retryConfig = {\n ...DEFAULT_RETRY_CONFIG,\n maxRetries: config.retries ?? DEFAULT_RETRY_CONFIG.maxRetries,\n };\n }\n\n async get<T = unknown>(\n endpoint: string,\n params?: Record<string, unknown>,\n options?: RequestOptions,\n ): Promise<ApiResponse<T>> {\n return this.request(\"GET\", endpoint, undefined, options, params);\n }\n\n async post<T = unknown>(\n endpoint: string,\n data?: unknown,\n options?: RequestOptions,\n ): Promise<ApiResponse<T>> {\n return this.request(\"POST\", endpoint, data, options);\n }\n\n async put<T = unknown>(\n endpoint: string,\n data?: unknown,\n options?: RequestOptions,\n ): Promise<ApiResponse<T>> {\n return this.request(\"PUT\", endpoint, data, options);\n }\n\n async delete<T = unknown>(\n endpoint: string,\n data?: unknown,\n options?: RequestOptions,\n ): Promise<ApiResponse<T>> {\n return this.request(\"DELETE\", endpoint, data, options);\n }\n\n /**\n * Core request method with retry logic\n */\n private async request<T = unknown>(\n method: string,\n endpoint: string,\n data?: unknown,\n options?: RequestOptions,\n params?: Record<string, unknown>,\n ): Promise<ApiResponse<T>> {\n const url = this.buildURL(endpoint, params);\n return this.executeRequest(method, url, data, options);\n }\n\n /**\n * Execute real API request with retry logic\n */\n private async executeRequest<T = unknown>(\n method: string,\n url: string,\n data?: unknown,\n options?: RequestOptions,\n attempt = 1,\n ): Promise<ApiResponse<T>> {\n try {\n const headers: Record<string, string> = {\n \"x-api-key\": this.config.apiKey,\n \"Content-Type\": \"application/json\",\n \"User-Agent\": \"commet/0.1.0\",\n };\n\n if (options?.idempotencyKey) {\n headers[\"Idempotency-Key\"] = options.idempotencyKey;\n } else if (method === \"POST\" && data) {\n headers[\"Idempotency-Key\"] = this.generateIdempotencyKey();\n }\n\n const requestConfig: RequestInit = {\n method,\n headers,\n signal: AbortSignal.timeout(\n options?.timeout ?? this.config.timeout ?? 30000,\n ),\n };\n\n if (data) {\n requestConfig.body = JSON.stringify(data);\n }\n\n if (this.config.debug) {\n console.log(`[Commet SDK] ${method} ${url}`);\n if (data) {\n console.log(\"Request data:\", JSON.stringify(data, null, 2));\n }\n }\n\n const response = await fetch(url, requestConfig);\n\n if (this.config.debug) {\n console.log(\n `[Commet SDK] Response status: ${response.status} ${response.statusText}`,\n );\n }\n\n let responseData: unknown;\n let responseText: string;\n\n try {\n responseData = await response.json();\n responseText = \"\";\n } catch (jsonError) {\n try {\n responseText = await response.text();\n } catch (textError) {\n responseText = \"Failed to read response body\";\n }\n if (this.config.debug) {\n console.log(\n \"[Commet SDK] Failed to parse JSON response:\",\n responseText,\n );\n }\n\n // For 404 errors with invalid JSON, return a graceful response\n // This handles cases like HTML error pages or empty responses\n if (response.status === 404) {\n return {\n success: false,\n error: \"Resource not found\",\n } as ApiResponse<T>;\n }\n\n throw new CommetAPIError(\n `Invalid JSON response: ${response.status} ${response.statusText}`,\n response.status,\n \"INVALID_JSON\",\n { responseText },\n );\n }\n\n if (!response.ok) {\n // Check if we should retry\n if (\n attempt <= this.retryConfig.maxRetries &&\n this.retryConfig.retryableStatusCodes.includes(response.status)\n ) {\n const delay = Math.min(\n this.retryConfig.baseDelay * 2 ** (attempt - 1),\n this.retryConfig.maxDelay,\n );\n\n if (this.config.debug) {\n console.log(\n `[Commet SDK] Retrying in ${delay}ms (attempt ${attempt}/${this.retryConfig.maxRetries})`,\n );\n }\n\n await this.sleep(delay);\n return this.executeRequest(method, url, data, options, attempt + 1);\n }\n\n // Log error response for debugging\n if (this.config.debug) {\n console.log(\n \"[Commet SDK] Error response:\",\n JSON.stringify(responseData, null, 2),\n );\n }\n\n // Type guard for error response\n const isErrorResponse = (\n data: unknown,\n ): data is {\n message?: string;\n errors?: Record<string, string[]>;\n code?: string;\n details?: unknown;\n } => {\n return typeof data === \"object\" && data !== null;\n };\n\n const errorData = isErrorResponse(responseData) ? responseData : {};\n\n // Handle different error types\n if (response.status === 400 && errorData.errors) {\n throw new CommetValidationError(\n errorData.message || \"Validation failed\",\n errorData.errors,\n );\n }\n\n throw new CommetAPIError(\n errorData.message || `Request failed with status ${response.status}`,\n response.status,\n errorData.code,\n errorData.details,\n );\n }\n\n if (this.config.debug) {\n console.log(\"[Commet SDK] Response:\", responseData);\n }\n\n return responseData as ApiResponse<T>;\n } catch (error) {\n // Handle network errors and timeouts\n if (error instanceof TypeError && error.message.includes(\"fetch\")) {\n if (attempt <= this.retryConfig.maxRetries) {\n const delay = Math.min(\n this.retryConfig.baseDelay * 2 ** (attempt - 1),\n this.retryConfig.maxDelay,\n );\n\n if (this.config.debug) {\n console.log(`[Commet SDK] Network error, retrying in ${delay}ms`);\n }\n\n await this.sleep(delay);\n return this.executeRequest(method, url, data, options, attempt + 1);\n }\n }\n\n throw error;\n }\n }\n\n /**\n * Get base URL based on environment\n */\n private getBaseURL(): string {\n return this.environment === \"production\"\n ? \"https://commet.co\"\n : \"https://sandbox.commet.co\";\n }\n\n /**\n * Build full URL from endpoint and params\n */\n private buildURL(endpoint: string, params?: Record<string, unknown>): string {\n const baseURL = this.getBaseURL();\n\n // Construct full path with /api prefix\n const normalizedEndpoint = endpoint.startsWith(\"/\")\n ? endpoint\n : `/${endpoint}`;\n const fullPath = `/api${normalizedEndpoint}`;\n\n // Debug logging\n if (this.config.debug) {\n console.log(\n `[Commet SDK] Building URL - baseURL: ${baseURL}, endpoint: ${endpoint}, fullPath: ${fullPath}`,\n );\n }\n\n const url = new URL(fullPath, baseURL);\n\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.append(key, String(value));\n }\n }\n }\n\n const finalUrl = url.toString();\n\n // Debug final URL\n if (this.config.debug) {\n console.log(`[Commet SDK] Final URL: ${finalUrl}`);\n }\n\n return finalUrl;\n }\n\n /**\n * Generate idempotency key\n */\n private generateIdempotencyKey(): string {\n // Generate UUID-like key for idempotency\n return `sdk_${Date.now()}_${Math.random().toString(36).substring(2)}`;\n }\n\n /**\n * Sleep for specified milliseconds\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","import { CustomerContext } from \"./customer\";\nimport { CustomersResource } from \"./resources/customers\";\nimport { FeaturesResource } from \"./resources/features\";\nimport { PlansResource } from \"./resources/plans\";\nimport { PortalResource } from \"./resources/portal\";\nimport { SeatsResource } from \"./resources/seats\";\nimport { SubscriptionsResource } from \"./resources/subscriptions\";\nimport { UsageResource } from \"./resources/usage\";\nimport { Webhooks } from \"./resources/webhooks\";\nimport type { CommetConfig, Environment } from \"./types/common\";\nimport { CommetHTTPClient } from \"./utils/http\";\n\n/**\n * Main Commet SDK client\n */\nexport class Commet {\n private httpClient: CommetHTTPClient;\n private environment: Environment;\n\n public readonly customers: CustomersResource;\n public readonly plans: PlansResource;\n public readonly usage: UsageResource;\n public readonly seats: SeatsResource;\n public readonly subscriptions: SubscriptionsResource;\n public readonly portal: PortalResource;\n public readonly features: FeaturesResource;\n public readonly webhooks: Webhooks;\n\n constructor(config: CommetConfig) {\n if (!config.apiKey) {\n throw new Error(\"Commet SDK: API key is required\");\n }\n\n if (!config.apiKey.startsWith(\"ck_\")) {\n throw new Error(\n \"Commet SDK: Invalid API key format. Expected format: ck_xxx...\",\n );\n }\n\n // Default to sandbox for safety\n this.environment = config.environment || \"sandbox\";\n\n this.httpClient = new CommetHTTPClient(config, this.environment);\n this.customers = new CustomersResource(this.httpClient);\n this.plans = new PlansResource(this.httpClient);\n this.usage = new UsageResource(this.httpClient);\n this.seats = new SeatsResource(this.httpClient);\n this.subscriptions = new SubscriptionsResource(this.httpClient);\n this.portal = new PortalResource(this.httpClient);\n this.features = new FeaturesResource(this.httpClient);\n this.webhooks = new Webhooks();\n\n if (config.debug) {\n console.log(`[Commet SDK] Initialized in ${this.environment} mode`);\n console.log(\"API Key:\", `${config.apiKey.substring(0, 12)}...`);\n const baseURL =\n this.environment === \"production\"\n ? \"https://commet.co\"\n : \"https://sandbox.commet.co\";\n console.log(\"Base URL:\", baseURL);\n }\n }\n\n /**\n * Create a customer-scoped context for cleaner API usage\n *\n * @example\n * ```typescript\n * const customer = commet.customer(\"user_123\");\n *\n * // All operations are now scoped to this customer\n * const seats = await customer.features.get(\"team_members\");\n * await customer.seats.add(\"member\");\n * await customer.usage.track(\"api_call\");\n * ```\n */\n customer(externalId: string): CustomerContext {\n return new CustomerContext(externalId, {\n features: this.features,\n seats: this.seats,\n usage: this.usage,\n subscriptions: this.subscriptions,\n portal: this.portal,\n });\n }\n\n getEnvironment(): Environment {\n return this.environment;\n }\n\n isSandbox(): boolean {\n return this.environment === \"sandbox\";\n }\n\n isProduction(): boolean {\n return this.environment === \"production\";\n }\n}\n","import type { Environment } from \"../types/common\";\n\n/**\n * Check if environment is sandbox\n */\nexport function isSandbox(environment: Environment): boolean {\n return environment === \"sandbox\";\n}\n\n/**\n * Check if environment is production\n */\nexport function isProduction(environment: Environment): boolean {\n return environment === \"production\";\n}\n"],"mappings":"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","names":["crypto","data"]}
package/dist/index.mjs CHANGED
@@ -5,9 +5,15 @@ var CustomerContext = class {
5
5
  * Feature access methods - delegates to FeaturesResource
6
6
  */
7
7
  this.features = {
8
- get: (code, options) => this.featuresResource.get(code, this.externalId, options),
9
- check: (code, options) => this.featuresResource.check(code, this.externalId, options),
10
- canUse: (code, options) => this.featuresResource.canUse(code, this.externalId, options),
8
+ get: (code, options) => this.featuresResource.get({ code, externalId: this.externalId }, options),
9
+ check: (code, options) => this.featuresResource.check(
10
+ { code, externalId: this.externalId },
11
+ options
12
+ ),
13
+ canUse: (code, options) => this.featuresResource.canUse(
14
+ { code, externalId: this.externalId },
15
+ options
16
+ ),
11
17
  list: (options) => this.featuresResource.list(this.externalId, options)
12
18
  };
13
19
  /**
@@ -41,7 +47,7 @@ var CustomerContext = class {
41
47
  * Subscription methods - delegates to SubscriptionsResource
42
48
  */
43
49
  this.subscription = {
44
- get: () => this.subscriptionsResource.get({ externalId: this.externalId })
50
+ get: () => this.subscriptionsResource.get(this.externalId)
45
51
  };
46
52
  /**
47
53
  * Portal methods - delegates to PortalResource
@@ -113,9 +119,9 @@ var CustomersResource = class {
113
119
  /**
114
120
  * Update a customer
115
121
  */
116
- async update(customerId, params, options) {
122
+ async update(params, options) {
117
123
  return this.httpClient.put(
118
- `/customers/${customerId}`,
124
+ `/customers/${params.customerId}`,
119
125
  {
120
126
  billingEmail: params.email,
121
127
  externalId: params.externalId,
@@ -159,11 +165,12 @@ var FeaturesResource = class {
159
165
  *
160
166
  * @example
161
167
  * ```typescript
162
- * const seats = await commet.features.get("team_members", "user_123");
168
+ * const seats = await commet.features.get({ code: "team_members", externalId: "user_123" });
163
169
  * console.log(seats.current, seats.included, seats.remaining);
164
170
  * ```
165
171
  */
166
- async get(code, externalId, options) {
172
+ async get(params, options) {
173
+ const { code, externalId } = params;
167
174
  return this.httpClient.get(
168
175
  `/features/${code}`,
169
176
  { externalId },
@@ -175,11 +182,15 @@ var FeaturesResource = class {
175
182
  *
176
183
  * @example
177
184
  * ```typescript
178
- * const { allowed } = await commet.features.check("custom_branding", "user_123");
185
+ * const { allowed } = await commet.features.check({
186
+ * code: "custom_branding",
187
+ * externalId: "user_123"
188
+ * });
179
189
  * if (!allowed) redirect("/upgrade");
180
190
  * ```
181
191
  */
182
- async check(code, externalId, options) {
192
+ async check(params, options) {
193
+ const { code, externalId } = params;
183
194
  const result = await this.httpClient.get(
184
195
  `/features/${code}`,
185
196
  { externalId },
@@ -206,7 +217,10 @@ var FeaturesResource = class {
206
217
  *
207
218
  * @example
208
219
  * ```typescript
209
- * const { allowed, willBeCharged } = await commet.features.canUse("team_members", "user_123");
220
+ * const { allowed, willBeCharged } = await commet.features.canUse({
221
+ * code: "team_members",
222
+ * externalId: "user_123"
223
+ * });
210
224
  *
211
225
  * if (!allowed) {
212
226
  * return { error: "Upgrade to add more members" };
@@ -217,7 +231,8 @@ var FeaturesResource = class {
217
231
  * }
218
232
  * ```
219
233
  */
220
- async canUse(code, externalId, options) {
234
+ async canUse(params, options) {
235
+ const { code, externalId } = params;
221
236
  return this.httpClient.get(
222
237
  `/features/${code}`,
223
238
  { externalId, action: "canUse" },
@@ -229,7 +244,7 @@ var FeaturesResource = class {
229
244
  *
230
245
  * @example
231
246
  * ```typescript
232
- * const features = await commet.features.list("user_123");
247
+ * const features = await commet.features.list({ externalId: "user_123" });
233
248
  * for (const feature of features) {
234
249
  * console.log(feature.code, feature.allowed);
235
250
  * }
@@ -369,10 +384,11 @@ var SeatsResource = class {
369
384
  * ```
370
385
  */
371
386
  async getBalance(params) {
387
+ const { customerId, externalId, seatType } = params;
372
388
  return this.httpClient.get("/seats/balance", {
373
- customerId: params.customerId,
374
- externalId: params.externalId,
375
- seatType: params.seatType
389
+ customerId,
390
+ externalId,
391
+ seatType
376
392
  });
377
393
  }
378
394
  /**
@@ -386,9 +402,10 @@ var SeatsResource = class {
386
402
  * ```
387
403
  */
388
404
  async getAllBalances(params) {
405
+ const { customerId, externalId } = params;
389
406
  return this.httpClient.get("/seats/balances", {
390
- customerId: params.customerId,
391
- externalId: params.externalId
407
+ customerId,
408
+ externalId
392
409
  });
393
410
  }
394
411
  };
@@ -419,25 +436,26 @@ var SubscriptionsResource = class {
419
436
  *
420
437
  * @example
421
438
  * ```typescript
422
- * const sub = await commet.subscriptions.get({ externalId: 'user_123' });
439
+ * const sub = await commet.subscriptions.get('user_123');
423
440
  * ```
424
441
  */
425
- async get(params) {
426
- return this.httpClient.get("/subscriptions/active", params);
442
+ async get(externalId) {
443
+ return this.httpClient.get("/subscriptions/active", { externalId });
427
444
  }
428
445
  /**
429
446
  * Change the plan of a subscription (upgrade/downgrade)
430
447
  *
431
448
  * @example
432
449
  * ```typescript
433
- * await commet.subscriptions.changePlan('sub_xxx', {
450
+ * await commet.subscriptions.changePlan({
451
+ * subscriptionId: 'sub_xxx',
434
452
  * planCode: 'enterprise' // autocomplete works after `commet pull`
435
453
  * });
436
454
  * ```
437
455
  */
438
- async changePlan(subscriptionId, params, options) {
456
+ async changePlan(params, options) {
439
457
  return this.httpClient.post(
440
- `/subscriptions/${subscriptionId}/change-plan`,
458
+ `/subscriptions/${params.subscriptionId}/change-plan`,
441
459
  params,
442
460
  options
443
461
  );
@@ -447,14 +465,15 @@ var SubscriptionsResource = class {
447
465
  *
448
466
  * @example
449
467
  * ```typescript
450
- * await commet.subscriptions.cancel('sub_xxx', {
468
+ * await commet.subscriptions.cancel({
469
+ * subscriptionId: 'sub_xxx',
451
470
  * reason: 'switched_to_competitor'
452
471
  * });
453
472
  * ```
454
473
  */
455
- async cancel(subscriptionId, params, options) {
474
+ async cancel(params, options) {
456
475
  return this.httpClient.post(
457
- `/subscriptions/${subscriptionId}/cancel`,
476
+ `/subscriptions/${params.subscriptionId}/cancel`,
458
477
  params || {},
459
478
  options
460
479
  );
@@ -558,12 +577,13 @@ var Webhooks = class {
558
577
  * }
559
578
  * ```
560
579
  */
561
- verify(payload, signature, secret) {
580
+ verify(params) {
581
+ const { payload, signature, secret } = params;
562
582
  if (!signature || !secret || !payload) {
563
583
  return false;
564
584
  }
565
585
  try {
566
- const expectedSignature = this.generateSignature(payload, secret);
586
+ const expectedSignature = this.generateSignature({ payload, secret });
567
587
  return crypto.timingSafeEqual(
568
588
  Buffer.from(signature, "hex"),
569
589
  Buffer.from(expectedSignature, "hex")
@@ -576,24 +596,20 @@ var Webhooks = class {
576
596
  * Generate HMAC-SHA256 signature (internal use)
577
597
  * @internal
578
598
  */
579
- generateSignature(payload, secret) {
599
+ generateSignature(params) {
600
+ const { payload, secret } = params;
580
601
  return crypto.createHmac("sha256", secret).update(payload).digest("hex");
581
602
  }
582
603
  /**
583
604
  * Parse and verify webhook payload in one step
584
605
  *
585
- * @param rawBody - Raw request body as string
586
- * @param signature - Value from X-Commet-Signature header
587
- * @param secret - Your webhook secret from Commet dashboard
588
- * @returns Parsed payload if valid, null if invalid
589
- *
590
606
  * @example
591
607
  * ```typescript
592
- * const payload = commet.webhooks.verifyAndParse(
608
+ * const payload = commet.webhooks.verifyAndParse({
593
609
  * rawBody,
594
610
  * signature,
595
- * process.env.COMMET_WEBHOOK_SECRET
596
- * );
611
+ * secret: process.env.COMMET_WEBHOOK_SECRET
612
+ * });
597
613
  *
598
614
  * if (!payload) {
599
615
  * return new Response('Invalid signature', { status: 401 });
@@ -605,12 +621,13 @@ var Webhooks = class {
605
621
  * }
606
622
  * ```
607
623
  */
608
- verifyAndParse(rawBody, signature, secret) {
609
- if (!this.verify(rawBody, signature, secret)) {
624
+ verifyAndParse(params) {
625
+ const { rawBody, signature, secret } = params;
626
+ if (!this.verify({ payload: rawBody, signature, secret })) {
610
627
  return null;
611
628
  }
612
629
  try {
613
- return JSON.parse(rawBody);
630
+ return JSON.parse(params.rawBody);
614
631
  } catch {
615
632
  return null;
616
633
  }