@waffo/pancake-nextjs 0.7.0 → 0.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
@@ -422,8 +422,9 @@ function Webhook(config) {
422
422
  }
423
423
 
424
424
  // src/index.ts
425
- import { WaffoPancakeError, TaxCategory, WebhookEventType } from "@waffo/pancake-ts";
425
+ import { WaffoPancakeError, ChangeTiming, TaxCategory, WebhookEventType } from "@waffo/pancake-ts";
426
426
  export {
427
+ ChangeTiming,
427
428
  CheckoutButton,
428
429
  TaxCategory,
429
430
  WaffoPancakeError,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/provider.tsx","../src/use-checkout.ts","../src/checkout-button.tsx","../src/use-customer.ts","../src/use-customer-data.ts","../src/use-query.ts","../src/use-merchant-data.ts","../src/webhook.ts","../src/index.ts"],"sourcesContent":["\"use client\";\n\nimport React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport type { CustomerTokenAction, CustomerSessionAction } from \"./server.js\";\n\n/** Customer configuration for automatic token management */\nexport interface CustomerConfig {\n /** Customer identity (email or merchant-provided identifier) */\n identity: string;\n /** Store ID (optional when `productId` is provided) */\n storeId?: string;\n /** Product ID — used to derive the store when `storeId` is omitted */\n productId?: string;\n /** Server action for issuing tokens — from `createCustomerTokenAction()` */\n issueToken: CustomerTokenAction;\n /** Server action for customer operations — from `createCustomerSessionAction()` */\n sessionAction: CustomerSessionAction;\n}\n\n/** @deprecated Use {@link CustomerConfig} instead. */\nexport type BuyerConfig = CustomerConfig;\n\ninterface TokenState {\n token: string;\n expiresAt: number;\n}\n\n/** @internal */\nexport interface PancakeContextValue {\n /** Get a valid customer token (auto-refreshes if expired) */\n getCustomerToken: () => Promise<string>;\n /** Execute a customer session operation via server action */\n customerSessionAction: CustomerSessionAction;\n /** Whether customer config is provided */\n hasCustomer: boolean;\n /** Whether the initial token is ready */\n isCustomerReady: boolean;\n}\n\n/** @internal Exported for direct useContext access in hooks */\nexport const PancakeContext = createContext<PancakeContextValue | null>(null);\n\n/** Token refresh buffer — refresh 30s before actual expiry */\nconst REFRESH_BUFFER_MS = 30_000;\n\nexport interface WaffoPancakeProviderProps {\n /** Customer configuration for automatic token management */\n customer?: CustomerConfig;\n /** @deprecated Use `customer` instead. */\n buyer?: CustomerConfig;\n children: React.ReactNode;\n}\n\n/**\n * Provider that manages customer token lifecycle via server actions.\n *\n * Auto-issues session tokens on mount and refreshes before expiry.\n * All customer hooks (`useCustomer`, `useCustomerOrders`, etc.) read from context.\n *\n * The private key never leaves the server — token issuance and customer\n * operations are delegated to server actions.\n *\n * @param props - Provider configuration\n * @param props.customer - Customer identity and server actions\n * @param props.buyer - Deprecated alias of `customer`\n * @param props.children - React children\n *\n * @example\n * ```tsx\n * // identity must match what you passed as `buyerIdentity` at checkout time —\n * // customer-portal lookups are keyed by merchant_provided_buyer_identity\n * <WaffoPancakeProvider customer={{\n * identity: user.id,\n * storeId: \"STO_xxx\",\n * issueToken, // from createCustomerTokenAction()\n * sessionAction, // from createCustomerSessionAction()\n * }}>\n * <App />\n * </WaffoPancakeProvider>\n * ```\n */\nexport function WaffoPancakeProvider({ customer, buyer, children }: WaffoPancakeProviderProps) {\n const config = customer ?? buyer;\n if (!config) throw new Error(\"WaffoPancakeProvider: the `customer` prop is required\");\n\n const tokenRef = useRef<TokenState | null>(null);\n const refreshPromiseRef = useRef<Promise<string> | null>(null);\n const [isCustomerReady, setIsCustomerReady] = useState(false);\n\n const refreshToken = useCallback(async (): Promise<string> => {\n const result = await config.issueToken({\n buyerIdentity: config.identity,\n storeId: config.storeId,\n productId: config.productId,\n });\n\n tokenRef.current = {\n token: result.token,\n expiresAt: new Date(result.expiresAt).getTime(),\n };\n\n return result.token;\n }, [config]);\n\n const getCustomerToken = useCallback(async (): Promise<string> => {\n const current = tokenRef.current;\n if (current && Date.now() < current.expiresAt - REFRESH_BUFFER_MS) {\n return current.token;\n }\n\n // Deduplicate concurrent refresh calls\n if (!refreshPromiseRef.current) {\n refreshPromiseRef.current = refreshToken().finally(() => {\n refreshPromiseRef.current = null;\n });\n }\n\n return refreshPromiseRef.current;\n }, [refreshToken]);\n\n // Issue initial token on mount\n useEffect(() => {\n refreshToken()\n .then(() => setIsCustomerReady(true))\n .catch(() => setIsCustomerReady(true));\n }, [refreshToken]);\n\n const value = useMemo<PancakeContextValue>(\n () => ({\n getCustomerToken,\n customerSessionAction: config.sessionAction,\n hasCustomer: true,\n isCustomerReady,\n }),\n [getCustomerToken, config.sessionAction, isCustomerReady],\n );\n\n return <PancakeContext.Provider value={value}>{children}</PancakeContext.Provider>;\n}\n\n/**\n * Access the Waffo Pancake context. Must be used within `<WaffoPancakeProvider>`.\n */\nexport function usePancakeContext(): PancakeContextValue {\n const ctx = useContext(PancakeContext);\n if (!ctx) throw new Error(\"usePancakeContext: must be used within <WaffoPancakeProvider>\");\n return ctx;\n}\n","\"use client\";\n\nimport { useCallback, useRef, useState } from \"react\";\n\nimport type { CheckoutProps, LinkCheckoutProps, UseCheckoutReturn } from \"./types.js\";\nimport type { CheckoutSessionResult, AuthenticatedCheckoutResult } from \"@waffo/pancake-ts\";\n\n\nconst LOADING_HTML = `<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Loading...</title><style>body{display:flex;align-items:center;justify-content:center;height:100vh;margin:0;font-family:system-ui,sans-serif;background:#f9fafb;color:#6b7280}@media(prefers-color-scheme:dark){body{background:#111827;color:#9ca3af}}</style></head><body><p>Redirecting to checkout...</p></body></html>`;\n\nconst DEFAULT_STOREFRONT_URL = \"https://pancake.waffo.ai\";\n\nconst SDK_FIELDS = new Set([\"action\", \"type\", \"mode\", \"popupLoadingUrl\", \"onSuccess\", \"onError\"]);\n\n/** Extract API checkout params from flattened props, removing SDK-specific fields */\nfunction extractApiParams(args: object): Record<string, unknown> {\n const params: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(args)) {\n if (!SDK_FIELDS.has(key)) params[key] = value;\n }\n return params;\n}\n\n/**\n * Build a product page URL for link checkout.\n */\nfunction buildLinkUrl(props: LinkCheckoutProps): string {\n const base = (props.baseUrl ?? DEFAULT_STOREFRONT_URL).replace(/\\/+$/, \"\");\n const url = new URL(`${base}/store/${props.storeSlug}/product/${props.productId}`);\n\n if (props.currency) url.searchParams.set(\"currency\", props.currency);\n if (props.email) url.searchParams.set(\"email\", props.email);\n if (props.successUrl) url.searchParams.set(\"success_url\", props.successUrl);\n if (props.test) url.searchParams.set(\"test\", \"true\");\n if (props.country) url.searchParams.set(\"country\", props.country);\n if (props.isBusiness) url.searchParams.set(\"is_business\", \"true\");\n\n return url.toString();\n}\n\n/**\n * React hook for triggering a Waffo Pancake checkout flow.\n *\n * Supports three checkout types:\n * - **link**: Builds a product page URL and navigates directly (no API call, synchronous)\n * - **anonymous**: Calls a server action to create a checkout session, then navigates\n * - **authenticated**: Calls a server action to create a session + token, then navigates\n *\n * The private key never leaves the server — anonymous and authenticated modes\n * use a server action created by `createCheckoutAction()`.\n *\n * @param args - Flattened checkout props\n * @returns `{ checkout, isLoading, error }`\n *\n * @example\n * ```tsx\n * // Link checkout — no server action needed\n * const { checkout } = useCheckout({\n * type: \"link\",\n * storeSlug: \"my-store\",\n * productId: \"PROD_xxx\",\n * currency: \"USD\",\n * });\n *\n * // Anonymous checkout — via server action\n * const { checkout, isLoading } = useCheckout({\n * action: checkout, // from createCheckoutAction()\n * productId: \"PROD_xxx\",\n * currency: \"USD\",\n * });\n * ```\n */\nexport function useCheckout(args: CheckoutProps): UseCheckoutReturn {\n const { mode = \"redirect\", popupLoadingUrl, onError } = args;\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const popupRef = useRef<Window | null>(null);\n\n const checkout = useCallback(() => {\n if (isLoading) return;\n\n // Link checkout — synchronous, no API call\n if (args.type === \"link\") {\n const url = buildLinkUrl(args);\n if (mode === \"popup\") {\n window.open(url, \"_blank\");\n } else {\n window.location.href = url;\n }\n return;\n }\n\n // Anonymous / Authenticated — server action\n if (mode === \"popup\") {\n const loadingUrl = popupLoadingUrl ?? `data:text/html;charset=utf-8,${encodeURIComponent(LOADING_HTML)}`;\n popupRef.current = window.open(loadingUrl, \"_blank\");\n }\n\n setIsLoading(true);\n setError(null);\n\n const { action } = args;\n const params = extractApiParams(args);\n const actionParams = args.type === \"authenticated\" ? { type: \"authenticated\" as const, ...params } : params;\n\n action(actionParams as unknown as Parameters<typeof action>[0])\n .then((result: CheckoutSessionResult | AuthenticatedCheckoutResult) => {\n if (mode === \"popup\" && popupRef.current) {\n popupRef.current.location.href = result.checkoutUrl;\n } else {\n window.location.href = result.checkoutUrl;\n }\n if (\"onSuccess\" in args && args.onSuccess) {\n (args.onSuccess as (r: CheckoutSessionResult | AuthenticatedCheckoutResult) => void)(result);\n }\n })\n .catch((err: Error) => {\n if (mode === \"popup\" && popupRef.current) {\n popupRef.current.close();\n popupRef.current = null;\n }\n setError(err);\n onError?.(err);\n })\n .finally(() => {\n setIsLoading(false);\n });\n }, [args, mode, popupLoadingUrl, onError, isLoading]);\n\n return { checkout, isLoading, error };\n}\n","\"use client\";\n\nimport React from \"react\";\n\nimport { useCheckout } from \"./use-checkout.js\";\n\nimport type { CheckoutProps, LinkCheckoutProps, AnonymousCheckoutProps, AuthenticatedCheckoutProps } from \"./types.js\";\n\ntype CheckoutButtonBaseProps = {\n /** Button content */\n children: React.ReactNode;\n /** Content shown while checkout session is being created */\n loadingChildren?: React.ReactNode;\n /** Additional class name */\n className?: string;\n /** Additional inline styles */\n style?: React.CSSProperties;\n /** Disabled state (merged with isLoading) */\n disabled?: boolean;\n} & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, \"onClick\" | \"disabled\" | \"children\">;\n\n/** Props for CheckoutButton — link mode */\nexport type LinkCheckoutButtonProps = CheckoutButtonBaseProps & LinkCheckoutProps;\n\n/** Props for CheckoutButton — anonymous mode */\nexport type AnonymousCheckoutButtonProps = CheckoutButtonBaseProps & AnonymousCheckoutProps;\n\n/** Props for CheckoutButton — authenticated mode */\nexport type AuthenticatedCheckoutButtonProps = CheckoutButtonBaseProps & AuthenticatedCheckoutProps;\n\nexport type CheckoutButtonProps = LinkCheckoutButtonProps | AnonymousCheckoutButtonProps | AuthenticatedCheckoutButtonProps;\n\n/**\n * A button that triggers a Waffo Pancake checkout flow on click.\n *\n * Three checkout types:\n * - **link**: Instant redirect to product page URL (no server action needed)\n * - **anonymous**: Calls server action to create session, then redirects\n * - **authenticated**: Calls server action to create session + token, then redirects\n *\n * The private key never leaves the server — anonymous and authenticated modes\n * use a server action created by `createCheckoutAction()`.\n *\n * @param props - Flattened checkout props, button content, and optional styling\n *\n * @example\n * ```tsx\n * // Link checkout — no server action needed\n * <CheckoutButton type=\"link\" storeSlug=\"my-store\" productId=\"PROD_xxx\" currency=\"USD\">\n * Buy Now\n * </CheckoutButton>\n *\n * // Anonymous checkout — via server action\n * <CheckoutButton action={checkout} productId=\"PROD_xxx\" currency=\"USD\">\n * Buy Now\n * </CheckoutButton>\n *\n * // Authenticated checkout — via server action\n * <CheckoutButton action={checkout} type=\"authenticated\" productId=\"PROD_xxx\" currency=\"USD\" buyerIdentity=\"userIdInYourSystem\" buyerEmail=\"user@example.com\">\n * Buy Now\n * </CheckoutButton>\n * ```\n */\nexport function CheckoutButton(props: CheckoutButtonProps) {\n const { children, loadingChildren, className, style, disabled, ...checkoutProps } = props;\n\n const { checkout, isLoading } = useCheckout(checkoutProps as CheckoutProps);\n\n return (\n <button type=\"button\" onClick={checkout} disabled={disabled || isLoading} className={className} style={style}>\n {isLoading ? (loadingChildren ?? children) : children}\n </button>\n );\n}\n","\"use client\";\n\nimport { useCallback, useContext, useMemo, useState } from \"react\";\n\nimport { PancakeContext } from \"./provider.js\";\n\nimport type {\n CancelSubscriptionParams,\n CancelSubscriptionResult,\n CancelOnetimeOrderParams,\n CancelOnetimeOrderResult,\n ReactivateSubscriptionParams,\n ReactivateSubscriptionResult,\n CreateRefundTicketParams,\n ResubmitRefundTicketParams,\n RefundTicket,\n GraphQLParams,\n GraphQLResponse,\n} from \"@waffo/pancake-ts\";\n\n/** State of an async customer action */\nexport interface CustomerActionState<T = unknown> {\n /** Execute the action */\n execute: (params: T) => Promise<void>;\n /** Whether the action is in progress */\n isLoading: boolean;\n /** Error from the last attempt */\n error: Error | null;\n}\n\n/** Return type of useCustomer hook */\nexport interface UseCustomerReturn {\n /** Cancel a subscription order */\n cancelSubscription: CustomerActionState<CancelSubscriptionParams> & { data: CancelSubscriptionResult | null };\n /** Cancel a one-time order */\n cancelOnetimeOrder: CustomerActionState<CancelOnetimeOrderParams> & { data: CancelOnetimeOrderResult | null };\n /** Reactivate a canceling subscription */\n reactivateSubscription: CustomerActionState<ReactivateSubscriptionParams> & { data: ReactivateSubscriptionResult | null };\n /** Create a refund ticket */\n createRefundTicket: CustomerActionState<CreateRefundTicketParams> & { data: RefundTicket | null };\n /** Resubmit a rejected refund ticket */\n resubmitRefundTicket: CustomerActionState<ResubmitRefundTicketParams> & { data: RefundTicket | null };\n /** Execute a GraphQL query */\n query: <T = Record<string, unknown>>(params: GraphQLParams) => Promise<GraphQLResponse<T>>;\n}\n\nfunction useCustomerAction<TParams, TResult>(\n actionFn: (params: TParams) => Promise<TResult>,\n): CustomerActionState<TParams> & { data: TResult | null } {\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [data, setData] = useState<TResult | null>(null);\n\n const execute = useCallback(\n async (params: TParams) => {\n setIsLoading(true);\n setError(null);\n try {\n const result = await actionFn(params);\n setData(result);\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n throw err;\n } finally {\n setIsLoading(false);\n }\n },\n [actionFn],\n );\n\n return { execute, isLoading, error, data };\n}\n\n/**\n * React hook for customer self-service actions.\n *\n * Must be used within `<WaffoPancakeProvider>`. All operations are executed\n * via server actions — the private key never leaves the server.\n *\n * @returns Customer action handlers with loading/error states\n *\n * @example\n * ```tsx\n * function AccountPage() {\n * const customer = useCustomer();\n * return (\n * <button onClick={() => customer.cancelSubscription.execute({ orderId: \"ORD_xxx\" })}>\n * Cancel\n * </button>\n * );\n * }\n * ```\n */\nexport function useCustomer(): UseCustomerReturn {\n const ctx = useContext(PancakeContext);\n if (!ctx) throw new Error(\"useCustomer: must be used within <WaffoPancakeProvider>\");\n\n const { getCustomerToken, customerSessionAction } = ctx;\n\n const callAction = useCallback(\n async (actionType: string, params: unknown) => {\n const token = await getCustomerToken();\n return customerSessionAction(token, actionType as never, params);\n },\n [getCustomerToken, customerSessionAction],\n );\n\n const cancelSubscription = useCustomerAction<CancelSubscriptionParams, CancelSubscriptionResult>(\n useCallback((params) => callAction(\"cancelSubscription\", params) as Promise<CancelSubscriptionResult>, [callAction]),\n );\n\n const cancelOnetimeOrder = useCustomerAction<CancelOnetimeOrderParams, CancelOnetimeOrderResult>(\n useCallback((params) => callAction(\"cancelOnetimeOrder\", params) as Promise<CancelOnetimeOrderResult>, [callAction]),\n );\n\n const reactivateSubscription = useCustomerAction<ReactivateSubscriptionParams, ReactivateSubscriptionResult>(\n useCallback((params) => callAction(\"reactivateSubscription\", params) as Promise<ReactivateSubscriptionResult>, [callAction]),\n );\n\n const createRefundTicket = useCustomerAction<CreateRefundTicketParams, { ticket: RefundTicket }>(\n useCallback((params) => callAction(\"createRefundTicket\", params) as Promise<{ ticket: RefundTicket }>, [callAction]),\n );\n const createRefundTicketMapped = useMemo(\n () => ({ ...createRefundTicket, data: createRefundTicket.data?.ticket ?? null }),\n [createRefundTicket],\n );\n\n const resubmitRefundTicket = useCustomerAction<ResubmitRefundTicketParams, { ticket: RefundTicket }>(\n useCallback((params) => callAction(\"resubmitRefundTicket\", params) as Promise<{ ticket: RefundTicket }>, [callAction]),\n );\n const resubmitRefundTicketMapped = useMemo(\n () => ({ ...resubmitRefundTicket, data: resubmitRefundTicket.data?.ticket ?? null }),\n [resubmitRefundTicket],\n );\n\n const query = useCallback(\n async <T = Record<string, unknown>>(params: GraphQLParams) => {\n const token = await getCustomerToken();\n return customerSessionAction(token, \"query\", params) as Promise<GraphQLResponse<T>>;\n },\n [getCustomerToken, customerSessionAction],\n );\n\n return {\n cancelSubscription,\n cancelOnetimeOrder,\n reactivateSubscription,\n createRefundTicket: createRefundTicketMapped,\n resubmitRefundTicket: resubmitRefundTicketMapped,\n query,\n };\n}\n\n// ============================================================\n// Deprecated Aliases\n// ============================================================\n\n/** @deprecated Use {@link CustomerActionState} instead. */\nexport type BuyerActionState<T = unknown> = CustomerActionState<T>;\n\n/** @deprecated Use {@link UseCustomerReturn} instead. */\nexport type UseBuyerReturn = UseCustomerReturn;\n\n/** @deprecated Use {@link useCustomer} instead. */\nexport const useBuyer = useCustomer;\n","\"use client\";\n\nimport { useCallback, useContext } from \"react\";\n\nimport { PancakeContext } from \"./provider.js\";\nimport { useQuery } from \"./use-query.js\";\n\nimport type { QueryState } from \"./use-query.js\";\nimport type { GraphQLResponse, RefundTicketVersionData } from \"@waffo/pancake-ts\";\n\n// ============================================================\n// Types\n// ============================================================\n\n/** A customer's one-time order */\nexport interface CustomerOnetimeOrder {\n id: string;\n status: string;\n currency: string;\n buyerEmail: string;\n product: { id: string; name: string } | null;\n payments: Array<{ id: string; status: string; snapshotDisplayAmount: string; snapshotDisplayCurrency: string; createdAt: string }>;\n createdAt: string;\n}\n\n/** A customer's subscription order */\nexport interface CustomerSubscriptionOrder {\n id: string;\n status: string;\n currency: string;\n buyerEmail: string;\n currentPeriodStart: string | null;\n currentPeriodEnd: string | null;\n cancelAt: string | null;\n product: { id: string; name: string; billingPeriod: string } | null;\n payments: Array<{ id: string; status: string; snapshotDisplayAmount: string; snapshotDisplayCurrency: string; createdAt: string }>;\n createdAt: string;\n}\n\n/** A customer's payment record */\nexport interface CustomerPayment {\n id: string;\n orderId: string;\n status: string;\n snapshotDisplayAmount: string;\n snapshotDisplayCurrency: string;\n failureReason: string | null;\n createdAt: string;\n}\n\n/**\n * A customer's refund ticket.\n *\n * Ticket-level fields are flat; per-version fields (`reason`, `requestedAmount`)\n * live under `versionData` because the customer can resubmit a rejected ticket and\n * each submission is a versioned record. `versionData` reflects the current\n * (latest) version. The `versionData` shape is shared with `@waffo/pancake-ts`'s\n * `RefundTicketVersionData`.\n */\nexport interface CustomerRefundTicket {\n id: string;\n status: string;\n versionNumber: number | null;\n versionData: RefundTicketVersionData | null;\n createdAt: string;\n}\n\n// ============================================================\n// Queries\n// ============================================================\n\nconst CUSTOMER_ORDERS_QUERY = `query {\n onetimeOrders(limit: 50) {\n id status currency buyerEmail createdAt\n product { id name }\n payments { id status snapshotDisplayAmount snapshotDisplayCurrency createdAt }\n }\n subscriptionOrders(limit: 50) {\n id status currency buyerEmail currentPeriodStart currentPeriodEnd cancelAt createdAt\n product { id name billingPeriod }\n payments { id status snapshotDisplayAmount snapshotDisplayCurrency createdAt }\n }\n}`;\n\nconst CUSTOMER_PAYMENTS_QUERY = `query {\n payments(limit: 50) {\n id orderId status snapshotDisplayAmount snapshotDisplayCurrency failureReason createdAt\n }\n}`;\n\nconst CUSTOMER_REFUND_TICKETS_QUERY = `query {\n refundTickets(limit: 50) {\n id status versionNumber\n versionData {\n reason\n requestedAmount { amount currency }\n }\n createdAt\n }\n}`;\n\n// ============================================================\n// Internal helper\n// ============================================================\n\nfunction useCustomerQuery<T>(query: string): QueryState<T> {\n const ctx = useContext(PancakeContext);\n if (!ctx) throw new Error(\"Customer data hook: must be used within <WaffoPancakeProvider>\");\n\n const { getCustomerToken, customerSessionAction, isCustomerReady } = ctx;\n\n const queryFn = useCallback(async () => {\n const token = await getCustomerToken();\n const result = (await customerSessionAction(token, \"query\", { query })) as unknown as GraphQLResponse<T>;\n return result.data as T;\n }, [getCustomerToken, customerSessionAction, query]);\n\n return useQuery(queryFn, isCustomerReady);\n}\n\n// ============================================================\n// Hooks\n// ============================================================\n\ninterface CustomerOrdersData {\n onetimeOrders: CustomerOnetimeOrder[];\n subscriptionOrders: CustomerSubscriptionOrder[];\n}\n\n/**\n * Fetch the customer's order history (one-time + subscription).\n *\n * Must be used within `<WaffoPancakeProvider>`. Token is auto-managed.\n *\n * @returns Orders with product info and payment history\n *\n * @example\n * ```tsx\n * const { data, isLoading, refetch } = useCustomerOrders();\n * // data.onetimeOrders + data.subscriptionOrders\n * ```\n */\nexport function useCustomerOrders(): QueryState<CustomerOrdersData> {\n return useCustomerQuery<CustomerOrdersData>(CUSTOMER_ORDERS_QUERY);\n}\n\n/**\n * Fetch the customer's payment history.\n *\n * Must be used within `<WaffoPancakeProvider>`. Token is auto-managed.\n *\n * @returns Payment records with amounts and status\n *\n * @example\n * ```tsx\n * const { data: payments, isLoading } = useCustomerPayments();\n * ```\n */\nexport function useCustomerPayments(): QueryState<CustomerPayment[]> {\n const result = useCustomerQuery<{ payments: CustomerPayment[] }>(CUSTOMER_PAYMENTS_QUERY);\n return { ...result, data: result.data?.payments ?? null };\n}\n\n/**\n * Fetch the customer's refund tickets.\n *\n * Must be used within `<WaffoPancakeProvider>`. Token is auto-managed.\n *\n * @returns Refund tickets with status and requested amounts\n *\n * @example\n * ```tsx\n * const { data: tickets, isLoading } = useCustomerRefundTickets();\n * ```\n */\nexport function useCustomerRefundTickets(): QueryState<CustomerRefundTicket[]> {\n const result = useCustomerQuery<{ refundTickets: CustomerRefundTicket[] }>(CUSTOMER_REFUND_TICKETS_QUERY);\n return { ...result, data: result.data?.refundTickets ?? null };\n}\n\n// ============================================================\n// Deprecated Aliases\n// ============================================================\n\n/** @deprecated Use {@link CustomerOnetimeOrder} instead. */\nexport type BuyerOnetimeOrder = CustomerOnetimeOrder;\n\n/** @deprecated Use {@link CustomerSubscriptionOrder} instead. */\nexport type BuyerSubscriptionOrder = CustomerSubscriptionOrder;\n\n/** @deprecated Use {@link CustomerPayment} instead. */\nexport type BuyerPayment = CustomerPayment;\n\n/** @deprecated Use {@link CustomerRefundTicket} instead. */\nexport type BuyerRefundTicket = CustomerRefundTicket;\n\n/** @deprecated Use {@link useCustomerOrders} instead. */\nexport const useBuyerOrders = useCustomerOrders;\n\n/** @deprecated Use {@link useCustomerPayments} instead. */\nexport const useBuyerPayments = useCustomerPayments;\n\n/** @deprecated Use {@link useCustomerRefundTickets} instead. */\nexport const useBuyerRefundTickets = useCustomerRefundTickets;\n","\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\n\n/** Query state with typed data */\nexport interface QueryState<T> {\n data: T | null;\n isLoading: boolean;\n error: Error | null;\n refetch: () => void;\n}\n\n/**\n * Internal hook for async data fetching with loading/error state.\n *\n * @param queryFn - Async function that returns the data\n * @param ready - Whether to start fetching (false = wait)\n * @returns Query state with data, loading, error, and refetch\n */\nexport function useQuery<T>(queryFn: () => Promise<T>, ready: boolean): QueryState<T> {\n const [data, setData] = useState<T | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetch = useCallback(() => {\n if (!ready) return;\n setIsLoading(true);\n setError(null);\n queryFn()\n .then(setData)\n .catch((err) => setError(err instanceof Error ? err : new Error(String(err))))\n .finally(() => setIsLoading(false));\n }, [queryFn, ready]);\n\n useEffect(() => {\n fetch();\n }, [fetch]);\n\n return { data, isLoading, error, refetch: fetch };\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\n\nimport { useQuery } from \"./use-query.js\";\n\nimport type { MerchantQueryAction } from \"./server.js\";\nimport type { QueryState } from \"./use-query.js\";\nimport type { GraphQLResponse } from \"@waffo/pancake-ts\";\n\n// ============================================================\n// Merchant Data Hooks (via server action)\n// ============================================================\n\n/** A merchant's recent order (one-time or subscription) */\nexport interface MerchantOrder {\n id: string;\n status: string;\n currency: string;\n buyerEmail: string;\n testMode: boolean;\n product: { id: string; name: string } | null;\n payments: Array<{ id: string; status: string; snapshotDisplayAmount: string; snapshotDisplayCurrency: string }>;\n createdAt: string;\n}\n\n/**\n * Sales overview statistics.\n *\n * Monetary fields (`totalRevenue`, `revenueByPeriod[].amount`) are returned as\n * display-formatted strings (e.g., `\"9.99\"`), not minor-currency-unit integers.\n * The conversion happens server-side via the GraphQL `currencyDisplayLoader`.\n */\nexport interface SalesOverview {\n totalOrders: number;\n /** Total succeeded payment revenue as display string (e.g., `\"1234.56\"`) */\n totalRevenue: string;\n totalCustomers: number;\n currency: string;\n ordersByStatus: Array<{ status: string; count: number }>;\n /** Revenue by period; `amount` is a display string (e.g., `\"9.99\"`) */\n revenueByPeriod: Array<{ period: string; amount: string }>;\n}\n\n/** Subscription overview */\nexport interface SubscriptionOverview {\n activeCount: number;\n cancelingCount: number;\n pastDueCount: number;\n totalCount: number;\n subscriptions: MerchantSubscription[];\n}\n\n/** A merchant's subscription with status details */\nexport interface MerchantSubscription {\n id: string;\n status: string;\n currency: string;\n buyerEmail: string;\n currentPeriodStart: string | null;\n currentPeriodEnd: string | null;\n cancelAt: string | null;\n product: { id: string; name: string; billingPeriod: string } | null;\n createdAt: string;\n}\n\nexport interface MerchantOrdersOptions {\n /** Store ID to filter by */\n storeId: string;\n /** Max results (default: 20) */\n limit?: number;\n}\n\nconst MERCHANT_ORDERS_QUERY = `query ($storeId: ID!, $limit: Int) {\n onetimeOrders(storeId: $storeId, limit: $limit) {\n id status currency buyerEmail testMode createdAt\n product { id name }\n payments { id status snapshotDisplayAmount snapshotDisplayCurrency }\n }\n subscriptionOrders(storeId: $storeId, limit: $limit) {\n id status currency buyerEmail testMode createdAt\n product { id name }\n payments { id status snapshotDisplayAmount snapshotDisplayCurrency }\n }\n}`;\n\n/**\n * Fetch recent orders for a store (one-time + subscription).\n *\n * @param query - Server action from `createMerchantQueryAction()`\n * @param options - Store ID and optional limit\n * @returns Recent orders with product info and payment summary\n *\n * @example\n * ```tsx\n * const { data, isLoading, refetch } = useMerchantOrders(merchantQuery, { storeId: \"STO_xxx\" });\n * ```\n */\nexport function useMerchantOrders(\n query: MerchantQueryAction,\n options: MerchantOrdersOptions,\n): QueryState<{ onetimeOrders: MerchantOrder[]; subscriptionOrders: MerchantOrder[] }> {\n const { storeId, limit = 20 } = options;\n\n const queryFn = useCallback(async () => {\n const result = (await query({\n query: MERCHANT_ORDERS_QUERY,\n variables: { storeId, limit },\n })) as unknown as GraphQLResponse<{ onetimeOrders: MerchantOrder[]; subscriptionOrders: MerchantOrder[] }>;\n return result.data as { onetimeOrders: MerchantOrder[]; subscriptionOrders: MerchantOrder[] };\n }, [query, storeId, limit]);\n\n return useQuery(queryFn, true);\n}\n\nconst MERCHANT_SALES_QUERY = `query ($storeId: ID!) {\n orderStatistics(storeId: $storeId) {\n totalCount\n countByStatus { status count }\n }\n paymentStatistics(storeId: $storeId) {\n totalSucceededAmount\n totalSucceededCurrency\n totalSucceededCount\n }\n customerAnalysis(storeId: $storeId) {\n totalCustomers\n }\n trendAnalysis(storeId: $storeId) {\n revenueByPeriod { period amount }\n }\n}`;\n\ninterface SalesQueryData {\n orderStatistics: { totalCount: number; countByStatus: Array<{ status: string; count: number }> };\n paymentStatistics: { totalSucceededAmount: string; totalSucceededCurrency: string; totalSucceededCount: number };\n customerAnalysis: { totalCustomers: number };\n trendAnalysis: { revenueByPeriod: Array<{ period: string; amount: string }> };\n}\n\n/**\n * Fetch sales overview for a store.\n *\n * @param query - Server action from `createMerchantQueryAction()`\n * @param storeId - Store ID\n * @returns Aggregated sales statistics\n *\n * @example\n * ```tsx\n * const { data: sales } = useMerchantSales(merchantQuery, \"STO_xxx\");\n * ```\n */\nexport function useMerchantSales(query: MerchantQueryAction, storeId: string): QueryState<SalesOverview> {\n const queryFn = useCallback(async () => {\n const result = (await query({\n query: MERCHANT_SALES_QUERY,\n variables: { storeId },\n })) as unknown as GraphQLResponse<SalesQueryData>;\n const d = result.data as SalesQueryData;\n return {\n totalOrders: d.orderStatistics.totalCount,\n totalRevenue: d.paymentStatistics.totalSucceededAmount,\n totalCustomers: d.customerAnalysis.totalCustomers,\n currency: d.paymentStatistics.totalSucceededCurrency,\n ordersByStatus: d.orderStatistics.countByStatus,\n revenueByPeriod: d.trendAnalysis.revenueByPeriod,\n };\n }, [query, storeId]);\n\n return useQuery(queryFn, true);\n}\n\nconst MERCHANT_SUBSCRIPTIONS_QUERY = `query ($storeId: ID!) {\n subscriptionOrders(storeId: $storeId, limit: 100) {\n id status currency buyerEmail currentPeriodStart currentPeriodEnd cancelAt createdAt\n product { id name billingPeriod }\n }\n}`;\n\n/**\n * Fetch subscription overview for a store.\n *\n * @param query - Server action from `createMerchantQueryAction()`\n * @param storeId - Store ID\n * @returns Subscription counts and detailed list\n *\n * @example\n * ```tsx\n * const { data: subs } = useMerchantSubscriptions(merchantQuery, \"STO_xxx\");\n * ```\n */\nexport function useMerchantSubscriptions(query: MerchantQueryAction, storeId: string): QueryState<SubscriptionOverview> {\n const queryFn = useCallback(async () => {\n const result = (await query({\n query: MERCHANT_SUBSCRIPTIONS_QUERY,\n variables: { storeId },\n })) as unknown as GraphQLResponse<{ subscriptionOrders: MerchantSubscription[] }>;\n const subs = (result.data as { subscriptionOrders: MerchantSubscription[] }).subscriptionOrders;\n return {\n activeCount: subs.filter((s) => s.status === \"active\").length,\n cancelingCount: subs.filter((s) => s.status === \"canceling\").length,\n pastDueCount: subs.filter((s) => s.status === \"past_due\").length,\n totalCount: subs.length,\n subscriptions: subs,\n };\n }, [query, storeId]);\n\n return useQuery(queryFn, true);\n}\n","import { verifyWebhook } from \"@waffo/pancake-ts\";\n\nimport type { VerifyWebhookOptions, WebhookEvent, WebhookEventData } from \"@waffo/pancake-ts\";\n\n/** Handler function for a specific webhook event */\ntype EventHandler<T = WebhookEventData> = (event: WebhookEvent<T>) => void | Promise<void>;\n\n/** Configuration for the Webhook route handler factory */\nexport interface WebhookConfig {\n /** Webhook signature verification options (environment, publicKey, tolerance, etc.) */\n verifyOptions?: VerifyWebhookOptions;\n\n /** Catch-all handler — called for every event regardless of type */\n onPayload?: EventHandler;\n\n /** One-time order first payment succeeded */\n onOrderCompleted?: EventHandler;\n /** Subscription first payment succeeded (newly activated) */\n onSubscriptionActivated?: EventHandler;\n /** Subscription payment succeeded — a pure payment event, carries no subscription period or status */\n onSubscriptionPaymentSucceeded?: EventHandler;\n /** Current billing period rolled forward (renewal) */\n onSubscriptionRenewed?: EventHandler;\n /** Subscription recovered from past due (a retried charge succeeded) */\n onSubscriptionRecovered?: EventHandler;\n /** Plan change took effect (upgrade/downgrade) */\n onSubscriptionPlanChanged?: EventHandler;\n /** Plan change confirmed, takes effect next billing period */\n onSubscriptionPlanChangeScheduled?: EventHandler;\n /** Plan change did not complete, the current plan stays in effect */\n onSubscriptionPlanChangeFailed?: EventHandler;\n /** Customer initiated cancellation (expires at end of current period) */\n onSubscriptionCanceling?: EventHandler;\n /** Customer withdrew cancellation (subscription restored) */\n onSubscriptionUncanceled?: EventHandler;\n /** Subscription fully terminated */\n onSubscriptionCanceled?: EventHandler;\n /** Renewal payment failed (past due) */\n onSubscriptionPastDue?: EventHandler;\n /** Refund succeeded */\n onRefundSucceeded?: EventHandler;\n /** Refund failed */\n onRefundFailed?: EventHandler;\n}\n\n/* eslint-disable @typescript-eslint/naming-convention -- event type keys use dot notation */\nconst EVENT_HANDLER_MAP: Record<string, keyof WebhookConfig> = {\n \"order.completed\": \"onOrderCompleted\",\n \"subscription.activated\": \"onSubscriptionActivated\",\n \"subscription.payment_succeeded\": \"onSubscriptionPaymentSucceeded\",\n \"subscription.renewed\": \"onSubscriptionRenewed\",\n \"subscription.recovered\": \"onSubscriptionRecovered\",\n \"subscription.plan_changed\": \"onSubscriptionPlanChanged\",\n \"subscription.plan_change_scheduled\": \"onSubscriptionPlanChangeScheduled\",\n \"subscription.plan_change_failed\": \"onSubscriptionPlanChangeFailed\",\n \"subscription.canceling\": \"onSubscriptionCanceling\",\n \"subscription.uncanceled\": \"onSubscriptionUncanceled\",\n \"subscription.canceled\": \"onSubscriptionCanceled\",\n \"subscription.past_due\": \"onSubscriptionPastDue\",\n \"refund.succeeded\": \"onRefundSucceeded\",\n \"refund.failed\": \"onRefundFailed\",\n};\n/* eslint-enable @typescript-eslint/naming-convention */\n\n/**\n * Create a Next.js POST route handler for Waffo Pancake webhooks.\n *\n * Automatically verifies the webhook signature using `@waffo/pancake-ts`,\n * then dispatches to the matching event handler.\n *\n * @param config - Verification options and event handlers\n * @returns A Next.js POST route handler\n *\n * @example\n * ```ts\n * // app/api/webhooks/waffo/route.ts\n * import { Webhook } from \"@waffo/pancake-nextjs\";\n *\n * export const POST = Webhook({\n * verifyOptions: { environment: \"prod\" },\n * onOrderCompleted: async (event) => {\n * console.log(\"Order completed:\", event.data.orderId);\n * // Grant access to the product\n * },\n * onSubscriptionActivated: async (event) => {\n * console.log(\"Subscription activated:\", event.data.orderId);\n * },\n * onRefundSucceeded: async (event) => {\n * console.log(\"Refund succeeded:\", event.data.refundId);\n * // Revoke access\n * },\n * });\n * ```\n */\nexport function Webhook(config: WebhookConfig) {\n return async function POST(request: Request): Promise<Response> {\n const payload = await request.text();\n const signature = request.headers.get(\"x-waffo-signature\");\n\n let event: WebhookEvent;\n try {\n event = verifyWebhook(payload, signature, config.verifyOptions);\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Webhook verification failed\";\n return new Response(JSON.stringify({ error: message }), {\n status: 401,\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n try {\n // Catch-all handler\n if (config.onPayload) {\n await config.onPayload(event);\n }\n\n // Event-specific handler\n const handlerKey = EVENT_HANDLER_MAP[event.eventType];\n if (handlerKey) {\n const handler = config[handlerKey] as EventHandler | undefined;\n if (handler) {\n await handler(event);\n }\n }\n\n return new Response(JSON.stringify({ received: true }), {\n status: 200,\n headers: { \"Content-Type\": \"application/json\" },\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Webhook handler error\";\n return new Response(JSON.stringify({ error: message }), {\n status: 500,\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n };\n}\n","export { WaffoPancakeProvider } from \"./provider.js\";\nexport { CheckoutButton } from \"./checkout-button.js\";\nexport { useCheckout } from \"./use-checkout.js\";\nexport { useCustomer, useBuyer } from \"./use-customer.js\";\nexport {\n useCustomerOrders,\n useCustomerPayments,\n useCustomerRefundTickets,\n useBuyerOrders,\n useBuyerPayments,\n useBuyerRefundTickets,\n} from \"./use-customer-data.js\";\nexport { useMerchantOrders, useMerchantSales, useMerchantSubscriptions } from \"./use-merchant-data.js\";\nexport { Webhook } from \"./webhook.js\";\n\n// Re-export types commonly used in client components\nexport { WaffoPancakeError, TaxCategory, WebhookEventType } from \"@waffo/pancake-ts\";\n\nexport type {\n PriceInfo,\n PriceSnapshot,\n BillingDetail,\n RequestedAmount,\n RefundTicketVersionData,\n WebhookEvent,\n WebhookEventData,\n CashierLanguage,\n PaymentMethod,\n} from \"@waffo/pancake-ts\";\n\n// Local types\nexport type {\n CheckoutMode,\n CheckoutBaseOptions,\n LinkCheckoutProps,\n AnonymousCheckoutProps,\n AuthenticatedCheckoutProps,\n CheckoutProps,\n UseCheckoutReturn,\n} from \"./types.js\";\n\nexport type { CustomerConfig, BuyerConfig, WaffoPancakeProviderProps } from \"./provider.js\";\n\nexport type {\n CheckoutButtonProps,\n LinkCheckoutButtonProps,\n AnonymousCheckoutButtonProps,\n AuthenticatedCheckoutButtonProps,\n} from \"./checkout-button.js\";\n\nexport type { CustomerActionState, UseCustomerReturn, BuyerActionState, UseBuyerReturn } from \"./use-customer.js\";\n\nexport type { QueryState } from \"./use-query.js\";\n\nexport type {\n CustomerOnetimeOrder,\n CustomerSubscriptionOrder,\n CustomerPayment,\n CustomerRefundTicket,\n BuyerOnetimeOrder,\n BuyerSubscriptionOrder,\n BuyerPayment,\n BuyerRefundTicket,\n} from \"./use-customer-data.js\";\n\nexport type {\n MerchantOrder,\n MerchantSubscription,\n SalesOverview,\n SubscriptionOverview,\n MerchantOrdersOptions,\n} from \"./use-merchant-data.js\";\n\nexport type { WebhookConfig } from \"./webhook.js\";\n\n// Server action types (for typing the action prop)\nexport type {\n CheckoutAction,\n CheckoutActionParams,\n CheckoutActionResult,\n CustomerTokenAction,\n CustomerSessionAction,\n BuyerTokenAction,\n BuyerSessionAction,\n MerchantQueryAction,\n} from \"./server.js\";\n"],"mappings":"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","names":["useCallback","useRef","useState","jsx","useCallback","useContext","useMemo","useState","useState","useCallback","useContext","useMemo","useCallback","useContext","useCallback","useEffect","useState","useContext","useCallback","useCallback","useCallback"]}
