@usethrottle/subscriptions 1.0.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.tsx","../src/errors.ts","../src/normalize.ts","../src/client.ts","../src/provider.tsx","../src/hooks.ts","../src/helpers.ts","../src/components.tsx"],"sourcesContent":["export { SubscriptionsClient, createSubscriptionsClient } from './client';\nexport { ThrottleSubscriptionsError } from './errors';\nexport {\n SubscriptionProvider,\n SubscriptionProviderWithClient,\n createSubscriptionFetcher,\n useSubscriptionClient,\n useSubscriptionInvalidation,\n} from './provider';\nexport {\n useCancelSubscription,\n useChangePlan,\n useCreateCheckoutSession,\n useCreateSubscription,\n useCustomerByExternalId,\n usePauseSubscription,\n useResumeSubscription,\n useSubscription,\n useSubscriptions,\n useTrialEligibility,\n useUpdateSubscription,\n} from './hooks';\nexport { DunningBanner, SubscriptionStatusBadge, TrialCountdown } from './components';\nexport {\n canCancelSubscription,\n canPauseSubscription,\n canResumeSubscription,\n daysUntil,\n isSubscriptionPastDue,\n isSubscriptionTrialing,\n isTerminalSubscription,\n} from './helpers';\nexport type * from './types';\n","export class ThrottleSubscriptionsError extends Error {\n readonly code: string;\n readonly statusCode: number;\n readonly details?: unknown;\n\n constructor(args: { code: string; message: string; statusCode: number; details?: unknown }) {\n super(args.message);\n this.name = 'ThrottleSubscriptionsError';\n this.code = args.code;\n this.statusCode = args.statusCode;\n this.details = args.details;\n }\n}\n","import type {\n CheckoutSession,\n Customer,\n Pagination,\n Subscription,\n SubscriptionInterval,\n SubscriptionStatus,\n TrialEligibilityResult,\n} from './types';\n\nexport function normalizeSubscription(raw: any): Subscription {\n return {\n id: requiredString(raw?.id, 'subscription.id'),\n merchantId: optionalString(raw?.merchantId ?? raw?.merchant_id),\n storeId: optionalString(raw?.storeId ?? raw?.store_id),\n customerId: requiredString(raw?.customerId ?? raw?.customer_id, 'subscription.customerId'),\n status: (raw?.status ?? 'active') as SubscriptionStatus,\n planReference: requiredString(\n raw?.planReference ?? raw?.plan_reference,\n 'subscription.planReference',\n ),\n planName: optionalString(raw?.planName ?? raw?.plan_name),\n interval: (raw?.interval ?? 'monthly') as SubscriptionInterval,\n amount: Number(raw?.amount ?? 0),\n currency: optionalString(raw?.currency) ?? 'USD',\n currentPeriodStart: requiredDateString(\n raw?.currentPeriodStart ?? raw?.current_period_start,\n 'subscription.currentPeriodStart',\n ),\n currentPeriodEnd: requiredDateString(\n raw?.currentPeriodEnd ?? raw?.current_period_end,\n 'subscription.currentPeriodEnd',\n ),\n trialEnd: optionalDateString(raw?.trialEnd ?? raw?.trial_end),\n cancelAtPeriodEnd: Boolean(raw?.cancelAtPeriodEnd ?? raw?.cancel_at_period_end ?? false),\n failureCount: Number(raw?.failureCount ?? raw?.failure_count ?? 0),\n lastPaymentAt: optionalDateString(raw?.lastPaymentAt ?? raw?.last_payment_at),\n pausedAt: optionalDateString(raw?.pausedAt ?? raw?.paused_at),\n cancelledAt: optionalDateString(raw?.cancelledAt ?? raw?.cancelled_at),\n metadata: objectOrEmpty(raw?.metadata),\n createdAt: optionalDateString(raw?.createdAt ?? raw?.created_at) ?? undefined,\n updatedAt: optionalDateString(raw?.updatedAt ?? raw?.updated_at) ?? undefined,\n };\n}\n\nexport function normalizeCustomer(raw: any): Customer | null {\n if (!raw) return null;\n return {\n id: requiredString(raw?.id, 'customer.id'),\n externalId: optionalString(raw?.externalId ?? raw?.external_id),\n email: optionalString(raw?.email),\n firstName: optionalString(raw?.firstName ?? raw?.first_name),\n lastName: optionalString(raw?.lastName ?? raw?.last_name),\n phone: optionalString(raw?.phone),\n metadata: objectOrEmpty(raw?.metadata),\n createdAt: optionalDateString(raw?.createdAt ?? raw?.created_at) ?? undefined,\n updatedAt: optionalDateString(raw?.updatedAt ?? raw?.updated_at) ?? undefined,\n };\n}\n\nexport function normalizeCheckoutSession(raw: any): CheckoutSession {\n const sessionId = raw?.sessionId ?? raw?.session_id ?? raw?.id;\n return {\n ...raw,\n id: optionalString(raw?.id),\n sessionId: requiredString(sessionId, 'checkoutSession.sessionId'),\n checkoutUrl: optionalString(raw?.checkoutUrl ?? raw?.checkout_url),\n embedToken: optionalString(raw?.embedToken ?? raw?.embed_token),\n expiresAt: optionalDateString(raw?.expiresAt ?? raw?.expires_at) ?? undefined,\n };\n}\n\nexport function normalizeTrialEligibility(raw: any): TrialEligibilityResult {\n return {\n eligible: Boolean(raw?.eligible),\n reason: raw?.reason,\n };\n}\n\nexport function normalizePagination(raw: any): Pagination | undefined {\n if (!raw) return undefined;\n return {\n cursor: raw.cursor ?? null,\n hasMore: Boolean(raw.hasMore ?? raw.has_more ?? false),\n };\n}\n\nexport function toIso(value: string | Date | undefined): string | undefined {\n if (value === undefined) return undefined;\n return value instanceof Date ? value.toISOString() : value;\n}\n\nfunction requiredString(value: unknown, label: string): string {\n if (typeof value === 'string' && value.length > 0) return value;\n throw new Error(`Invalid Throttle response: missing ${label}`);\n}\n\nfunction optionalString(value: unknown): string | null {\n return typeof value === 'string' ? value : null;\n}\n\nfunction requiredDateString(value: unknown, label: string): string {\n if (value instanceof Date) return value.toISOString();\n if (typeof value === 'string' && value.length > 0) return value;\n throw new Error(`Invalid Throttle response: missing ${label}`);\n}\n\nfunction optionalDateString(value: unknown): string | null {\n if (value instanceof Date) return value.toISOString();\n if (typeof value === 'string' && value.length > 0) return value;\n return null;\n}\n\nfunction objectOrEmpty(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n}\n","import { ThrottleSubscriptionsError } from './errors';\nimport {\n normalizeCheckoutSession,\n normalizeCustomer,\n normalizePagination,\n normalizeSubscription,\n normalizeTrialEligibility,\n toIso,\n} from './normalize';\nimport type {\n ChangePlanInput,\n CheckoutSession,\n CreateCheckoutSessionInput,\n CreateSubscriptionInput,\n Customer,\n ListSubscriptionsParams,\n PaginatedSubscriptions,\n Subscription,\n SubscriptionsClientContract,\n SubscriptionsClientOptions,\n ThrottleEnvelope,\n TrialEligibilityInput,\n TrialEligibilityResult,\n UpdateSubscriptionInput,\n} from './types';\n\nexport class SubscriptionsClient implements SubscriptionsClientContract {\n private readonly apiKey?: string;\n private readonly baseUrl: string;\n private readonly fetchImpl: typeof globalThis.fetch;\n private readonly fetcher?: SubscriptionsClientOptions['fetcher'];\n private readonly timeoutMs: number;\n\n constructor(opts: SubscriptionsClientOptions = {}) {\n const fetchImpl = opts.fetch ?? globalThis.fetch;\n if (!fetchImpl) throw new Error('SubscriptionsClient: fetch is required');\n if (!opts.apiKey && !opts.fetcher) {\n throw new Error('SubscriptionsClient: apiKey or fetcher is required');\n }\n\n this.apiKey = opts.apiKey;\n this.baseUrl = (opts.baseUrl ?? 'https://api.usethrottle.dev').replace(/\\/+$/, '');\n this.fetchImpl = fetchImpl;\n this.fetcher = opts.fetcher;\n this.timeoutMs = opts.timeoutMs ?? 30_000;\n }\n\n async request<T = unknown>(method: string, path: string, body?: unknown): Promise<T> {\n const envelope = await this.requestEnvelope<T>(method, path, body);\n return envelope.data as T;\n }\n\n async requestEnvelope<T = unknown>(\n method: string,\n path: string,\n body?: unknown,\n ): Promise<ThrottleEnvelope<T>> {\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);\n\n try {\n const init: RequestInit = {\n method,\n headers: {\n 'content-type': 'application/json',\n ...(this.apiKey ? { 'x-api-key': this.apiKey } : {}),\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n signal: ctrl.signal,\n };\n\n const res = this.fetcher\n ? await this.fetcher(path, init)\n : await this.fetchImpl(toAbsoluteUrl(this.baseUrl, path), init);\n\n if (res.status === 204) return { data: undefined as T };\n\n const json = (await res.json().catch(() => ({}))) as ThrottleEnvelope<T>;\n if (!res.ok) {\n throw new ThrottleSubscriptionsError({\n code: json.error?.code ?? 'unknown_error',\n message: json.error?.message ?? `HTTP ${res.status}`,\n statusCode: res.status,\n details: json.error?.details,\n });\n }\n return json;\n } finally {\n clearTimeout(timer);\n }\n }\n\n async create(input: CreateSubscriptionInput): Promise<Subscription> {\n const customerId = await this.resolveCustomerId(input.customerId, input.externalCustomerId);\n const data = await this.request<unknown>('POST', '/api/v1/subscriptions', {\n storeId: input.storeId,\n customerId,\n planReference: input.planReference,\n planName: input.planName,\n interval: input.interval,\n amount: input.amount,\n currency: input.currency,\n currentPeriodStart: toIso(input.currentPeriodStart),\n currentPeriodEnd: toIso(input.currentPeriodEnd),\n trialEnd: toIso(input.trialEnd),\n metadata: input.metadata ?? {},\n });\n return normalizeSubscription(data);\n }\n\n async list(params: ListSubscriptionsParams = {}): Promise<PaginatedSubscriptions> {\n const query = new URLSearchParams();\n setQuery(query, 'customerId', params.customerId);\n setQuery(query, 'externalCustomerId', params.externalCustomerId);\n setQuery(query, 'status', params.status);\n setQuery(query, 'interval', params.interval);\n setQuery(query, 'q', params.q);\n setQuery(query, 'cursor', params.cursor);\n setQuery(query, 'limit', params.limit);\n setQuery(query, 'sort', params.sort);\n setQuery(query, 'createdAfter', toIso(params.createdAfter));\n setQuery(query, 'createdBefore', toIso(params.createdBefore));\n\n const suffix = query.toString() ? `?${query}` : '';\n const envelope = await this.requestEnvelope<unknown[]>('GET', `/api/v1/subscriptions${suffix}`);\n return {\n data: (envelope.data ?? []).map(normalizeSubscription),\n pagination: normalizePagination(envelope.meta?.pagination),\n };\n }\n\n async get(id: string): Promise<Subscription> {\n const data = await this.request<unknown>(\n 'GET',\n `/api/v1/subscriptions/${encodeURIComponent(id)}`,\n );\n return normalizeSubscription(data);\n }\n\n async update(id: string, input: UpdateSubscriptionInput): Promise<Subscription> {\n const data = await this.request<unknown>(\n 'PATCH',\n `/api/v1/subscriptions/${encodeURIComponent(id)}`,\n input,\n );\n return normalizeSubscription(data);\n }\n\n changePlan(input: ChangePlanInput): Promise<Subscription> {\n const { id, ...body } = input;\n return this.update(id, body);\n }\n\n async pause(id: string): Promise<Subscription> {\n const data = await this.request<unknown>(\n 'POST',\n `/api/v1/subscriptions/${encodeURIComponent(id)}/pause`,\n );\n return normalizeSubscription(data);\n }\n\n async resume(id: string): Promise<Subscription> {\n const data = await this.request<unknown>(\n 'POST',\n `/api/v1/subscriptions/${encodeURIComponent(id)}/resume`,\n );\n return normalizeSubscription(data);\n }\n\n async cancel(id: string, input: { atPeriodEnd?: boolean } = {}): Promise<Subscription> {\n const data = await this.request<unknown>(\n 'POST',\n `/api/v1/subscriptions/${encodeURIComponent(id)}/cancel`,\n { atPeriodEnd: input.atPeriodEnd ?? false },\n );\n return normalizeSubscription(data);\n }\n\n async createCheckoutSession(input: CreateCheckoutSessionInput): Promise<CheckoutSession> {\n const data = await this.request<unknown>('POST', '/api/v1/checkout/sessions', input);\n return normalizeCheckoutSession(data);\n }\n\n async checkTrialEligibility(input: TrialEligibilityInput): Promise<TrialEligibilityResult> {\n const data = await this.request<unknown>('POST', '/api/v1/subscriptions/eligibility-check', {\n payment_method_id: input.paymentMethodId,\n });\n return normalizeTrialEligibility(data);\n }\n\n async getCustomerByExternalId(externalId: string): Promise<Customer | null> {\n try {\n const data = await this.request<unknown>(\n 'GET',\n `/api/v1/customers/by-external/${encodeURIComponent(externalId)}`,\n );\n return normalizeCustomer(data);\n } catch (err) {\n if (err instanceof ThrottleSubscriptionsError && err.statusCode === 404) return null;\n throw err;\n }\n }\n\n private async resolveCustomerId(\n customerId?: string,\n externalCustomerId?: string,\n ): Promise<string> {\n if (customerId) return customerId;\n if (!externalCustomerId) {\n throw new ThrottleSubscriptionsError({\n code: 'invalid_request',\n message: 'customerId or externalCustomerId is required',\n statusCode: 400,\n });\n }\n\n const customer = await this.getCustomerByExternalId(externalCustomerId);\n if (!customer) {\n throw new ThrottleSubscriptionsError({\n code: 'customer_not_found',\n message: 'Customer not found',\n statusCode: 404,\n });\n }\n return customer.id;\n }\n}\n\nexport function createSubscriptionsClient(opts: SubscriptionsClientOptions): SubscriptionsClient {\n return new SubscriptionsClient(opts);\n}\n\nfunction toAbsoluteUrl(baseUrl: string, path: string): string {\n if (/^https?:\\/\\//i.test(path)) return path;\n return `${baseUrl}${path.startsWith('/') ? path : `/${path}`}`;\n}\n\nfunction setQuery(query: URLSearchParams, key: string, value: unknown): void {\n if (value === undefined || value === null || value === '') return;\n query.set(key, String(value));\n}\n","import { createContext, useCallback, useContext, useMemo, useReducer, type ReactNode } from 'react';\nimport { SubscriptionsClient } from './client';\nimport type {\n SubscriptionFetcher,\n SubscriptionProviderProps,\n SubscriptionsClientContract,\n} from './types';\n\ninterface SubscriptionContextValue {\n client: SubscriptionsClientContract;\n cacheVersion: number;\n invalidate: () => void;\n}\n\nconst SubscriptionContext = createContext<SubscriptionContextValue | null>(null);\n\nexport function SubscriptionProvider({\n children,\n client,\n fetcher,\n baseUrl,\n timeoutMs,\n}: SubscriptionProviderProps) {\n const [cacheVersion, invalidate] = useReducer((value: number) => value + 1, 0);\n const resolvedClient = useMemo(() => {\n if (client) return client;\n return new SubscriptionsClient({\n fetcher: fetcher ?? createSubscriptionFetcher('/api/throttle'),\n baseUrl,\n timeoutMs,\n });\n }, [baseUrl, client, fetcher, timeoutMs]);\n\n const value = useMemo(\n () => ({ client: resolvedClient, cacheVersion, invalidate }),\n [cacheVersion, resolvedClient],\n );\n\n return <SubscriptionContext.Provider value={value}>{children}</SubscriptionContext.Provider>;\n}\n\nexport function useSubscriptionClient(): SubscriptionsClientContract {\n return useSubscriptionContext().client;\n}\n\nexport function useSubscriptionInvalidation(): () => void {\n return useSubscriptionContext().invalidate;\n}\n\nexport function useSubscriptionCacheVersion(): number {\n return useSubscriptionContext().cacheVersion;\n}\n\nexport function createSubscriptionFetcher(basePath: string): SubscriptionFetcher {\n const cleanBase = basePath.replace(/\\/+$/, '');\n return (path, init) => {\n const cleanPath = path.startsWith('/') ? path : `/${path}`;\n return fetch(`${cleanBase}${cleanPath}`, init);\n };\n}\n\nexport function useSubscriptionContext(): SubscriptionContextValue {\n const ctx = useContext(SubscriptionContext);\n if (!ctx) {\n throw new Error(\n '@usethrottle/subscriptions hooks must be used inside <SubscriptionProvider />',\n );\n }\n return ctx;\n}\n\nexport function SubscriptionProviderWithClient({\n children,\n client,\n}: {\n children: ReactNode;\n client: SubscriptionsClientContract;\n}) {\n const [cacheVersion, invalidate] = useReducer((value: number) => value + 1, 0);\n const value = useMemo(() => ({ client, cacheVersion, invalidate }), [cacheVersion, client]);\n return <SubscriptionContext.Provider value={value}>{children}</SubscriptionContext.Provider>;\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n useSubscriptionCacheVersion,\n useSubscriptionClient,\n useSubscriptionInvalidation,\n} from './provider';\nimport type {\n CancelSubscriptionInput,\n ChangePlanInput,\n CheckoutSession,\n CreateCheckoutSessionInput,\n CreateSubscriptionInput,\n Customer,\n ListSubscriptionsParams,\n MutationState,\n PaginatedSubscriptions,\n QueryOptions,\n QueryState,\n Subscription,\n TrialEligibilityInput,\n TrialEligibilityResult,\n UpdateSubscriptionInput,\n} from './types';\n\nexport function useSubscriptions(\n params: ListSubscriptionsParams = {},\n options: QueryOptions<PaginatedSubscriptions> = {},\n): QueryState<PaginatedSubscriptions> {\n const client = useSubscriptionClient();\n const cacheVersion = useSubscriptionCacheVersion();\n const stableParams = useStableValue(params);\n return useAsyncQuery(\n () => client.list(stableParams),\n [client, stableParams, cacheVersion],\n options,\n );\n}\n\nexport function useSubscription(\n id: string | null | undefined,\n options: QueryOptions<Subscription> = {},\n): QueryState<Subscription> {\n const client = useSubscriptionClient();\n const cacheVersion = useSubscriptionCacheVersion();\n return useAsyncQuery(\n () => (id ? client.get(id) : Promise.resolve(null)),\n [client, id, cacheVersion],\n { ...options, enabled: options.enabled ?? Boolean(id) },\n );\n}\n\nexport function useCustomerByExternalId(\n externalId: string | null | undefined,\n options: QueryOptions<Customer> = {},\n): QueryState<Customer> {\n const client = useSubscriptionClient();\n const cacheVersion = useSubscriptionCacheVersion();\n return useAsyncQuery(\n () => (externalId ? client.getCustomerByExternalId(externalId) : Promise.resolve(null)),\n [client, externalId, cacheVersion],\n { ...options, enabled: options.enabled ?? Boolean(externalId) },\n );\n}\n\nexport function useTrialEligibility(): MutationState<\n TrialEligibilityResult,\n TrialEligibilityInput\n> {\n const client = useSubscriptionClient();\n return useAsyncMutation((input) => client.checkTrialEligibility(input));\n}\n\nexport function useCreateSubscription(): MutationState<Subscription, CreateSubscriptionInput> {\n const client = useSubscriptionClient();\n const invalidate = useSubscriptionInvalidation();\n return useAsyncMutation((input) => client.create(input), invalidate);\n}\n\nexport function useUpdateSubscription(): MutationState<\n Subscription,\n { id: string; data: UpdateSubscriptionInput }\n> {\n const client = useSubscriptionClient();\n const invalidate = useSubscriptionInvalidation();\n return useAsyncMutation(({ id, data }) => client.update(id, data), invalidate);\n}\n\nexport function useChangePlan(): MutationState<Subscription, ChangePlanInput> {\n const client = useSubscriptionClient();\n const invalidate = useSubscriptionInvalidation();\n return useAsyncMutation((input) => client.changePlan(input), invalidate);\n}\n\nexport function useCancelSubscription(): MutationState<Subscription, CancelSubscriptionInput> {\n const client = useSubscriptionClient();\n const invalidate = useSubscriptionInvalidation();\n return useAsyncMutation(\n (input) => client.cancel(input.id, { atPeriodEnd: input.atPeriodEnd }),\n invalidate,\n );\n}\n\nexport function usePauseSubscription(): MutationState<Subscription, { id: string }> {\n const client = useSubscriptionClient();\n const invalidate = useSubscriptionInvalidation();\n return useAsyncMutation((input) => client.pause(input.id), invalidate);\n}\n\nexport function useResumeSubscription(): MutationState<Subscription, { id: string }> {\n const client = useSubscriptionClient();\n const invalidate = useSubscriptionInvalidation();\n return useAsyncMutation((input) => client.resume(input.id), invalidate);\n}\n\nexport function useCreateCheckoutSession(): MutationState<\n CheckoutSession,\n CreateCheckoutSessionInput\n> {\n const client = useSubscriptionClient();\n return useAsyncMutation((input) => client.createCheckoutSession(input));\n}\n\nfunction useAsyncQuery<T>(\n load: () => Promise<T | null>,\n deps: readonly unknown[],\n options: QueryOptions<T>,\n): QueryState<T> {\n const enabled = options.enabled ?? true;\n const [data, setData] = useState<T | null>(options.initialData ?? null);\n const [error, setError] = useState<unknown>(null);\n const [isLoading, setIsLoading] = useState(enabled && options.initialData === undefined);\n const [isFetching, setIsFetching] = useState(false);\n const loadRef = useRef(load);\n loadRef.current = load;\n\n const refetch = useCallback(async () => {\n if (!enabled) return data;\n setIsFetching(true);\n setError(null);\n try {\n const next = await loadRef.current();\n setData(next);\n return next;\n } catch (err) {\n setError(err);\n throw err;\n } finally {\n setIsFetching(false);\n setIsLoading(false);\n }\n }, [data, enabled]);\n\n useEffect(() => {\n if (!enabled) {\n setIsLoading(false);\n return;\n }\n let cancelled = false;\n setIsFetching(true);\n setError(null);\n load()\n .then((next) => {\n if (!cancelled) setData(next);\n })\n .catch((err) => {\n if (!cancelled) setError(err);\n })\n .finally(() => {\n if (!cancelled) {\n setIsLoading(false);\n setIsFetching(false);\n }\n });\n\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [enabled, ...deps]);\n\n return { data, error, isLoading, isFetching, refetch };\n}\n\nfunction useAsyncMutation<TData, TVariables>(\n action: (variables: TVariables) => Promise<TData>,\n onSuccess?: () => void,\n): MutationState<TData, TVariables> {\n const [data, setData] = useState<TData | null>(null);\n const [error, setError] = useState<unknown>(null);\n const [isPending, setIsPending] = useState(false);\n\n const mutateAsync = useCallback(\n async (variables: TVariables) => {\n setIsPending(true);\n setError(null);\n try {\n const next = await action(variables);\n setData(next);\n onSuccess?.();\n return next;\n } catch (err) {\n setError(err);\n throw err;\n } finally {\n setIsPending(false);\n }\n },\n [action, onSuccess],\n );\n\n const mutate = useCallback(\n (variables: TVariables) => {\n void mutateAsync(variables).catch(() => undefined);\n },\n [mutateAsync],\n );\n\n const reset = useCallback(() => {\n setData(null);\n setError(null);\n setIsPending(false);\n }, []);\n\n return { data, error, isPending, mutate, mutateAsync, reset };\n}\n\nfunction useStableValue<T>(value: T): T {\n const key = JSON.stringify(value);\n return useMemo(() => value, [key]);\n}\n","import type { Subscription, SubscriptionStatus } from './types';\n\nexport function isTerminalSubscription(status: SubscriptionStatus | Subscription): boolean {\n return getStatus(status) === 'cancelled';\n}\n\nexport function canPauseSubscription(status: SubscriptionStatus | Subscription): boolean {\n return getStatus(status) === 'active';\n}\n\nexport function canResumeSubscription(status: SubscriptionStatus | Subscription): boolean {\n return getStatus(status) === 'paused';\n}\n\nexport function canCancelSubscription(status: SubscriptionStatus | Subscription): boolean {\n return getStatus(status) !== 'cancelled';\n}\n\nexport function isSubscriptionPastDue(status: SubscriptionStatus | Subscription): boolean {\n return getStatus(status) === 'past_due';\n}\n\nexport function isSubscriptionTrialing(status: SubscriptionStatus | Subscription): boolean {\n return getStatus(status) === 'trialing';\n}\n\nexport function daysUntil(date: string | Date, now = new Date()): number {\n const end = date instanceof Date ? date : new Date(date);\n const ms = end.getTime() - now.getTime();\n if (!Number.isFinite(ms)) return 0;\n return Math.max(0, Math.ceil(ms / 86_400_000));\n}\n\nfunction getStatus(input: SubscriptionStatus | Subscription): SubscriptionStatus {\n return typeof input === 'string' ? input : input.status;\n}\n","import type { CSSProperties } from 'react';\nimport { daysUntil } from './helpers';\nimport type {\n DunningBannerProps,\n SubscriptionStatus,\n SubscriptionStatusBadgeProps,\n TrialCountdownProps,\n} from './types';\n\nconst STATUS_LABELS: Record<SubscriptionStatus, string> = {\n active: 'Active',\n paused: 'Paused',\n cancelled: 'Cancelled',\n past_due: 'Past due',\n trialing: 'Trialing',\n};\n\nconst STATUS_STYLES: Record<SubscriptionStatus, CSSProperties> = {\n active: { color: '#035c4f', background: '#dff8ef', borderColor: '#a8e8d2' },\n paused: { color: '#735c00', background: '#fff4ca', borderColor: '#f3d46b' },\n cancelled: { color: '#6c2632', background: '#ffe1e7', borderColor: '#f4a9b8' },\n past_due: { color: '#7a2d00', background: '#ffe8d6', borderColor: '#f5b47f' },\n trialing: { color: '#124c73', background: '#dff1ff', borderColor: '#9ed3fb' },\n};\n\nexport function SubscriptionStatusBadge({\n status,\n className,\n style,\n labels,\n}: SubscriptionStatusBadgeProps) {\n return (\n <span\n className={className}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n border: '1px solid',\n borderRadius: 999,\n padding: '2px 8px',\n fontSize: 12,\n fontWeight: 700,\n lineHeight: 1.6,\n whiteSpace: 'nowrap',\n ...STATUS_STYLES[status],\n ...style,\n }}\n >\n {labels?.[status] ?? STATUS_LABELS[status]}\n </span>\n );\n}\n\nexport function TrialCountdown({\n endDate,\n now,\n className,\n style,\n expiredLabel = 'Trial ended',\n prefix = 'Trial ends in',\n}: TrialCountdownProps) {\n const days = daysUntil(endDate, now);\n const label = days <= 0 ? expiredLabel : `${prefix} ${days} ${days === 1 ? 'day' : 'days'}`;\n\n return (\n <span className={className} style={style}>\n {label}\n </span>\n );\n}\n\nexport function DunningBanner({\n subscription,\n onUpdateCard,\n title = 'Payment needs attention',\n message,\n actionLabel = 'Update card',\n className,\n style,\n}: DunningBannerProps) {\n if (subscription.status !== 'past_due') return null;\n const fallbackMessage =\n subscription.failureCount > 0\n ? `We could not renew this subscription after ${subscription.failureCount} failed payment attempt${\n subscription.failureCount === 1 ? '' : 's'\n }.`\n : 'We could not renew this subscription with the saved payment method.';\n\n return (\n <div\n role=\"status\"\n className={className}\n style={{\n border: '1px solid #f5b47f',\n borderRadius: 8,\n background: '#fff7ed',\n color: '#7a2d00',\n padding: 16,\n display: 'grid',\n gap: 10,\n ...style,\n }}\n >\n <strong>{title}</strong>\n <span>{message ?? fallbackMessage}</span>\n {onUpdateCard ? (\n <button\n type=\"button\"\n onClick={onUpdateCard}\n style={{\n width: 'fit-content',\n border: '1px solid #7a2d00',\n borderRadius: 6,\n background: '#7a2d00',\n color: '#fff',\n padding: '8px 12px',\n fontWeight: 700,\n cursor: 'pointer',\n }}\n >\n {actionLabel}\n </button>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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","names":["value","import_react","import_jsx_runtime"]}
@@ -0,0 +1,84 @@
1
+ import { S as SubscriptionsClientContract, a as SubscriptionsClientOptions, T as ThrottleEnvelope, C as CreateSubscriptionInput, b as Subscription, L as ListSubscriptionsParams, P as PaginatedSubscriptions, U as UpdateSubscriptionInput, c as ChangePlanInput, d as CreateCheckoutSessionInput, e as CheckoutSession, f as TrialEligibilityInput, g as TrialEligibilityResult, h as Customer, i as SubscriptionProviderProps, j as SubscriptionFetcher, M as MutationState, k as CancelSubscriptionInput, Q as QueryOptions, l as QueryState, D as DunningBannerProps, m as SubscriptionStatusBadgeProps, n as TrialCountdownProps, o as SubscriptionStatus } from './types-PiTA3r6t.cjs';
2
+ export { p as CheckoutCollectInput, q as CheckoutCustomerInput, r as Pagination, R as RecurringIntent, s as SubscriptionInterval, t as SubscriptionSort, u as TrialEligibilityReason } from './types-PiTA3r6t.cjs';
3
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
+ import { ReactNode } from 'react';
5
+
6
+ declare class SubscriptionsClient implements SubscriptionsClientContract {
7
+ private readonly apiKey?;
8
+ private readonly baseUrl;
9
+ private readonly fetchImpl;
10
+ private readonly fetcher?;
11
+ private readonly timeoutMs;
12
+ constructor(opts?: SubscriptionsClientOptions);
13
+ request<T = unknown>(method: string, path: string, body?: unknown): Promise<T>;
14
+ requestEnvelope<T = unknown>(method: string, path: string, body?: unknown): Promise<ThrottleEnvelope<T>>;
15
+ create(input: CreateSubscriptionInput): Promise<Subscription>;
16
+ list(params?: ListSubscriptionsParams): Promise<PaginatedSubscriptions>;
17
+ get(id: string): Promise<Subscription>;
18
+ update(id: string, input: UpdateSubscriptionInput): Promise<Subscription>;
19
+ changePlan(input: ChangePlanInput): Promise<Subscription>;
20
+ pause(id: string): Promise<Subscription>;
21
+ resume(id: string): Promise<Subscription>;
22
+ cancel(id: string, input?: {
23
+ atPeriodEnd?: boolean;
24
+ }): Promise<Subscription>;
25
+ createCheckoutSession(input: CreateCheckoutSessionInput): Promise<CheckoutSession>;
26
+ checkTrialEligibility(input: TrialEligibilityInput): Promise<TrialEligibilityResult>;
27
+ getCustomerByExternalId(externalId: string): Promise<Customer | null>;
28
+ private resolveCustomerId;
29
+ }
30
+ declare function createSubscriptionsClient(opts: SubscriptionsClientOptions): SubscriptionsClient;
31
+
32
+ declare class ThrottleSubscriptionsError extends Error {
33
+ readonly code: string;
34
+ readonly statusCode: number;
35
+ readonly details?: unknown;
36
+ constructor(args: {
37
+ code: string;
38
+ message: string;
39
+ statusCode: number;
40
+ details?: unknown;
41
+ });
42
+ }
43
+
44
+ declare function SubscriptionProvider({ children, client, fetcher, baseUrl, timeoutMs, }: SubscriptionProviderProps): react_jsx_runtime.JSX.Element;
45
+ declare function useSubscriptionClient(): SubscriptionsClientContract;
46
+ declare function useSubscriptionInvalidation(): () => void;
47
+ declare function createSubscriptionFetcher(basePath: string): SubscriptionFetcher;
48
+ declare function SubscriptionProviderWithClient({ children, client, }: {
49
+ children: ReactNode;
50
+ client: SubscriptionsClientContract;
51
+ }): react_jsx_runtime.JSX.Element;
52
+
53
+ declare function useSubscriptions(params?: ListSubscriptionsParams, options?: QueryOptions<PaginatedSubscriptions>): QueryState<PaginatedSubscriptions>;
54
+ declare function useSubscription(id: string | null | undefined, options?: QueryOptions<Subscription>): QueryState<Subscription>;
55
+ declare function useCustomerByExternalId(externalId: string | null | undefined, options?: QueryOptions<Customer>): QueryState<Customer>;
56
+ declare function useTrialEligibility(): MutationState<TrialEligibilityResult, TrialEligibilityInput>;
57
+ declare function useCreateSubscription(): MutationState<Subscription, CreateSubscriptionInput>;
58
+ declare function useUpdateSubscription(): MutationState<Subscription, {
59
+ id: string;
60
+ data: UpdateSubscriptionInput;
61
+ }>;
62
+ declare function useChangePlan(): MutationState<Subscription, ChangePlanInput>;
63
+ declare function useCancelSubscription(): MutationState<Subscription, CancelSubscriptionInput>;
64
+ declare function usePauseSubscription(): MutationState<Subscription, {
65
+ id: string;
66
+ }>;
67
+ declare function useResumeSubscription(): MutationState<Subscription, {
68
+ id: string;
69
+ }>;
70
+ declare function useCreateCheckoutSession(): MutationState<CheckoutSession, CreateCheckoutSessionInput>;
71
+
72
+ declare function SubscriptionStatusBadge({ status, className, style, labels, }: SubscriptionStatusBadgeProps): react_jsx_runtime.JSX.Element;
73
+ declare function TrialCountdown({ endDate, now, className, style, expiredLabel, prefix, }: TrialCountdownProps): react_jsx_runtime.JSX.Element;
74
+ declare function DunningBanner({ subscription, onUpdateCard, title, message, actionLabel, className, style, }: DunningBannerProps): react_jsx_runtime.JSX.Element | null;
75
+
76
+ declare function isTerminalSubscription(status: SubscriptionStatus | Subscription): boolean;
77
+ declare function canPauseSubscription(status: SubscriptionStatus | Subscription): boolean;
78
+ declare function canResumeSubscription(status: SubscriptionStatus | Subscription): boolean;
79
+ declare function canCancelSubscription(status: SubscriptionStatus | Subscription): boolean;
80
+ declare function isSubscriptionPastDue(status: SubscriptionStatus | Subscription): boolean;
81
+ declare function isSubscriptionTrialing(status: SubscriptionStatus | Subscription): boolean;
82
+ declare function daysUntil(date: string | Date, now?: Date): number;
83
+
84
+ export { CancelSubscriptionInput, ChangePlanInput, CheckoutSession, CreateCheckoutSessionInput, CreateSubscriptionInput, Customer, DunningBanner, DunningBannerProps, ListSubscriptionsParams, MutationState, PaginatedSubscriptions, QueryOptions, QueryState, Subscription, SubscriptionFetcher, SubscriptionProvider, SubscriptionProviderProps, SubscriptionProviderWithClient, SubscriptionStatus, SubscriptionStatusBadge, SubscriptionStatusBadgeProps, SubscriptionsClient, SubscriptionsClientContract, SubscriptionsClientOptions, ThrottleEnvelope, ThrottleSubscriptionsError, TrialCountdown, TrialCountdownProps, TrialEligibilityInput, TrialEligibilityResult, UpdateSubscriptionInput, canCancelSubscription, canPauseSubscription, canResumeSubscription, createSubscriptionFetcher, createSubscriptionsClient, daysUntil, isSubscriptionPastDue, isSubscriptionTrialing, isTerminalSubscription, useCancelSubscription, useChangePlan, useCreateCheckoutSession, useCreateSubscription, useCustomerByExternalId, usePauseSubscription, useResumeSubscription, useSubscription, useSubscriptionClient, useSubscriptionInvalidation, useSubscriptions, useTrialEligibility, useUpdateSubscription };
@@ -0,0 +1,84 @@
1
+ import { S as SubscriptionsClientContract, a as SubscriptionsClientOptions, T as ThrottleEnvelope, C as CreateSubscriptionInput, b as Subscription, L as ListSubscriptionsParams, P as PaginatedSubscriptions, U as UpdateSubscriptionInput, c as ChangePlanInput, d as CreateCheckoutSessionInput, e as CheckoutSession, f as TrialEligibilityInput, g as TrialEligibilityResult, h as Customer, i as SubscriptionProviderProps, j as SubscriptionFetcher, M as MutationState, k as CancelSubscriptionInput, Q as QueryOptions, l as QueryState, D as DunningBannerProps, m as SubscriptionStatusBadgeProps, n as TrialCountdownProps, o as SubscriptionStatus } from './types-PiTA3r6t.js';
2
+ export { p as CheckoutCollectInput, q as CheckoutCustomerInput, r as Pagination, R as RecurringIntent, s as SubscriptionInterval, t as SubscriptionSort, u as TrialEligibilityReason } from './types-PiTA3r6t.js';
3
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
+ import { ReactNode } from 'react';
5
+
6
+ declare class SubscriptionsClient implements SubscriptionsClientContract {
7
+ private readonly apiKey?;
8
+ private readonly baseUrl;
9
+ private readonly fetchImpl;
10
+ private readonly fetcher?;
11
+ private readonly timeoutMs;
12
+ constructor(opts?: SubscriptionsClientOptions);
13
+ request<T = unknown>(method: string, path: string, body?: unknown): Promise<T>;
14
+ requestEnvelope<T = unknown>(method: string, path: string, body?: unknown): Promise<ThrottleEnvelope<T>>;
15
+ create(input: CreateSubscriptionInput): Promise<Subscription>;
16
+ list(params?: ListSubscriptionsParams): Promise<PaginatedSubscriptions>;
17
+ get(id: string): Promise<Subscription>;
18
+ update(id: string, input: UpdateSubscriptionInput): Promise<Subscription>;
19
+ changePlan(input: ChangePlanInput): Promise<Subscription>;
20
+ pause(id: string): Promise<Subscription>;
21
+ resume(id: string): Promise<Subscription>;
22
+ cancel(id: string, input?: {
23
+ atPeriodEnd?: boolean;
24
+ }): Promise<Subscription>;
25
+ createCheckoutSession(input: CreateCheckoutSessionInput): Promise<CheckoutSession>;
26
+ checkTrialEligibility(input: TrialEligibilityInput): Promise<TrialEligibilityResult>;
27
+ getCustomerByExternalId(externalId: string): Promise<Customer | null>;
28
+ private resolveCustomerId;
29
+ }
30
+ declare function createSubscriptionsClient(opts: SubscriptionsClientOptions): SubscriptionsClient;
31
+
32
+ declare class ThrottleSubscriptionsError extends Error {
33
+ readonly code: string;
34
+ readonly statusCode: number;
35
+ readonly details?: unknown;
36
+ constructor(args: {
37
+ code: string;
38
+ message: string;
39
+ statusCode: number;
40
+ details?: unknown;
41
+ });
42
+ }
43
+
44
+ declare function SubscriptionProvider({ children, client, fetcher, baseUrl, timeoutMs, }: SubscriptionProviderProps): react_jsx_runtime.JSX.Element;
45
+ declare function useSubscriptionClient(): SubscriptionsClientContract;
46
+ declare function useSubscriptionInvalidation(): () => void;
47
+ declare function createSubscriptionFetcher(basePath: string): SubscriptionFetcher;
48
+ declare function SubscriptionProviderWithClient({ children, client, }: {
49
+ children: ReactNode;
50
+ client: SubscriptionsClientContract;
51
+ }): react_jsx_runtime.JSX.Element;
52
+
53
+ declare function useSubscriptions(params?: ListSubscriptionsParams, options?: QueryOptions<PaginatedSubscriptions>): QueryState<PaginatedSubscriptions>;
54
+ declare function useSubscription(id: string | null | undefined, options?: QueryOptions<Subscription>): QueryState<Subscription>;
55
+ declare function useCustomerByExternalId(externalId: string | null | undefined, options?: QueryOptions<Customer>): QueryState<Customer>;
56
+ declare function useTrialEligibility(): MutationState<TrialEligibilityResult, TrialEligibilityInput>;
57
+ declare function useCreateSubscription(): MutationState<Subscription, CreateSubscriptionInput>;
58
+ declare function useUpdateSubscription(): MutationState<Subscription, {
59
+ id: string;
60
+ data: UpdateSubscriptionInput;
61
+ }>;
62
+ declare function useChangePlan(): MutationState<Subscription, ChangePlanInput>;
63
+ declare function useCancelSubscription(): MutationState<Subscription, CancelSubscriptionInput>;
64
+ declare function usePauseSubscription(): MutationState<Subscription, {
65
+ id: string;
66
+ }>;
67
+ declare function useResumeSubscription(): MutationState<Subscription, {
68
+ id: string;
69
+ }>;
70
+ declare function useCreateCheckoutSession(): MutationState<CheckoutSession, CreateCheckoutSessionInput>;
71
+
72
+ declare function SubscriptionStatusBadge({ status, className, style, labels, }: SubscriptionStatusBadgeProps): react_jsx_runtime.JSX.Element;
73
+ declare function TrialCountdown({ endDate, now, className, style, expiredLabel, prefix, }: TrialCountdownProps): react_jsx_runtime.JSX.Element;
74
+ declare function DunningBanner({ subscription, onUpdateCard, title, message, actionLabel, className, style, }: DunningBannerProps): react_jsx_runtime.JSX.Element | null;
75
+
76
+ declare function isTerminalSubscription(status: SubscriptionStatus | Subscription): boolean;
77
+ declare function canPauseSubscription(status: SubscriptionStatus | Subscription): boolean;
78
+ declare function canResumeSubscription(status: SubscriptionStatus | Subscription): boolean;
79
+ declare function canCancelSubscription(status: SubscriptionStatus | Subscription): boolean;
80
+ declare function isSubscriptionPastDue(status: SubscriptionStatus | Subscription): boolean;
81
+ declare function isSubscriptionTrialing(status: SubscriptionStatus | Subscription): boolean;
82
+ declare function daysUntil(date: string | Date, now?: Date): number;
83
+
84
+ export { CancelSubscriptionInput, ChangePlanInput, CheckoutSession, CreateCheckoutSessionInput, CreateSubscriptionInput, Customer, DunningBanner, DunningBannerProps, ListSubscriptionsParams, MutationState, PaginatedSubscriptions, QueryOptions, QueryState, Subscription, SubscriptionFetcher, SubscriptionProvider, SubscriptionProviderProps, SubscriptionProviderWithClient, SubscriptionStatus, SubscriptionStatusBadge, SubscriptionStatusBadgeProps, SubscriptionsClient, SubscriptionsClientContract, SubscriptionsClientOptions, ThrottleEnvelope, ThrottleSubscriptionsError, TrialCountdown, TrialCountdownProps, TrialEligibilityInput, TrialEligibilityResult, UpdateSubscriptionInput, canCancelSubscription, canPauseSubscription, canResumeSubscription, createSubscriptionFetcher, createSubscriptionsClient, daysUntil, isSubscriptionPastDue, isSubscriptionTrialing, isTerminalSubscription, useCancelSubscription, useChangePlan, useCreateCheckoutSession, useCreateSubscription, useCustomerByExternalId, usePauseSubscription, useResumeSubscription, useSubscription, useSubscriptionClient, useSubscriptionInvalidation, useSubscriptions, useTrialEligibility, useUpdateSubscription };
package/dist/index.js ADDED
@@ -0,0 +1,392 @@
1
+ import {
2
+ SubscriptionsClient,
3
+ ThrottleSubscriptionsError,
4
+ createSubscriptionsClient
5
+ } from "./chunk-LJAXLA7O.js";
6
+
7
+ // src/provider.tsx
8
+ import { createContext, useContext, useMemo, useReducer } from "react";
9
+ import { jsx } from "react/jsx-runtime";
10
+ var SubscriptionContext = createContext(null);
11
+ function SubscriptionProvider({
12
+ children,
13
+ client,
14
+ fetcher,
15
+ baseUrl,
16
+ timeoutMs
17
+ }) {
18
+ const [cacheVersion, invalidate] = useReducer((value2) => value2 + 1, 0);
19
+ const resolvedClient = useMemo(() => {
20
+ if (client) return client;
21
+ return new SubscriptionsClient({
22
+ fetcher: fetcher ?? createSubscriptionFetcher("/api/throttle"),
23
+ baseUrl,
24
+ timeoutMs
25
+ });
26
+ }, [baseUrl, client, fetcher, timeoutMs]);
27
+ const value = useMemo(
28
+ () => ({ client: resolvedClient, cacheVersion, invalidate }),
29
+ [cacheVersion, resolvedClient]
30
+ );
31
+ return /* @__PURE__ */ jsx(SubscriptionContext.Provider, { value, children });
32
+ }
33
+ function useSubscriptionClient() {
34
+ return useSubscriptionContext().client;
35
+ }
36
+ function useSubscriptionInvalidation() {
37
+ return useSubscriptionContext().invalidate;
38
+ }
39
+ function useSubscriptionCacheVersion() {
40
+ return useSubscriptionContext().cacheVersion;
41
+ }
42
+ function createSubscriptionFetcher(basePath) {
43
+ const cleanBase = basePath.replace(/\/+$/, "");
44
+ return (path, init) => {
45
+ const cleanPath = path.startsWith("/") ? path : `/${path}`;
46
+ return fetch(`${cleanBase}${cleanPath}`, init);
47
+ };
48
+ }
49
+ function useSubscriptionContext() {
50
+ const ctx = useContext(SubscriptionContext);
51
+ if (!ctx) {
52
+ throw new Error(
53
+ "@usethrottle/subscriptions hooks must be used inside <SubscriptionProvider />"
54
+ );
55
+ }
56
+ return ctx;
57
+ }
58
+ function SubscriptionProviderWithClient({
59
+ children,
60
+ client
61
+ }) {
62
+ const [cacheVersion, invalidate] = useReducer((value2) => value2 + 1, 0);
63
+ const value = useMemo(() => ({ client, cacheVersion, invalidate }), [cacheVersion, client]);
64
+ return /* @__PURE__ */ jsx(SubscriptionContext.Provider, { value, children });
65
+ }
66
+
67
+ // src/hooks.ts
68
+ import { useCallback as useCallback2, useEffect, useMemo as useMemo2, useRef, useState } from "react";
69
+ function useSubscriptions(params = {}, options = {}) {
70
+ const client = useSubscriptionClient();
71
+ const cacheVersion = useSubscriptionCacheVersion();
72
+ const stableParams = useStableValue(params);
73
+ return useAsyncQuery(
74
+ () => client.list(stableParams),
75
+ [client, stableParams, cacheVersion],
76
+ options
77
+ );
78
+ }
79
+ function useSubscription(id, options = {}) {
80
+ const client = useSubscriptionClient();
81
+ const cacheVersion = useSubscriptionCacheVersion();
82
+ return useAsyncQuery(
83
+ () => id ? client.get(id) : Promise.resolve(null),
84
+ [client, id, cacheVersion],
85
+ { ...options, enabled: options.enabled ?? Boolean(id) }
86
+ );
87
+ }
88
+ function useCustomerByExternalId(externalId, options = {}) {
89
+ const client = useSubscriptionClient();
90
+ const cacheVersion = useSubscriptionCacheVersion();
91
+ return useAsyncQuery(
92
+ () => externalId ? client.getCustomerByExternalId(externalId) : Promise.resolve(null),
93
+ [client, externalId, cacheVersion],
94
+ { ...options, enabled: options.enabled ?? Boolean(externalId) }
95
+ );
96
+ }
97
+ function useTrialEligibility() {
98
+ const client = useSubscriptionClient();
99
+ return useAsyncMutation((input) => client.checkTrialEligibility(input));
100
+ }
101
+ function useCreateSubscription() {
102
+ const client = useSubscriptionClient();
103
+ const invalidate = useSubscriptionInvalidation();
104
+ return useAsyncMutation((input) => client.create(input), invalidate);
105
+ }
106
+ function useUpdateSubscription() {
107
+ const client = useSubscriptionClient();
108
+ const invalidate = useSubscriptionInvalidation();
109
+ return useAsyncMutation(({ id, data }) => client.update(id, data), invalidate);
110
+ }
111
+ function useChangePlan() {
112
+ const client = useSubscriptionClient();
113
+ const invalidate = useSubscriptionInvalidation();
114
+ return useAsyncMutation((input) => client.changePlan(input), invalidate);
115
+ }
116
+ function useCancelSubscription() {
117
+ const client = useSubscriptionClient();
118
+ const invalidate = useSubscriptionInvalidation();
119
+ return useAsyncMutation(
120
+ (input) => client.cancel(input.id, { atPeriodEnd: input.atPeriodEnd }),
121
+ invalidate
122
+ );
123
+ }
124
+ function usePauseSubscription() {
125
+ const client = useSubscriptionClient();
126
+ const invalidate = useSubscriptionInvalidation();
127
+ return useAsyncMutation((input) => client.pause(input.id), invalidate);
128
+ }
129
+ function useResumeSubscription() {
130
+ const client = useSubscriptionClient();
131
+ const invalidate = useSubscriptionInvalidation();
132
+ return useAsyncMutation((input) => client.resume(input.id), invalidate);
133
+ }
134
+ function useCreateCheckoutSession() {
135
+ const client = useSubscriptionClient();
136
+ return useAsyncMutation((input) => client.createCheckoutSession(input));
137
+ }
138
+ function useAsyncQuery(load, deps, options) {
139
+ const enabled = options.enabled ?? true;
140
+ const [data, setData] = useState(options.initialData ?? null);
141
+ const [error, setError] = useState(null);
142
+ const [isLoading, setIsLoading] = useState(enabled && options.initialData === void 0);
143
+ const [isFetching, setIsFetching] = useState(false);
144
+ const loadRef = useRef(load);
145
+ loadRef.current = load;
146
+ const refetch = useCallback2(async () => {
147
+ if (!enabled) return data;
148
+ setIsFetching(true);
149
+ setError(null);
150
+ try {
151
+ const next = await loadRef.current();
152
+ setData(next);
153
+ return next;
154
+ } catch (err) {
155
+ setError(err);
156
+ throw err;
157
+ } finally {
158
+ setIsFetching(false);
159
+ setIsLoading(false);
160
+ }
161
+ }, [data, enabled]);
162
+ useEffect(() => {
163
+ if (!enabled) {
164
+ setIsLoading(false);
165
+ return;
166
+ }
167
+ let cancelled = false;
168
+ setIsFetching(true);
169
+ setError(null);
170
+ load().then((next) => {
171
+ if (!cancelled) setData(next);
172
+ }).catch((err) => {
173
+ if (!cancelled) setError(err);
174
+ }).finally(() => {
175
+ if (!cancelled) {
176
+ setIsLoading(false);
177
+ setIsFetching(false);
178
+ }
179
+ });
180
+ return () => {
181
+ cancelled = true;
182
+ };
183
+ }, [enabled, ...deps]);
184
+ return { data, error, isLoading, isFetching, refetch };
185
+ }
186
+ function useAsyncMutation(action, onSuccess) {
187
+ const [data, setData] = useState(null);
188
+ const [error, setError] = useState(null);
189
+ const [isPending, setIsPending] = useState(false);
190
+ const mutateAsync = useCallback2(
191
+ async (variables) => {
192
+ setIsPending(true);
193
+ setError(null);
194
+ try {
195
+ const next = await action(variables);
196
+ setData(next);
197
+ onSuccess?.();
198
+ return next;
199
+ } catch (err) {
200
+ setError(err);
201
+ throw err;
202
+ } finally {
203
+ setIsPending(false);
204
+ }
205
+ },
206
+ [action, onSuccess]
207
+ );
208
+ const mutate = useCallback2(
209
+ (variables) => {
210
+ void mutateAsync(variables).catch(() => void 0);
211
+ },
212
+ [mutateAsync]
213
+ );
214
+ const reset = useCallback2(() => {
215
+ setData(null);
216
+ setError(null);
217
+ setIsPending(false);
218
+ }, []);
219
+ return { data, error, isPending, mutate, mutateAsync, reset };
220
+ }
221
+ function useStableValue(value) {
222
+ const key = JSON.stringify(value);
223
+ return useMemo2(() => value, [key]);
224
+ }
225
+
226
+ // src/helpers.ts
227
+ function isTerminalSubscription(status) {
228
+ return getStatus(status) === "cancelled";
229
+ }
230
+ function canPauseSubscription(status) {
231
+ return getStatus(status) === "active";
232
+ }
233
+ function canResumeSubscription(status) {
234
+ return getStatus(status) === "paused";
235
+ }
236
+ function canCancelSubscription(status) {
237
+ return getStatus(status) !== "cancelled";
238
+ }
239
+ function isSubscriptionPastDue(status) {
240
+ return getStatus(status) === "past_due";
241
+ }
242
+ function isSubscriptionTrialing(status) {
243
+ return getStatus(status) === "trialing";
244
+ }
245
+ function daysUntil(date, now = /* @__PURE__ */ new Date()) {
246
+ const end = date instanceof Date ? date : new Date(date);
247
+ const ms = end.getTime() - now.getTime();
248
+ if (!Number.isFinite(ms)) return 0;
249
+ return Math.max(0, Math.ceil(ms / 864e5));
250
+ }
251
+ function getStatus(input) {
252
+ return typeof input === "string" ? input : input.status;
253
+ }
254
+
255
+ // src/components.tsx
256
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
257
+ var STATUS_LABELS = {
258
+ active: "Active",
259
+ paused: "Paused",
260
+ cancelled: "Cancelled",
261
+ past_due: "Past due",
262
+ trialing: "Trialing"
263
+ };
264
+ var STATUS_STYLES = {
265
+ active: { color: "#035c4f", background: "#dff8ef", borderColor: "#a8e8d2" },
266
+ paused: { color: "#735c00", background: "#fff4ca", borderColor: "#f3d46b" },
267
+ cancelled: { color: "#6c2632", background: "#ffe1e7", borderColor: "#f4a9b8" },
268
+ past_due: { color: "#7a2d00", background: "#ffe8d6", borderColor: "#f5b47f" },
269
+ trialing: { color: "#124c73", background: "#dff1ff", borderColor: "#9ed3fb" }
270
+ };
271
+ function SubscriptionStatusBadge({
272
+ status,
273
+ className,
274
+ style,
275
+ labels
276
+ }) {
277
+ return /* @__PURE__ */ jsx2(
278
+ "span",
279
+ {
280
+ className,
281
+ style: {
282
+ display: "inline-flex",
283
+ alignItems: "center",
284
+ border: "1px solid",
285
+ borderRadius: 999,
286
+ padding: "2px 8px",
287
+ fontSize: 12,
288
+ fontWeight: 700,
289
+ lineHeight: 1.6,
290
+ whiteSpace: "nowrap",
291
+ ...STATUS_STYLES[status],
292
+ ...style
293
+ },
294
+ children: labels?.[status] ?? STATUS_LABELS[status]
295
+ }
296
+ );
297
+ }
298
+ function TrialCountdown({
299
+ endDate,
300
+ now,
301
+ className,
302
+ style,
303
+ expiredLabel = "Trial ended",
304
+ prefix = "Trial ends in"
305
+ }) {
306
+ const days = daysUntil(endDate, now);
307
+ const label = days <= 0 ? expiredLabel : `${prefix} ${days} ${days === 1 ? "day" : "days"}`;
308
+ return /* @__PURE__ */ jsx2("span", { className, style, children: label });
309
+ }
310
+ function DunningBanner({
311
+ subscription,
312
+ onUpdateCard,
313
+ title = "Payment needs attention",
314
+ message,
315
+ actionLabel = "Update card",
316
+ className,
317
+ style
318
+ }) {
319
+ if (subscription.status !== "past_due") return null;
320
+ const fallbackMessage = subscription.failureCount > 0 ? `We could not renew this subscription after ${subscription.failureCount} failed payment attempt${subscription.failureCount === 1 ? "" : "s"}.` : "We could not renew this subscription with the saved payment method.";
321
+ return /* @__PURE__ */ jsxs(
322
+ "div",
323
+ {
324
+ role: "status",
325
+ className,
326
+ style: {
327
+ border: "1px solid #f5b47f",
328
+ borderRadius: 8,
329
+ background: "#fff7ed",
330
+ color: "#7a2d00",
331
+ padding: 16,
332
+ display: "grid",
333
+ gap: 10,
334
+ ...style
335
+ },
336
+ children: [
337
+ /* @__PURE__ */ jsx2("strong", { children: title }),
338
+ /* @__PURE__ */ jsx2("span", { children: message ?? fallbackMessage }),
339
+ onUpdateCard ? /* @__PURE__ */ jsx2(
340
+ "button",
341
+ {
342
+ type: "button",
343
+ onClick: onUpdateCard,
344
+ style: {
345
+ width: "fit-content",
346
+ border: "1px solid #7a2d00",
347
+ borderRadius: 6,
348
+ background: "#7a2d00",
349
+ color: "#fff",
350
+ padding: "8px 12px",
351
+ fontWeight: 700,
352
+ cursor: "pointer"
353
+ },
354
+ children: actionLabel
355
+ }
356
+ ) : null
357
+ ]
358
+ }
359
+ );
360
+ }
361
+ export {
362
+ DunningBanner,
363
+ SubscriptionProvider,
364
+ SubscriptionProviderWithClient,
365
+ SubscriptionStatusBadge,
366
+ SubscriptionsClient,
367
+ ThrottleSubscriptionsError,
368
+ TrialCountdown,
369
+ canCancelSubscription,
370
+ canPauseSubscription,
371
+ canResumeSubscription,
372
+ createSubscriptionFetcher,
373
+ createSubscriptionsClient,
374
+ daysUntil,
375
+ isSubscriptionPastDue,
376
+ isSubscriptionTrialing,
377
+ isTerminalSubscription,
378
+ useCancelSubscription,
379
+ useChangePlan,
380
+ useCreateCheckoutSession,
381
+ useCreateSubscription,
382
+ useCustomerByExternalId,
383
+ usePauseSubscription,
384
+ useResumeSubscription,
385
+ useSubscription,
386
+ useSubscriptionClient,
387
+ useSubscriptionInvalidation,
388
+ useSubscriptions,
389
+ useTrialEligibility,
390
+ useUpdateSubscription
391
+ };
392
+ //# sourceMappingURL=index.js.map