@commet/node 1.8.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -221,14 +221,14 @@ var FeaturesResource = class {
221
221
  if (!result.success || !result.data) {
222
222
  return {
223
223
  success: false,
224
- data: { allowed: false },
225
- message: result.message
224
+ code: result.code,
225
+ message: result.message,
226
+ details: result.details
226
227
  };
227
228
  }
228
229
  return {
229
230
  success: true,
230
- data: { allowed: result.data.allowed },
231
- message: result.message
231
+ data: { allowed: result.data.allowed }
232
232
  };
233
233
  }
234
234
  async canUse(params, options) {
@@ -568,7 +568,7 @@ var CommetHTTPClient = class {
568
568
  const headers = {
569
569
  "x-api-key": this.config.apiKey,
570
570
  "Content-Type": "application/json",
571
- "User-Agent": "commet/0.1.0"
571
+ "User-Agent": "commet-node/1.9.0"
572
572
  };
573
573
  if (options?.idempotencyKey) {
574
574
  headers["Idempotency-Key"] = options.idempotencyKey;
@@ -614,13 +614,6 @@ var CommetHTTPClient = class {
614
614
  responseText
615
615
  );
616
616
  }
617
- if (response.status === 404) {
618
- return {
619
- success: false,
620
- code: "not_found",
621
- message: "Resource not found"
622
- };
623
- }
624
617
  throw new CommetAPIError(
625
618
  `Invalid JSON response: ${response.status} ${response.statusText}`,
626
619
  response.status,
@@ -675,7 +668,10 @@ var CommetHTTPClient = class {
675
668
  }
676
669
  return responseData;
677
670
  } catch (error) {
678
- if (error instanceof TypeError && error.message.includes("fetch")) {
671
+ const isNetworkError = error instanceof TypeError && error.message.includes("fetch");
672
+ const isTimeoutError = error instanceof DOMException && error.name === "AbortError";
673
+ const isTimeoutErrorModern = typeof globalThis.DOMException !== "undefined" && error instanceof DOMException && error.name === "TimeoutError";
674
+ if (isNetworkError || isTimeoutError || isTimeoutErrorModern) {
679
675
  if (attempt <= this.retryConfig.maxRetries) {
680
676
  const delay = Math.min(
681
677
  this.retryConfig.baseDelay * 2 ** (attempt - 1),
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/customer.ts","../src/resources/credit-packs.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// Credit Packs\nexport type { CreditPack } from \"./resources/credit-packs\";\n// Customers\nexport type {\n BatchResult as CustomersBatchResult,\n CreateParams as CreateCustomerParams,\n Customer,\n CustomerAddress,\n ListCustomersParams,\n UpdateParams as UpdateCustomerParams,\n} from \"./resources/customers\";\n// Features\nexport type {\n CanUseFeatureParams,\n CanUseResult,\n CheckFeatureParams,\n CheckResult,\n FeatureAccess,\n GetFeatureParams,\n} from \"./resources/features\";\n// Plans\nexport type {\n BillingInterval,\n FeatureType,\n ListPlansParams,\n Plan,\n PlanDetail,\n PlanFeature,\n PlanID,\n PlanPrice,\n} from \"./resources/plans\";\n// Portal\nexport type { GetUrlParams, PortalAccess } from \"./resources/portal\";\n// Seats\nexport type {\n AddParams as AddSeatsParams,\n GetAllBalancesParams,\n GetBalanceParams,\n RemoveParams as RemoveSeatsParams,\n SeatBalance,\n SeatEvent,\n SetAllParams as SetAllSeatsParams,\n SetParams as SetSeatsParams,\n} from \"./resources/seats\";\n// Subscriptions\nexport type {\n ActiveSubscription,\n CancelParams,\n CreatedSubscription,\n CreateSubscriptionParams,\n FeatureSummary,\n Subscription,\n SubscriptionStatus,\n} from \"./resources/subscriptions\";\n// Usage\nexport type {\n TrackModelTokensParams,\n TrackParams,\n TrackUsageParams,\n UsageEvent,\n UsageEventProperty,\n} from \"./resources/usage\";\nexport type {\n WebhookData,\n WebhookEvent,\n WebhookPayload,\n} from \"./resources/webhooks\";\n// Webhooks\nexport { Webhooks } from \"./resources/webhooks\";\n// Type exports\nexport type {\n ApiResponse,\n CommetConfig,\n CommetGeneratedTypes,\n Currency,\n CustomerID,\n Environment,\n EventID,\n GeneratedFeatureCode,\n GeneratedPlanCode,\n GeneratedSeatType,\n PaginatedList,\n PaginatedResponse,\n RequestOptions,\n} from \"./types/common\";\n// Error exports\nexport {\n CommetAPIError,\n CommetError,\n CommetValidationError,\n} from \"./types/common\";\n\n// Utility exports\nexport { isProduction, isSandbox } 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 customerId\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 customerId: 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 customerId: string,\n resources: {\n features: FeaturesResource;\n seats: SeatsResource;\n usage: UsageResource;\n subscriptions: SubscriptionsResource;\n portal: PortalResource;\n },\n ) {\n this.customerId = customerId;\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 features = {\n get: (code: string, options?: RequestOptions) =>\n this.featuresResource.get({ code, customerId: this.customerId }, options),\n\n check: (code: string, options?: RequestOptions) =>\n this.featuresResource.check(\n { code, customerId: this.customerId },\n options,\n ),\n\n canUse: (code: string, options?: RequestOptions) =>\n this.featuresResource.canUse(\n { code, customerId: this.customerId },\n options,\n ),\n\n list: (options?: RequestOptions) =>\n this.featuresResource.list(this.customerId, options),\n };\n\n seats = {\n add: (seatType: string, count = 1, options?: RequestOptions) =>\n this.seatsResource.add(\n { customerId: this.customerId, seatType, count },\n options,\n ),\n\n remove: (seatType: string, count = 1, options?: RequestOptions) =>\n this.seatsResource.remove(\n { customerId: this.customerId, seatType, count },\n options,\n ),\n\n set: (seatType: string, count: number, options?: RequestOptions) =>\n this.seatsResource.set(\n { customerId: this.customerId, seatType, count },\n options,\n ),\n\n getBalance: (seatType: string) =>\n this.seatsResource.getBalance({ customerId: this.customerId, seatType }),\n };\n\n usage = {\n track: (\n feature: string,\n value?: number,\n properties?: Record<string, string>,\n options?: RequestOptions,\n ) =>\n this.usageResource.track(\n { customerId: this.customerId, feature, value, properties },\n options,\n ),\n };\n\n subscription = {\n get: () => this.subscriptionsResource.get(this.customerId),\n };\n\n portal = {\n getUrl: (options?: RequestOptions) =>\n this.portalResource.getUrl({ customerId: this.customerId }, options),\n };\n}\n","import type { ApiResponse } from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\n\nexport interface CreditPack {\n id: string;\n name: string;\n description: string | null;\n credits: number;\n price: number;\n currency: string;\n}\n\n/**\n * Credit Packs resource for listing available credit packs\n */\nexport class CreditPacksResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n /**\n * List all active credit packs\n *\n * @example\n * ```typescript\n * const packs = await commet.creditPacks.list();\n * console.log(packs.data); // [{ id: \"cp_xxx\", name: \"100 Credits\", ... }]\n * ```\n */\n async list(): Promise<ApiResponse<CreditPack[]>> {\n return this.httpClient.get(\"/credit-packs\");\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 fullName?: 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 id?: string; // Your user ID — stored as externalId, used to identify the customer in all SDK methods\n fullName?: 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 email?: string;\n fullName?: 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 ListCustomersParams extends BaseListParams {\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 when id is provided)\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.id,\n fullName: params.fullName,\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.id,\n fullName: c.fullName,\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 fullName: params.fullName,\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 * 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 CustomerID,\n GeneratedFeatureCode,\n RequestOptions,\n} from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\n\nexport interface FeatureParams {\n customerId: CustomerID;\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 enabled?: boolean;\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\nexport class FeaturesResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n async get(\n params: GetFeatureParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<FeatureAccess>> {\n return this.httpClient.get(\n `/features/${params.code}`,\n { customerId: params.customerId },\n options,\n );\n }\n\n async check(\n params: CheckFeatureParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<CheckResult>> {\n const result = await this.httpClient.get<FeatureAccess>(\n `/features/${params.code}`,\n { customerId: params.customerId },\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 async canUse(\n params: CanUseFeatureParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<CanUseResult>> {\n return this.httpClient.get(\n `/features/${params.code}`,\n { customerId: params.customerId, action: \"canUse\" },\n options,\n );\n }\n\n async list(\n customerId: CustomerID,\n options?: RequestOptions,\n ): Promise<ApiResponse<FeatureAccess[]>> {\n return this.httpClient.get(\"/features\", { customerId }, 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 trialDays: number;\n}\n\nexport interface PlanFeature {\n code: string;\n name: string;\n type: FeatureType;\n unitName: string | null;\n enabled?: boolean;\n includedAmount?: number;\n unlimited?: boolean;\n overageEnabled?: boolean;\n overageUnitPrice?: number;\n}\n\nexport interface Plan {\n id: PlanID;\n code: string;\n name: string;\n description: string | null;\n isPublic: boolean;\n isFree: boolean;\n isDefault: boolean;\n sortOrder: number;\n prices: PlanPrice[];\n features: PlanFeature[];\n createdAt: string;\n}\n\nexport interface PlanDetailPrice {\n billingInterval: BillingInterval;\n price: number;\n isDefault: boolean;\n trialDays: number;\n introOffer: {\n enabled: boolean;\n discountType: \"percentage\" | \"amount\" | null;\n discountValue: number | null;\n durationCycles: number | null;\n } | null;\n}\n\nexport interface PlanDetailFeature extends PlanFeature {\n overage: {\n enabled: boolean;\n model: \"per_unit\" | \"tiered\" | null;\n unitPrice: number | null;\n } | null;\n}\n\nexport interface PlanDetail {\n id: PlanID;\n code: string;\n name: string;\n description: string | null;\n isPublic: boolean;\n isDefault: boolean;\n sortOrder: number;\n prices: PlanDetailPrice[];\n features: PlanDetailFeature[];\n createdAt: string;\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}\n\ninterface GetUrlByEmail {\n email: string;\n customerId?: never;\n}\n\nexport type GetUrlParams = GetUrlByCustomerId | GetUrlByEmail;\n\nexport class PortalResource {\n constructor(private httpClient: CommetHTTPClient) {}\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 seatType: GeneratedSeatType;\n count: number;\n}\n\nexport interface RemoveParams {\n customerId: CustomerID;\n seatType: GeneratedSeatType;\n count: number;\n}\n\nexport interface SetParams {\n customerId: CustomerID;\n seatType: GeneratedSeatType;\n count: number;\n}\n\nexport interface SetAllParams {\n customerId: CustomerID;\n seats: Record<string, number>;\n}\n\nexport interface GetBalanceParams {\n customerId: CustomerID;\n seatType: GeneratedSeatType;\n}\n\nexport interface GetAllBalancesParams {\n customerId: CustomerID;\n}\n\nexport class SeatsResource {\n constructor(private httpClient: CommetHTTPClient) {}\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 async remove(\n params: RemoveParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<SeatEvent>> {\n return this.httpClient.delete(\"/seats\", params, options);\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 async setAll(\n params: SetAllParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<SeatEvent[]>> {\n return this.httpClient.put(\"/seats/bulk\", params, options);\n }\n\n async getBalance(\n params: GetBalanceParams,\n ): Promise<ApiResponse<SeatBalance>> {\n return this.httpClient.get(\"/seats/balance\", {\n customerId: params.customerId,\n seatType: params.seatType,\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 });\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 | null;\n };\n name: string;\n description: string | null;\n status: SubscriptionStatus;\n trialEndsAt: string | null;\n currentPeriod: {\n start: string;\n end: string;\n daysRemaining: number;\n };\n features: FeatureSummary[];\n startDate: string;\n endDate: string | null;\n billingDayOfMonth: number;\n nextBillingDate: string;\n checkoutUrl: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CreatedSubscription {\n id: string;\n customerId: string;\n planId: string;\n planName: string;\n name: string;\n status: SubscriptionStatus;\n billingInterval: BillingInterval | null;\n trialEndsAt: string | null;\n startDate: string;\n endDate: string | null;\n currentPeriodStart: string | null;\n currentPeriodEnd: string | null;\n billingDayOfMonth: number;\n checkoutUrl: string | null;\n createdAt: string;\n updatedAt: string;\n introOfferEndsAt: string | null;\n introOfferDiscountType: \"percentage\" | \"amount\" | null;\n introOfferDiscountValue: number | null;\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\ntype PlanIdentifier =\n | { planCode: GeneratedPlanCode; planId?: never }\n | { planCode?: never; planId: string };\n\nexport type CreateSubscriptionParams = PlanIdentifier & {\n customerId: string;\n} & {\n billingInterval?: BillingInterval;\n initialSeats?: Record<string, number>;\n skipTrial?: boolean;\n name?: string;\n startDate?: string;\n successUrl?: string;\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<CreatedSubscription>> {\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 customerId: string,\n ): Promise<ApiResponse<ActiveSubscription | null>> {\n return this.httpClient.get(\"/subscriptions/active\", { customerId });\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 GeneratedFeatureCode,\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 feature: string;\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\ninterface TrackBaseParams {\n feature: GeneratedFeatureCode;\n customerId: CustomerID;\n idempotencyKey?: string;\n timestamp?: string;\n properties?: Record<string, string>;\n}\n\nexport interface TrackUsageParams extends TrackBaseParams {\n value?: number;\n model?: never;\n}\n\nexport interface TrackModelTokensParams extends TrackBaseParams {\n model: string;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n value?: never;\n}\n\nexport type TrackParams = TrackUsageParams | TrackModelTokensParams;\n\nexport class UsageResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n async track(\n params: TrackParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<UsageEvent>> {\n const eventData: Record<string, unknown> = {\n feature: params.feature,\n customerId: params.customerId,\n idempotencyKey: params.idempotencyKey,\n timestamp: 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 if (\"model\" in params && params.model) {\n eventData.model = params.model;\n eventData.inputTokens = params.inputTokens;\n eventData.outputTokens = params.outputTokens;\n if (params.cacheReadTokens) {\n eventData.cacheReadTokens = params.cacheReadTokens;\n }\n if (params.cacheWriteTokens) {\n eventData.cacheWriteTokens = params.cacheWriteTokens;\n }\n } else {\n eventData.value = (params as TrackUsageParams).value;\n }\n\n return this.httpClient.post(\"/usage/events\", eventData, 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 code?: string;\n message?: string;\n details?: unknown;\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 = 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/types.d.ts file that augments this interface with your\n * organization's specific feature codes, seat types, and plan codes.\n *\n * @example\n * // After running `commet pull`, TypeScript will automatically know your types:\n * await commet.usage.track({\n * feature: 'api_calls', // Autocomplete works!\n * externalId: 'user_123'\n * });\n */\n\n// biome-ignore lint/suspicious/noEmptyInterface: augmented by CLI-generated .commet/types.d.ts\nexport interface CommetGeneratedTypes {}\n\nexport type GeneratedSeatType = CommetGeneratedTypes extends {\n seatType: infer T;\n}\n ? T\n : string;\n\nexport type GeneratedPlanCode = CommetGeneratedTypes extends {\n planCode: infer T;\n}\n ? T\n : string;\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 code: \"not_found\",\n message: \"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 code?: string;\n details?: unknown;\n } => {\n return typeof data === \"object\" && data !== null;\n };\n\n const errorData = isErrorResponse(responseData) ? responseData : {};\n\n // Handle validation errors (new normalized shape)\n if (\n errorData.code === \"validation_error\" &&\n Array.isArray(errorData.details)\n ) {\n const errors: Record<string, string[]> = {};\n for (const detail of errorData.details as Array<{\n field: string;\n message: string;\n }>) {\n if (!errors[detail.field]) errors[detail.field] = [];\n errors[detail.field].push(detail.message);\n }\n throw new CommetValidationError(\n errorData.message || \"Validation failed\",\n 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 { CreditPacksResource } from \"./resources/credit-packs\";\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 creditPacks: CreditPacksResource;\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.creditPacks = new CreditPacksResource(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(customerId: string): CustomerContext {\n return new CustomerContext(customerId, {\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/credit-packs.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// Credit Packs\nexport type { CreditPack } from \"./resources/credit-packs\";\n// Customers\nexport type {\n BatchResult as CustomersBatchResult,\n CreateParams as CreateCustomerParams,\n Customer,\n CustomerAddress,\n ListCustomersParams,\n UpdateParams as UpdateCustomerParams,\n} from \"./resources/customers\";\n// Features\nexport type {\n CanUseFeatureParams,\n CanUseResult,\n CheckFeatureParams,\n CheckResult,\n FeatureAccess,\n GetFeatureParams,\n} from \"./resources/features\";\n// Plans\nexport type {\n BillingInterval,\n FeatureType,\n ListPlansParams,\n Plan,\n PlanDetail,\n PlanFeature,\n PlanID,\n PlanPrice,\n} from \"./resources/plans\";\n// Portal\nexport type { GetUrlParams, PortalAccess } from \"./resources/portal\";\n// Seats\nexport type {\n AddParams as AddSeatsParams,\n GetAllBalancesParams,\n GetBalanceParams,\n RemoveParams as RemoveSeatsParams,\n SeatBalance,\n SeatEvent,\n SetAllParams as SetAllSeatsParams,\n SetParams as SetSeatsParams,\n} from \"./resources/seats\";\n// Subscriptions\nexport type {\n ActiveSubscription,\n CancelParams,\n CreatedSubscription,\n CreateSubscriptionParams,\n FeatureSummary,\n Subscription,\n SubscriptionStatus,\n} from \"./resources/subscriptions\";\n// Usage\nexport type {\n TrackModelTokensParams,\n TrackParams,\n TrackUsageParams,\n UsageEvent,\n UsageEventProperty,\n} from \"./resources/usage\";\nexport type {\n WebhookData,\n WebhookEvent,\n WebhookPayload,\n} from \"./resources/webhooks\";\n// Webhooks\nexport { Webhooks } from \"./resources/webhooks\";\n// Type exports\nexport type {\n ApiResponse,\n CommetConfig,\n CommetGeneratedTypes,\n Currency,\n CustomerID,\n Environment,\n EventID,\n GeneratedFeatureCode,\n GeneratedPlanCode,\n GeneratedSeatType,\n PaginatedList,\n PaginatedResponse,\n RequestOptions,\n} from \"./types/common\";\n// Error exports\nexport {\n CommetAPIError,\n CommetError,\n CommetValidationError,\n} from \"./types/common\";\n\n// Utility exports\nexport { isProduction, isSandbox } 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 customerId\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 customerId: 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 customerId: string,\n resources: {\n features: FeaturesResource;\n seats: SeatsResource;\n usage: UsageResource;\n subscriptions: SubscriptionsResource;\n portal: PortalResource;\n },\n ) {\n this.customerId = customerId;\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 features = {\n get: (code: string, options?: RequestOptions) =>\n this.featuresResource.get({ code, customerId: this.customerId }, options),\n\n check: (code: string, options?: RequestOptions) =>\n this.featuresResource.check(\n { code, customerId: this.customerId },\n options,\n ),\n\n canUse: (code: string, options?: RequestOptions) =>\n this.featuresResource.canUse(\n { code, customerId: this.customerId },\n options,\n ),\n\n list: (options?: RequestOptions) =>\n this.featuresResource.list(this.customerId, options),\n };\n\n seats = {\n add: (seatType: string, count = 1, options?: RequestOptions) =>\n this.seatsResource.add(\n { customerId: this.customerId, seatType, count },\n options,\n ),\n\n remove: (seatType: string, count = 1, options?: RequestOptions) =>\n this.seatsResource.remove(\n { customerId: this.customerId, seatType, count },\n options,\n ),\n\n set: (seatType: string, count: number, options?: RequestOptions) =>\n this.seatsResource.set(\n { customerId: this.customerId, seatType, count },\n options,\n ),\n\n getBalance: (seatType: string) =>\n this.seatsResource.getBalance({ customerId: this.customerId, seatType }),\n };\n\n usage = {\n track: (\n feature: string,\n value?: number,\n properties?: Record<string, string>,\n options?: RequestOptions,\n ) =>\n this.usageResource.track(\n { customerId: this.customerId, feature, value, properties },\n options,\n ),\n };\n\n subscription = {\n get: () => this.subscriptionsResource.get(this.customerId),\n };\n\n portal = {\n getUrl: (options?: RequestOptions) =>\n this.portalResource.getUrl({ customerId: this.customerId }, options),\n };\n}\n","import type { ApiResponse } from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\n\nexport interface CreditPack {\n id: string;\n name: string;\n description: string | null;\n credits: number;\n price: number;\n currency: string;\n}\n\n/**\n * Credit Packs resource for listing available credit packs\n */\nexport class CreditPacksResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n /**\n * List all active credit packs\n *\n * @example\n * ```typescript\n * const packs = await commet.creditPacks.list();\n * console.log(packs.data); // [{ id: \"cp_xxx\", name: \"100 Credits\", ... }]\n * ```\n */\n async list(): Promise<ApiResponse<CreditPack[]>> {\n return this.httpClient.get(\"/credit-packs\");\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 fullName?: 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 id?: string; // Your user ID — stored as externalId, used to identify the customer in all SDK methods\n fullName?: 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 email?: string;\n fullName?: 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 ListCustomersParams extends BaseListParams {\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 when id is provided)\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.id,\n fullName: params.fullName,\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.id,\n fullName: c.fullName,\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 fullName: params.fullName,\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 * 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 CustomerID,\n GeneratedFeatureCode,\n RequestOptions,\n} from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\n\nexport interface FeatureParams {\n customerId: CustomerID;\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 enabled?: boolean;\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\nexport class FeaturesResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n async get(\n params: GetFeatureParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<FeatureAccess>> {\n return this.httpClient.get(\n `/features/${params.code}`,\n { customerId: params.customerId },\n options,\n );\n }\n\n async check(\n params: CheckFeatureParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<CheckResult>> {\n const result = await this.httpClient.get<FeatureAccess>(\n `/features/${params.code}`,\n { customerId: params.customerId },\n options,\n );\n\n if (!result.success || !result.data) {\n return {\n success: false,\n code: result.code,\n message: result.message,\n details: result.details,\n };\n }\n\n return {\n success: true,\n data: { allowed: result.data.allowed },\n };\n }\n\n async canUse(\n params: CanUseFeatureParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<CanUseResult>> {\n return this.httpClient.get(\n `/features/${params.code}`,\n { customerId: params.customerId, action: \"canUse\" },\n options,\n );\n }\n\n async list(\n customerId: CustomerID,\n options?: RequestOptions,\n ): Promise<ApiResponse<FeatureAccess[]>> {\n return this.httpClient.get(\"/features\", { customerId }, 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 trialDays: number;\n}\n\nexport interface PlanFeature {\n code: string;\n name: string;\n type: FeatureType;\n unitName: string | null;\n enabled?: boolean;\n includedAmount?: number;\n unlimited?: boolean;\n overageEnabled?: boolean;\n overageUnitPrice?: number;\n}\n\nexport interface Plan {\n id: PlanID;\n code: string;\n name: string;\n description: string | null;\n isPublic: boolean;\n isFree: boolean;\n isDefault: boolean;\n sortOrder: number;\n prices: PlanPrice[];\n features: PlanFeature[];\n createdAt: string;\n}\n\nexport interface PlanDetailPrice {\n billingInterval: BillingInterval;\n price: number;\n isDefault: boolean;\n trialDays: number;\n introOffer: {\n enabled: boolean;\n discountType: \"percentage\" | \"amount\" | null;\n discountValue: number | null;\n durationCycles: number | null;\n } | null;\n}\n\nexport interface PlanDetailFeature extends PlanFeature {\n overage: {\n enabled: boolean;\n model: \"per_unit\" | \"tiered\" | null;\n unitPrice: number | null;\n } | null;\n}\n\nexport interface PlanDetail {\n id: PlanID;\n code: string;\n name: string;\n description: string | null;\n isPublic: boolean;\n isDefault: boolean;\n sortOrder: number;\n prices: PlanDetailPrice[];\n features: PlanDetailFeature[];\n createdAt: string;\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}\n\ninterface GetUrlByEmail {\n email: string;\n customerId?: never;\n}\n\nexport type GetUrlParams = GetUrlByCustomerId | GetUrlByEmail;\n\nexport class PortalResource {\n constructor(private httpClient: CommetHTTPClient) {}\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 seatType: GeneratedSeatType;\n count: number;\n}\n\nexport interface RemoveParams {\n customerId: CustomerID;\n seatType: GeneratedSeatType;\n count: number;\n}\n\nexport interface SetParams {\n customerId: CustomerID;\n seatType: GeneratedSeatType;\n count: number;\n}\n\nexport interface SetAllParams {\n customerId: CustomerID;\n seats: Record<string, number>;\n}\n\nexport interface GetBalanceParams {\n customerId: CustomerID;\n seatType: GeneratedSeatType;\n}\n\nexport interface GetAllBalancesParams {\n customerId: CustomerID;\n}\n\nexport class SeatsResource {\n constructor(private httpClient: CommetHTTPClient) {}\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 async remove(\n params: RemoveParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<SeatEvent>> {\n return this.httpClient.delete(\"/seats\", params, options);\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 async setAll(\n params: SetAllParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<SeatEvent[]>> {\n return this.httpClient.put(\"/seats/bulk\", params, options);\n }\n\n async getBalance(\n params: GetBalanceParams,\n ): Promise<ApiResponse<SeatBalance>> {\n return this.httpClient.get(\"/seats/balance\", {\n customerId: params.customerId,\n seatType: params.seatType,\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 });\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 | null;\n };\n name: string;\n description: string | null;\n status: SubscriptionStatus;\n trialEndsAt: string | null;\n currentPeriod: {\n start: string;\n end: string;\n daysRemaining: number;\n };\n features: FeatureSummary[];\n startDate: string;\n endDate: string | null;\n billingDayOfMonth: number;\n nextBillingDate: string;\n checkoutUrl: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CreatedSubscription {\n id: string;\n customerId: string;\n planId: string;\n planName: string;\n name: string;\n status: SubscriptionStatus;\n billingInterval: BillingInterval | null;\n trialEndsAt: string | null;\n startDate: string;\n endDate: string | null;\n currentPeriodStart: string | null;\n currentPeriodEnd: string | null;\n billingDayOfMonth: number;\n checkoutUrl: string | null;\n createdAt: string;\n updatedAt: string;\n introOfferEndsAt: string | null;\n introOfferDiscountType: \"percentage\" | \"amount\" | null;\n introOfferDiscountValue: number | null;\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\ntype PlanIdentifier =\n | { planCode: GeneratedPlanCode; planId?: never }\n | { planCode?: never; planId: string };\n\nexport type CreateSubscriptionParams = PlanIdentifier & {\n customerId: string;\n} & {\n billingInterval?: BillingInterval;\n initialSeats?: Record<string, number>;\n skipTrial?: boolean;\n name?: string;\n startDate?: string;\n successUrl?: string;\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<CreatedSubscription>> {\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 customerId: string,\n ): Promise<ApiResponse<ActiveSubscription | null>> {\n return this.httpClient.get(\"/subscriptions/active\", { customerId });\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 GeneratedFeatureCode,\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 feature: string;\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\ninterface TrackBaseParams {\n feature: GeneratedFeatureCode;\n customerId: CustomerID;\n idempotencyKey?: string;\n timestamp?: string;\n properties?: Record<string, string>;\n}\n\nexport interface TrackUsageParams extends TrackBaseParams {\n value?: number;\n model?: never;\n}\n\nexport interface TrackModelTokensParams extends TrackBaseParams {\n model: string;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n value?: never;\n}\n\nexport type TrackParams = TrackUsageParams | TrackModelTokensParams;\n\nexport class UsageResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n async track(\n params: TrackParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<UsageEvent>> {\n const eventData: Record<string, unknown> = {\n feature: params.feature,\n customerId: params.customerId,\n idempotencyKey: params.idempotencyKey,\n timestamp: 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 if (\"model\" in params && params.model) {\n eventData.model = params.model;\n eventData.inputTokens = params.inputTokens;\n eventData.outputTokens = params.outputTokens;\n if (params.cacheReadTokens) {\n eventData.cacheReadTokens = params.cacheReadTokens;\n }\n if (params.cacheWriteTokens) {\n eventData.cacheWriteTokens = params.cacheWriteTokens;\n }\n } else {\n eventData.value = (params as TrackUsageParams).value;\n }\n\n return this.httpClient.post(\"/usage/events\", eventData, 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 code?: string;\n message?: string;\n details?: unknown;\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 = 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/types.d.ts file that augments this interface with your\n * organization's specific feature codes, seat types, and plan codes.\n *\n * @example\n * // After running `commet pull`, TypeScript will automatically know your types:\n * await commet.usage.track({\n * feature: 'api_calls', // Autocomplete works!\n * externalId: 'user_123'\n * });\n */\n\n// biome-ignore lint/suspicious/noEmptyInterface: augmented by CLI-generated .commet/types.d.ts\nexport interface CommetGeneratedTypes {}\n\nexport type GeneratedSeatType = CommetGeneratedTypes extends {\n seatType: infer T;\n}\n ? T\n : string;\n\nexport type GeneratedPlanCode = CommetGeneratedTypes extends {\n planCode: infer T;\n}\n ? T\n : string;\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-node/1.9.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 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 code?: string;\n details?: unknown;\n } => {\n return typeof data === \"object\" && data !== null;\n };\n\n const errorData = isErrorResponse(responseData) ? responseData : {};\n\n // Handle validation errors (new normalized shape)\n if (\n errorData.code === \"validation_error\" &&\n Array.isArray(errorData.details)\n ) {\n const errors: Record<string, string[]> = {};\n for (const detail of errorData.details as Array<{\n field: string;\n message: string;\n }>) {\n if (!errors[detail.field]) errors[detail.field] = [];\n errors[detail.field].push(detail.message);\n }\n throw new CommetValidationError(\n errorData.message || \"Validation failed\",\n 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 const isNetworkError =\n error instanceof TypeError && error.message.includes(\"fetch\");\n const isTimeoutError =\n error instanceof DOMException && error.name === \"AbortError\";\n const isTimeoutErrorModern =\n typeof globalThis.DOMException !== \"undefined\" &&\n error instanceof DOMException &&\n error.name === \"TimeoutError\";\n\n if (isNetworkError || isTimeoutError || isTimeoutErrorModern) {\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 { CreditPacksResource } from \"./resources/credit-packs\";\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 creditPacks: CreditPacksResource;\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.creditPacks = new CreditPacksResource(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(customerId: string): CustomerContext {\n return new CustomerContext(customerId, {\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACuBO,IAAM,kBAAN,MAAsB;AAAA,EAQ3B,YACE,YACA,WAOA;AASF,oBAAW;AAAA,MACT,KAAK,CAAC,MAAc,YAClB,KAAK,iBAAiB,IAAI,EAAE,MAAM,YAAY,KAAK,WAAW,GAAG,OAAO;AAAA,MAE1E,OAAO,CAAC,MAAc,YACpB,KAAK,iBAAiB;AAAA,QACpB,EAAE,MAAM,YAAY,KAAK,WAAW;AAAA,QACpC;AAAA,MACF;AAAA,MAEF,QAAQ,CAAC,MAAc,YACrB,KAAK,iBAAiB;AAAA,QACpB,EAAE,MAAM,YAAY,KAAK,WAAW;AAAA,QACpC;AAAA,MACF;AAAA,MAEF,MAAM,CAAC,YACL,KAAK,iBAAiB,KAAK,KAAK,YAAY,OAAO;AAAA,IACvD;AAEA,iBAAQ;AAAA,MACN,KAAK,CAAC,UAAkB,QAAQ,GAAG,YACjC,KAAK,cAAc;AAAA,QACjB,EAAE,YAAY,KAAK,YAAY,UAAU,MAAM;AAAA,QAC/C;AAAA,MACF;AAAA,MAEF,QAAQ,CAAC,UAAkB,QAAQ,GAAG,YACpC,KAAK,cAAc;AAAA,QACjB,EAAE,YAAY,KAAK,YAAY,UAAU,MAAM;AAAA,QAC/C;AAAA,MACF;AAAA,MAEF,KAAK,CAAC,UAAkB,OAAe,YACrC,KAAK,cAAc;AAAA,QACjB,EAAE,YAAY,KAAK,YAAY,UAAU,MAAM;AAAA,QAC/C;AAAA,MACF;AAAA,MAEF,YAAY,CAAC,aACX,KAAK,cAAc,WAAW,EAAE,YAAY,KAAK,YAAY,SAAS,CAAC;AAAA,IAC3E;AAEA,iBAAQ;AAAA,MACN,OAAO,CACL,SACA,OACA,YACA,YAEA,KAAK,cAAc;AAAA,QACjB,EAAE,YAAY,KAAK,YAAY,SAAS,OAAO,WAAW;AAAA,QAC1D;AAAA,MACF;AAAA,IACJ;AAEA,wBAAe;AAAA,MACb,KAAK,MAAM,KAAK,sBAAsB,IAAI,KAAK,UAAU;AAAA,IAC3D;AAEA,kBAAS;AAAA,MACP,QAAQ,CAAC,YACP,KAAK,eAAe,OAAO,EAAE,YAAY,KAAK,WAAW,GAAG,OAAO;AAAA,IACvE;AAvEE,SAAK,aAAa;AAClB,SAAK,mBAAmB,UAAU;AAClC,SAAK,gBAAgB,UAAU;AAC/B,SAAK,gBAAgB,UAAU;AAC/B,SAAK,wBAAwB,UAAU;AACvC,SAAK,iBAAiB,UAAU;AAAA,EAClC;AAkEF;;;AClGO,IAAM,sBAAN,MAA0B;AAAA,EAC/B,YAAoB,YAA8B;AAA9B;AAAA,EAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWnD,MAAM,OAA2C;AAC/C,WAAO,KAAK,WAAW,IAAI,eAAe;AAAA,EAC5C;AACF;;;ACgDO,IAAM,oBAAN,MAAwB;AAAA,EAC7B,YAAoB,YAA8B;AAA9B;AAAA,EAA+B;AAAA;AAAA;AAAA;AAAA,EAKnD,MAAM,OACJ,QACA,SACgC;AAChC,WAAO,KAAK,WAAW;AAAA,MACrB;AAAA,MACA;AAAA,QACE,cAAc,OAAO;AAAA,QACrB,YAAY,OAAO;AAAA,QACnB,UAAU,OAAO;AAAA,QACjB,QAAQ,OAAO;AAAA,QACf,SAAS,OAAO;AAAA,QAChB,UAAU,OAAO;AAAA,QACjB,UAAU,OAAO;AAAA,QACjB,UAAU,OAAO;AAAA,QACjB,UAAU,OAAO;AAAA,QACjB,SAAS,OAAO;AAAA,MAClB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YACJ,QACA,SACmC;AACnC,UAAM,YAAY,OAAO,UAAU,IAAI,CAAC,OAAO;AAAA,MAC7C,cAAc,EAAE;AAAA,MAChB,YAAY,EAAE;AAAA,MACd,UAAU,EAAE;AAAA,MACZ,QAAQ,EAAE;AAAA,MACV,SAAS,EAAE;AAAA,MACX,UAAU,EAAE;AAAA,MACZ,UAAU,EAAE;AAAA,MACZ,UAAU,EAAE;AAAA,MACZ,UAAU,EAAE;AAAA,MACZ,SAAS,EAAE;AAAA,IACb,EAAE;AACF,WAAO,KAAK,WAAW,KAAK,oBAAoB,EAAE,UAAU,GAAG,OAAO;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IAAI,YAAwD;AAChE,WAAO,KAAK,WAAW,IAAI,cAAc,UAAU,EAAE;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OACJ,QACA,SACgC;AAChC,WAAO,KAAK,WAAW;AAAA,MACrB,cAAc,OAAO,UAAU;AAAA,MAC/B;AAAA,QACE,cAAc,OAAO;AAAA,QACrB,UAAU,OAAO;AAAA,QACjB,QAAQ,OAAO;AAAA,QACf,SAAS,OAAO;AAAA,QAChB,UAAU,OAAO;AAAA,QACjB,UAAU,OAAO;AAAA,QACjB,UAAU,OAAO;AAAA,QACjB,UAAU,OAAO;AAAA,QACjB,SAAS,OAAO;AAAA,MAClB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAK,QAAgE;AACzE,WAAO,KAAK,WAAW,IAAI,cAAc,MAAiC;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QACJ,YACA,SACgC;AAChC,WAAO,KAAK,WAAW;AAAA,MACrB,cAAc,UAAU;AAAA,MACxB,EAAE,UAAU,MAAM;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AACF;;;ACzIO,IAAM,mBAAN,MAAuB;AAAA,EAC5B,YAAoB,YAA8B;AAA9B;AAAA,EAA+B;AAAA,EAEnD,MAAM,IACJ,QACA,SACqC;AACrC,WAAO,KAAK,WAAW;AAAA,MACrB,aAAa,OAAO,IAAI;AAAA,MACxB,EAAE,YAAY,OAAO,WAAW;AAAA,MAChC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,MACJ,QACA,SACmC;AACnC,UAAM,SAAS,MAAM,KAAK,WAAW;AAAA,MACnC,aAAa,OAAO,IAAI;AAAA,MACxB,EAAE,YAAY,OAAO,WAAW;AAAA,MAChC;AAAA,IACF;AAEA,QAAI,CAAC,OAAO,WAAW,CAAC,OAAO,MAAM;AACnC,aAAO;AAAA,QACL,SAAS;AAAA,QACT,MAAM,OAAO;AAAA,QACb,SAAS,OAAO;AAAA,QAChB,SAAS,OAAO;AAAA,MAClB;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,MACT,MAAM,EAAE,SAAS,OAAO,KAAK,QAAQ;AAAA,IACvC;AAAA,EACF;AAAA,EAEA,MAAM,OACJ,QACA,SACoC;AACpC,WAAO,KAAK,WAAW;AAAA,MACrB,aAAa,OAAO,IAAI;AAAA,MACxB,EAAE,YAAY,OAAO,YAAY,QAAQ,SAAS;AAAA,MAClD;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,KACJ,YACA,SACuC;AACvC,WAAO,KAAK,WAAW,IAAI,aAAa,EAAE,WAAW,GAAG,OAAO;AAAA,EACjE;AACF;;;ACZO,IAAM,gBAAN,MAAoB;AAAA,EACzB,YAAoB,YAA8B;AAA9B;AAAA,EAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcnD,MAAM,KAAK,QAAwD;AACjE,WAAO,KAAK,WAAW,IAAI,UAAU,MAAM;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,IAAI,UAA+D;AACvE,WAAO,KAAK,WAAW,IAAI,UAAU,QAAQ,EAAE;AAAA,EACjD;AACF;;;ACjGO,IAAM,iBAAN,MAAqB;AAAA,EAC1B,YAAoB,YAA8B;AAA9B;AAAA,EAA+B;AAAA,EAEnD,MAAM,OACJ,QACA,SACoC;AACpC,WAAO,KAAK,WAAW,KAAK,0BAA0B,QAAQ,OAAO;AAAA,EACvE;AACF;;;AC4BO,IAAM,gBAAN,MAAoB;AAAA,EACzB,YAAoB,YAA8B;AAA9B;AAAA,EAA+B;AAAA,EAEnD,MAAM,IACJ,QACA,SACiC;AACjC,WAAO,KAAK,WAAW,KAAK,UAAU,QAAQ,OAAO;AAAA,EACvD;AAAA,EAEA,MAAM,OACJ,QACA,SACiC;AACjC,WAAO,KAAK,WAAW,OAAO,UAAU,QAAQ,OAAO;AAAA,EACzD;AAAA,EAEA,MAAM,IACJ,QACA,SACiC;AACjC,WAAO,KAAK,WAAW,IAAI,UAAU,QAAQ,OAAO;AAAA,EACtD;AAAA,EAEA,MAAM,OACJ,QACA,SACmC;AACnC,WAAO,KAAK,WAAW,IAAI,eAAe,QAAQ,OAAO;AAAA,EAC3D;AAAA,EAEA,MAAM,WACJ,QACmC;AACnC,WAAO,KAAK,WAAW,IAAI,kBAAkB;AAAA,MAC3C,YAAY,OAAO;AAAA,MACnB,UAAU,OAAO;AAAA,IACnB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,eACJ,QACmD;AACnD,WAAO,KAAK,WAAW,IAAI,mBAAmB;AAAA,MAC5C,YAAY,OAAO;AAAA,IACrB,CAAC;AAAA,EACH;AACF;;;ACsBO,IAAM,wBAAN,MAA4B;AAAA,EACjC,YAAoB,YAA8B;AAA9B;AAAA,EAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAenD,MAAM,OACJ,QACA,SAC2C;AAC3C,WAAO,KAAK,WAAW,KAAK,kBAAkB,QAAQ,OAAO;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,IACJ,YACiD;AACjD,WAAO,KAAK,WAAW,IAAI,yBAAyB,EAAE,WAAW,CAAC;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,OACJ,QACA,SACoC;AACpC,WAAO,KAAK,WAAW;AAAA,MACrB,kBAAkB,OAAO,cAAc;AAAA,MACvC,UAAU,CAAC;AAAA,MACX;AAAA,IACF;AAAA,EACF;AACF;;;ACrIO,IAAM,gBAAN,MAAoB;AAAA,EACzB,YAAoB,YAA8B;AAA9B;AAAA,EAA+B;AAAA,EAEnD,MAAM,MACJ,QACA,SACkC;AAClC,UAAM,YAAqC;AAAA,MACzC,SAAS,OAAO;AAAA,MAChB,YAAY,OAAO;AAAA,MACnB,gBAAgB,OAAO;AAAA,MACvB,WAAW,OAAO,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACtD,YAAY,OAAO,aACf,OAAO,QAAQ,OAAO,UAAU,EAAE,IAAI,CAAC,CAAC,UAAU,KAAK,OAAO;AAAA,QAC5D;AAAA,QACA;AAAA,MACF,EAAE,IACF;AAAA,IACN;AAEA,QAAI,WAAW,UAAU,OAAO,OAAO;AACrC,gBAAU,QAAQ,OAAO;AACzB,gBAAU,cAAc,OAAO;AAC/B,gBAAU,eAAe,OAAO;AAChC,UAAI,OAAO,iBAAiB;AAC1B,kBAAU,kBAAkB,OAAO;AAAA,MACrC;AACA,UAAI,OAAO,kBAAkB;AAC3B,kBAAU,mBAAmB,OAAO;AAAA,MACtC;AAAA,IACF,OAAO;AACL,gBAAU,QAAS,OAA4B;AAAA,IACjD;AAEA,WAAO,KAAK,WAAW,KAAK,iBAAiB,WAAW,OAAO;AAAA,EACjE;AACF;;;ACxFA,yBAAmB;AAwDZ,IAAM,WAAN,MAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkCpB,OAAO,QAA+B;AACpC,UAAM,EAAE,SAAS,WAAW,OAAO,IAAI;AAEvC,QAAI,CAAC,aAAa,CAAC,UAAU,CAAC,SAAS;AACrC,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,oBAAoB,KAAK,kBAAkB,EAAE,SAAS,OAAO,CAAC;AAGpE,aAAO,mBAAAA,QAAO;AAAA,QACZ,OAAO,KAAK,WAAW,KAAK;AAAA,QAC5B,OAAO,KAAK,mBAAmB,KAAK;AAAA,MACtC;AAAA,IACF,SAAS,QAAQ;AAEf,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,kBAAkB,QAAyC;AACjE,UAAM,EAAE,SAAS,OAAO,IAAI;AAC5B,WAAO,mBAAAA,QAAO,WAAW,UAAU,MAAM,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AAAA,EACzE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBA,eAAe,QAAqD;AAClE,UAAM,EAAE,SAAS,WAAW,OAAO,IAAI;AAEvC,QAAI,CAAC,KAAK,OAAO,EAAE,SAAS,SAAS,WAAW,OAAO,CAAC,GAAG;AACzD,aAAO;AAAA,IACT;AAEA,QAAI;AACF,aAAO,KAAK,MAAM,OAAO,OAAO;AAAA,IAClC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;ACvHO,IAAM,cAAN,cAA0B,MAAM;AAAA,EACrC,YACE,SACO,MACA,YACA,SACP;AACA,UAAM,OAAO;AAJN;AACA;AACA;AAGP,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,iBAAN,cAA6B,YAAY;AAAA,EAC9C,YACE,SACO,YACA,MACA,SACP;AACA,UAAM,SAAS,MAAM,YAAY,OAAO;AAJjC;AACA;AACA;AAGP,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,wBAAN,cAAoC,YAAY;AAAA,EACrD,YACE,SACO,kBACP;AACA,UAAM,OAAO;AAFN;AAGP,SAAK,OAAO;AAAA,EACd;AACF;;;ACpDA,IAAM,uBAAoC;AAAA,EACxC,YAAY;AAAA,EACZ,WAAW;AAAA;AAAA,EACX,UAAU;AAAA;AAAA,EACV,sBAAsB,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG;AACrD;AAEO,IAAM,mBAAN,MAAuB;AAAA,EAK5B,YAAY,QAAsB,aAA0B;AAC1D,SAAK,SAAS;AACd,SAAK,cAAc;AACnB,SAAK,cAAc;AAAA,MACjB,GAAG;AAAA,MACH,YAAY,OAAO,WAAW,qBAAqB;AAAA,IACrD;AAAA,EACF;AAAA,EAEA,MAAM,IACJ,UACA,QACA,SACyB;AACzB,WAAO,KAAK,QAAQ,OAAO,UAAU,QAAW,SAAS,MAAM;AAAA,EACjE;AAAA,EAEA,MAAM,KACJ,UACA,MACA,SACyB;AACzB,WAAO,KAAK,QAAQ,QAAQ,UAAU,MAAM,OAAO;AAAA,EACrD;AAAA,EAEA,MAAM,IACJ,UACA,MACA,SACyB;AACzB,WAAO,KAAK,QAAQ,OAAO,UAAU,MAAM,OAAO;AAAA,EACpD;AAAA,EAEA,MAAM,OACJ,UACA,MACA,SACyB;AACzB,WAAO,KAAK,QAAQ,UAAU,UAAU,MAAM,OAAO;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,QACZ,QACA,UACA,MACA,SACA,QACyB;AACzB,UAAM,MAAM,KAAK,SAAS,UAAU,MAAM;AAC1C,WAAO,KAAK,eAAe,QAAQ,KAAK,MAAM,OAAO;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,eACZ,QACA,KACA,MACA,SACA,UAAU,GACe;AACzB,QAAI;AACF,YAAM,UAAkC;AAAA,QACtC,aAAa,KAAK,OAAO;AAAA,QACzB,gBAAgB;AAAA,QAChB,cAAc;AAAA,MAChB;AAEA,UAAI,SAAS,gBAAgB;AAC3B,gBAAQ,iBAAiB,IAAI,QAAQ;AAAA,MACvC,WAAW,WAAW,UAAU,MAAM;AACpC,gBAAQ,iBAAiB,IAAI,KAAK,uBAAuB;AAAA,MAC3D;AAEA,YAAM,gBAA6B;AAAA,QACjC;AAAA,QACA;AAAA,QACA,QAAQ,YAAY;AAAA,UAClB,SAAS,WAAW,KAAK,OAAO,WAAW;AAAA,QAC7C;AAAA,MACF;AAEA,UAAI,MAAM;AACR,sBAAc,OAAO,KAAK,UAAU,IAAI;AAAA,MAC1C;AAEA,UAAI,KAAK,OAAO,OAAO;AACrB,gBAAQ,IAAI,gBAAgB,MAAM,IAAI,GAAG,EAAE;AAC3C,YAAI,MAAM;AACR,kBAAQ,IAAI,iBAAiB,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,QAC5D;AAAA,MACF;AAEA,YAAM,WAAW,MAAM,MAAM,KAAK,aAAa;AAE/C,UAAI,KAAK,OAAO,OAAO;AACrB,gBAAQ;AAAA,UACN,iCAAiC,SAAS,MAAM,IAAI,SAAS,UAAU;AAAA,QACzE;AAAA,MACF;AAEA,UAAI;AACJ,UAAI;AAEJ,UAAI;AACF,uBAAe,MAAM,SAAS,KAAK;AACnC,uBAAe;AAAA,MACjB,SAAS,YAAY;AACnB,YAAI;AACF,yBAAe,MAAM,SAAS,KAAK;AAAA,QACrC,SAAS,YAAY;AACnB,yBAAe;AAAA,QACjB;AACA,YAAI,KAAK,OAAO,OAAO;AACrB,kBAAQ;AAAA,YACN;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAEA,cAAM,IAAI;AAAA,UACR,0BAA0B,SAAS,MAAM,IAAI,SAAS,UAAU;AAAA,UAChE,SAAS;AAAA,UACT;AAAA,UACA,EAAE,aAAa;AAAA,QACjB;AAAA,MACF;AAEA,UAAI,CAAC,SAAS,IAAI;AAEhB,YACE,WAAW,KAAK,YAAY,cAC5B,KAAK,YAAY,qBAAqB,SAAS,SAAS,MAAM,GAC9D;AACA,gBAAM,QAAQ,KAAK;AAAA,YACjB,KAAK,YAAY,YAAY,MAAM,UAAU;AAAA,YAC7C,KAAK,YAAY;AAAA,UACnB;AAEA,cAAI,KAAK,OAAO,OAAO;AACrB,oBAAQ;AAAA,cACN,4BAA4B,KAAK,eAAe,OAAO,IAAI,KAAK,YAAY,UAAU;AAAA,YACxF;AAAA,UACF;AAEA,gBAAM,KAAK,MAAM,KAAK;AACtB,iBAAO,KAAK,eAAe,QAAQ,KAAK,MAAM,SAAS,UAAU,CAAC;AAAA,QACpE;AAGA,YAAI,KAAK,OAAO,OAAO;AACrB,kBAAQ;AAAA,YACN;AAAA,YACA,KAAK,UAAU,cAAc,MAAM,CAAC;AAAA,UACtC;AAAA,QACF;AAGA,cAAM,kBAAkB,CACtBC,UAKG;AACH,iBAAO,OAAOA,UAAS,YAAYA,UAAS;AAAA,QAC9C;AAEA,cAAM,YAAY,gBAAgB,YAAY,IAAI,eAAe,CAAC;AAGlE,YACE,UAAU,SAAS,sBACnB,MAAM,QAAQ,UAAU,OAAO,GAC/B;AACA,gBAAM,SAAmC,CAAC;AAC1C,qBAAW,UAAU,UAAU,SAG3B;AACF,gBAAI,CAAC,OAAO,OAAO,KAAK,EAAG,QAAO,OAAO,KAAK,IAAI,CAAC;AACnD,mBAAO,OAAO,KAAK,EAAE,KAAK,OAAO,OAAO;AAAA,UAC1C;AACA,gBAAM,IAAI;AAAA,YACR,UAAU,WAAW;AAAA,YACrB;AAAA,UACF;AAAA,QACF;AAEA,cAAM,IAAI;AAAA,UACR,UAAU,WAAW,8BAA8B,SAAS,MAAM;AAAA,UAClE,SAAS;AAAA,UACT,UAAU;AAAA,UACV,UAAU;AAAA,QACZ;AAAA,MACF;AAEA,UAAI,KAAK,OAAO,OAAO;AACrB,gBAAQ,IAAI,0BAA0B,YAAY;AAAA,MACpD;AAEA,aAAO;AAAA,IACT,SAAS,OAAO;AAEd,YAAM,iBACJ,iBAAiB,aAAa,MAAM,QAAQ,SAAS,OAAO;AAC9D,YAAM,iBACJ,iBAAiB,gBAAgB,MAAM,SAAS;AAClD,YAAM,uBACJ,OAAO,WAAW,iBAAiB,eACnC,iBAAiB,gBACjB,MAAM,SAAS;AAEjB,UAAI,kBAAkB,kBAAkB,sBAAsB;AAC5D,YAAI,WAAW,KAAK,YAAY,YAAY;AAC1C,gBAAM,QAAQ,KAAK;AAAA,YACjB,KAAK,YAAY,YAAY,MAAM,UAAU;AAAA,YAC7C,KAAK,YAAY;AAAA,UACnB;AAEA,cAAI,KAAK,OAAO,OAAO;AACrB,oBAAQ,IAAI,2CAA2C,KAAK,IAAI;AAAA,UAClE;AAEA,gBAAM,KAAK,MAAM,KAAK;AACtB,iBAAO,KAAK,eAAe,QAAQ,KAAK,MAAM,SAAS,UAAU,CAAC;AAAA,QACpE;AAAA,MACF;AAEA,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAqB;AAC3B,WAAO,KAAK,gBAAgB,eACxB,sBACA;AAAA,EACN;AAAA;AAAA;AAAA;AAAA,EAKQ,SAAS,UAAkB,QAA0C;AAC3E,UAAM,UAAU,KAAK,WAAW;AAGhC,UAAM,qBAAqB,SAAS,WAAW,GAAG,IAC9C,WACA,IAAI,QAAQ;AAChB,UAAM,WAAW,OAAO,kBAAkB;AAG1C,QAAI,KAAK,OAAO,OAAO;AACrB,cAAQ;AAAA,QACN,wCAAwC,OAAO,eAAe,QAAQ,eAAe,QAAQ;AAAA,MAC/F;AAAA,IACF;AAEA,UAAM,MAAM,IAAI,IAAI,UAAU,OAAO;AAErC,QAAI,QAAQ;AACV,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,YAAI,UAAU,UAAa,UAAU,MAAM;AACzC,cAAI,aAAa,OAAO,KAAK,OAAO,KAAK,CAAC;AAAA,QAC5C;AAAA,MACF;AAAA,IACF;AAEA,UAAM,WAAW,IAAI,SAAS;AAG9B,QAAI,KAAK,OAAO,OAAO;AACrB,cAAQ,IAAI,2BAA2B,QAAQ,EAAE;AAAA,IACnD;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,yBAAiC;AAEvC,WAAO,OAAO,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,CAAC,CAAC;AAAA,EACrE;AAAA;AAAA;AAAA;AAAA,EAKQ,MAAM,IAA2B;AACvC,WAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAAA,EACzD;AACF;;;ACtTO,IAAM,SAAN,MAAa;AAAA,EAclB,YAAY,QAAsB;AAChC,QAAI,CAAC,OAAO,QAAQ;AAClB,YAAM,IAAI,MAAM,iCAAiC;AAAA,IACnD;AAEA,QAAI,CAAC,OAAO,OAAO,WAAW,KAAK,GAAG;AACpC,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAGA,SAAK,cAAc,OAAO,eAAe;AAEzC,SAAK,aAAa,IAAI,iBAAiB,QAAQ,KAAK,WAAW;AAC/D,SAAK,YAAY,IAAI,kBAAkB,KAAK,UAAU;AACtD,SAAK,cAAc,IAAI,oBAAoB,KAAK,UAAU;AAC1D,SAAK,QAAQ,IAAI,cAAc,KAAK,UAAU;AAC9C,SAAK,QAAQ,IAAI,cAAc,KAAK,UAAU;AAC9C,SAAK,QAAQ,IAAI,cAAc,KAAK,UAAU;AAC9C,SAAK,gBAAgB,IAAI,sBAAsB,KAAK,UAAU;AAC9D,SAAK,SAAS,IAAI,eAAe,KAAK,UAAU;AAChD,SAAK,WAAW,IAAI,iBAAiB,KAAK,UAAU;AACpD,SAAK,WAAW,IAAI,SAAS;AAE7B,QAAI,OAAO,OAAO;AAChB,cAAQ,IAAI,+BAA+B,KAAK,WAAW,OAAO;AAClE,cAAQ,IAAI,YAAY,GAAG,OAAO,OAAO,UAAU,GAAG,EAAE,CAAC,KAAK;AAC9D,YAAM,UACJ,KAAK,gBAAgB,eACjB,sBACA;AACN,cAAQ,IAAI,aAAa,OAAO;AAAA,IAClC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,SAAS,YAAqC;AAC5C,WAAO,IAAI,gBAAgB,YAAY;AAAA,MACrC,UAAU,KAAK;AAAA,MACf,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK;AAAA,MACZ,eAAe,KAAK;AAAA,MACpB,QAAQ,KAAK;AAAA,IACf,CAAC;AAAA,EACH;AAAA,EAEA,iBAA8B;AAC5B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,YAAqB;AACnB,WAAO,KAAK,gBAAgB;AAAA,EAC9B;AAAA,EAEA,eAAwB;AACtB,WAAO,KAAK,gBAAgB;AAAA,EAC9B;AACF;;;AC/FO,SAAS,UAAU,aAAmC;AAC3D,SAAO,gBAAgB;AACzB;AAKO,SAAS,aAAa,aAAmC;AAC9D,SAAO,gBAAgB;AACzB;;;AdwFA,IAAO,gBAAQ;","names":["crypto","data"]}
package/dist/index.mjs CHANGED
@@ -177,14 +177,14 @@ var FeaturesResource = class {
177
177
  if (!result.success || !result.data) {
178
178
  return {
179
179
  success: false,
180
- data: { allowed: false },
181
- message: result.message
180
+ code: result.code,
181
+ message: result.message,
182
+ details: result.details
182
183
  };
183
184
  }
184
185
  return {
185
186
  success: true,
186
- data: { allowed: result.data.allowed },
187
- message: result.message
187
+ data: { allowed: result.data.allowed }
188
188
  };
189
189
  }
190
190
  async canUse(params, options) {
@@ -524,7 +524,7 @@ var CommetHTTPClient = class {
524
524
  const headers = {
525
525
  "x-api-key": this.config.apiKey,
526
526
  "Content-Type": "application/json",
527
- "User-Agent": "commet/0.1.0"
527
+ "User-Agent": "commet-node/1.9.0"
528
528
  };
529
529
  if (options?.idempotencyKey) {
530
530
  headers["Idempotency-Key"] = options.idempotencyKey;
@@ -570,13 +570,6 @@ var CommetHTTPClient = class {
570
570
  responseText
571
571
  );
572
572
  }
573
- if (response.status === 404) {
574
- return {
575
- success: false,
576
- code: "not_found",
577
- message: "Resource not found"
578
- };
579
- }
580
573
  throw new CommetAPIError(
581
574
  `Invalid JSON response: ${response.status} ${response.statusText}`,
582
575
  response.status,
@@ -631,7 +624,10 @@ var CommetHTTPClient = class {
631
624
  }
632
625
  return responseData;
633
626
  } catch (error) {
634
- if (error instanceof TypeError && error.message.includes("fetch")) {
627
+ const isNetworkError = error instanceof TypeError && error.message.includes("fetch");
628
+ const isTimeoutError = error instanceof DOMException && error.name === "AbortError";
629
+ const isTimeoutErrorModern = typeof globalThis.DOMException !== "undefined" && error instanceof DOMException && error.name === "TimeoutError";
630
+ if (isNetworkError || isTimeoutError || isTimeoutErrorModern) {
635
631
  if (attempt <= this.retryConfig.maxRetries) {
636
632
  const delay = Math.min(
637
633
  this.retryConfig.baseDelay * 2 ** (attempt - 1),
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/customer.ts","../src/resources/credit-packs.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","../src/index.ts"],"sourcesContent":["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 customerId\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 customerId: 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 customerId: string,\n resources: {\n features: FeaturesResource;\n seats: SeatsResource;\n usage: UsageResource;\n subscriptions: SubscriptionsResource;\n portal: PortalResource;\n },\n ) {\n this.customerId = customerId;\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 features = {\n get: (code: string, options?: RequestOptions) =>\n this.featuresResource.get({ code, customerId: this.customerId }, options),\n\n check: (code: string, options?: RequestOptions) =>\n this.featuresResource.check(\n { code, customerId: this.customerId },\n options,\n ),\n\n canUse: (code: string, options?: RequestOptions) =>\n this.featuresResource.canUse(\n { code, customerId: this.customerId },\n options,\n ),\n\n list: (options?: RequestOptions) =>\n this.featuresResource.list(this.customerId, options),\n };\n\n seats = {\n add: (seatType: string, count = 1, options?: RequestOptions) =>\n this.seatsResource.add(\n { customerId: this.customerId, seatType, count },\n options,\n ),\n\n remove: (seatType: string, count = 1, options?: RequestOptions) =>\n this.seatsResource.remove(\n { customerId: this.customerId, seatType, count },\n options,\n ),\n\n set: (seatType: string, count: number, options?: RequestOptions) =>\n this.seatsResource.set(\n { customerId: this.customerId, seatType, count },\n options,\n ),\n\n getBalance: (seatType: string) =>\n this.seatsResource.getBalance({ customerId: this.customerId, seatType }),\n };\n\n usage = {\n track: (\n feature: string,\n value?: number,\n properties?: Record<string, string>,\n options?: RequestOptions,\n ) =>\n this.usageResource.track(\n { customerId: this.customerId, feature, value, properties },\n options,\n ),\n };\n\n subscription = {\n get: () => this.subscriptionsResource.get(this.customerId),\n };\n\n portal = {\n getUrl: (options?: RequestOptions) =>\n this.portalResource.getUrl({ customerId: this.customerId }, options),\n };\n}\n","import type { ApiResponse } from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\n\nexport interface CreditPack {\n id: string;\n name: string;\n description: string | null;\n credits: number;\n price: number;\n currency: string;\n}\n\n/**\n * Credit Packs resource for listing available credit packs\n */\nexport class CreditPacksResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n /**\n * List all active credit packs\n *\n * @example\n * ```typescript\n * const packs = await commet.creditPacks.list();\n * console.log(packs.data); // [{ id: \"cp_xxx\", name: \"100 Credits\", ... }]\n * ```\n */\n async list(): Promise<ApiResponse<CreditPack[]>> {\n return this.httpClient.get(\"/credit-packs\");\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 fullName?: 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 id?: string; // Your user ID — stored as externalId, used to identify the customer in all SDK methods\n fullName?: 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 email?: string;\n fullName?: 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 ListCustomersParams extends BaseListParams {\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 when id is provided)\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.id,\n fullName: params.fullName,\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.id,\n fullName: c.fullName,\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 fullName: params.fullName,\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 * 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 CustomerID,\n GeneratedFeatureCode,\n RequestOptions,\n} from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\n\nexport interface FeatureParams {\n customerId: CustomerID;\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 enabled?: boolean;\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\nexport class FeaturesResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n async get(\n params: GetFeatureParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<FeatureAccess>> {\n return this.httpClient.get(\n `/features/${params.code}`,\n { customerId: params.customerId },\n options,\n );\n }\n\n async check(\n params: CheckFeatureParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<CheckResult>> {\n const result = await this.httpClient.get<FeatureAccess>(\n `/features/${params.code}`,\n { customerId: params.customerId },\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 async canUse(\n params: CanUseFeatureParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<CanUseResult>> {\n return this.httpClient.get(\n `/features/${params.code}`,\n { customerId: params.customerId, action: \"canUse\" },\n options,\n );\n }\n\n async list(\n customerId: CustomerID,\n options?: RequestOptions,\n ): Promise<ApiResponse<FeatureAccess[]>> {\n return this.httpClient.get(\"/features\", { customerId }, 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 trialDays: number;\n}\n\nexport interface PlanFeature {\n code: string;\n name: string;\n type: FeatureType;\n unitName: string | null;\n enabled?: boolean;\n includedAmount?: number;\n unlimited?: boolean;\n overageEnabled?: boolean;\n overageUnitPrice?: number;\n}\n\nexport interface Plan {\n id: PlanID;\n code: string;\n name: string;\n description: string | null;\n isPublic: boolean;\n isFree: boolean;\n isDefault: boolean;\n sortOrder: number;\n prices: PlanPrice[];\n features: PlanFeature[];\n createdAt: string;\n}\n\nexport interface PlanDetailPrice {\n billingInterval: BillingInterval;\n price: number;\n isDefault: boolean;\n trialDays: number;\n introOffer: {\n enabled: boolean;\n discountType: \"percentage\" | \"amount\" | null;\n discountValue: number | null;\n durationCycles: number | null;\n } | null;\n}\n\nexport interface PlanDetailFeature extends PlanFeature {\n overage: {\n enabled: boolean;\n model: \"per_unit\" | \"tiered\" | null;\n unitPrice: number | null;\n } | null;\n}\n\nexport interface PlanDetail {\n id: PlanID;\n code: string;\n name: string;\n description: string | null;\n isPublic: boolean;\n isDefault: boolean;\n sortOrder: number;\n prices: PlanDetailPrice[];\n features: PlanDetailFeature[];\n createdAt: string;\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}\n\ninterface GetUrlByEmail {\n email: string;\n customerId?: never;\n}\n\nexport type GetUrlParams = GetUrlByCustomerId | GetUrlByEmail;\n\nexport class PortalResource {\n constructor(private httpClient: CommetHTTPClient) {}\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 seatType: GeneratedSeatType;\n count: number;\n}\n\nexport interface RemoveParams {\n customerId: CustomerID;\n seatType: GeneratedSeatType;\n count: number;\n}\n\nexport interface SetParams {\n customerId: CustomerID;\n seatType: GeneratedSeatType;\n count: number;\n}\n\nexport interface SetAllParams {\n customerId: CustomerID;\n seats: Record<string, number>;\n}\n\nexport interface GetBalanceParams {\n customerId: CustomerID;\n seatType: GeneratedSeatType;\n}\n\nexport interface GetAllBalancesParams {\n customerId: CustomerID;\n}\n\nexport class SeatsResource {\n constructor(private httpClient: CommetHTTPClient) {}\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 async remove(\n params: RemoveParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<SeatEvent>> {\n return this.httpClient.delete(\"/seats\", params, options);\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 async setAll(\n params: SetAllParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<SeatEvent[]>> {\n return this.httpClient.put(\"/seats/bulk\", params, options);\n }\n\n async getBalance(\n params: GetBalanceParams,\n ): Promise<ApiResponse<SeatBalance>> {\n return this.httpClient.get(\"/seats/balance\", {\n customerId: params.customerId,\n seatType: params.seatType,\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 });\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 | null;\n };\n name: string;\n description: string | null;\n status: SubscriptionStatus;\n trialEndsAt: string | null;\n currentPeriod: {\n start: string;\n end: string;\n daysRemaining: number;\n };\n features: FeatureSummary[];\n startDate: string;\n endDate: string | null;\n billingDayOfMonth: number;\n nextBillingDate: string;\n checkoutUrl: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CreatedSubscription {\n id: string;\n customerId: string;\n planId: string;\n planName: string;\n name: string;\n status: SubscriptionStatus;\n billingInterval: BillingInterval | null;\n trialEndsAt: string | null;\n startDate: string;\n endDate: string | null;\n currentPeriodStart: string | null;\n currentPeriodEnd: string | null;\n billingDayOfMonth: number;\n checkoutUrl: string | null;\n createdAt: string;\n updatedAt: string;\n introOfferEndsAt: string | null;\n introOfferDiscountType: \"percentage\" | \"amount\" | null;\n introOfferDiscountValue: number | null;\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\ntype PlanIdentifier =\n | { planCode: GeneratedPlanCode; planId?: never }\n | { planCode?: never; planId: string };\n\nexport type CreateSubscriptionParams = PlanIdentifier & {\n customerId: string;\n} & {\n billingInterval?: BillingInterval;\n initialSeats?: Record<string, number>;\n skipTrial?: boolean;\n name?: string;\n startDate?: string;\n successUrl?: string;\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<CreatedSubscription>> {\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 customerId: string,\n ): Promise<ApiResponse<ActiveSubscription | null>> {\n return this.httpClient.get(\"/subscriptions/active\", { customerId });\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 GeneratedFeatureCode,\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 feature: string;\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\ninterface TrackBaseParams {\n feature: GeneratedFeatureCode;\n customerId: CustomerID;\n idempotencyKey?: string;\n timestamp?: string;\n properties?: Record<string, string>;\n}\n\nexport interface TrackUsageParams extends TrackBaseParams {\n value?: number;\n model?: never;\n}\n\nexport interface TrackModelTokensParams extends TrackBaseParams {\n model: string;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n value?: never;\n}\n\nexport type TrackParams = TrackUsageParams | TrackModelTokensParams;\n\nexport class UsageResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n async track(\n params: TrackParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<UsageEvent>> {\n const eventData: Record<string, unknown> = {\n feature: params.feature,\n customerId: params.customerId,\n idempotencyKey: params.idempotencyKey,\n timestamp: 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 if (\"model\" in params && params.model) {\n eventData.model = params.model;\n eventData.inputTokens = params.inputTokens;\n eventData.outputTokens = params.outputTokens;\n if (params.cacheReadTokens) {\n eventData.cacheReadTokens = params.cacheReadTokens;\n }\n if (params.cacheWriteTokens) {\n eventData.cacheWriteTokens = params.cacheWriteTokens;\n }\n } else {\n eventData.value = (params as TrackUsageParams).value;\n }\n\n return this.httpClient.post(\"/usage/events\", eventData, 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 code?: string;\n message?: string;\n details?: unknown;\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 = 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/types.d.ts file that augments this interface with your\n * organization's specific feature codes, seat types, and plan codes.\n *\n * @example\n * // After running `commet pull`, TypeScript will automatically know your types:\n * await commet.usage.track({\n * feature: 'api_calls', // Autocomplete works!\n * externalId: 'user_123'\n * });\n */\n\n// biome-ignore lint/suspicious/noEmptyInterface: augmented by CLI-generated .commet/types.d.ts\nexport interface CommetGeneratedTypes {}\n\nexport type GeneratedSeatType = CommetGeneratedTypes extends {\n seatType: infer T;\n}\n ? T\n : string;\n\nexport type GeneratedPlanCode = CommetGeneratedTypes extends {\n planCode: infer T;\n}\n ? T\n : string;\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 code: \"not_found\",\n message: \"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 code?: string;\n details?: unknown;\n } => {\n return typeof data === \"object\" && data !== null;\n };\n\n const errorData = isErrorResponse(responseData) ? responseData : {};\n\n // Handle validation errors (new normalized shape)\n if (\n errorData.code === \"validation_error\" &&\n Array.isArray(errorData.details)\n ) {\n const errors: Record<string, string[]> = {};\n for (const detail of errorData.details as Array<{\n field: string;\n message: string;\n }>) {\n if (!errors[detail.field]) errors[detail.field] = [];\n errors[detail.field].push(detail.message);\n }\n throw new CommetValidationError(\n errorData.message || \"Validation failed\",\n 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 { CreditPacksResource } from \"./resources/credit-packs\";\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 creditPacks: CreditPacksResource;\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.creditPacks = new CreditPacksResource(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(customerId: string): CustomerContext {\n return new CustomerContext(customerId, {\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","/**\n * Commet SDK - Billing and usage tracking for SaaS\n */\nexport { Commet } from \"./client\";\nexport { CustomerContext } from \"./customer\";\n// Credit Packs\nexport type { CreditPack } from \"./resources/credit-packs\";\n// Customers\nexport type {\n BatchResult as CustomersBatchResult,\n CreateParams as CreateCustomerParams,\n Customer,\n CustomerAddress,\n ListCustomersParams,\n UpdateParams as UpdateCustomerParams,\n} from \"./resources/customers\";\n// Features\nexport type {\n CanUseFeatureParams,\n CanUseResult,\n CheckFeatureParams,\n CheckResult,\n FeatureAccess,\n GetFeatureParams,\n} from \"./resources/features\";\n// Plans\nexport type {\n BillingInterval,\n FeatureType,\n ListPlansParams,\n Plan,\n PlanDetail,\n PlanFeature,\n PlanID,\n PlanPrice,\n} from \"./resources/plans\";\n// Portal\nexport type { GetUrlParams, PortalAccess } from \"./resources/portal\";\n// Seats\nexport type {\n AddParams as AddSeatsParams,\n GetAllBalancesParams,\n GetBalanceParams,\n RemoveParams as RemoveSeatsParams,\n SeatBalance,\n SeatEvent,\n SetAllParams as SetAllSeatsParams,\n SetParams as SetSeatsParams,\n} from \"./resources/seats\";\n// Subscriptions\nexport type {\n ActiveSubscription,\n CancelParams,\n CreatedSubscription,\n CreateSubscriptionParams,\n FeatureSummary,\n Subscription,\n SubscriptionStatus,\n} from \"./resources/subscriptions\";\n// Usage\nexport type {\n TrackModelTokensParams,\n TrackParams,\n TrackUsageParams,\n UsageEvent,\n UsageEventProperty,\n} from \"./resources/usage\";\nexport type {\n WebhookData,\n WebhookEvent,\n WebhookPayload,\n} from \"./resources/webhooks\";\n// Webhooks\nexport { Webhooks } from \"./resources/webhooks\";\n// Type exports\nexport type {\n ApiResponse,\n CommetConfig,\n CommetGeneratedTypes,\n Currency,\n CustomerID,\n Environment,\n EventID,\n GeneratedFeatureCode,\n GeneratedPlanCode,\n GeneratedSeatType,\n PaginatedList,\n PaginatedResponse,\n RequestOptions,\n} from \"./types/common\";\n// Error exports\nexport {\n CommetAPIError,\n CommetError,\n CommetValidationError,\n} from \"./types/common\";\n\n// Utility exports\nexport { isProduction, isSandbox } from \"./utils/environment\";\n\n// Default export\nimport { Commet } from \"./client\";\nexport default Commet;\n"],"mappings":"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","names":["data"]}
1
+ {"version":3,"sources":["../src/customer.ts","../src/resources/credit-packs.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","../src/index.ts"],"sourcesContent":["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 customerId\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 customerId: 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 customerId: string,\n resources: {\n features: FeaturesResource;\n seats: SeatsResource;\n usage: UsageResource;\n subscriptions: SubscriptionsResource;\n portal: PortalResource;\n },\n ) {\n this.customerId = customerId;\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 features = {\n get: (code: string, options?: RequestOptions) =>\n this.featuresResource.get({ code, customerId: this.customerId }, options),\n\n check: (code: string, options?: RequestOptions) =>\n this.featuresResource.check(\n { code, customerId: this.customerId },\n options,\n ),\n\n canUse: (code: string, options?: RequestOptions) =>\n this.featuresResource.canUse(\n { code, customerId: this.customerId },\n options,\n ),\n\n list: (options?: RequestOptions) =>\n this.featuresResource.list(this.customerId, options),\n };\n\n seats = {\n add: (seatType: string, count = 1, options?: RequestOptions) =>\n this.seatsResource.add(\n { customerId: this.customerId, seatType, count },\n options,\n ),\n\n remove: (seatType: string, count = 1, options?: RequestOptions) =>\n this.seatsResource.remove(\n { customerId: this.customerId, seatType, count },\n options,\n ),\n\n set: (seatType: string, count: number, options?: RequestOptions) =>\n this.seatsResource.set(\n { customerId: this.customerId, seatType, count },\n options,\n ),\n\n getBalance: (seatType: string) =>\n this.seatsResource.getBalance({ customerId: this.customerId, seatType }),\n };\n\n usage = {\n track: (\n feature: string,\n value?: number,\n properties?: Record<string, string>,\n options?: RequestOptions,\n ) =>\n this.usageResource.track(\n { customerId: this.customerId, feature, value, properties },\n options,\n ),\n };\n\n subscription = {\n get: () => this.subscriptionsResource.get(this.customerId),\n };\n\n portal = {\n getUrl: (options?: RequestOptions) =>\n this.portalResource.getUrl({ customerId: this.customerId }, options),\n };\n}\n","import type { ApiResponse } from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\n\nexport interface CreditPack {\n id: string;\n name: string;\n description: string | null;\n credits: number;\n price: number;\n currency: string;\n}\n\n/**\n * Credit Packs resource for listing available credit packs\n */\nexport class CreditPacksResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n /**\n * List all active credit packs\n *\n * @example\n * ```typescript\n * const packs = await commet.creditPacks.list();\n * console.log(packs.data); // [{ id: \"cp_xxx\", name: \"100 Credits\", ... }]\n * ```\n */\n async list(): Promise<ApiResponse<CreditPack[]>> {\n return this.httpClient.get(\"/credit-packs\");\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 fullName?: 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 id?: string; // Your user ID — stored as externalId, used to identify the customer in all SDK methods\n fullName?: 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 email?: string;\n fullName?: 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 ListCustomersParams extends BaseListParams {\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 when id is provided)\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.id,\n fullName: params.fullName,\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.id,\n fullName: c.fullName,\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 fullName: params.fullName,\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 * 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 CustomerID,\n GeneratedFeatureCode,\n RequestOptions,\n} from \"../types/common\";\nimport type { CommetHTTPClient } from \"../utils/http\";\n\nexport interface FeatureParams {\n customerId: CustomerID;\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 enabled?: boolean;\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\nexport class FeaturesResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n async get(\n params: GetFeatureParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<FeatureAccess>> {\n return this.httpClient.get(\n `/features/${params.code}`,\n { customerId: params.customerId },\n options,\n );\n }\n\n async check(\n params: CheckFeatureParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<CheckResult>> {\n const result = await this.httpClient.get<FeatureAccess>(\n `/features/${params.code}`,\n { customerId: params.customerId },\n options,\n );\n\n if (!result.success || !result.data) {\n return {\n success: false,\n code: result.code,\n message: result.message,\n details: result.details,\n };\n }\n\n return {\n success: true,\n data: { allowed: result.data.allowed },\n };\n }\n\n async canUse(\n params: CanUseFeatureParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<CanUseResult>> {\n return this.httpClient.get(\n `/features/${params.code}`,\n { customerId: params.customerId, action: \"canUse\" },\n options,\n );\n }\n\n async list(\n customerId: CustomerID,\n options?: RequestOptions,\n ): Promise<ApiResponse<FeatureAccess[]>> {\n return this.httpClient.get(\"/features\", { customerId }, 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 trialDays: number;\n}\n\nexport interface PlanFeature {\n code: string;\n name: string;\n type: FeatureType;\n unitName: string | null;\n enabled?: boolean;\n includedAmount?: number;\n unlimited?: boolean;\n overageEnabled?: boolean;\n overageUnitPrice?: number;\n}\n\nexport interface Plan {\n id: PlanID;\n code: string;\n name: string;\n description: string | null;\n isPublic: boolean;\n isFree: boolean;\n isDefault: boolean;\n sortOrder: number;\n prices: PlanPrice[];\n features: PlanFeature[];\n createdAt: string;\n}\n\nexport interface PlanDetailPrice {\n billingInterval: BillingInterval;\n price: number;\n isDefault: boolean;\n trialDays: number;\n introOffer: {\n enabled: boolean;\n discountType: \"percentage\" | \"amount\" | null;\n discountValue: number | null;\n durationCycles: number | null;\n } | null;\n}\n\nexport interface PlanDetailFeature extends PlanFeature {\n overage: {\n enabled: boolean;\n model: \"per_unit\" | \"tiered\" | null;\n unitPrice: number | null;\n } | null;\n}\n\nexport interface PlanDetail {\n id: PlanID;\n code: string;\n name: string;\n description: string | null;\n isPublic: boolean;\n isDefault: boolean;\n sortOrder: number;\n prices: PlanDetailPrice[];\n features: PlanDetailFeature[];\n createdAt: string;\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}\n\ninterface GetUrlByEmail {\n email: string;\n customerId?: never;\n}\n\nexport type GetUrlParams = GetUrlByCustomerId | GetUrlByEmail;\n\nexport class PortalResource {\n constructor(private httpClient: CommetHTTPClient) {}\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 seatType: GeneratedSeatType;\n count: number;\n}\n\nexport interface RemoveParams {\n customerId: CustomerID;\n seatType: GeneratedSeatType;\n count: number;\n}\n\nexport interface SetParams {\n customerId: CustomerID;\n seatType: GeneratedSeatType;\n count: number;\n}\n\nexport interface SetAllParams {\n customerId: CustomerID;\n seats: Record<string, number>;\n}\n\nexport interface GetBalanceParams {\n customerId: CustomerID;\n seatType: GeneratedSeatType;\n}\n\nexport interface GetAllBalancesParams {\n customerId: CustomerID;\n}\n\nexport class SeatsResource {\n constructor(private httpClient: CommetHTTPClient) {}\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 async remove(\n params: RemoveParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<SeatEvent>> {\n return this.httpClient.delete(\"/seats\", params, options);\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 async setAll(\n params: SetAllParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<SeatEvent[]>> {\n return this.httpClient.put(\"/seats/bulk\", params, options);\n }\n\n async getBalance(\n params: GetBalanceParams,\n ): Promise<ApiResponse<SeatBalance>> {\n return this.httpClient.get(\"/seats/balance\", {\n customerId: params.customerId,\n seatType: params.seatType,\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 });\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 | null;\n };\n name: string;\n description: string | null;\n status: SubscriptionStatus;\n trialEndsAt: string | null;\n currentPeriod: {\n start: string;\n end: string;\n daysRemaining: number;\n };\n features: FeatureSummary[];\n startDate: string;\n endDate: string | null;\n billingDayOfMonth: number;\n nextBillingDate: string;\n checkoutUrl: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CreatedSubscription {\n id: string;\n customerId: string;\n planId: string;\n planName: string;\n name: string;\n status: SubscriptionStatus;\n billingInterval: BillingInterval | null;\n trialEndsAt: string | null;\n startDate: string;\n endDate: string | null;\n currentPeriodStart: string | null;\n currentPeriodEnd: string | null;\n billingDayOfMonth: number;\n checkoutUrl: string | null;\n createdAt: string;\n updatedAt: string;\n introOfferEndsAt: string | null;\n introOfferDiscountType: \"percentage\" | \"amount\" | null;\n introOfferDiscountValue: number | null;\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\ntype PlanIdentifier =\n | { planCode: GeneratedPlanCode; planId?: never }\n | { planCode?: never; planId: string };\n\nexport type CreateSubscriptionParams = PlanIdentifier & {\n customerId: string;\n} & {\n billingInterval?: BillingInterval;\n initialSeats?: Record<string, number>;\n skipTrial?: boolean;\n name?: string;\n startDate?: string;\n successUrl?: string;\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<CreatedSubscription>> {\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 customerId: string,\n ): Promise<ApiResponse<ActiveSubscription | null>> {\n return this.httpClient.get(\"/subscriptions/active\", { customerId });\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 GeneratedFeatureCode,\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 feature: string;\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\ninterface TrackBaseParams {\n feature: GeneratedFeatureCode;\n customerId: CustomerID;\n idempotencyKey?: string;\n timestamp?: string;\n properties?: Record<string, string>;\n}\n\nexport interface TrackUsageParams extends TrackBaseParams {\n value?: number;\n model?: never;\n}\n\nexport interface TrackModelTokensParams extends TrackBaseParams {\n model: string;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n value?: never;\n}\n\nexport type TrackParams = TrackUsageParams | TrackModelTokensParams;\n\nexport class UsageResource {\n constructor(private httpClient: CommetHTTPClient) {}\n\n async track(\n params: TrackParams,\n options?: RequestOptions,\n ): Promise<ApiResponse<UsageEvent>> {\n const eventData: Record<string, unknown> = {\n feature: params.feature,\n customerId: params.customerId,\n idempotencyKey: params.idempotencyKey,\n timestamp: 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 if (\"model\" in params && params.model) {\n eventData.model = params.model;\n eventData.inputTokens = params.inputTokens;\n eventData.outputTokens = params.outputTokens;\n if (params.cacheReadTokens) {\n eventData.cacheReadTokens = params.cacheReadTokens;\n }\n if (params.cacheWriteTokens) {\n eventData.cacheWriteTokens = params.cacheWriteTokens;\n }\n } else {\n eventData.value = (params as TrackUsageParams).value;\n }\n\n return this.httpClient.post(\"/usage/events\", eventData, 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 code?: string;\n message?: string;\n details?: unknown;\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 = 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/types.d.ts file that augments this interface with your\n * organization's specific feature codes, seat types, and plan codes.\n *\n * @example\n * // After running `commet pull`, TypeScript will automatically know your types:\n * await commet.usage.track({\n * feature: 'api_calls', // Autocomplete works!\n * externalId: 'user_123'\n * });\n */\n\n// biome-ignore lint/suspicious/noEmptyInterface: augmented by CLI-generated .commet/types.d.ts\nexport interface CommetGeneratedTypes {}\n\nexport type GeneratedSeatType = CommetGeneratedTypes extends {\n seatType: infer T;\n}\n ? T\n : string;\n\nexport type GeneratedPlanCode = CommetGeneratedTypes extends {\n planCode: infer T;\n}\n ? T\n : string;\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-node/1.9.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 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 code?: string;\n details?: unknown;\n } => {\n return typeof data === \"object\" && data !== null;\n };\n\n const errorData = isErrorResponse(responseData) ? responseData : {};\n\n // Handle validation errors (new normalized shape)\n if (\n errorData.code === \"validation_error\" &&\n Array.isArray(errorData.details)\n ) {\n const errors: Record<string, string[]> = {};\n for (const detail of errorData.details as Array<{\n field: string;\n message: string;\n }>) {\n if (!errors[detail.field]) errors[detail.field] = [];\n errors[detail.field].push(detail.message);\n }\n throw new CommetValidationError(\n errorData.message || \"Validation failed\",\n 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 const isNetworkError =\n error instanceof TypeError && error.message.includes(\"fetch\");\n const isTimeoutError =\n error instanceof DOMException && error.name === \"AbortError\";\n const isTimeoutErrorModern =\n typeof globalThis.DOMException !== \"undefined\" &&\n error instanceof DOMException &&\n error.name === \"TimeoutError\";\n\n if (isNetworkError || isTimeoutError || isTimeoutErrorModern) {\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 { CreditPacksResource } from \"./resources/credit-packs\";\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 creditPacks: CreditPacksResource;\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.creditPacks = new CreditPacksResource(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(customerId: string): CustomerContext {\n return new CustomerContext(customerId, {\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","/**\n * Commet SDK - Billing and usage tracking for SaaS\n */\nexport { Commet } from \"./client\";\nexport { CustomerContext } from \"./customer\";\n// Credit Packs\nexport type { CreditPack } from \"./resources/credit-packs\";\n// Customers\nexport type {\n BatchResult as CustomersBatchResult,\n CreateParams as CreateCustomerParams,\n Customer,\n CustomerAddress,\n ListCustomersParams,\n UpdateParams as UpdateCustomerParams,\n} from \"./resources/customers\";\n// Features\nexport type {\n CanUseFeatureParams,\n CanUseResult,\n CheckFeatureParams,\n CheckResult,\n FeatureAccess,\n GetFeatureParams,\n} from \"./resources/features\";\n// Plans\nexport type {\n BillingInterval,\n FeatureType,\n ListPlansParams,\n Plan,\n PlanDetail,\n PlanFeature,\n PlanID,\n PlanPrice,\n} from \"./resources/plans\";\n// Portal\nexport type { GetUrlParams, PortalAccess } from \"./resources/portal\";\n// Seats\nexport type {\n AddParams as AddSeatsParams,\n GetAllBalancesParams,\n GetBalanceParams,\n RemoveParams as RemoveSeatsParams,\n SeatBalance,\n SeatEvent,\n SetAllParams as SetAllSeatsParams,\n SetParams as SetSeatsParams,\n} from \"./resources/seats\";\n// Subscriptions\nexport type {\n ActiveSubscription,\n CancelParams,\n CreatedSubscription,\n CreateSubscriptionParams,\n FeatureSummary,\n Subscription,\n SubscriptionStatus,\n} from \"./resources/subscriptions\";\n// Usage\nexport type {\n TrackModelTokensParams,\n TrackParams,\n TrackUsageParams,\n UsageEvent,\n UsageEventProperty,\n} from \"./resources/usage\";\nexport type {\n WebhookData,\n WebhookEvent,\n WebhookPayload,\n} from \"./resources/webhooks\";\n// Webhooks\nexport { Webhooks } from \"./resources/webhooks\";\n// Type exports\nexport type {\n ApiResponse,\n CommetConfig,\n CommetGeneratedTypes,\n Currency,\n CustomerID,\n Environment,\n EventID,\n GeneratedFeatureCode,\n GeneratedPlanCode,\n GeneratedSeatType,\n PaginatedList,\n PaginatedResponse,\n RequestOptions,\n} from \"./types/common\";\n// Error exports\nexport {\n CommetAPIError,\n CommetError,\n CommetValidationError,\n} from \"./types/common\";\n\n// Utility exports\nexport { isProduction, isSandbox } from \"./utils/environment\";\n\n// Default export\nimport { Commet } from \"./client\";\nexport default Commet;\n"],"mappings":"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","names":["data"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@commet/node",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "description": "Commet SDK for Node.js - Billing and usage tracking",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -27,13 +27,12 @@
27
27
  ],
28
28
  "author": "Commet Team",
29
29
  "license": "MIT",
30
- "dependencies": {
31
- "zod": "4.1.12"
32
- },
30
+ "dependencies": {},
33
31
  "devDependencies": {
34
32
  "@types/node": "24.10.1",
35
33
  "tsup": "8.5.1",
36
- "typescript": "5.9.3"
34
+ "typescript": "5.9.3",
35
+ "vitest": "4.0.13"
37
36
  },
38
37
  "peerDependencies": {
39
38
  "typescript": ">=5.0.0"
@@ -56,6 +55,8 @@
56
55
  "dev": "tsup --watch",
57
56
  "lint": "biome lint src/",
58
57
  "lint:fix": "biome lint --write src/",
59
- "typecheck": "tsc --noEmit"
58
+ "typecheck": "tsc --noEmit",
59
+ "test": "vitest run",
60
+ "test:watch": "vitest"
60
61
  }
61
62
  }