UNPKG

@teerai/teer-react

Version:

React components and hooks for Teer billing integration

1 lines 26.7 kB
{"version":3,"sources":["../src/index.ts","../src/context/TeerContext.tsx","../src/api/teerApi.ts","../src/hooks/useTeer.ts","../src/utils/index.ts"],"sourcesContent":["// Export types\nexport * from './types'\n\n// Export context and provider\nexport { TeerContext, TeerProvider } from './context/TeerContext'\n\n// Export hooks\nexport { useTeer, useBillingConfig, useCustomer, useSubscriptions, useCheckout, useBillingPortal, useUsageReporting } from './hooks'\n\n// Export utilities\nexport { getActiveSubscriptions, getPlanById, getPriceById, getActivePlanPrice } from './utils'\n","import * as React from 'react'\nconst { createContext, useEffect, useMemo, useState, useRef, useCallback } = React\nimport { TeerApi } from '../api/teerApi'\nimport {\n BillingConfig,\n BillingPortalOptions,\n BillingPortalSession,\n CheckoutOptions,\n CheckoutSession,\n Customer,\n Subscription,\n TeerContextValue,\n UsageData,\n} from '../types'\n\n// Create the context with a default value\nexport const TeerContext = createContext<TeerContextValue | undefined>(undefined)\n\nexport interface TeerProviderProps {\n /**\n * Provider configuration\n */\n publishableKey: string\n\n /**\n * Optional customer ID\n */\n customerId?: string\n\n /**\n * Optional customer email\n */\n customerEmail?: string\n\n /**\n * Success URL for checkout redirects\n */\n successUrl?: string\n\n /**\n * Cancel URL for checkout redirects\n */\n cancelUrl?: string\n\n /**\n * Whether to fetch billing configuration on mount\n */\n fetchOnMount?: boolean\n\n /**\n * Children components\n */\n children: React.ReactNode\n}\n\n/**\n * Teer Provider Component\n */\nexport const TeerProvider: React.FC<TeerProviderProps> = ({\n publishableKey,\n customerId,\n customerEmail,\n successUrl,\n cancelUrl,\n fetchOnMount = true,\n children,\n}: TeerProviderProps) => {\n // Create API client\n const api = useMemo(() => new TeerApi(publishableKey), [publishableKey])\n\n // State\n const [isLoading, setIsLoading] = useState<boolean>(false)\n const [isReady, setIsReady] = useState<boolean>(false)\n const [error, setError] = useState<Error | null>(null)\n const [billingConfig, setBillingConfig] = useState<BillingConfig | null>(null)\n const [customer, setCustomer] = useState<Customer | null>(null)\n const [subscriptions, setSubscriptions] = useState<Subscription[]>([])\n\n // Refs to track request state and prevent duplicate requests\n const isFetchingRef = useRef<boolean>(false)\n const abortControllerRef = useRef<AbortController | null>(null)\n\n // Stable references to props for effect dependencies\n const publishableKeyRef = useRef<string>(publishableKey)\n const customerIdRef = useRef<string | undefined>(customerId)\n\n // Update refs when props change\n useEffect(() => {\n publishableKeyRef.current = publishableKey\n customerIdRef.current = customerId\n }, [publishableKey, customerId])\n\n // Fetch billing configuration with abort controller and duplicate request prevention\n const fetchBillingConfig = useCallback(async () => {\n // Prevent duplicate requests\n if (isFetchingRef.current) {\n return\n }\n\n try {\n // Cancel any in-flight requests\n if (abortControllerRef.current) {\n abortControllerRef.current.abort()\n }\n\n // Create new abort controller\n abortControllerRef.current = new AbortController()\n isFetchingRef.current = true\n\n setIsLoading(true)\n setError(null)\n\n // Use the signal for fetch requests\n const signal = abortControllerRef.current.signal\n\n const config = await api.getBillingConfig(signal)\n\n // Check if request was aborted\n if (signal.aborted) return\n\n setBillingConfig(config)\n\n // If customerId is provided, fetch customer and subscriptions\n if (customerIdRef.current) {\n const customerData = await api.getCustomer(customerIdRef.current, signal)\n\n // Check if request was aborted\n if (signal.aborted) return\n\n setCustomer(customerData)\n\n const subscriptionsData = await api.getSubscriptions(customerIdRef.current, signal)\n\n // Check if request was aborted\n if (signal.aborted) return\n\n setSubscriptions(subscriptionsData)\n } else {\n // Clear customer data if no customerId\n setCustomer(null)\n setSubscriptions([])\n }\n\n setIsReady(true)\n } catch (err) {\n // Don't update state if the request was aborted\n if (err instanceof DOMException && err.name === 'AbortError') {\n return\n }\n\n setError(err instanceof Error ? err : new Error('Failed to fetch billing configuration'))\n } finally {\n isFetchingRef.current = false\n setIsLoading(false)\n }\n }, [api]) // Only depend on the API client\n\n // Refetch billing configuration - exposed in the context\n const refetch = useCallback(async () => {\n await fetchBillingConfig()\n }, [fetchBillingConfig])\n\n // Create checkout session\n const checkout = useCallback(\n async (options: CheckoutOptions | string): Promise<CheckoutSession> => {\n // Use a local loading state to avoid conflicts with other operations\n let localLoading = false\n // Create a local abort controller for this operation\n const abortController = new AbortController()\n const signal = abortController.signal\n\n try {\n // Only set global loading if no other operation is in progress\n if (!isFetchingRef.current) {\n setIsLoading(true)\n localLoading = true\n }\n\n // If options is a string, assume it's a priceId\n const checkoutOptions: CheckoutOptions = typeof options === 'string' ? { priceId: options } : options\n\n // Add default values if not provided\n if (!checkoutOptions.successUrl && successUrl) {\n checkoutOptions.successUrl = successUrl\n }\n\n if (!checkoutOptions.cancelUrl && cancelUrl) {\n checkoutOptions.cancelUrl = cancelUrl\n }\n\n if (!checkoutOptions.customerId && customerIdRef.current) {\n checkoutOptions.customerId = customerIdRef.current\n }\n\n if (!checkoutOptions.customerEmail && customerEmail) {\n checkoutOptions.customerEmail = customerEmail\n }\n\n const session = await api.createCheckoutSession(checkoutOptions, signal)\n\n // Check if the request was aborted\n if (signal.aborted) {\n throw new DOMException('Request aborted', 'AbortError')\n }\n\n // Redirect to checkout page\n if (typeof window !== 'undefined' && session.url) {\n window.location.href = session.url\n }\n\n return session\n } catch (err) {\n // Don't update state if the request was aborted\n if (err instanceof DOMException && err.name === 'AbortError') {\n throw err\n }\n\n const error = err instanceof Error ? err : new Error('Failed to create checkout session')\n setError(error)\n throw error\n } finally {\n // Clean up abort controller\n abortController.abort()\n\n // Only reset global loading if we set it\n if (localLoading) {\n setIsLoading(false)\n }\n }\n },\n [api, successUrl, cancelUrl, customerEmail]\n )\n\n // Create billing portal session\n const billingPortal = useCallback(\n async (options?: BillingPortalOptions): Promise<BillingPortalSession> => {\n // Use a local loading state to avoid conflicts with other operations\n let localLoading = false\n // Create a local abort controller for this operation\n const abortController = new AbortController()\n const signal = abortController.signal\n\n try {\n // Only set global loading if no other operation is in progress\n if (!isFetchingRef.current) {\n setIsLoading(true)\n localLoading = true\n }\n\n const portalOptions: BillingPortalOptions = options || {}\n\n // Add default values if not provided\n if (!portalOptions.customerId && customerIdRef.current) {\n portalOptions.customerId = customerIdRef.current\n }\n\n if (!portalOptions.returnUrl && typeof window !== 'undefined') {\n portalOptions.returnUrl = window.location.href\n }\n\n const session = await api.createBillingPortalSession(portalOptions, signal)\n\n // Check if the request was aborted\n if (signal.aborted) {\n throw new DOMException('Request aborted', 'AbortError')\n }\n\n // Redirect to billing portal\n if (typeof window !== 'undefined' && session.url) {\n window.location.href = session.url\n }\n\n return session\n } catch (err) {\n // Don't update state if the request was aborted\n if (err instanceof DOMException && err.name === 'AbortError') {\n throw err\n }\n\n const error = err instanceof Error ? err : new Error('Failed to create billing portal session')\n setError(error)\n throw error\n } finally {\n // Clean up abort controller\n abortController.abort()\n\n // Only reset global loading if we set it\n if (localLoading) {\n setIsLoading(false)\n }\n }\n },\n [api]\n )\n\n // Report usage\n const reportUsage = useCallback(\n async (subscriptionItemId: string, quantity: number): Promise<UsageData> => {\n // Use a local loading state to avoid conflicts with other operations\n let localLoading = false\n // Create a local abort controller for this operation\n const abortController = new AbortController()\n const signal = abortController.signal\n\n try {\n // Only set global loading if no other operation is in progress\n if (!isFetchingRef.current) {\n setIsLoading(true)\n localLoading = true\n }\n\n const result = await api.reportUsage(subscriptionItemId, quantity, signal)\n\n // Check if the request was aborted\n if (signal.aborted) {\n throw new DOMException('Request aborted', 'AbortError')\n }\n\n return result\n } catch (err) {\n // Don't update state if the request was aborted\n if (err instanceof DOMException && err.name === 'AbortError') {\n throw err\n }\n\n const error = err instanceof Error ? err : new Error('Failed to report usage')\n setError(error)\n throw error\n } finally {\n // Clean up abort controller\n abortController.abort()\n\n // Only reset global loading if we set it\n if (localLoading) {\n setIsLoading(false)\n }\n }\n },\n [api]\n )\n\n // Cleanup function for abort controller\n useEffect(() => {\n return () => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort()\n }\n }\n }, [])\n\n // Fetch billing configuration on mount or when key dependencies change\n useEffect(() => {\n if (fetchOnMount) {\n fetchBillingConfig()\n }\n\n // Cleanup on unmount or when dependencies change\n return () => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort()\n }\n }\n }, [fetchOnMount, fetchBillingConfig])\n\n // Context value - memoized to prevent unnecessary re-renders\n const contextValue = useMemo<TeerContextValue>(\n () => ({\n isLoading,\n isReady,\n error,\n billingConfig,\n customer,\n subscriptions,\n refetch,\n checkout,\n billingPortal,\n reportUsage,\n }),\n [isLoading, isReady, error, billingConfig, customer, subscriptions, refetch, checkout, billingPortal, reportUsage]\n )\n\n return <TeerContext.Provider value={contextValue}>{children}</TeerContext.Provider>\n}\n","import {\n BillingConfig,\n BillingPortalOptions,\n BillingPortalSession,\n CheckoutOptions,\n CheckoutSession,\n Customer,\n Subscription,\n UsageData,\n} from '../types'\n\n/**\n * Teer API client\n */\nexport class TeerApi {\n private readonly publishableKey: string\n private readonly baseUrl: string = 'https://api.teer.ai/v1'\n\n constructor(publishableKey: string) {\n this.publishableKey = publishableKey\n }\n\n /**\n * Make a request to the Teer API\n */\n private async request<T>(\n method: 'GET' | 'POST' | 'PUT' | 'DELETE',\n path: string,\n data?: Record<string, any>,\n signal?: AbortSignal\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`\n const headers = {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.publishableKey}`,\n }\n\n const options: RequestInit = {\n method,\n headers,\n credentials: 'include',\n signal, // Add abort signal to request\n }\n\n if (data) {\n options.body = JSON.stringify(data)\n }\n\n try {\n const response = await fetch(url, options)\n\n // Check if the request was aborted\n if (signal?.aborted) {\n throw new DOMException('Request aborted', 'AbortError')\n }\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}))\n throw new Error(errorData.message || `API request failed with status ${response.status}`)\n }\n\n return response.json()\n } catch (error) {\n // Rethrow AbortError as is\n if (error instanceof DOMException && error.name === 'AbortError') {\n throw error\n }\n\n // Wrap other errors\n if (error instanceof Error) {\n throw error\n }\n\n throw new Error('Unknown error occurred during API request')\n }\n }\n\n /**\n * Get billing configuration\n */\n async getBillingConfig(signal?: AbortSignal): Promise<BillingConfig> {\n return this.request<BillingConfig>('GET', '/billing/config', undefined, signal)\n }\n\n /**\n * Get customer by ID\n */\n async getCustomer(customerId: string, signal?: AbortSignal): Promise<Customer> {\n return this.request<Customer>('GET', `/customers/${customerId}`, undefined, signal)\n }\n\n /**\n * Get customer subscriptions\n */\n async getSubscriptions(customerId: string, signal?: AbortSignal): Promise<Subscription[]> {\n return this.request<Subscription[]>('GET', `/customers/${customerId}/subscriptions`, undefined, signal)\n }\n\n /**\n * Create a checkout session\n */\n async createCheckoutSession(options: CheckoutOptions, signal?: AbortSignal): Promise<CheckoutSession> {\n return this.request<CheckoutSession>('POST', '/checkout/sessions', options, signal)\n }\n\n /**\n * Create a billing portal session\n */\n async createBillingPortalSession(options: BillingPortalOptions, signal?: AbortSignal): Promise<BillingPortalSession> {\n return this.request<BillingPortalSession>('POST', '/billing/portal/sessions', options, signal)\n }\n\n /**\n * Report usage\n */\n async reportUsage(subscriptionItemId: string, quantity: number, signal?: AbortSignal): Promise<UsageData> {\n return this.request<UsageData>(\n 'POST',\n `/subscription-items/${subscriptionItemId}/usage`,\n {\n quantity,\n timestamp: Math.floor(Date.now() / 1000),\n },\n signal\n )\n }\n}\n","import { useContext } from 'react';\nimport { TeerContext } from '../context/TeerContext';\nimport { TeerContextValue } from '../types';\n\n/**\n * Hook to access the Teer context\n */\nexport function useTeer(): TeerContextValue {\n const context = useContext(TeerContext);\n \n if (context === undefined) {\n throw new Error('useTeer must be used within a TeerProvider');\n }\n \n return context;\n}\n\n/**\n * Hook to access billing configuration\n */\nexport function useBillingConfig() {\n const { billingConfig, isLoading, error } = useTeer();\n \n return {\n billingConfig,\n isLoading,\n error,\n };\n}\n\n/**\n * Hook to access customer data\n */\nexport function useCustomer() {\n const { customer, isLoading, error } = useTeer();\n \n return {\n customer,\n isLoading,\n error,\n };\n}\n\n/**\n * Hook to access subscriptions\n */\nexport function useSubscriptions() {\n const { subscriptions, isLoading, error } = useTeer();\n \n return {\n subscriptions,\n isLoading,\n error,\n };\n}\n\n/**\n * Hook to access checkout functionality\n */\nexport function useCheckout() {\n const { checkout, isLoading, error } = useTeer();\n \n return {\n checkout,\n isLoading,\n error,\n };\n}\n\n/**\n * Hook to access billing portal functionality\n */\nexport function useBillingPortal() {\n const { billingPortal, isLoading, error } = useTeer();\n \n return {\n billingPortal,\n isLoading,\n error,\n };\n}\n\n/**\n * Hook to access usage reporting functionality\n */\nexport function useUsageReporting() {\n const { reportUsage, isLoading, error } = useTeer();\n \n return {\n reportUsage,\n isLoading,\n error,\n };\n}\n","import { BillingPlan, BillingPrice, Subscription } from '../types'\n\n/**\n * Get active subscriptions (active or trialing)\n */\nexport function getActiveSubscriptions(subscriptions: Subscription[]): Subscription[] {\n return subscriptions.filter((subscription) => subscription.status === 'active' || subscription.status === 'trialing')\n}\n\n/**\n * Get a plan by ID\n */\nexport function getPlanById(plans: BillingPlan[], planId: string): BillingPlan | undefined {\n return plans.find((plan) => plan.id === planId)\n}\n\n/**\n * Get a price by ID\n */\nexport function getPriceById(plans: BillingPlan[], priceId: string): BillingPrice | undefined {\n for (const plan of plans) {\n const price = plan.prices.find((price) => price.id === priceId)\n if (price) {\n return price\n }\n }\n return undefined\n}\n\n/**\n * Get active price for a plan based on currency and interval\n */\nexport function getActivePlanPrice(plan: BillingPlan, options: { currency?: string; interval?: string } = {}): BillingPrice | undefined {\n const { currency = 'usd', interval = 'month' } = options\n\n // First try to find a price with the exact currency and interval\n let price = plan.prices.find((price) => price.currency.toLowerCase() === currency.toLowerCase() && price.interval === interval)\n\n // If not found, try to find a price with just the currency\n if (!price) {\n price = plan.prices.find((price) => price.currency.toLowerCase() === currency.toLowerCase())\n }\n\n // If still not found, return the first price\n if (!price && plan.prices.length > 0) {\n price = plan.prices[0]\n }\n\n return price\n}\n"],"mappings":"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","names":["error","price"]}