{"version":3,"sources":["../src/creem-server.ts","../src/utils.ts"],"sourcesContent":["import { Creem } from \"creem\";\nimport { logger } from \"better-auth\";\nimport type { CreemOptions } from \"./types.js\";\nimport type { CreateCheckoutInput, CreateCheckoutResponse } from \"./checkout-types.js\";\nimport type { CreatePortalResponse } from \"./portal-types.js\";\nimport type { SubscriptionData } from \"./retrieve-subscription-types.js\";\nimport type { SearchTransactionsResponse } from \"./search-transactions-types.js\";\nimport { generateSignature } from \"./utils.js\";\n\n/**\n * Configuration for server-side Creem operations.\n */\nexport interface CreemServerConfig {\n  /** Creem API key */\n  apiKey: string;\n  /** Whether to use test mode */\n  testMode?: boolean;\n}\n\n/**\n * Initialize a Creem client for server-side operations.\n * Use this for direct API calls outside of Better Auth endpoints.\n *\n * @param config - Configuration options\n * @returns Configured Creem client instance\n *\n * @example\n * ```typescript\n * import { createCreemClient } from \"@creem_io/better-auth/server\";\n *\n * const creem = createCreemClient({\n *   apiKey: process.env.CREEM_API_KEY!,\n *   testMode: true\n * });\n *\n * // Use directly in Server Actions or API routes\n * const subscription = await creem.subscriptions.get(\"sub_123\");\n * ```\n */\nexport function createCreemClient(config: CreemServerConfig): Creem {\n  const serverURL = config.testMode ? \"https://test-api.creem.io\" : \"https://api.creem.io\";\n\n  return new Creem({ apiKey: config.apiKey, serverURL });\n}\n\n/**\n * Check if a subscription status indicates active access.\n *\n * @param status - The subscription status from Creem\n * @returns True if subscription grants access\n *\n * @example\n * ```typescript\n * import { isActiveSubscription } from \"@creem_io/better-auth/server\";\n *\n * if (isActiveSubscription(subscription.status)) {\n *   // User has active access\n * }\n * ```\n */\nexport function isActiveSubscription(status: string): boolean {\n  return [\"active\", \"trialing\", \"paid\"].includes(status.toLowerCase());\n}\n\n/**\n * Format Creem Unix timestamp to JavaScript Date.\n *\n * @param timestamp - Unix timestamp from Creem (seconds)\n * @returns JavaScript Date object\n *\n * @example\n * ```typescript\n * import { formatCreemDate } from \"@creem_io/better-auth/server\";\n *\n * const renewalDate = formatCreemDate(subscription.next_billing_date);\n * console.log(renewalDate.toLocaleDateString());\n * ```\n */\nexport function formatCreemDate(timestamp: number): Date {\n  return new Date(timestamp * 1000);\n}\n\n/**\n * Calculate days until subscription renewal.\n *\n * @param periodEndTimestamp - Unix timestamp of period end\n * @returns Number of days until renewal (negative if overdue)\n *\n * @example\n * ```typescript\n * import { getDaysUntilRenewal } from \"@creem_io/better-auth/server\";\n *\n * const days = getDaysUntilRenewal(subscription.current_period_end_date);\n * if (days > 0) {\n *   console.log(`Renews in ${days} days`);\n * } else {\n *   console.log(`Overdue by ${Math.abs(days)} days`);\n * }\n * ```\n */\nexport function getDaysUntilRenewal(periodEndTimestamp: number): number {\n  const renewalDate = formatCreemDate(periodEndTimestamp);\n  const now = new Date();\n  const diffTime = renewalDate.getTime() - now.getTime();\n  return Math.ceil(diffTime / (1000 * 60 * 60 * 24));\n}\n\n/**\n * Validate webhook signature from Creem.\n * Use this to verify webhook authenticity in custom webhook handlers.\n *\n * @param payload - Raw webhook payload string\n * @param signature - Signature from 'creem-signature' header\n * @param secret - Your webhook secret\n * @returns True if signature is valid\n *\n * @example\n * ```typescript\n * import { validateWebhookSignature } from \"@creem_io/better-auth/server\";\n *\n * export async function POST(req: Request) {\n *   const payload = await req.text();\n *   const signature = req.headers.get('creem-signature');\n *\n *   if (!await validateWebhookSignature(payload, signature, process.env.CREEM_WEBHOOK_SECRET!)) {\n *     return new Response('Invalid signature', { status: 401 });\n *   }\n *\n *   const event = JSON.parse(payload);\n *   // Process webhook\n * }\n * ```\n */\nexport async function validateWebhookSignature(\n  payload: string,\n  signature: string | null,\n  secret: string,\n): Promise<boolean> {\n  if (!signature) return false;\n  const computedSignature = await generateSignature(payload, secret);\n  return computedSignature === signature;\n}\n\n/**\n * Create a checkout session directly (without using Better Auth endpoints).\n * Useful in Server Components, Server Actions, or custom API routes.\n *\n * @param config - Creem configuration\n * @param input - Checkout parameters\n * @returns Checkout URL and redirect flag\n *\n * @example\n * ```typescript\n * import { createCheckout } from \"@creem_io/better-auth/server\";\n *\n * // Server Action\n * export async function startCheckout(productId: string) {\n *   const { url } = await createCheckout(\n *     {\n *       apiKey: process.env.CREEM_API_KEY!,\n *       testMode: true\n *     },\n *     {\n *       productId,\n *       customer: { email: user.email },\n *       successUrl: \"/success\",\n *       metadata: { userId: user.id }\n *     }\n *   );\n *\n *   redirect(url);\n * }\n * ```\n *\n * @example\n * // With trial abuse prevention (check user.hadTrial from your database)\n * ```typescript\n * const { url } = await createCheckout(\n *   config,\n *   {\n *     productId,\n *     customer: { email: user.email },\n *     successUrl: \"/success\",\n *     skipTrial: user.hadTrial, // Pass true if user has already used a trial\n *   }\n * );\n * ```\n */\nexport async function createCheckout(\n  config: CreemServerConfig,\n  input: Omit<CreateCheckoutInput, \"customer\"> & {\n    customer: { email?: string; id?: string };\n    /**\n     * If true, tells Creem to skip the trial period for this checkout.\n     * Use this for trial abuse prevention - pass true if the user has\n     * already used a trial (check user.hadTrial from your database).\n     *\n     * @since 1.1.0\n     */\n    skipTrial?: boolean;\n  },\n): Promise<CreateCheckoutResponse> {\n  if (!config.apiKey) {\n    throw new Error(\n      \"Creem API key is not configured. Please provide an apiKey in the CreemServerConfig.\",\n    );\n  }\n\n  const creem = createCreemClient(config);\n\n  const checkout = await creem.checkouts.create({\n    productId: input.productId,\n    requestId: input.requestId,\n    units: input.units,\n    discountCode: input.discountCode,\n    customer: input.customer,\n    customFields: input.customFields ?? input.customField,\n    successUrl: input.successUrl,\n    metadata: {\n      ...(input.metadata || {}),\n      // Trial abuse prevention: signal to Creem that this user has already had a trial\n      ...(input.skipTrial && { skipTrial: true }),\n    },\n  });\n\n  return {\n    url:\n      checkout.checkoutUrl ??\n      (() => {\n        throw new Error(\"Creem API returned no checkout URL\");\n      })(),\n    redirect: true,\n  };\n}\n\n/**\n * Create a customer portal session directly.\n * Useful in Server Components, Server Actions, or custom API routes.\n *\n * @param config - Creem configuration\n * @param customerId - Creem customer ID\n * @returns Portal URL and redirect flag\n *\n * @example\n * ```typescript\n * import { createPortal } from \"@creem_io/better-auth/server\";\n *\n * // Server Component\n * export default async function BillingPage() {\n *   const session = await getSession();\n *\n *   async function openPortal() {\n *     'use server';\n *     const { url } = await createPortal(\n *       {\n *         apiKey: process.env.CREEM_API_KEY!,\n *         testMode: true\n *       },\n *       session.user.creemCustomerId\n *     );\n *     redirect(url);\n *   }\n *\n *   return <form action={openPortal}>...</form>;\n * }\n * ```\n */\nexport async function createPortal(\n  config: CreemServerConfig,\n  customerId: string,\n): Promise<CreatePortalResponse> {\n  if (!config.apiKey) {\n    throw new Error(\n      \"Creem API key is not configured. Please provide an apiKey in the CreemServerConfig.\",\n    );\n  }\n\n  const creem = createCreemClient(config);\n\n  const portal = await creem.customers.generateBillingLinks({\n    customerId,\n  });\n\n  return {\n    url: portal.customerPortalLink,\n    redirect: true,\n  };\n}\n\n/**\n * Cancel a subscription directly.\n * Useful in Server Actions or custom API routes.\n *\n * @param config - Creem configuration\n * @param subscriptionId - Subscription ID to cancel\n * @returns Success status and message\n *\n * @example\n * ```typescript\n * import { cancelSubscription } from \"@creem_io/better-auth/server\";\n *\n * // Server Action\n * export async function handleCancelSubscription(subId: string) {\n *   const result = await cancelSubscription(\n *     {\n *       apiKey: process.env.CREEM_API_KEY!,\n *       testMode: true\n *     },\n *     subId\n *   );\n *\n *   if (result.success) {\n *     revalidatePath('/billing');\n *   }\n * }\n * ```\n */\nexport async function cancelSubscription(\n  config: CreemServerConfig,\n  subscriptionId: string,\n): Promise<{ success: boolean; message: string }> {\n  if (!config.apiKey) {\n    throw new Error(\n      \"Creem API key is not configured. Please provide an apiKey in the CreemServerConfig.\",\n    );\n  }\n\n  const creem = createCreemClient(config);\n\n  await creem.subscriptions.cancel(subscriptionId, {});\n\n  return {\n    success: true,\n    message: \"Subscription cancelled successfully\",\n  };\n}\n\n/**\n * Retrieve subscription details directly.\n * Useful in Server Components, Server Actions, or custom API routes.\n *\n * @param config - Creem configuration\n * @param subscriptionId - Subscription ID to retrieve\n * @returns Subscription data\n *\n * @example\n * ```typescript\n * import { retrieveSubscription } from \"@creem_io/better-auth/server\";\n *\n * // Server Component\n * export default async function SubscriptionPage({ params }) {\n *   const subscription = await retrieveSubscription(\n *     {\n *       apiKey: process.env.CREEM_API_KEY!,\n *       testMode: true\n *     },\n *     params.subscriptionId\n *   );\n *\n *   return (\n *     <div>\n *       <h1>{subscription.product.name}</h1>\n *       <p>Status: {subscription.status}</p>\n *     </div>\n *   );\n * }\n * ```\n */\nexport async function retrieveSubscription(\n  config: CreemServerConfig,\n  subscriptionId: string,\n): Promise<SubscriptionData> {\n  if (!config.apiKey) {\n    throw new Error(\n      \"Creem API key is not configured. Please provide an apiKey in the CreemServerConfig.\",\n    );\n  }\n\n  const creem = createCreemClient(config);\n\n  const subscription = await creem.subscriptions.get(subscriptionId);\n\n  return subscription as unknown as SubscriptionData;\n}\n\n/**\n * Search transactions directly.\n * Useful in Server Components, Server Actions, or custom API routes.\n *\n * @param config - Creem configuration\n * @param filters - Search filters\n * @returns Transaction search results\n *\n * @example\n * ```typescript\n * import { searchTransactions } from \"@creem_io/better-auth/server\";\n *\n * // Server Component\n * export default async function TransactionsPage() {\n *   const { items, pagination } = await searchTransactions(\n *     {\n *       apiKey: process.env.CREEM_API_KEY!,\n *       testMode: true\n *     },\n *     {\n *       customerId: user.creemCustomerId,\n *       pageSize: 50\n *     }\n *   );\n *\n *   return <TransactionList transactions={items} />;\n * }\n * ```\n */\nexport async function searchTransactions(\n  config: CreemServerConfig,\n  filters?: {\n    customerId?: string;\n    productId?: string;\n    orderId?: string;\n    pageNumber?: number;\n    pageSize?: number;\n  },\n): Promise<SearchTransactionsResponse> {\n  if (!config.apiKey) {\n    throw new Error(\n      \"Creem API key is not configured. Please provide an apiKey in the CreemServerConfig.\",\n    );\n  }\n\n  const creem = createCreemClient(config);\n\n  const response = await creem.transactions.search(\n    filters?.customerId,\n    filters?.orderId,\n    filters?.productId,\n    filters?.pageNumber,\n    filters?.pageSize,\n  );\n\n  return response as unknown as SearchTransactionsResponse;\n}\n\n/**\n * Check if user has active subscription with access.\n * Works in both database-enabled and database-free modes.\n *\n * **Database Mode:** Queries local subscription table for fast access checks.\n * **API Mode:** Queries Creem API directly (requires API call).\n *\n * @param config - Creem configuration\n * @param options - Check options\n * @returns Access status information\n *\n * @example\n * ```typescript\n * // Database mode (when persistSubscriptions: true)\n * import { checkSubscriptionAccess } from \"@creem_io/better-auth/server\";\n * import { auth } from \"@/lib/auth\";\n *\n * const status = await checkSubscriptionAccess(\n *   {\n *     apiKey: process.env.CREEM_API_KEY!,\n *     testMode: true\n *   },\n *   {\n *     database: auth.options.database, // Pass database adapter\n *     userId: session.user.id\n *   }\n * );\n *\n * // API mode (when persistSubscriptions: false or no database)\n * const status = await checkSubscriptionAccess(\n *   {\n *     apiKey: process.env.CREEM_API_KEY!,\n *     testMode: true\n *   },\n *   {\n *     customerId: session.user.creemCustomerId\n *   }\n * );\n *\n * if (!status.hasAccess) {\n *   redirect('/subscribe');\n * }\n * ```\n */\nexport async function checkSubscriptionAccess(\n  config: CreemServerConfig,\n  options:\n    | { database: any; userId: string; customerId?: never }\n    | { customerId: string; database?: never; userId?: never },\n): Promise<{\n  hasAccess: boolean;\n  status?: string;\n  subscriptionId?: string;\n  expiresAt?: Date;\n  productName?: string;\n}> {\n  // Database mode\n  // TODO: This uses a raw query builder API (select/from/where) that may not match\n  // all Better Auth database adapters. For reliable access checks, prefer the\n  // `hasAccessGranted` Better Auth endpoint which uses the adapter correctly.\n  if (options.database && options.userId) {\n    try {\n      const subscriptions = await options.database\n        .select()\n        .from(\"creem_subscription\")\n        .where(\"referenceId\", \"=\", options.userId);\n\n      const activeSubscription = subscriptions.find(\n        (sub: any) => sub.status === \"active\" || sub.status === \"trialing\" || sub.status === \"paid\",\n      );\n\n      if (activeSubscription) {\n        return {\n          hasAccess: true,\n          status: activeSubscription.status,\n          subscriptionId: activeSubscription.creemSubscriptionId,\n          expiresAt: activeSubscription.periodEnd\n            ? new Date(activeSubscription.periodEnd)\n            : undefined,\n        };\n      }\n\n      return { hasAccess: false };\n    } catch (error) {\n      const message = error instanceof Error ? error.message : String(error);\n      logger.error(`[creem] Failed to check subscription access (database mode): ${message}`);\n      // Fall through to API check\n    }\n  }\n\n  // API mode\n  if (options.customerId) {\n    // API mode not yet supported — use database mode for access checks\n    return { hasAccess: false };\n  }\n\n  return { hasAccess: false };\n}\n\n/**\n * Get all active subscriptions for a user or customer.\n * Works in both database-enabled and database-free modes.\n *\n * @param config - Creem configuration\n * @param options - Query options\n * @returns List of active subscriptions\n *\n * @example\n * ```typescript\n * import { getActiveSubscriptions } from \"@creem_io/better-auth/server\";\n *\n * // Database mode\n * const subscriptions = await getActiveSubscriptions(\n *   config,\n *   { database: auth.options.database, userId: user.id }\n * );\n *\n * // API mode\n * const subscriptions = await getActiveSubscriptions(\n *   config,\n *   { customerId: user.creemCustomerId }\n * );\n * ```\n */\nexport async function getActiveSubscriptions(\n  config: CreemServerConfig,\n  options:\n    | { database: any; userId: string; customerId?: never }\n    | { customerId: string; database?: never; userId?: never },\n): Promise<\n  Array<{\n    id: string;\n    status: string;\n    productId: string;\n    productName?: string;\n    periodEnd?: Date;\n  }>\n> {\n  // Database mode\n  // TODO: Same raw query builder caveat as checkSubscriptionAccess above.\n  if (options.database && options.userId) {\n    try {\n      const subscriptions = await options.database\n        .select()\n        .from(\"creem_subscription\")\n        .where(\"referenceId\", \"=\", options.userId);\n\n      return subscriptions\n        .filter(\n          (sub: any) =>\n            sub.status === \"active\" || sub.status === \"trialing\" || sub.status === \"paid\",\n        )\n        .map((sub: any) => ({\n          id: sub.creemSubscriptionId,\n          status: sub.status,\n          productId: sub.productId,\n          periodEnd: sub.periodEnd ? new Date(sub.periodEnd) : undefined,\n        }));\n    } catch (error) {\n      const message = error instanceof Error ? error.message : String(error);\n      logger.error(`[creem] Failed to get active subscriptions (database mode): ${message}`);\n      return [];\n    }\n  }\n\n  // API mode\n  if (options.customerId) {\n    // API mode not yet supported — use database mode for subscription queries\n    return [];\n  }\n\n  return [];\n}\n","import type { GenericEndpointContext } from \"better-auth\";\nimport { generateSignature, parseWebhookEvent } from \"@creem_io/webhook-types\";\n\nexport { generateSignature, parseWebhookEvent };\n\n/**\n * Converts a relative URL to an absolute URL using the request context\n * If the URL is already absolute, returns it as-is\n */\nexport function resolveSuccessUrl(\n  url: string | undefined,\n  ctx: GenericEndpointContext,\n): string | undefined {\n  if (!url) return undefined;\n\n  // Check if URL is already absolute (contains protocol)\n  try {\n    new URL(url);\n    return url; // Already absolute URL\n  } catch {\n    // URL is relative, convert to absolute\n    const headers = ctx.request?.headers;\n    const host = headers?.get(\"host\") || headers?.get(\"x-forwarded-host\");\n    const protocol = headers?.get(\"x-forwarded-proto\") || headers?.get(\"x-forwarded-protocol\");\n\n    if (!host) {\n      return url; // Return as-is if we can't resolve\n    }\n\n    const baseUrl = `${protocol || \"https\"}://${host}`;\n    return new URL(url, baseUrl).toString();\n  }\n}\n"],"mappings":"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","names":[]}