1
+ {"version":3,"sources":["../src/provider.tsx","../src/use-checkout.ts","../src/checkout-button.tsx","../src/use-customer.ts","../src/use-customer-data.ts","../src/use-query.ts","../src/use-merchant-data.ts","../src/webhook.ts","../src/index.ts"],"sourcesContent":["\"use client\";\n\nimport React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport type { CustomerTokenAction, CustomerSessionAction } from \"./server.js\";\n\n/** Customer configuration for automatic token management */\nexport interface CustomerConfig {\n /** Customer identity (email or merchant-provided identifier) */\n identity: string;\n /** Store ID (optional when `productId` is provided) */\n storeId?: string;\n /** Product ID — used to derive the store when `storeId` is omitted */\n productId?: string;\n /** Server action for issuing tokens — from `createCustomerTokenAction()` */\n issueToken: CustomerTokenAction;\n /** Server action for customer operations — from `createCustomerSessionAction()` */\n sessionAction: CustomerSessionAction;\n}\n\n/** @deprecated Use {@link CustomerConfig} instead. */\nexport type BuyerConfig = CustomerConfig;\n\ninterface TokenState {\n token: string;\n expiresAt: number;\n}\n\n/** @internal */\nexport interface PancakeContextValue {\n /** Get a valid customer token (auto-refreshes if expired) */\n getCustomerToken: () => Promise<string>;\n /** Execute a customer session operation via server action */\n customerSessionAction: CustomerSessionAction;\n /** Whether customer config is provided */\n hasCustomer: boolean;\n /** Whether the initial token is ready */\n isCustomerReady: boolean;\n}\n\n/** @internal Exported for direct useContext access in hooks */\nexport const PancakeContext = createContext<PancakeContextValue | null>(null);\n\n/** Token refresh buffer — refresh 30s before actual expiry */\nconst REFRESH_BUFFER_MS = 30_000;\n\nexport interface WaffoPancakeProviderProps {\n /** Customer configuration for automatic token management */\n customer?: CustomerConfig;\n /** @deprecated Use `customer` instead. */\n buyer?: CustomerConfig;\n children: React.ReactNode;\n}\n\n/**\n * Provider that manages customer token lifecycle via server actions.\n *\n * Auto-issues session tokens on mount and refreshes before expiry.\n * All customer hooks (`useCustomer`, `useCustomerOrders`, etc.) read from context.\n *\n * The private key never leaves the server — token issuance and customer\n * operations are delegated to server actions.\n *\n * @param props - Provider configuration\n * @param props.customer - Customer identity and server actions\n * @param props.buyer - Deprecated alias of `customer`\n * @param props.children - React children\n *\n * @example\n * ```tsx\n * // identity must match what you passed as `buyerIdentity` at checkout time —\n * // customer-portal lookups are keyed by merchant_provided_buyer_identity\n * <WaffoPancakeProvider customer={{\n * identity: user.id,\n * storeId: \"STO_xxx\",\n * issueToken, // from createCustomerTokenAction()\n * sessionAction, // from createCustomerSessionAction()\n * }}>\n * <App />\n * </WaffoPancakeProvider>\n * ```\n */\nexport function WaffoPancakeProvider({ customer, buyer, children }: WaffoPancakeProviderProps) {\n const config = customer ?? buyer;\n if (!config) throw new Error(\"WaffoPancakeProvider: the `customer` prop is required\");\n\n const tokenRef = useRef<TokenState | null>(null);\n const refreshPromiseRef = useRef<Promise<string> | null>(null);\n const [isCustomerReady, setIsCustomerReady] = useState(false);\n\n const refreshToken = useCallback(async (): Promise<string> => {\n const result = await config.issueToken({\n buyerIdentity: config.identity,\n storeId: config.storeId,\n productId: config.productId,\n });\n\n tokenRef.current = {\n token: result.token,\n expiresAt: new Date(result.expiresAt).getTime(),\n };\n\n return result.token;\n }, [config]);\n\n const getCustomerToken = useCallback(async (): Promise<string> => {\n const current = tokenRef.current;\n if (current && Date.now() < current.expiresAt - REFRESH_BUFFER_MS) {\n return current.token;\n }\n\n // Deduplicate concurrent refresh calls\n if (!refreshPromiseRef.current) {\n refreshPromiseRef.current = refreshToken().finally(() => {\n refreshPromiseRef.current = null;\n });\n }\n\n return refreshPromiseRef.current;\n }, [refreshToken]);\n\n // Issue initial token on mount\n useEffect(() => {\n refreshToken()\n .then(() => setIsCustomerReady(true))\n .catch(() => setIsCustomerReady(true));\n }, [refreshToken]);\n\n const value = useMemo<PancakeContextValue>(\n () => ({\n getCustomerToken,\n customerSessionAction: config.sessionAction,\n hasCustomer: true,\n isCustomerReady,\n }),\n [getCustomerToken, config.sessionAction, isCustomerReady],\n );\n\n return <PancakeContext.Provider value={value}>{children}</PancakeContext.Provider>;\n}\n\n/**\n * Access the Waffo Pancake context. Must be used within `<WaffoPancakeProvider>`.\n */\nexport function usePancakeContext(): PancakeContextValue {\n const ctx = useContext(PancakeContext);\n if (!ctx) throw new Error(\"usePancakeContext: must be used within <WaffoPancakeProvider>\");\n return ctx;\n}\n","\"use client\";\n\nimport { useCallback, useRef, useState } from \"react\";\n\nimport type { CheckoutProps, LinkCheckoutProps, UseCheckoutReturn } from \"./types.js\";\nimport type { CheckoutSessionResult, AuthenticatedCheckoutResult } from \"@waffo/pancake-ts\";\n\n\nconst LOADING_HTML = `<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Loading...</title><style>body{display:flex;align-items:center;justify-content:center;height:100vh;margin:0;font-family:system-ui,sans-serif;background:#f9fafb;color:#6b7280}@media(prefers-color-scheme:dark){body{background:#111827;color:#9ca3af}}</style></head><body><p>Redirecting to checkout...</p></body></html>`;\n\nconst DEFAULT_STOREFRONT_URL = \"https://pancake.waffo.ai\";\n\nconst SDK_FIELDS = new Set([\"action\", \"type\", \"mode\", \"popupLoadingUrl\", \"onSuccess\", \"onError\"]);\n\n/** Extract API checkout params from flattened props, removing SDK-specific fields */\nfunction extractApiParams(args: object): Record<string, unknown> {\n const params: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(args)) {\n if (!SDK_FIELDS.has(key)) params[key] = value;\n }\n return params;\n}\n\n/**\n * Build a product page URL for link checkout.\n */\nfunction buildLinkUrl(props: LinkCheckoutProps): string {\n const base = (props.baseUrl ?? DEFAULT_STOREFRONT_URL).replace(/\\/+$/, \"\");\n const url = new URL(`${base}/store/${props.storeSlug}/product/${props.productId}`);\n\n if (props.currency) url.searchParams.set(\"currency\", props.currency);\n if (props.email) url.searchParams.set(\"email\", props.email);\n if (props.successUrl) url.searchParams.set(\"success_url\", props.successUrl);\n if (props.test) url.searchParams.set(\"test\", \"true\");\n if (props.country) url.searchParams.set(\"country\", props.country);\n if (props.isBusiness) url.searchParams.set(\"is_business\", \"true\");\n\n return url.toString();\n}\n\n/**\n * React hook for triggering a Waffo Pancake checkout flow.\n *\n * Supports three checkout types:\n * - **link**: Builds a product page URL and navigates directly (no API call, synchronous)\n * - **anonymous**: Calls a server action to create a checkout session, then navigates\n * - **authenticated**: Calls a server action to create a session + token, then navigates\n *\n * The private key never leaves the server — anonymous and authenticated modes\n * use a server action created by `createCheckoutAction()`.\n *\n * @param args - Flattened checkout props\n * @returns `{ checkout, isLoading, error }`\n *\n * @example\n * ```tsx\n * // Link checkout — no server action needed\n * const { checkout } = useCheckout({\n * type: \"link\",\n * storeSlug: \"my-store\",\n * productId: \"PROD_xxx\",\n * currency: \"USD\",\n * });\n *\n * // Anonymous checkout — via server action\n * const { checkout, isLoading } = useCheckout({\n * action: checkout, // from createCheckoutAction()\n * productId: \"PROD_xxx\",\n * currency: \"USD\",\n * });\n * ```\n */\nexport function useCheckout(args: CheckoutProps): UseCheckoutReturn {\n const { mode = \"redirect\", popupLoadingUrl, onError } = args;\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const popupRef = useRef<Window | null>(null);\n\n const checkout = useCallback(() => {\n if (isLoading) return;\n\n // Link checkout — synchronous, no API call\n if (args.type === \"link\") {\n const url = buildLinkUrl(args);\n if (mode === \"popup\") {\n window.open(url, \"_blank\");\n } else {\n window.location.href = url;\n }\n return;\n }\n\n // Anonymous / Authenticated — server action\n if (mode === \"popup\") {\n const loadingUrl = popupLoadingUrl ?? `data:text/html;charset=utf-8,${encodeURIComponent(LOADING_HTML)}`;\n popupRef.current = window.open(loadingUrl, \"_blank\");\n }\n\n setIsLoading(true);\n setError(null);\n\n const { action } = args;\n const params = extractApiParams(args);\n const actionParams = args.type === \"authenticated\" ? { type: \"authenticated\" as const, ...params } : params;\n\n action(actionParams as unknown as Parameters<typeof action>[0])\n .then((result: CheckoutSessionResult | AuthenticatedCheckoutResult) => {\n if (mode === \"popup\" && popupRef.current) {\n popupRef.current.location.href = result.checkoutUrl;\n } else {\n window.location.href = result.checkoutUrl;\n }\n if (\"onSuccess\" in args && args.onSuccess) {\n (args.onSuccess as (r: CheckoutSessionResult | AuthenticatedCheckoutResult) => void)(result);\n }\n })\n .catch((err: Error) => {\n if (mode === \"popup\" && popupRef.current) {\n popupRef.current.close();\n popupRef.current = null;\n }\n setError(err);\n onError?.(err);\n })\n .finally(() => {\n setIsLoading(false);\n });\n }, [args, mode, popupLoadingUrl, onError, isLoading]);\n\n return { checkout, isLoading, error };\n}\n","\"use client\";\n\nimport React from \"react\";\n\nimport { useCheckout } from \"./use-checkout.js\";\n\nimport type { CheckoutProps, LinkCheckoutProps, AnonymousCheckoutProps, AuthenticatedCheckoutProps } from \"./types.js\";\n\ntype CheckoutButtonBaseProps = {\n /** Button content */\n children: React.ReactNode;\n /** Content shown while checkout session is being created */\n loadingChildren?: React.ReactNode;\n /** Additional class name */\n className?: string;\n /** Additional inline styles */\n style?: React.CSSProperties;\n /** Disabled state (merged with isLoading) */\n disabled?: boolean;\n} & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, \"onClick\" | \"disabled\" | \"children\">;\n\n/** Props for CheckoutButton — link mode */\nexport type LinkCheckoutButtonProps = CheckoutButtonBaseProps & LinkCheckoutProps;\n\n/** Props for CheckoutButton — anonymous mode */\nexport type AnonymousCheckoutButtonProps = CheckoutButtonBaseProps & AnonymousCheckoutProps;\n\n/** Props for CheckoutButton — authenticated mode */\nexport type AuthenticatedCheckoutButtonProps = CheckoutButtonBaseProps & AuthenticatedCheckoutProps;\n\nexport type CheckoutButtonProps = LinkCheckoutButtonProps | AnonymousCheckoutButtonProps | AuthenticatedCheckoutButtonProps;\n\n/**\n * A button that triggers a Waffo Pancake checkout flow on click.\n *\n * Three checkout types:\n * - **link**: Instant redirect to product page URL (no server action needed)\n * - **anonymous**: Calls server action to create session, then redirects\n * - **authenticated**: Calls server action to create session + token, then redirects\n *\n * The private key never leaves the server — anonymous and authenticated modes\n * use a server action created by `createCheckoutAction()`.\n *\n * @param props - Flattened checkout props, button content, and optional styling\n *\n * @example\n * ```tsx\n * // Link checkout — no server action needed\n * <CheckoutButton type=\"link\" storeSlug=\"my-store\" productId=\"PROD_xxx\" currency=\"USD\">\n * Buy Now\n * </CheckoutButton>\n *\n * // Anonymous checkout — via server action\n * <CheckoutButton action={checkout} productId=\"PROD_xxx\" currency=\"USD\">\n * Buy Now\n * </CheckoutButton>\n *\n * // Authenticated checkout — via server action\n * <CheckoutButton action={checkout} type=\"authenticated\" productId=\"PROD_xxx\" currency=\"USD\" buyerIdentity=\"userIdInYourSystem\" buyerEmail=\"user@example.com\">\n * Buy Now\n * </CheckoutButton>\n * ```\n */\nexport function CheckoutButton(props: CheckoutButtonProps) {\n const { children, loadingChildren, className, style, disabled, ...checkoutProps } = props;\n\n const { checkout, isLoading } = useCheckout(checkoutProps as CheckoutProps);\n\n return (\n <button type=\"button\" onClick={checkout} disabled={disabled || isLoading} className={className} style={style}>\n {isLoading ? (loadingChildren ?? children) : children}\n </button>\n );\n}\n","\"use client\";\n\nimport { useCallback, useContext, useMemo, useState } from \"react\";\n\nimport { PancakeContext } from \"./provider.js\";\n\nimport type {\n CancelSubscriptionParams,\n CancelSubscriptionResult,\n CancelOnetimeOrderParams,\n CancelOnetimeOrderResult,\n ReactivateSubscriptionParams,\n ReactivateSubscriptionResult,\n CreateRefundTicketParams,\n ResubmitRefundTicketParams,\n RefundTicket,\n GraphQLParams,\n GraphQLResponse,\n} from \"@waffo/pancake-ts\";\n\n/** State of an async customer action */\nexport interface CustomerActionState<T = unknown> {\n /** Execute the action */\n execute: (params: T) => Promise<void>;\n /** Whether the action is in progress */\n isLoading: boolean;\n /** Error from the last attempt */\n error: Error | null;\n}\n\n/** Return type of useCustomer hook */\nexport interface UseCustomerReturn {\n /** Cancel a subscription order */\n cancelSubscription: CustomerActionState<CancelSubscriptionParams> & { data: CancelSubscriptionResult | null };\n /** Cancel a one-time order */\n cancelOnetimeOrder: CustomerActionState<CancelOnetimeOrderParams> & { data: CancelOnetimeOrderResult | null };\n /** Reactivate a canceling subscription */\n reactivateSubscription: CustomerActionState<ReactivateSubscriptionParams> & { data: ReactivateSubscriptionResult | null };\n /** Create a refund ticket */\n createRefundTicket: CustomerActionState<CreateRefundTicketParams> & { data: RefundTicket | null };\n /** Resubmit a rejected refund ticket */\n resubmitRefundTicket: CustomerActionState<ResubmitRefundTicketParams> & { data: RefundTicket | null };\n /** Execute a GraphQL query */\n query: <T = Record<string, unknown>>(params: GraphQLParams) => Promise<GraphQLResponse<T>>;\n}\n\nfunction useCustomerAction<TParams, TResult>(\n actionFn: (params: TParams) => Promise<TResult>,\n): CustomerActionState<TParams> & { data: TResult | null } {\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [data, setData] = useState<TResult | null>(null);\n\n const execute = useCallback(\n async (params: TParams) => {\n setIsLoading(true);\n setError(null);\n try {\n const result = await actionFn(params);\n setData(result);\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n throw err;\n } finally {\n setIsLoading(false);\n }\n },\n [actionFn],\n );\n\n return { execute, isLoading, error, data };\n}\n\n/**\n * React hook for customer self-service actions.\n *\n * Must be used within `<WaffoPancakeProvider>`. All operations are executed\n * via server actions — the private key never leaves the server.\n *\n * @returns Customer action handlers with loading/error states\n *\n * @example\n * ```tsx\n * function AccountPage() {\n * const customer = useCustomer();\n * return (\n * <button onClick={() => customer.cancelSubscription.execute({ orderId: \"ORD_xxx\" })}>\n * Cancel\n * </button>\n * );\n * }\n * ```\n */\nexport function useCustomer(): UseCustomerReturn {\n const ctx = useContext(PancakeContext);\n if (!ctx) throw new Error(\"useCustomer: must be used within <WaffoPancakeProvider>\");\n\n const { getCustomerToken, customerSessionAction } = ctx;\n\n const callAction = useCallback(\n async (actionType: string, params: unknown) => {\n const token = await getCustomerToken();\n return customerSessionAction(token, actionType as never, params);\n },\n [getCustomerToken, customerSessionAction],\n );\n\n const cancelSubscription = useCustomerAction<CancelSubscriptionParams, CancelSubscriptionResult>(\n useCallback((params) => callAction(\"cancelSubscription\", params) as Promise<CancelSubscriptionResult>, [callAction]),\n );\n\n const cancelOnetimeOrder = useCustomerAction<CancelOnetimeOrderParams, CancelOnetimeOrderResult>(\n useCallback((params) => callAction(\"cancelOnetimeOrder\", params) as Promise<CancelOnetimeOrderResult>, [callAction]),\n );\n\n const reactivateSubscription = useCustomerAction<ReactivateSubscriptionParams, ReactivateSubscriptionResult>(\n useCallback((params) => callAction(\"reactivateSubscription\", params) as Promise<ReactivateSubscriptionResult>, [callAction]),\n );\n\n const createRefundTicket = useCustomerAction<CreateRefundTicketParams, { ticket: RefundTicket }>(\n useCallback((params) => callAction(\"createRefundTicket\", params) as Promise<{ ticket: RefundTicket }>, [callAction]),\n );\n const createRefundTicketMapped = useMemo(\n () => ({ ...createRefundTicket, data: createRefundTicket.data?.ticket ?? null }),\n [createRefundTicket],\n );\n\n const resubmitRefundTicket = useCustomerAction<ResubmitRefundTicketParams, { ticket: RefundTicket }>(\n useCallback((params) => callAction(\"resubmitRefundTicket\", params) as Promise<{ ticket: RefundTicket }>, [callAction]),\n );\n const resubmitRefundTicketMapped = useMemo(\n () => ({ ...resubmitRefundTicket, data: resubmitRefundTicket.data?.ticket ?? null }),\n [resubmitRefundTicket],\n );\n\n const query = useCallback(\n async <T = Record<string, unknown>>(params: GraphQLParams) => {\n const token = await getCustomerToken();\n return customerSessionAction(token, \"query\", params) as Promise<GraphQLResponse<T>>;\n },\n [getCustomerToken, customerSessionAction],\n );\n\n return {\n cancelSubscription,\n cancelOnetimeOrder,\n reactivateSubscription,\n createRefundTicket: createRefundTicketMapped,\n resubmitRefundTicket: resubmitRefundTicketMapped,\n query,\n };\n}\n\n// ============================================================\n// Deprecated Aliases\n// ============================================================\n\n/** @deprecated Use {@link CustomerActionState} instead. */\nexport type BuyerActionState<T = unknown> = CustomerActionState<T>;\n\n/** @deprecated Use {@link UseCustomerReturn} instead. */\nexport type UseBuyerReturn = UseCustomerReturn;\n\n/** @deprecated Use {@link useCustomer} instead. */\nexport const useBuyer = useCustomer;\n","\"use client\";\n\nimport { useCallback, useContext } from \"react\";\n\nimport { PancakeContext } from \"./provider.js\";\nimport { useQuery } from \"./use-query.js\";\n\nimport type { QueryState } from \"./use-query.js\";\nimport type { GraphQLResponse, RefundTicketVersionData } from \"@waffo/pancake-ts\";\n\n// ============================================================\n// Types\n// ============================================================\n\n/** A customer's one-time order */\nexport interface CustomerOnetimeOrder {\n id: string;\n status: string;\n currency: string;\n buyerEmail: string;\n product: { id: string; name: string } | null;\n payments: Array<{ id: string; status: string; snapshotDisplayAmount: string; snapshotDisplayCurrency: string; createdAt: string }>;\n createdAt: string;\n}\n\n/** A customer's subscription order */\nexport interface CustomerSubscriptionOrder {\n id: string;\n status: string;\n currency: string;\n buyerEmail: string;\n currentPeriodStart: string | null;\n currentPeriodEnd: string | null;\n cancelAt: string | null;\n product: { id: string; name: string; billingPeriod: string } | null;\n payments: Array<{ id: string; status: string; snapshotDisplayAmount: string; snapshotDisplayCurrency: string; createdAt: string }>;\n createdAt: string;\n}\n\n/** A customer's payment record */\nexport interface CustomerPayment {\n id: string;\n orderId: string;\n status: string;\n snapshotDisplayAmount: string;\n snapshotDisplayCurrency: string;\n failureReason: string | null;\n createdAt: string;\n}\n\n/**\n * A customer's refund ticket.\n *\n * Ticket-level fields are flat; per-version fields (`reason`, `requestedAmount`)\n * live under `versionData` because the customer can resubmit a rejected ticket and\n * each submission is a versioned record. `versionData` reflects the current\n * (latest) version. The `versionData` shape is shared with `@waffo/pancake-ts`'s\n * `RefundTicketVersionData`.\n */\nexport interface CustomerRefundTicket {\n id: string;\n status: string;\n versionNumber: number | null;\n versionData: RefundTicketVersionData | null;\n createdAt: string;\n}\n\n// ============================================================\n// Queries\n// ============================================================\n\nconst CUSTOMER_ORDERS_QUERY = `query {\n onetimeOrders(limit: 50) {\n id status currency buyerEmail createdAt\n product { id name }\n payments { id status snapshotDisplayAmount snapshotDisplayCurrency createdAt }\n }\n subscriptionOrders(limit: 50) {\n id status currency buyerEmail currentPeriodStart currentPeriodEnd cancelAt createdAt\n product { id name billingPeriod }\n payments { id status snapshotDisplayAmount snapshotDisplayCurrency createdAt }\n }\n}`;\n\nconst CUSTOMER_PAYMENTS_QUERY = `query {\n payments(limit: 50) {\n id orderId status snapshotDisplayAmount snapshotDisplayCurrency failureReason createdAt\n }\n}`;\n\nconst CUSTOMER_REFUND_TICKETS_QUERY = `query {\n refundTickets(limit: 50) {\n id status versionNumber\n versionData {\n reason\n requestedAmount { amount currency }\n }\n createdAt\n }\n}`;\n\n// ============================================================\n// Internal helper\n// ============================================================\n\nfunction useCustomerQuery<T>(query: string): QueryState<T> {\n const ctx = useContext(PancakeContext);\n if (!ctx) throw new Error(\"Customer data hook: must be used within <WaffoPancakeProvider>\");\n\n const { getCustomerToken, customerSessionAction, isCustomerReady } = ctx;\n\n const queryFn = useCallback(async () => {\n const token = await getCustomerToken();\n const result = (await customerSessionAction(token, \"query\", { query })) as unknown as GraphQLResponse<T>;\n return result.data as T;\n }, [getCustomerToken, customerSessionAction, query]);\n\n return useQuery(queryFn, isCustomerReady);\n}\n\n// ============================================================\n// Hooks\n// ============================================================\n\ninterface CustomerOrdersData {\n onetimeOrders: CustomerOnetimeOrder[];\n subscriptionOrders: CustomerSubscriptionOrder[];\n}\n\n/**\n * Fetch the customer's order history (one-time + subscription).\n *\n * Must be used within `<WaffoPancakeProvider>`. Token is auto-managed.\n *\n * @returns Orders with product info and payment history\n *\n * @example\n * ```tsx\n * const { data, isLoading, refetch } = useCustomerOrders();\n * // data.onetimeOrders + data.subscriptionOrders\n * ```\n */\nexport function useCustomerOrders(): QueryState<CustomerOrdersData> {\n return useCustomerQuery<CustomerOrdersData>(CUSTOMER_ORDERS_QUERY);\n}\n\n/**\n * Fetch the customer's payment history.\n *\n * Must be used within `<WaffoPancakeProvider>`. Token is auto-managed.\n *\n * @returns Payment records with amounts and status\n *\n * @example\n * ```tsx\n * const { data: payments, isLoading } = useCustomerPayments();\n * ```\n */\nexport function useCustomerPayments(): QueryState<CustomerPayment[]> {\n const result = useCustomerQuery<{ payments: CustomerPayment[] }>(CUSTOMER_PAYMENTS_QUERY);\n return { ...result, data: result.data?.payments ?? null };\n}\n\n/**\n * Fetch the customer's refund tickets.\n *\n * Must be used within `<WaffoPancakeProvider>`. Token is auto-managed.\n *\n * @returns Refund tickets with status and requested amounts\n *\n * @example\n * ```tsx\n * const { data: tickets, isLoading } = useCustomerRefundTickets();\n * ```\n */\nexport function useCustomerRefundTickets(): QueryState<CustomerRefundTicket[]> {\n const result = useCustomerQuery<{ refundTickets: CustomerRefundTicket[] }>(CUSTOMER_REFUND_TICKETS_QUERY);\n return { ...result, data: result.data?.refundTickets ?? null };\n}\n\n// ============================================================\n// Deprecated Aliases\n// ============================================================\n\n/** @deprecated Use {@link CustomerOnetimeOrder} instead. */\nexport type BuyerOnetimeOrder = CustomerOnetimeOrder;\n\n/** @deprecated Use {@link CustomerSubscriptionOrder} instead. */\nexport type BuyerSubscriptionOrder = CustomerSubscriptionOrder;\n\n/** @deprecated Use {@link CustomerPayment} instead. */\nexport type BuyerPayment = CustomerPayment;\n\n/** @deprecated Use {@link CustomerRefundTicket} instead. */\nexport type BuyerRefundTicket = CustomerRefundTicket;\n\n/** @deprecated Use {@link useCustomerOrders} instead. */\nexport const useBuyerOrders = useCustomerOrders;\n\n/** @deprecated Use {@link useCustomerPayments} instead. */\nexport const useBuyerPayments = useCustomerPayments;\n\n/** @deprecated Use {@link useCustomerRefundTickets} instead. */\nexport const useBuyerRefundTickets = useCustomerRefundTickets;\n","\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\n\n/** Query state with typed data */\nexport interface QueryState<T> {\n data: T | null;\n isLoading: boolean;\n error: Error | null;\n refetch: () => void;\n}\n\n/**\n * Internal hook for async data fetching with loading/error state.\n *\n * @param queryFn - Async function that returns the data\n * @param ready - Whether to start fetching (false = wait)\n * @returns Query state with data, loading, error, and refetch\n */\nexport function useQuery<T>(queryFn: () => Promise<T>, ready: boolean): QueryState<T> {\n const [data, setData] = useState<T | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetch = useCallback(() => {\n if (!ready) return;\n setIsLoading(true);\n setError(null);\n queryFn()\n .then(setData)\n .catch((err) => setError(err instanceof Error ? err : new Error(String(err))))\n .finally(() => setIsLoading(false));\n }, [queryFn, ready]);\n\n useEffect(() => {\n fetch();\n }, [fetch]);\n\n return { data, isLoading, error, refetch: fetch };\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\n\nimport { useQuery } from \"./use-query.js\";\n\nimport type { MerchantQueryAction } from \"./server.js\";\nimport type { QueryState } from \"./use-query.js\";\nimport type { GraphQLResponse } from \"@waffo/pancake-ts\";\n\n// ============================================================\n// Merchant Data Hooks (via server action)\n// ============================================================\n\n/** A merchant's recent order (one-time or subscription) */\nexport interface MerchantOrder {\n id: string;\n status: string;\n currency: string;\n buyerEmail: string;\n testMode: boolean;\n product: { id: string; name: string } | null;\n payments: Array<{ id: string; status: string; snapshotDisplayAmount: string; snapshotDisplayCurrency: string }>;\n createdAt: string;\n}\n\n/**\n * Sales overview statistics.\n *\n * Monetary fields (`totalRevenue`, `revenueByPeriod[].amount`) are returned as\n * display-formatted strings (e.g., `\"9.99\"`), not minor-currency-unit integers.\n * The conversion happens server-side via the GraphQL `currencyDisplayLoader`.\n */\nexport interface SalesOverview {\n totalOrders: number;\n /** Total succeeded payment revenue as display string (e.g., `\"1234.56\"`) */\n totalRevenue: string;\n totalCustomers: number;\n currency: string;\n ordersByStatus: Array<{ status: string; count: number }>;\n /** Revenue by period; `amount` is a display string (e.g., `\"9.99\"`) */\n revenueByPeriod: Array<{ period: string; amount: string }>;\n}\n\n/** Subscription overview */\nexport interface SubscriptionOverview {\n activeCount: number;\n cancelingCount: number;\n pastDueCount: number;\n totalCount: number;\n subscriptions: MerchantSubscription[];\n}\n\n/** A merchant's subscription with status details */\nexport interface MerchantSubscription {\n id: string;\n status: string;\n currency: string;\n buyerEmail: string;\n currentPeriodStart: string | null;\n currentPeriodEnd: string | null;\n cancelAt: string | null;\n product: { id: string; name: string; billingPeriod: string } | null;\n createdAt: string;\n}\n\nexport interface MerchantOrdersOptions {\n /** Store ID to filter by */\n storeId: string;\n /** Max results (default: 20) */\n limit?: number;\n}\n\nconst MERCHANT_ORDERS_QUERY = `query ($storeId: ID!, $limit: Int) {\n onetimeOrders(storeId: $storeId, limit: $limit) {\n id status currency buyerEmail testMode createdAt\n product { id name }\n payments { id status snapshotDisplayAmount snapshotDisplayCurrency }\n }\n subscriptionOrders(storeId: $storeId, limit: $limit) {\n id status currency buyerEmail testMode createdAt\n product { id name }\n payments { id status snapshotDisplayAmount snapshotDisplayCurrency }\n }\n}`;\n\n/**\n * Fetch recent orders for a store (one-time + subscription).\n *\n * @param query - Server action from `createMerchantQueryAction()`\n * @param options - Store ID and optional limit\n * @returns Recent orders with product info and payment summary\n *\n * @example\n * ```tsx\n * const { data, isLoading, refetch } = useMerchantOrders(merchantQuery, { storeId: \"STO_xxx\" });\n * ```\n */\nexport function useMerchantOrders(\n query: MerchantQueryAction,\n options: MerchantOrdersOptions,\n): QueryState<{ onetimeOrders: MerchantOrder[]; subscriptionOrders: MerchantOrder[] }> {\n const { storeId, limit = 20 } = options;\n\n const queryFn = useCallback(async () => {\n const result = (await query({\n query: MERCHANT_ORDERS_QUERY,\n variables: { storeId, limit },\n })) as unknown as GraphQLResponse<{ onetimeOrders: MerchantOrder[]; subscriptionOrders: MerchantOrder[] }>;\n return result.data as { onetimeOrders: MerchantOrder[]; subscriptionOrders: MerchantOrder[] };\n }, [query, storeId, limit]);\n\n return useQuery(queryFn, true);\n}\n\nconst MERCHANT_SALES_QUERY = `query ($storeId: ID!) {\n orderStatistics(storeId: $storeId) {\n totalCount\n countByStatus { status count }\n }\n paymentStatistics(storeId: $storeId) {\n totalSucceededAmount\n totalSucceededCurrency\n totalSucceededCount\n }\n customerAnalysis(storeId: $storeId) {\n totalCustomers\n }\n trendAnalysis(storeId: $storeId) {\n revenueByPeriod { period amount }\n }\n}`;\n\ninterface SalesQueryData {\n orderStatistics: { totalCount: number; countByStatus: Array<{ status: string; count: number }> };\n paymentStatistics: { totalSucceededAmount: string; totalSucceededCurrency: string; totalSucceededCount: number };\n customerAnalysis: { totalCustomers: number };\n trendAnalysis: { revenueByPeriod: Array<{ period: string; amount: string }> };\n}\n\n/**\n * Fetch sales overview for a store.\n *\n * @param query - Server action from `createMerchantQueryAction()`\n * @param storeId - Store ID\n * @returns Aggregated sales statistics\n *\n * @example\n * ```tsx\n * const { data: sales } = useMerchantSales(merchantQuery, \"STO_xxx\");\n * ```\n */\nexport function useMerchantSales(query: MerchantQueryAction, storeId: string): QueryState<SalesOverview> {\n const queryFn = useCallback(async () => {\n const result = (await query({\n query: MERCHANT_SALES_QUERY,\n variables: { storeId },\n })) as unknown as GraphQLResponse<SalesQueryData>;\n const d = result.data as SalesQueryData;\n return {\n totalOrders: d.orderStatistics.totalCount,\n totalRevenue: d.paymentStatistics.totalSucceededAmount,\n totalCustomers: d.customerAnalysis.totalCustomers,\n currency: d.paymentStatistics.totalSucceededCurrency,\n ordersByStatus: d.orderStatistics.countByStatus,\n revenueByPeriod: d.trendAnalysis.revenueByPeriod,\n };\n }, [query, storeId]);\n\n return useQuery(queryFn, true);\n}\n\nconst MERCHANT_SUBSCRIPTIONS_QUERY = `query ($storeId: ID!) {\n subscriptionOrders(storeId: $storeId, limit: 100) {\n id status currency buyerEmail currentPeriodStart currentPeriodEnd cancelAt createdAt\n product { id name billingPeriod }\n }\n}`;\n\n/**\n * Fetch subscription overview for a store.\n *\n * @param query - Server action from `createMerchantQueryAction()`\n * @param storeId - Store ID\n * @returns Subscription counts and detailed list\n *\n * @example\n * ```tsx\n * const { data: subs } = useMerchantSubscriptions(merchantQuery, \"STO_xxx\");\n * ```\n */\nexport function useMerchantSubscriptions(query: MerchantQueryAction, storeId: string): QueryState<SubscriptionOverview> {\n const queryFn = useCallback(async () => {\n const result = (await query({\n query: MERCHANT_SUBSCRIPTIONS_QUERY,\n variables: { storeId },\n })) as unknown as GraphQLResponse<{ subscriptionOrders: MerchantSubscription[] }>;\n const subs = (result.data as { subscriptionOrders: MerchantSubscription[] }).subscriptionOrders;\n return {\n activeCount: subs.filter((s) => s.status === \"active\").length,\n cancelingCount: subs.filter((s) => s.status === \"canceling\").length,\n pastDueCount: subs.filter((s) => s.status === \"past_due\").length,\n totalCount: subs.length,\n subscriptions: subs,\n };\n }, [query, storeId]);\n\n return useQuery(queryFn, true);\n}\n","import { verifyWebhook } from \"@waffo/pancake-ts\";\n\nimport type { VerifyWebhookOptions, WebhookEvent, WebhookEventData } from \"@waffo/pancake-ts\";\n\n/** Handler function for a specific webhook event */\ntype EventHandler<T = WebhookEventData> = (event: WebhookEvent<T>) => void | Promise<void>;\n\n/** Configuration for the Webhook route handler factory */\nexport interface WebhookConfig {\n /** Webhook signature verification options (environment, publicKey, tolerance, etc.) */\n verifyOptions?: VerifyWebhookOptions;\n\n /** Catch-all handler — called for every event regardless of type */\n onPayload?: EventHandler;\n\n /** One-time order first payment succeeded */\n onOrderCompleted?: EventHandler;\n /** Subscription first payment succeeded (newly activated) */\n onSubscriptionActivated?: EventHandler;\n /** Subscription payment succeeded — a pure payment event, carries no subscription period or status */\n onSubscriptionPaymentSucceeded?: EventHandler;\n /** Current billing period rolled forward (renewal) */\n onSubscriptionRenewed?: EventHandler;\n /** Subscription recovered from past due (a retried charge succeeded) */\n onSubscriptionRecovered?: EventHandler;\n /** Plan change took effect (upgrade/downgrade) */\n onSubscriptionPlanChanged?: EventHandler;\n /** Plan change confirmed, takes effect next billing period */\n onSubscriptionPlanChangeScheduled?: EventHandler;\n /** Plan change did not complete, the current plan stays in effect */\n onSubscriptionPlanChangeFailed?: EventHandler;\n /** Customer initiated cancellation (expires at end of current period) */\n onSubscriptionCanceling?: EventHandler;\n /** Customer withdrew cancellation (subscription restored) */\n onSubscriptionUncanceled?: EventHandler;\n /** Subscription fully terminated */\n onSubscriptionCanceled?: EventHandler;\n /** Renewal payment failed (past due) */\n onSubscriptionPastDue?: EventHandler;\n /** Refund succeeded */\n onRefundSucceeded?: EventHandler;\n /** Refund failed */\n onRefundFailed?: EventHandler;\n}\n\n/* eslint-disable @typescript-eslint/naming-convention -- event type keys use dot notation */\nconst EVENT_HANDLER_MAP: Record<string, keyof WebhookConfig> = {\n \"order.completed\": \"onOrderCompleted\",\n \"subscription.activated\": \"onSubscriptionActivated\",\n \"subscription.payment_succeeded\": \"onSubscriptionPaymentSucceeded\",\n \"subscription.renewed\": \"onSubscriptionRenewed\",\n \"subscription.recovered\": \"onSubscriptionRecovered\",\n \"subscription.plan_changed\": \"onSubscriptionPlanChanged\",\n \"subscription.plan_change_scheduled\": \"onSubscriptionPlanChangeScheduled\",\n \"subscription.plan_change_failed\": \"onSubscriptionPlanChangeFailed\",\n \"subscription.canceling\": \"onSubscriptionCanceling\",\n \"subscription.uncanceled\": \"onSubscriptionUncanceled\",\n \"subscription.canceled\": \"onSubscriptionCanceled\",\n \"subscription.past_due\": \"onSubscriptionPastDue\",\n \"refund.succeeded\": \"onRefundSucceeded\",\n \"refund.failed\": \"onRefundFailed\",\n};\n/* eslint-enable @typescript-eslint/naming-convention */\n\n/**\n * Create a Next.js POST route handler for Waffo Pancake webhooks.\n *\n * Automatically verifies the webhook signature using `@waffo/pancake-ts`,\n * then dispatches to the matching event handler.\n *\n * @param config - Verification options and event handlers\n * @returns A Next.js POST route handler\n *\n * @example\n * ```ts\n * // app/api/webhooks/waffo/route.ts\n * import { Webhook } from \"@waffo/pancake-nextjs\";\n *\n * export const POST = Webhook({\n * verifyOptions: { environment: \"prod\" },\n * onOrderCompleted: async (event) => {\n * console.log(\"Order completed:\", event.data.orderId);\n * // Grant access to the product\n * },\n * onSubscriptionActivated: async (event) => {\n * console.log(\"Subscription activated:\", event.data.orderId);\n * },\n * onRefundSucceeded: async (event) => {\n * console.log(\"Refund succeeded:\", event.data.refundId);\n * // Revoke access\n * },\n * });\n * ```\n */\nexport function Webhook(config: WebhookConfig) {\n return async function POST(request: Request): Promise<Response> {\n const payload = await request.text();\n const signature = request.headers.get(\"x-waffo-signature\");\n\n let event: WebhookEvent;\n try {\n event = verifyWebhook(payload, signature, config.verifyOptions);\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Webhook verification failed\";\n return new Response(JSON.stringify({ error: message }), {\n status: 401,\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n try {\n // Catch-all handler\n if (config.onPayload) {\n await config.onPayload(event);\n }\n\n // Event-specific handler\n const handlerKey = EVENT_HANDLER_MAP[event.eventType];\n if (handlerKey) {\n const handler = config[handlerKey] as EventHandler | undefined;\n if (handler) {\n await handler(event);\n }\n }\n\n return new Response(JSON.stringify({ received: true }), {\n status: 200,\n headers: { \"Content-Type\": \"application/json\" },\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Webhook handler error\";\n return new Response(JSON.stringify({ error: message }), {\n status: 500,\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n };\n}\n","export { WaffoPancakeProvider } from \"./provider.js\";\nexport { CheckoutButton } from \"./checkout-button.js\";\nexport { useCheckout } from \"./use-checkout.js\";\nexport { useCustomer, useBuyer } from \"./use-customer.js\";\nexport {\n useCustomerOrders,\n useCustomerPayments,\n useCustomerRefundTickets,\n useBuyerOrders,\n useBuyerPayments,\n useBuyerRefundTickets,\n} from \"./use-customer-data.js\";\nexport { useMerchantOrders, useMerchantSales, useMerchantSubscriptions } from \"./use-merchant-data.js\";\nexport { Webhook } from \"./webhook.js\";\n\n// Re-export types commonly used in client components\nexport { WaffoPancakeError, ChangeTiming, TaxCategory, WebhookEventType } from \"@waffo/pancake-ts\";\n\nexport type {\n PriceInfo,\n PriceSnapshot,\n BillingDetail,\n RequestedAmount,\n RefundTicketVersionData,\n WebhookEvent,\n WebhookEventData,\n CashierLanguage,\n PaymentMethod,\n RequestOptions,\n} from \"@waffo/pancake-ts\";\n\n// Local types\nexport type {\n CheckoutMode,\n CheckoutBaseOptions,\n LinkCheckoutProps,\n AnonymousCheckoutProps,\n AuthenticatedCheckoutProps,\n CheckoutProps,\n UseCheckoutReturn,\n} from \"./types.js\";\n\nexport type { CustomerConfig, BuyerConfig, WaffoPancakeProviderProps } from \"./provider.js\";\n\nexport type {\n CheckoutButtonProps,\n LinkCheckoutButtonProps,\n AnonymousCheckoutButtonProps,\n AuthenticatedCheckoutButtonProps,\n} from \"./checkout-button.js\";\n\nexport type { CustomerActionState, UseCustomerReturn, BuyerActionState, UseBuyerReturn } from \"./use-customer.js\";\n\nexport type { QueryState } from \"./use-query.js\";\n\nexport type {\n CustomerOnetimeOrder,\n CustomerSubscriptionOrder,\n CustomerPayment,\n CustomerRefundTicket,\n BuyerOnetimeOrder,\n BuyerSubscriptionOrder,\n BuyerPayment,\n BuyerRefundTicket,\n} from \"./use-customer-data.js\";\n\nexport type {\n MerchantOrder,\n MerchantSubscription,\n SalesOverview,\n SubscriptionOverview,\n MerchantOrdersOptions,\n} from \"./use-merchant-data.js\";\n\nexport type { WebhookConfig } from \"./webhook.js\";\n\n// Server action types (for typing the action prop)\nexport type {\n CheckoutAction,\n CheckoutActionParams,\n CheckoutActionResult,\n CustomerTokenAction,\n CustomerSessionAction,\n BuyerTokenAction,\n BuyerSessionAction,\n MerchantQueryAction,\n} from \"./server.js\";\n"],"mappings":"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","names":["useCallback","useRef","useState","jsx","useCallback","useContext","useMemo","useState","useState","useCallback","useContext","useMemo","useCallback","useContext","useCallback","useEffect","useState","useContext","useCallback","useCallback","useCallback"]}
package/dist/server.cjs CHANGED
@@ -23,6 +23,7 @@ __export(server_exports, {
23
23
  createBuyerSessionAction: () => createBuyerSessionAction,
24
24
  createBuyerTokenAction: () => createBuyerTokenAction,
25
25
  createCheckoutAction: () => createCheckoutAction,
26
+ createCustomerPortalRedirect: () => createCustomerPortalRedirect,
26
27
  createCustomerSessionAction: () => createCustomerSessionAction,
27
28
  createCustomerTokenAction: () => createCustomerTokenAction,
28
29
  createMerchantQueryAction: () => createMerchantQueryAction
@@ -31,36 +32,95 @@ module.exports = __toCommonJS(server_exports);
31
32
  var import_pancake_ts = require("@waffo/pancake-ts");
32
33
  function createCheckoutAction(config) {
33
34
  const client = new import_pancake_ts.WaffoPancake(config);
34
- return async (params) => {
35
+ return async (params, options) => {
35
36
  if (params.type === "authenticated") {
36
37
  const { type: type2, ...sdkParams2 } = params;
37
- return client.checkout.authenticated.create(sdkParams2);
38
+ return client.checkout.authenticated.create(sdkParams2, options);
39
+ }
40
+ if (params.type === "planChange") {
41
+ const { type: type2, ...sdkParams2 } = params;
42
+ return client.checkout.createPlanChangeSession(sdkParams2, options);
43
+ }
44
+ if (params.type === "authenticatedPlanChange") {
45
+ const { type: type2, ...sdkParams2 } = params;
46
+ return client.checkout.authenticated.createPlanChange(sdkParams2, options);
38
47
  }
39
48
  const { type, ...sdkParams } = params;
40
- return client.checkout.anonymous.create(sdkParams);
49
+ return client.checkout.anonymous.create(sdkParams, options);
41
50
  };
42
51
  }
43
52
  function createCustomerTokenAction(config) {
44
53
  const client = new import_pancake_ts.WaffoPancake(config);
45
- return async (params) => {
46
- return client.auth.issueSessionToken(params);
54
+ return async (params, options) => {
55
+ return client.auth.issueSessionToken(params, options);
56
+ };
57
+ }
58
+ function portalHeaders(extra) {
59
+ const headers = new Headers(extra);
60
+ headers.set("Cache-Control", "no-store");
61
+ headers.set("Referrer-Policy", "no-referrer");
62
+ return headers;
63
+ }
64
+ function safeErrorMessage(error) {
65
+ const message = error instanceof Error ? error.message : String(error);
66
+ return message.replace(/#token=[^\s"'&]*/g, "#token=[redacted]").replace(/\s+/g, " ");
67
+ }
68
+ function createCustomerPortalRedirect(config, options) {
69
+ const client = new import_pancake_ts.WaffoPancake(config);
70
+ return async function GET(request) {
71
+ const customer = await options.resolveAuthenticatedCustomer(request);
72
+ if (!customer) {
73
+ if (options.loginUrl === void 0) {
74
+ return new Response(JSON.stringify({ error: "Unauthorized" }), {
75
+ status: 401,
76
+ headers: portalHeaders({ "Content-Type": "application/json" })
77
+ });
78
+ }
79
+ const loginUrl = typeof options.loginUrl === "function" ? options.loginUrl(request) : options.loginUrl;
80
+ return new Response(null, {
81
+ status: 302,
82
+ headers: portalHeaders({ Location: new URL(loginUrl, request.url).toString() })
83
+ });
84
+ }
85
+ let portalUrl;
86
+ try {
87
+ ({ portalUrl } = await client.auth.createCustomerPortalLink({
88
+ storeId: customer.storeId,
89
+ buyerIdentity: customer.buyerIdentity
90
+ }));
91
+ } catch (error) {
92
+ if (options.onError) {
93
+ return options.onError(error, request);
94
+ }
95
+ console.error("[waffo-pancake] createCustomerPortalRedirect failed:", safeErrorMessage(error));
96
+ return new Response(JSON.stringify({ error: "Failed to create customer portal link" }), {
97
+ status: 502,
98
+ headers: portalHeaders({ "Content-Type": "application/json" })
99
+ });
100
+ }
101
+ return new Response(null, {
102
+ status: 302,
103
+ headers: portalHeaders({ Location: portalUrl })
104
+ });
47
105
  };
48
106
  }
49
107
  function createCustomerSessionAction(config) {
50
108
  const client = new import_pancake_ts.WaffoPancake(config);
51
- return async (token, actionType, params) => {
109
+ return async (token, actionType, params, options) => {
52
110
  const customer = client.buyer(token);
53
111
  switch (actionType) {
54
112
  case "cancelSubscription":
55
- return customer.cancelSubscription(params);
113
+ return customer.cancelSubscription(params, options);
56
114
  case "cancelOnetimeOrder":
57
- return customer.cancelOnetimeOrder(params);
115
+ return customer.cancelOnetimeOrder(params, options);
58
116
  case "reactivateSubscription":
59
- return customer.reactivateSubscription(params);
117
+ return customer.reactivateSubscription(params, options);
60
118
  case "createRefundTicket":
61
- return customer.createRefundTicket(params);
119
+ return customer.createRefundTicket(params, options);
62
120
  case "resubmitRefundTicket":
63
- return customer.resubmitRefundTicket(params);
121
+ return customer.resubmitRefundTicket(params, options);
122
+ case "createPlanChangeSession":
123
+ return customer.createPlanChangeSession(params, options);
64
124
  case "query":
65
125
  return customer.graphql.query(params);
66
126
  default:
@@ -81,6 +141,7 @@ var createBuyerSessionAction = createCustomerSessionAction;
81
141
  createBuyerSessionAction,
82
142
  createBuyerTokenAction,
83
143
  createCheckoutAction,
144
+ createCustomerPortalRedirect,
84
145
  createCustomerSessionAction,
85
146
  createCustomerTokenAction,
86
147
  createMerchantQueryAction
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts"],"sourcesContent":["/**\n * Server-side entry point for @waffo/pancake-nextjs.\n *\n * All functions in this module use the private key for RSA signing\n * and must only run on the server (Next.js Server Actions / Route Handlers).\n *\n * @example\n * ```ts\n * // app/lib/waffo.ts\n * \"use server\";\n * import { createCheckoutAction, createCustomerTokenAction, createMerchantQueryAction } from \"@waffo/pancake-nextjs/server\";\n *\n * const config = {\n * merchantId: process.env.WAFFO_MERCHANT_ID!,\n * privateKey: process.env.WAFFO_PRIVATE_KEY!,\n * };\n *\n * export const checkout = createCheckoutAction(config);\n * export const issueCustomerToken = createCustomerTokenAction(config);\n * export const merchantQuery = createMerchantQueryAction(config);\n * ```\n */\nimport { WaffoPancake } from \"@waffo/pancake-ts\";\n\nimport type {\n WaffoPancakeConfig,\n AnonymousCheckoutParams,\n AuthenticatedCheckoutParams,\n CheckoutSessionResult,\n AuthenticatedCheckoutResult,\n IssueSessionTokenParams,\n SessionToken,\n GraphQLParams,\n GraphQLResponse,\n} from \"@waffo/pancake-ts\";\n\n// ============================================================\n// Checkout Action\n// ============================================================\n\n/** Parameters for the checkout server action */\nexport type CheckoutActionParams =\n | ({ type?: \"anonymous\" } & AnonymousCheckoutParams)\n | ({ type: \"authenticated\" } & AuthenticatedCheckoutParams);\n\n/** Result of the checkout server action */\nexport type CheckoutActionResult = CheckoutSessionResult | AuthenticatedCheckoutResult;\n\n/** Server action signature for checkout */\nexport type CheckoutAction = (params: CheckoutActionParams) => Promise<CheckoutActionResult>;\n\n/**\n * Create a server action that handles checkout session creation.\n *\n * The private key is captured in the closure and never sent to the client.\n *\n * @param config - WaffoPancake client configuration (merchantId + privateKey)\n * @returns A server action function\n *\n * @example\n * ```ts\n * \"use server\";\n * import { createCheckoutAction } from \"@waffo/pancake-nextjs/server\";\n *\n * export const checkout = createCheckoutAction({\n * merchantId: process.env.WAFFO_MERCHANT_ID!,\n * privateKey: process.env.WAFFO_PRIVATE_KEY!,\n * });\n * ```\n */\nexport function createCheckoutAction(config: WaffoPancakeConfig): CheckoutAction {\n const client = new WaffoPancake(config);\n\n return async (params: CheckoutActionParams): Promise<CheckoutActionResult> => {\n if (params.type === \"authenticated\") {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars -- remove type field before passing to SDK\n const { type, ...sdkParams } = params;\n return client.checkout.authenticated.create(sdkParams);\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars -- remove type field before passing to SDK\n const { type, ...sdkParams } = params;\n return client.checkout.anonymous.create(sdkParams);\n };\n}\n\n// ============================================================\n// Customer Token Action\n// ============================================================\n\n/** Server action signature for issuing customer tokens */\nexport type CustomerTokenAction = (params: IssueSessionTokenParams) => Promise<SessionToken>;\n\n/**\n * Create a server action that issues customer session tokens.\n *\n * @param config - WaffoPancake client configuration\n * @returns A server action function\n *\n * @example\n * ```ts\n * \"use server\";\n * import { createCustomerTokenAction } from \"@waffo/pancake-nextjs/server\";\n *\n * export const issueCustomerToken = createCustomerTokenAction({\n * merchantId: process.env.WAFFO_MERCHANT_ID!,\n * privateKey: process.env.WAFFO_PRIVATE_KEY!,\n * });\n * ```\n */\nexport function createCustomerTokenAction(config: WaffoPancakeConfig): CustomerTokenAction {\n const client = new WaffoPancake(config);\n\n return async (params: IssueSessionTokenParams): Promise<SessionToken> => {\n return client.auth.issueSessionToken(params);\n };\n}\n\n// ============================================================\n// Customer Session Action\n// ============================================================\n\n/** Customer action types */\nexport type CustomerSessionActionType =\n | \"cancelSubscription\"\n | \"cancelOnetimeOrder\"\n | \"reactivateSubscription\"\n | \"createRefundTicket\"\n | \"resubmitRefundTicket\"\n | \"query\";\n\n/** Server action signature for customer session operations */\nexport type CustomerSessionAction = (token: string, actionType: CustomerSessionActionType, params: unknown) => Promise<unknown>;\n\n/**\n * Create a server action that executes customer self-service operations.\n *\n * `config.environment` is required — session tokens carry no environment, and the\n * gateway rejects a session request without the matching header.\n *\n * @param config - WaffoPancake client configuration\n * @returns A server action function\n *\n * @example\n * ```ts\n * \"use server\";\n * import { createCustomerSessionAction } from \"@waffo/pancake-nextjs/server\";\n *\n * export const customerAction = createCustomerSessionAction({\n * merchantId: process.env.WAFFO_MERCHANT_ID!,\n * privateKey: process.env.WAFFO_PRIVATE_KEY!,\n * environment: \"test\",\n * });\n * ```\n */\nexport function createCustomerSessionAction(config: WaffoPancakeConfig): CustomerSessionAction {\n const client = new WaffoPancake(config);\n\n return async (token: string, actionType: CustomerSessionActionType, params: unknown): Promise<unknown> => {\n const customer = client.buyer(token);\n switch (actionType) {\n case \"cancelSubscription\":\n return customer.cancelSubscription(params as Parameters<typeof customer.cancelSubscription>[0]);\n case \"cancelOnetimeOrder\":\n return customer.cancelOnetimeOrder(params as Parameters<typeof customer.cancelOnetimeOrder>[0]);\n case \"reactivateSubscription\":\n return customer.reactivateSubscription(params as Parameters<typeof customer.reactivateSubscription>[0]);\n case \"createRefundTicket\":\n return customer.createRefundTicket(params as Parameters<typeof customer.createRefundTicket>[0]);\n case \"resubmitRefundTicket\":\n return customer.resubmitRefundTicket(params as Parameters<typeof customer.resubmitRefundTicket>[0]);\n case \"query\":\n return customer.graphql.query(params as GraphQLParams);\n default:\n throw new Error(`Unknown customer action: ${actionType}`);\n }\n };\n}\n\n// ============================================================\n// Merchant Query Action\n// ============================================================\n\n/** Server action signature for merchant GraphQL queries */\nexport type MerchantQueryAction = (params: GraphQLParams) => Promise<GraphQLResponse>;\n\n/**\n * Create a server action that executes merchant GraphQL queries.\n *\n * @param config - WaffoPancake client configuration\n * @returns A server action function\n *\n * @example\n * ```ts\n * \"use server\";\n * import { createMerchantQueryAction } from \"@waffo/pancake-nextjs/server\";\n *\n * export const merchantQuery = createMerchantQueryAction({\n * merchantId: process.env.WAFFO_MERCHANT_ID!,\n * privateKey: process.env.WAFFO_PRIVATE_KEY!,\n * });\n * ```\n */\nexport function createMerchantQueryAction(config: WaffoPancakeConfig): MerchantQueryAction {\n const client = new WaffoPancake(config);\n\n return async (params: GraphQLParams): Promise<GraphQLResponse> => {\n return client.graphql.query(params);\n };\n}\n\n// ============================================================\n// Deprecated Aliases\n// ============================================================\n\n/** @deprecated Use {@link CustomerTokenAction} instead. */\nexport type BuyerTokenAction = CustomerTokenAction;\n\n/** @deprecated Use {@link createCustomerTokenAction} instead. */\nexport const createBuyerTokenAction = createCustomerTokenAction;\n\n/** @deprecated Use {@link CustomerSessionActionType} instead. */\nexport type BuyerSessionActionType = CustomerSessionActionType;\n\n/** @deprecated Use {@link CustomerSessionAction} instead. */\nexport type BuyerSessionAction = CustomerSessionAction;\n\n/** @deprecated Use {@link createCustomerSessionAction} instead. */\nexport const createBuyerSessionAction = createCustomerSessionAction;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBA,wBAA6B;AAgDtB,SAAS,qBAAqB,QAA4C;AAC/E,QAAM,SAAS,IAAI,+BAAa,MAAM;AAEtC,SAAO,OAAO,WAAgE;AAC5E,QAAI,OAAO,SAAS,iBAAiB;AAEnC,YAAM,EAAE,MAAAA,OAAM,GAAGC,WAAU,IAAI;AAC/B,aAAO,OAAO,SAAS,cAAc,OAAOA,UAAS;AAAA,IACvD;AAEA,UAAM,EAAE,MAAM,GAAG,UAAU,IAAI;AAC/B,WAAO,OAAO,SAAS,UAAU,OAAO,SAAS;AAAA,EACnD;AACF;AA0BO,SAAS,0BAA0B,QAAiD;AACzF,QAAM,SAAS,IAAI,+BAAa,MAAM;AAEtC,SAAO,OAAO,WAA2D;AACvE,WAAO,OAAO,KAAK,kBAAkB,MAAM;AAAA,EAC7C;AACF;AAuCO,SAAS,4BAA4B,QAAmD;AAC7F,QAAM,SAAS,IAAI,+BAAa,MAAM;AAEtC,SAAO,OAAO,OAAe,YAAuC,WAAsC;AACxG,UAAM,WAAW,OAAO,MAAM,KAAK;AACnC,YAAQ,YAAY;AAAA,MAClB,KAAK;AACH,eAAO,SAAS,mBAAmB,MAA2D;AAAA,MAChG,KAAK;AACH,eAAO,SAAS,mBAAmB,MAA2D;AAAA,MAChG,KAAK;AACH,eAAO,SAAS,uBAAuB,MAA+D;AAAA,MACxG,KAAK;AACH,eAAO,SAAS,mBAAmB,MAA2D;AAAA,MAChG,KAAK;AACH,eAAO,SAAS,qBAAqB,MAA6D;AAAA,MACpG,KAAK;AACH,eAAO,SAAS,QAAQ,MAAM,MAAuB;AAAA,MACvD;AACE,cAAM,IAAI,MAAM,4BAA4B,UAAU,EAAE;AAAA,IAC5D;AAAA,EACF;AACF;AA0BO,SAAS,0BAA0B,QAAiD;AACzF,QAAM,SAAS,IAAI,+BAAa,MAAM;AAEtC,SAAO,OAAO,WAAoD;AAChE,WAAO,OAAO,QAAQ,MAAM,MAAM;AAAA,EACpC;AACF;AAUO,IAAM,yBAAyB;AAS/B,IAAM,2BAA2B;","names":["type","sdkParams"]}
1
+ {"version":3,"sources":["../src/server.ts"],"sourcesContent":["/**\n * Server-side entry point for @waffo/pancake-nextjs.\n *\n * All functions in this module use the private key for RSA signing\n * and must only run on the server (Next.js Server Actions / Route Handlers).\n *\n * @example\n * ```ts\n * // app/lib/waffo.ts\n * \"use server\";\n * import { createCheckoutAction, createCustomerTokenAction, createMerchantQueryAction } from \"@waffo/pancake-nextjs/server\";\n *\n * const config = {\n * merchantId: process.env.WAFFO_MERCHANT_ID!,\n * privateKey: process.env.WAFFO_PRIVATE_KEY!,\n * };\n *\n * export const checkout = createCheckoutAction(config);\n * export const issueCustomerToken = createCustomerTokenAction(config);\n * export const merchantQuery = createMerchantQueryAction(config);\n * ```\n *\n * @example\n * ```ts\n * // app/account/billing-portal/route.ts — customer portal entry from your own login\n * import { createCustomerPortalRedirect } from \"@waffo/pancake-nextjs/server\";\n *\n * export const GET = createCustomerPortalRedirect(config, {\n * resolveAuthenticatedCustomer: async (request) => getSignedInCustomer(request), // your session\n * });\n * ```\n */\nimport { WaffoPancake } from \"@waffo/pancake-ts\";\n\nimport type {\n RequestOptions,\n WaffoPancakeConfig,\n AnonymousCheckoutParams,\n AuthenticatedCheckoutParams,\n AuthenticatedPlanChangeParams,\n CreatePlanChangeSessionParams,\n CheckoutSessionResult,\n AuthenticatedCheckoutResult,\n IssueSessionTokenParams,\n SessionToken,\n GraphQLParams,\n GraphQLResponse,\n} from \"@waffo/pancake-ts\";\n\n// ============================================================\n// Checkout Action\n// ============================================================\n\n/**\n * Parameters for the checkout server action.\n *\n * The `type` field selects the flow: a new purchase (`anonymous` / `authenticated`)\n * or a plan change for an existing subscription (`planChange` /\n * `authenticatedPlanChange`, which carry the required `originOrderId`).\n */\nexport type CheckoutActionParams =\n | ({ type?: \"anonymous\" } & AnonymousCheckoutParams)\n | ({ type: \"authenticated\" } & AuthenticatedCheckoutParams)\n | ({ type: \"planChange\" } & CreatePlanChangeSessionParams)\n | ({ type: \"authenticatedPlanChange\" } & AuthenticatedPlanChangeParams);\n\n/** Result of the checkout server action */\nexport type CheckoutActionResult = CheckoutSessionResult | AuthenticatedCheckoutResult;\n\n/**\n * Server action signature for checkout.\n *\n * The optional `options` carries an `idempotencyKey`; without one no key is sent\n * and a retried call creates a second session.\n */\nexport type CheckoutAction = (params: CheckoutActionParams, options?: RequestOptions) => Promise<CheckoutActionResult>;\n\n/**\n * Create a server action that handles checkout session creation.\n *\n * The private key is captured in the closure and never sent to the client.\n *\n * Handles both new purchases and plan changes; `params.type` selects the flow.\n *\n * @param config - WaffoPancake client configuration (merchantId + privateKey)\n * @returns A server action function\n *\n * @example\n * ```ts\n * \"use server\";\n * import { createCheckoutAction } from \"@waffo/pancake-nextjs/server\";\n *\n * export const checkout = createCheckoutAction({\n * merchantId: process.env.WAFFO_MERCHANT_ID!,\n * privateKey: process.env.WAFFO_PRIVATE_KEY!,\n * });\n * ```\n *\n * @example\n * ```ts\n * // Plan change link for an existing subscription — originOrderId is required\n * const session = await checkout({\n * type: \"planChange\",\n * originOrderId: \"ORD_xxx\",\n * productId: \"PROD_target_plan\",\n * currency: \"USD\",\n * });\n * // session.checkoutUrl points at the change confirmation page\n * ```\n */\nexport function createCheckoutAction(config: WaffoPancakeConfig): CheckoutAction {\n const client = new WaffoPancake(config);\n\n return async (params: CheckoutActionParams, options?: RequestOptions): Promise<CheckoutActionResult> => {\n if (params.type === \"authenticated\") {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars -- remove type field before passing to SDK\n const { type, ...sdkParams } = params;\n return client.checkout.authenticated.create(sdkParams, options);\n }\n if (params.type === \"planChange\") {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars -- remove type field before passing to SDK\n const { type, ...sdkParams } = params;\n return client.checkout.createPlanChangeSession(sdkParams, options);\n }\n if (params.type === \"authenticatedPlanChange\") {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars -- remove type field before passing to SDK\n const { type, ...sdkParams } = params;\n return client.checkout.authenticated.createPlanChange(sdkParams, options);\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars -- remove type field before passing to SDK\n const { type, ...sdkParams } = params;\n return client.checkout.anonymous.create(sdkParams, options);\n };\n}\n\n// ============================================================\n// Customer Token Action\n// ============================================================\n\n/** Server action signature for issuing customer tokens */\nexport type CustomerTokenAction = (params: IssueSessionTokenParams, options?: RequestOptions) => Promise<SessionToken>;\n\n/**\n * Create a server action that issues customer session tokens.\n *\n * This is a generic token primitive: it signs whatever `buyerIdentity` it is\n * handed. Never expose it to the browser as a portal or sign-in entry — a\n * Server Action is callable with arbitrary arguments, so a client-chosen\n * `buyerIdentity` would yield another customer's token. To send a signed-in\n * customer to the customer portal, use {@link createCustomerPortalRedirect},\n * which derives identity from your own session.\n *\n * @param config - WaffoPancake client configuration\n * @returns A server action function\n *\n * @example\n * ```ts\n * \"use server\";\n * import { createCustomerTokenAction } from \"@waffo/pancake-nextjs/server\";\n *\n * export const issueCustomerToken = createCustomerTokenAction({\n * merchantId: process.env.WAFFO_MERCHANT_ID!,\n * privateKey: process.env.WAFFO_PRIVATE_KEY!,\n * });\n * ```\n */\nexport function createCustomerTokenAction(config: WaffoPancakeConfig): CustomerTokenAction {\n const client = new WaffoPancake(config);\n\n return async (params: IssueSessionTokenParams, options?: RequestOptions): Promise<SessionToken> => {\n return client.auth.issueSessionToken(params, options);\n };\n}\n\n// ============================================================\n// Customer Portal Redirect\n// ============================================================\n\n/**\n * Store and customer identity for a customer portal link, resolved by the\n * merchant app from its own authenticated session.\n */\nexport interface AuthenticatedPortalCustomer {\n /** Store ID (Short ID `STO_xxx`) whose portal the customer enters */\n storeId: string;\n /** Customer identity in your system — the same value used for authenticated checkout */\n buyerIdentity: string;\n}\n\n/** Options for {@link createCustomerPortalRedirect}. */\nexport interface CustomerPortalRedirectOptions {\n /**\n * Resolve the signed-in customer from YOUR app's authenticated session\n * (session cookie, auth library, …). Return `null` when nobody is signed in.\n *\n * Must not read `buyerIdentity` or `storeId` from anything the browser\n * controls — query string, body, form fields or custom headers. Whoever\n * controls `buyerIdentity` gets that customer's portal.\n */\n resolveAuthenticatedCustomer: (request: Request) => Promise<AuthenticatedPortalCustomer | null> | AuthenticatedPortalCustomer | null;\n /**\n * Where to send a visitor for whom the resolver returned `null`. A path or\n * absolute URL, resolved against the request URL; a function receives the\n * request (e.g. to add your own `returnTo`). Omit to answer 401 instead.\n *\n * Build it from constants or an allow-list, never by copying request\n * parameters verbatim (e.g. a `?next=` value) — that turns this route into an\n * open redirect.\n */\n loginUrl?: string | ((request: Request) => string);\n /**\n * Build the response when creating the portal link fails (API error, invalid\n * store ID, network error). This is the place for your own logging and error\n * reporting. Defaults to a 502 JSON `{ error }` response with a generic\n * message, after one `console.error` line carrying only the error message;\n * the error itself is not echoed to the browser.\n */\n onError?: (error: unknown, request: Request) => Response | Promise<Response>;\n}\n\n/** GET Route Handler returned by {@link createCustomerPortalRedirect}. */\nexport type CustomerPortalRouteHandler = (request: Request) => Promise<Response>;\n\n/**\n * Build headers for a portal route response. Every response — redirect, 401 or\n * error — is `no-store` and `no-referrer`, so a tokenized `Location` is neither\n * cached nor forwarded as a Referer.\n */\nfunction portalHeaders(extra: Record<string, string>): Headers {\n const headers = new Headers(extra);\n headers.set(\"Cache-Control\", \"no-store\");\n headers.set(\"Referrer-Policy\", \"no-referrer\");\n return headers;\n}\n\n/**\n * One-line, log-safe description of a portal link failure: the error message\n * only (never the error object, which may carry a response body), with any\n * `#token=...` fragment redacted.\n */\nfunction safeErrorMessage(error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n return message.replace(/#token=[^\\s\"'&]*/g, \"#token=[redacted]\").replace(/\\s+/g, \" \");\n}\n\n/**\n * Create a GET Route Handler that sends the signed-in customer to your store's\n * Pancake customer portal, without the portal's email verification step.\n *\n * Behavior:\n * - Calls `resolveAuthenticatedCustomer(request)` — your own session check — to\n * get `{ storeId, buyerIdentity }`. Nothing is read from the request's query\n * string, body or headers by the SDK\n * - Signed in: creates a portal link with `client.auth.createCustomerPortalLink()`\n * and answers `302` to `portalUrl` (which carries `#token=...`)\n * - Not signed in: `302` to `loginUrl` when set, otherwise `401`\n * - Link creation fails: `onError(error, request)`, or by default one server-side\n * `console.error` line with the error message and a generic `502 { error }`\n *\n * Side effects:\n * - One signed API request per signed-in visit; each visit issues a new portal session\n * - Every response it builds (not a custom `onError` one) sets `Cache-Control: no-store` and `Referrer-Policy: no-referrer`\n * so the tokenized `Location` is neither cached nor forwarded as a Referer\n *\n * Boundary conditions:\n * - The portal environment is the environment of the API Key in `config`\n * (test key → test portal, prod key → prod portal)\n * - Errors thrown by `resolveAuthenticatedCustomer` propagate (Next.js answers 500)\n * - The default error log is the message only, with any `#token=` fragment redacted;\n * pass `onError` to log or report failures your own way\n * - `loginUrl` must not echo request parameters verbatim, or the route becomes an open redirect\n *\n * A Route Handler rather than a Server Action: the portal entry is a plain link\n * navigation, and only an HTTP redirect keeps the tokenized URL out of client\n * JavaScript while letting the response carry `no-store` / `no-referrer`.\n *\n * @param config - WaffoPancake client configuration (merchantId + privateKey)\n * @param options - Session resolver, login redirect and error handling\n * @returns A Next.js GET Route Handler\n *\n * @example\n * ```ts\n * // app/account/billing-portal/route.ts\n * import { createCustomerPortalRedirect } from \"@waffo/pancake-nextjs/server\";\n * import { auth } from \"@/lib/auth\"; // your auth library\n *\n * export const dynamic = \"force-dynamic\";\n *\n * export const GET = createCustomerPortalRedirect(\n * { merchantId: process.env.WAFFO_MERCHANT_ID!, privateKey: process.env.WAFFO_PRIVATE_KEY! },\n * {\n * resolveAuthenticatedCustomer: async () => {\n * const session = await auth();\n * if (!session?.user) return null;\n * return { storeId: process.env.WAFFO_STORE_ID!, buyerIdentity: session.user.id };\n * },\n * loginUrl: \"/login?returnTo=/account/billing-portal\",\n * },\n * );\n * // In a page: <a href=\"/account/billing-portal\">Manage billing</a>\n * ```\n */\nexport function createCustomerPortalRedirect(\n config: WaffoPancakeConfig,\n options: CustomerPortalRedirectOptions,\n): CustomerPortalRouteHandler {\n const client = new WaffoPancake(config);\n\n return async function GET(request: Request): Promise<Response> {\n const customer = await options.resolveAuthenticatedCustomer(request);\n\n if (!customer) {\n if (options.loginUrl === undefined) {\n return new Response(JSON.stringify({ error: \"Unauthorized\" }), {\n status: 401,\n headers: portalHeaders({ \"Content-Type\": \"application/json\" }),\n });\n }\n const loginUrl = typeof options.loginUrl === \"function\" ? options.loginUrl(request) : options.loginUrl;\n return new Response(null, {\n status: 302,\n headers: portalHeaders({ Location: new URL(loginUrl, request.url).toString() }),\n });\n }\n\n let portalUrl: string;\n try {\n ({ portalUrl } = await client.auth.createCustomerPortalLink({\n storeId: customer.storeId,\n buyerIdentity: customer.buyerIdentity,\n }));\n } catch (error) {\n if (options.onError) {\n return options.onError(error, request);\n }\n console.error(\"[waffo-pancake] createCustomerPortalRedirect failed:\", safeErrorMessage(error));\n return new Response(JSON.stringify({ error: \"Failed to create customer portal link\" }), {\n status: 502,\n headers: portalHeaders({ \"Content-Type\": \"application/json\" }),\n });\n }\n\n return new Response(null, {\n status: 302,\n headers: portalHeaders({ Location: portalUrl }),\n });\n };\n}\n\n// ============================================================\n// Customer Session Action\n// ============================================================\n\n/** Customer action types */\nexport type CustomerSessionActionType =\n | \"cancelSubscription\"\n | \"cancelOnetimeOrder\"\n | \"reactivateSubscription\"\n | \"createRefundTicket\"\n | \"resubmitRefundTicket\"\n | \"createPlanChangeSession\"\n | \"query\";\n\n/** Server action signature for customer session operations */\nexport type CustomerSessionAction = (\n token: string,\n actionType: CustomerSessionActionType,\n params: unknown,\n options?: RequestOptions,\n) => Promise<unknown>;\n\n/**\n * Create a server action that executes customer self-service operations.\n *\n * `config.environment` is required — session tokens carry no environment, and the\n * gateway rejects a session request without the matching header.\n *\n * `createPlanChangeSession` is the customer-driven half of a plan change: it returns\n * a confirmation-page URL, and the platform allows it only when the subscription\n * belongs to that customer, the target plan is in the same product group, and that\n * group's `selfServicePlanChange` is on — otherwise 403. The merchant-only pricing\n * fields are not part of its params; the platform drops them on this path silently.\n *\n * No call sends an idempotency key unless you pass one (`options.idempotencyKey`,\n * the last argument) — the same rule as every other method in the SDK — so a write\n * retried after a timeout executes twice.\n *\n * @param config - WaffoPancake client configuration\n * @returns A server action function\n *\n * @example\n * ```ts\n * \"use server\";\n * import { createCustomerSessionAction } from \"@waffo/pancake-nextjs/server\";\n *\n * export const customerAction = createCustomerSessionAction({\n * merchantId: process.env.WAFFO_MERCHANT_ID!,\n * privateKey: process.env.WAFFO_PRIVATE_KEY!,\n * environment: \"test\",\n * });\n * ```\n */\nexport function createCustomerSessionAction(config: WaffoPancakeConfig): CustomerSessionAction {\n const client = new WaffoPancake(config);\n\n return async (token: string, actionType: CustomerSessionActionType, params: unknown, options?: RequestOptions): Promise<unknown> => {\n const customer = client.buyer(token);\n switch (actionType) {\n case \"cancelSubscription\":\n return customer.cancelSubscription(params as Parameters<typeof customer.cancelSubscription>[0], options);\n case \"cancelOnetimeOrder\":\n return customer.cancelOnetimeOrder(params as Parameters<typeof customer.cancelOnetimeOrder>[0], options);\n case \"reactivateSubscription\":\n return customer.reactivateSubscription(params as Parameters<typeof customer.reactivateSubscription>[0], options);\n case \"createRefundTicket\":\n return customer.createRefundTicket(params as Parameters<typeof customer.createRefundTicket>[0], options);\n case \"resubmitRefundTicket\":\n return customer.resubmitRefundTicket(params as Parameters<typeof customer.resubmitRefundTicket>[0], options);\n case \"createPlanChangeSession\":\n return customer.createPlanChangeSession(params as Parameters<typeof customer.createPlanChangeSession>[0], options);\n case \"query\":\n // Reads take no key: a cached replay would serve stale data.\n return customer.graphql.query(params as GraphQLParams);\n default:\n throw new Error(`Unknown customer action: ${actionType}`);\n }\n };\n}\n\n// ============================================================\n// Merchant Query Action\n// ============================================================\n\n/** Server action signature for merchant GraphQL queries */\nexport type MerchantQueryAction = (params: GraphQLParams) => Promise<GraphQLResponse>;\n\n/**\n * Create a server action that executes merchant GraphQL queries.\n *\n * @param config - WaffoPancake client configuration\n * @returns A server action function\n *\n * @example\n * ```ts\n * \"use server\";\n * import { createMerchantQueryAction } from \"@waffo/pancake-nextjs/server\";\n *\n * export const merchantQuery = createMerchantQueryAction({\n * merchantId: process.env.WAFFO_MERCHANT_ID!,\n * privateKey: process.env.WAFFO_PRIVATE_KEY!,\n * });\n * ```\n */\nexport function createMerchantQueryAction(config: WaffoPancakeConfig): MerchantQueryAction {\n const client = new WaffoPancake(config);\n\n return async (params: GraphQLParams): Promise<GraphQLResponse> => {\n return client.graphql.query(params);\n };\n}\n\n// ============================================================\n// Deprecated Aliases\n// ============================================================\n\n/** @deprecated Use {@link CustomerTokenAction} instead. */\nexport type BuyerTokenAction = CustomerTokenAction;\n\n/** @deprecated Use {@link createCustomerTokenAction} instead. */\nexport const createBuyerTokenAction = createCustomerTokenAction;\n\n/** @deprecated Use {@link CustomerSessionActionType} instead. */\nexport type BuyerSessionActionType = CustomerSessionActionType;\n\n/** @deprecated Use {@link CustomerSessionAction} instead. */\nexport type BuyerSessionAction = CustomerSessionAction;\n\n/** @deprecated Use {@link createCustomerSessionAction} instead. */\nexport const createBuyerSessionAction = createCustomerSessionAction;\n"],"mappings":"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","names":["type","sdkParams"]}