UNPKG

autumn-js

Version:
1,708 lines (1,668 loc) 57.7 kB
"use client"; "use strict"; "use client"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/libraries/react/BaseAutumnProvider.tsx var BaseAutumnProvider_exports = {}; __export(BaseAutumnProvider_exports, { BaseAutumnProvider: () => BaseAutumnProvider }); module.exports = __toCommonJS(BaseAutumnProvider_exports); var import_react3 = require("react"); var import_react4 = require("react"); // src/libraries/react/hooks/helpers/useDialog.tsx var import_react = require("react"); var useDialog = (component) => { const [dialogProps, setDialogProps] = (0, import_react.useState)(null); const [dialogOpen, setDialogOpen] = (0, import_react.useState)(false); (0, import_react.useEffect)(() => { if (!dialogOpen) { setTimeout(() => { setDialogProps(null); }, 200); } }, [dialogOpen]); return [dialogProps, setDialogProps, dialogOpen, setDialogOpen]; }; // src/libraries/react/hooks/useCustomerBase.tsx var import_swr2 = __toESM(require("swr")); // src/sdk/error.ts var AutumnError = class _AutumnError extends Error { message; code; constructor(response) { super(response.message); this.message = response.message; this.code = response.code; } static fromError(error) { return new _AutumnError({ message: error.message || "Unknown error", code: error.code || "unknown_error" }); } toString() { return `${this.message} (code: ${this.code})`; } toJSON() { return { message: this.message, code: this.code }; } }; // src/sdk/general/genMethods.ts var handleCheckout = async ({ instance, params }) => { return instance.post("/checkout", params); }; var handleAttach = async ({ instance, params }) => { return instance.post("/attach", params); }; var handleSetupPayment = async ({ instance, params }) => { return instance.post("/setup_payment", params); }; var handleCancel = async ({ instance, params }) => { return instance.post("/cancel", params); }; var handleTrack = async ({ instance, params }) => { return instance.post("/track", params); }; var handleUsage = async ({ instance, params }) => { return instance.post("/usage", params); }; var handleCheck = async ({ instance, params }) => { return instance.post("/check", params); }; var handleQuery = async ({ instance, params }) => { return instance.post("/query", params); }; // src/libraries/backend/constants.ts var autumnApiUrl = "https://api.useautumn.com/v1"; // src/sdk/utils.ts var import_query_string = __toESM(require("query-string")); var staticWrapper = (callback, instance, args) => { if (!instance) { instance = new Autumn(); } return callback({ instance, ...args }); }; var buildQueryString = (params) => { if (!params) return ""; return import_query_string.default.stringify(params, { skipNull: true, skipEmptyString: true }); }; var buildPathWithQuery = (basePath, params) => { const query = buildQueryString(params); return query ? `${basePath}?${query}` : basePath; }; // src/sdk/customers/cusMethods.ts var customerMethods = (instance) => { return { list: (params) => staticWrapper(listCustomers, instance, { params }), get: (id, params) => staticWrapper(getCustomer, instance, { id, params }), create: (params) => staticWrapper(createCustomer, instance, { params }), update: (id, params) => staticWrapper(updateCustomer, instance, { id, params }), delete: (id, params) => staticWrapper(deleteCustomer, instance, { id, params }), billingPortal: (id, params) => staticWrapper(billingPortal, instance, { id, params }), updateBalances: (id, params) => staticWrapper(updateBalances, instance, { id, params }) }; }; var getExpandStr = (expand) => { if (!expand) { return ""; } return `expand=${expand.join(",")}`; }; var listCustomers = async ({ instance, params }) => { const path = buildPathWithQuery("/customers", params); return instance.get(path); }; var getCustomer = async ({ instance, id, params }) => { if (!id) { return { data: null, error: new AutumnError({ message: "Customer ID is required", code: "CUSTOMER_ID_REQUIRED" }) }; } return instance.get(`/customers/${id}?${getExpandStr(params?.expand)}`); }; var createCustomer = async ({ instance, params }) => { return instance.post(`/customers?${getExpandStr(params?.expand)}`, params); }; var updateCustomer = async ({ instance, id, params }) => { return instance.post(`/customers/${id}`, params); }; var deleteCustomer = async ({ instance, id, params }) => { return instance.delete(`/customers/${id}${params?.delete_in_stripe ? "?delete_in_stripe=true" : ""}`); }; var billingPortal = async ({ instance, id, params }) => { return instance.post(`/customers/${id}/billing_portal`, params); }; var updateBalances = async ({ instance, id, params }) => { return instance.post(`/customers/${id}/balances`, { balances: Array.isArray(params) ? params : [params] }); }; // src/sdk/customers/entities/entMethods.ts var entityMethods = (instance) => { return { get: (customer_id, entity_id, params) => staticWrapper(getEntity, instance, { customer_id, entity_id, params }), create: (customer_id, params) => staticWrapper(createEntity, instance, { customer_id, params }), transfer: (customer_id, params) => staticWrapper(transferProduct, instance, { customer_id, params }), delete: (customer_id, entity_id) => staticWrapper(deleteEntity, instance, { customer_id, entity_id }) }; }; var getExpandStr2 = (expand) => { if (!expand) { return ""; } return `expand=${expand.join(",")}`; }; var getEntity = async ({ instance, customer_id, entity_id, params }) => { return instance.get( `/customers/${customer_id}/entities/${entity_id}?${getExpandStr2( params?.expand )}` ); }; var createEntity = async ({ instance, customer_id, params }) => { return instance.post(`/customers/${customer_id}/entities`, params); }; var deleteEntity = async ({ instance, customer_id, entity_id }) => { return instance.delete(`/customers/${customer_id}/entities/${entity_id}`); }; var transferProduct = async ({ instance, customer_id, params }) => { return instance.post(`/customers/${customer_id}/transfer`, params); }; // src/sdk/products/prodMethods.ts var productMethods = (instance) => { return { get: (id) => staticWrapper(getProduct, instance, { id }), create: (params) => staticWrapper(createProduct, instance, { params }), list: (params) => staticWrapper(listProducts, instance, { params }), delete: (id) => staticWrapper(deleteProduct, instance, { id }) }; }; var listProducts = async ({ instance, params }) => { let path = "/products_beta"; if (params) { const queryParams = new URLSearchParams(); for (const [key, value] of Object.entries(params)) { if (value !== void 0) { queryParams.append(key, String(value)); } } const queryString2 = queryParams.toString(); if (queryString2) { path += `?${queryString2}`; } } return instance.get(path); }; var getProduct = async ({ instance, id }) => { return instance.get(`/products/${id}`); }; var createProduct = async ({ instance, params }) => { return instance.post("/products", params); }; var deleteProduct = async ({ instance, id, params }) => { const path = buildPathWithQuery(`/products/${id}`, params); return instance.delete(path); }; // src/sdk/referrals/referralMethods.ts var referralMethods = (instance) => { return { createCode: (params) => staticWrapper(createReferralCode, instance, { params }), redeemCode: (params) => staticWrapper(redeemReferralCode, instance, { params }) }; }; var createReferralCode = async ({ instance, params }) => { return instance.post("/referrals/code", params); }; var redeemReferralCode = async ({ instance, params }) => { return instance.post("/referrals/redeem", params); }; // src/sdk/response.ts var toContainerResult = async ({ response, logger: logger2, logError = true }) => { if (response.status < 200 || response.status >= 300) { let error; try { error = await response.json(); if (logError) { logger2.error(`[Autumn] ${error.message}`); } } catch (error2) { throw error2; } return { data: null, error: new AutumnError({ message: error.message, code: error.code }), statusCode: response.status }; } try { const data = await response.json(); return { data, error: null, statusCode: response?.status }; } catch (error) { throw error; } }; // src/utils/logger.ts var getTime = () => { let timeString = (/* @__PURE__ */ new Date()).toISOString(); return `[${timeString.split("T")[1].split(".")[0]}]`; }; var greaterThanLevel = (level) => { return levels.indexOf(level) >= levels.indexOf(logger.level); }; var levels = ["debug", "info", "warn", "error", "fatal"]; var logger = { ...console, level: "info", debug: (...args) => { if (greaterThanLevel("debug")) { console.log(getTime(), "DEBUG", ...args); } }, log: (...args) => { console.log(getTime(), "INFO", ...args); }, info: (...args) => { if (greaterThanLevel("info")) { console.log(getTime(), "INFO", ...args); } }, warn: (...args) => { if (greaterThanLevel("warn")) { console.log(getTime(), "WARN", ...args); } }, error: (...args) => { if (greaterThanLevel("error")) { console.log(getTime(), "ERROR", ...args); } } }; // src/sdk/features/featureMethods.ts var featureMethods = (instance) => { return { list: () => staticWrapper(listFeatures, instance, {}), get: (id) => staticWrapper(getFeature, instance, { id }) }; }; var listFeatures = async ({ instance, params }) => { let path = "/features"; if (params) { const queryParams = new URLSearchParams(); for (const [key, value] of Object.entries(params)) { if (value !== void 0) { queryParams.append(key, String(value)); } } const queryString2 = queryParams.toString(); if (queryString2) { path += `?${queryString2}`; } } return instance.get(path); }; var getFeature = async ({ instance, id }) => { return instance.get(`/features/${id}`); }; // src/sdk/client.ts var LATEST_API_VERSION = "1.2"; var Autumn = class { secretKey; publishableKey; headers; url; logger = console; constructor(options) { try { this.secretKey = options?.secretKey || process.env.AUTUMN_SECRET_KEY; this.publishableKey = options?.publishableKey || process.env.AUTUMN_PUBLISHABLE_KEY; } catch (error) { } if (!this.secretKey && !this.publishableKey && !options?.headers) { throw new Error("Autumn secret key or publishable key is required"); } this.headers = options?.headers || { Authorization: `Bearer ${this.secretKey || this.publishableKey}`, "Content-Type": "application/json" }; let version = options?.version || LATEST_API_VERSION; this.headers["x-api-version"] = version; this.url = options?.url || autumnApiUrl; this.logger = logger; this.logger.level = options?.logLevel || "info"; } async get(path) { const response = await fetch(`${this.url}${path}`, { headers: this.headers }); return toContainerResult({ response, logger: this.logger }); } async post(path, body) { try { const response = await fetch(`${this.url}${path}`, { method: "POST", headers: this.headers, body: JSON.stringify(body) }); return toContainerResult({ response, logger: this.logger }); } catch (error) { console.error("Error sending request:", error); throw error; } } async delete(path) { const response = await fetch(`${this.url}${path}`, { method: "DELETE", headers: this.headers }); return toContainerResult({ response, logger: this.logger }); } static customers = customerMethods(); static products = productMethods(); static entities = entityMethods(); static referrals = referralMethods(); static features = featureMethods(); customers = customerMethods(this); products = productMethods(this); entities = entityMethods(this); referrals = referralMethods(this); features = featureMethods(this); /** * Initiates a checkout flow for a product purchase. * * The checkout function handles the purchase process for products with pricing. * It determines whether to show a dialog for user input or redirect directly * to Stripe based on the customer's state and product requirements. * * @param params - Checkout parameters including product ID, customer data, and options * @returns Promise resolving to checkout details including pricing, prorations, and URLs * * @example * ```typescript * const result = await autumn.checkout({ * customer_id: "user_123", * product_id: "pro", * success_url: "https://myapp.com/success" * }); * * if (result.url) { * // Redirect to Stripe checkout * window.location.href = result.url; * } * ``` */ async checkout(params) { return handleCheckout({ instance: this, params }); } static checkout = (params) => staticWrapper(handleCheckout, void 0, { params }); static usage = (params) => staticWrapper(handleUsage, void 0, { params }); /** * Attaches a product to a customer, enabling access and handling billing. * * The attach function activates a product for a customer and applies all product items. * When you attach a product: * - The customer gains access to all features in the product * - If the product has prices, the customer will be billed accordingly * - If there's no existing payment method, a checkout URL will be generated * * @param params - Attach parameters including customer ID, product ID, and options * @returns Promise resolving to attachment result with checkout URL if needed * * @example * ```typescript * const result = await autumn.attach({ * customer_id: "user_123", * product_id: "pro", * success_url: "https://myapp.com/success" * }); * * if (result.checkout_url) { * // Payment required - redirect to checkout * window.location.href = result.checkout_url; * } else { * // Product successfully attached * console.log("Access granted:", result.message); * } * ``` */ async attach(params) { return handleAttach({ instance: this, params }); } static attach = (params) => staticWrapper(handleAttach, void 0, { params }); static setupPayment = (params) => staticWrapper(handleSetupPayment, void 0, { params }); /** * Sets up a payment method for a customer. * * This method allows you to set up payment methods for customers without * immediately charging them. Useful for collecting payment information * before product attachment or for updating existing payment methods. * * @param params - Setup payment parameters including customer information * @returns Promise resolving to setup payment result * * @example * ```typescript * const result = await autumn.setupPayment({ * customer_id: "user_123" * }); * ``` */ async setupPayment(params) { return handleSetupPayment({ instance: this, params }); } static cancel = (params) => staticWrapper(handleCancel, void 0, { params }); /** * Cancels a customer's subscription or product attachment. * * This method allows you to cancel a customer's subscription to a specific product. * You can choose to cancel immediately or at the end of the billing cycle. * * @param params - Cancel parameters including customer ID and product ID * @returns Promise resolving to cancellation result * * @example * ```typescript * const result = await autumn.cancel({ * customer_id: "user_123", * product_id: "pro", * cancel_immediately: false // Cancel at end of billing cycle * }); * ``` */ async cancel(params) { return handleCancel({ instance: this, params }); } static check = (params) => staticWrapper(handleCheck, void 0, { params }); /** * Checks if a customer has access to a specific feature. * * This method verifies whether a customer has permission to use a feature * and checks their remaining balance/usage limits. It can be used to gate * features and determine when to show upgrade prompts. * * @param params - Check parameters including customer ID and feature ID * @returns Promise resolving to access check result with allowed status and balance info * * @example * ```typescript * const result = await autumn.check({ * customer_id: "user_123", * feature_id: "messages", * required_balance: 1 * }); * * if (!result.allowed) { * console.log("Feature access denied - upgrade required"); * } * ``` */ async check(params) { return handleCheck({ instance: this, params }); } static track = (params) => staticWrapper(handleTrack, void 0, { params }); /** * Tracks usage events for features or analytics. * * This method records usage events for metered features, updating the customer's * balance and usage statistics. It's typically used server-side to ensure * accurate tracking that cannot be manipulated by users. * * @param params - Track parameters including customer ID, feature ID, and usage value * @returns Promise resolving to tracking result * * @example * ```typescript * const result = await autumn.track({ * customer_id: "user_123", * feature_id: "messages", * value: 1 // Track 1 message sent * }); * ``` */ async track(params) { return handleTrack({ instance: this, params }); } /** * Retrieves usage statistics and analytics for a customer. * * This method fetches detailed usage information for a customer's features, * including current balances, usage history, and analytics data. Useful * for displaying usage dashboards or generating reports. * * @param params - Usage parameters including customer ID and optional filters * @returns Promise resolving to usage statistics and analytics data * * @example * ```typescript * const result = await autumn.usage({ * customer_id: "user_123", * feature_id: "messages" * value: 20 // Usage value * }); * ``` */ async usage(params) { return handleUsage({ instance: this, params }); } static query = (params) => staticWrapper(handleQuery, void 0, { params }); /** * Performs advanced queries on customer data and analytics. * * This method allows you to run complex queries against customer data, * usage patterns, and billing information. Useful for generating reports, * analytics, and custom data insights. * * @param params - Query parameters including customer ID and query specifications * @returns Promise resolving to query results with requested data * * @example * ```typescript * const result = await autumn.query({ * customer_id: "user_123", * feature_id: "messages" // feature id to fetch for query, can also be an array * }); * * ``` */ async query(params) { return handleQuery({ instance: this, params }); } }; // src/sdk/products/prodEnums.ts var ProductItemInterval = /* @__PURE__ */ ((ProductItemInterval2) => { ProductItemInterval2["Minute"] = "minute"; ProductItemInterval2["Hour"] = "hour"; ProductItemInterval2["Day"] = "day"; ProductItemInterval2["Week"] = "week"; ProductItemInterval2["Month"] = "month"; ProductItemInterval2["Quarter"] = "quarter"; ProductItemInterval2["SemiAnnual"] = "semi_annual"; ProductItemInterval2["Year"] = "year"; ProductItemInterval2["Multiple"] = "multiple"; return ProductItemInterval2; })(ProductItemInterval || {}); // src/sdk/customers/cusEnums.ts var import_v4 = require("zod/v4"); var CustomerExpandEnum = import_v4.z.enum([ "invoices", "rewards", "trials_used", "entities", "referrals", "payment_method" ]); // src/sdk/customers/cusTypes.ts var import_v42 = require("zod/v4"); var CoreCusFeatureSchema = import_v42.z.object({ unlimited: import_v42.z.boolean().optional(), interval: import_v42.z.enum(ProductItemInterval).optional(), balance: import_v42.z.number().nullish(), usage: import_v42.z.number().optional(), included_usage: import_v42.z.number().optional(), next_reset_at: import_v42.z.number().nullish(), overage_allowed: import_v42.z.boolean().optional(), usage_limit: import_v42.z.number().optional(), rollovers: import_v42.z.object({ balance: import_v42.z.number(), expires_at: import_v42.z.number() }).optional(), breakdown: import_v42.z.array( import_v42.z.object({ interval: import_v42.z.enum(ProductItemInterval), balance: import_v42.z.number().optional(), usage: import_v42.z.number().optional(), included_usage: import_v42.z.number().optional(), next_reset_at: import_v42.z.number().optional() }) ).optional(), credit_schema: import_v42.z.array( import_v42.z.object({ feature_id: import_v42.z.string(), credit_amount: import_v42.z.number() }) ).optional() }); var CustomerDataSchema = import_v42.z.object({ name: import_v42.z.string().nullish(), email: import_v42.z.string().nullish(), fingerprint: import_v42.z.string().nullish() }); var CreateCustomerParamsSchema = import_v42.z.object({ id: import_v42.z.string().nullish(), email: import_v42.z.string().nullish(), name: import_v42.z.string().nullish(), fingerprint: import_v42.z.string().nullish(), metadata: import_v42.z.record(import_v42.z.string(), import_v42.z.any()).optional(), expand: import_v42.z.array(CustomerExpandEnum).optional(), stripe_id: import_v42.z.string().nullish() }); var BillingPortalParamsSchema = import_v42.z.object({ return_url: import_v42.z.string().optional() }); var UpdateBalancesParamsSchema = import_v42.z.object({ feature_id: import_v42.z.string(), balance: import_v42.z.number() }).or( import_v42.z.array( import_v42.z.object({ feature_id: import_v42.z.string(), balance: import_v42.z.number() }) ) ); var DeleteCustomerParamsSchema = import_v42.z.object({ delete_in_stripe: import_v42.z.boolean().optional() }); var ListCustomersParamsSchema = import_v42.z.object({ limit: import_v42.z.number().optional(), offset: import_v42.z.number().optional() }); // src/sdk/general/checkTypes.ts var import_v43 = require("zod/v4"); var CheckFeatureResultSchema = import_v43.z.object({ allowed: import_v43.z.boolean(), feature_id: import_v43.z.string(), customer_id: import_v43.z.string(), entity_id: import_v43.z.string().optional(), required_balance: import_v43.z.number() }).extend(CoreCusFeatureSchema.shape); // src/sdk/customers/entities/entTypes.ts var import_v44 = require("zod/v4"); var EntityDataSchema = import_v44.z.object({ name: import_v44.z.string().optional(), feature_id: import_v44.z.string() }); var TransferProductParamsSchema = import_v44.z.object({ from_entity_id: import_v44.z.string(), to_entity_id: import_v44.z.string(), product_id: import_v44.z.string() }); // src/sdk/general/genTypes.ts var import_v45 = require("zod/v4"); var CancelParamsSchema = import_v45.z.object({ customer_id: import_v45.z.string(), product_id: import_v45.z.string(), entity_id: import_v45.z.string().optional(), cancel_immediately: import_v45.z.boolean().optional() }); var CancelResultSchema = import_v45.z.object({ success: import_v45.z.boolean(), customer_id: import_v45.z.string(), product_id: import_v45.z.string() }); var TrackParamsSchema = import_v45.z.object({ customer_id: import_v45.z.string(), value: import_v45.z.number().optional(), feature_id: import_v45.z.string().optional(), event_name: import_v45.z.string().optional(), entity_id: import_v45.z.string().optional(), customer_data: import_v45.z.any().optional(), idempotency_key: import_v45.z.string().optional(), entity_data: import_v45.z.any().optional(), properties: import_v45.z.record(import_v45.z.string(), import_v45.z.any()).optional() }); var TrackResultSchema = import_v45.z.object({ id: import_v45.z.string(), code: import_v45.z.string(), customer_id: import_v45.z.string(), feature_id: import_v45.z.string().optional(), event_name: import_v45.z.string().optional() }); var CheckParamsSchema = import_v45.z.object({ customer_id: import_v45.z.string(), feature_id: import_v45.z.string().optional(), product_id: import_v45.z.string().optional(), entity_id: import_v45.z.string().optional(), customer_data: import_v45.z.any().optional(), required_balance: import_v45.z.number().optional(), send_event: import_v45.z.boolean().optional(), with_preview: import_v45.z.boolean().optional(), entity_data: EntityDataSchema.optional() }); var QueryRangeEnum = import_v45.z.enum(["24h", "7d", "30d", "90d", "last_cycle"]); var QueryParamsSchema = import_v45.z.object({ customer_id: import_v45.z.string(), feature_id: import_v45.z.string().or(import_v45.z.array(import_v45.z.string())), range: QueryRangeEnum.optional() }); // src/sdk/referrals/referralTypes.ts var import_v46 = require("zod/v4"); var CreateReferralCodeParamsSchema = import_v46.z.object({ customer_id: import_v46.z.string(), program_id: import_v46.z.string() }); var RedeemReferralCodeParamsSchema = import_v46.z.object({ code: import_v46.z.string(), customer_id: import_v46.z.string() }); // src/sdk/general/attachTypes.ts var import_v47 = require("zod/v4"); var AttachFeatureOptionsSchema = import_v47.z.object({ feature_id: import_v47.z.string(), quantity: import_v47.z.number() }); var AttachParamsSchema = import_v47.z.object({ customer_id: import_v47.z.string(), product_id: import_v47.z.string().optional(), entity_id: import_v47.z.string().optional(), options: import_v47.z.array(AttachFeatureOptionsSchema).optional(), product_ids: import_v47.z.array(import_v47.z.string()).optional(), free_trial: import_v47.z.boolean().optional(), success_url: import_v47.z.string().optional(), metadata: import_v47.z.record(import_v47.z.string(), import_v47.z.string()).optional(), force_checkout: import_v47.z.boolean().optional(), customer_data: CustomerDataSchema.optional(), entity_data: import_v47.z.any().optional(), checkout_session_params: import_v47.z.record(import_v47.z.string(), import_v47.z.any()).optional(), reward: import_v47.z.string().optional(), invoice: import_v47.z.boolean().optional() }); var AttachResultSchema = import_v47.z.object({ checkout_url: import_v47.z.string().optional(), customer_id: import_v47.z.string(), product_ids: import_v47.z.array(import_v47.z.string()), code: import_v47.z.string(), message: import_v47.z.string(), customer_data: import_v47.z.any().optional(), invoice: import_v47.z.object({ status: import_v47.z.string(), stripe_id: import_v47.z.string(), hosted_invoice_url: import_v47.z.string().nullable(), total: import_v47.z.number(), currency: import_v47.z.string() }).optional() }); var CheckoutParamsSchema = import_v47.z.object({ customer_id: import_v47.z.string(), product_id: import_v47.z.string(), product_ids: import_v47.z.array(import_v47.z.string()).optional(), entity_id: import_v47.z.string().optional(), options: import_v47.z.array(AttachFeatureOptionsSchema).optional(), force_checkout: import_v47.z.boolean().optional(), invoice: import_v47.z.boolean().optional(), success_url: import_v47.z.string().optional(), customer_data: CustomerDataSchema.optional(), entity_data: import_v47.z.any().optional(), checkout_session_params: import_v47.z.record(import_v47.z.string(), import_v47.z.any()).optional(), reward: import_v47.z.string().optional() }); // src/sdk/features/featureTypes.ts var import_v48 = require("zod/v4"); var FeatureType = /* @__PURE__ */ ((FeatureType2) => { FeatureType2["Boolean"] = "boolean"; FeatureType2["SingleUse"] = "single_use"; FeatureType2["ContinuousUse"] = "continuous_use"; FeatureType2["CreditSystem"] = "credit_system"; return FeatureType2; })(FeatureType || {}); var FeatureSchema = import_v48.z.object({ id: import_v48.z.string(), name: import_v48.z.string(), type: import_v48.z.enum(FeatureType), display: import_v48.z.object({ singular: import_v48.z.string(), plural: import_v48.z.string() }).nullish(), credit_schema: import_v48.z.array( import_v48.z.object({ metered_feature_id: import_v48.z.string(), credit_cost: import_v48.z.number() }) ).nullish(), archived: import_v48.z.boolean() }); // src/libraries/react/hooks/helpers/handleCheck.ts var getCusFeature = ({ customer, featureId, requiredBalance = 1 }) => { let cusFeature = customer.features[featureId]; if (cusFeature && typeof cusFeature.balance === "number" && cusFeature.balance >= requiredBalance) { return { cusFeature, requiredBalance }; } let creditSchema = Object.values(customer.features).find( (f) => f.credit_schema && f.credit_schema.some((c) => c.feature_id === featureId) ); if (creditSchema) { let schemaItem = creditSchema.credit_schema?.find( (c) => c.feature_id === featureId ); return { cusFeature: creditSchema, requiredBalance: schemaItem.credit_amount * requiredBalance }; } return { cusFeature: customer.features[featureId], requiredBalance }; }; var getFeatureAllowed = ({ cusFeature, requiredBalance }) => { if (!cusFeature) return false; if (cusFeature.type == "static") return true; if (cusFeature.unlimited || cusFeature.overage_allowed) return true; if (cusFeature.usage_limit) { let extraUsage = (cusFeature.usage_limit || 0) - (cusFeature.included_usage || 0); return (cusFeature.balance || 0) + extraUsage >= requiredBalance; } return (cusFeature.balance || 0) >= requiredBalance; }; var handleFeatureCheck = ({ customer, isEntity, params }) => { let { cusFeature, requiredBalance } = getCusFeature({ customer, featureId: params.featureId, ...params.requiredBalance ? { requiredBalance: params.requiredBalance } : {} }); let allowed = getFeatureAllowed({ cusFeature, requiredBalance: requiredBalance ?? 1 }); let result = { allowed, feature_id: cusFeature?.id ?? params.featureId, customer_id: isEntity ? customer.customer_id : customer.id, required_balance: requiredBalance, ...cusFeature }; if (isEntity) { result.entity_id = customer.id; } try { return CheckFeatureResultSchema.parse(result); } catch (error) { return result; } }; var handleProductCheck = ({ customer, isEntity, params }) => { let product = customer.products.find((p) => p.id == params.productId); let allowed = product?.status === "active"; let result = { allowed, customer_id: isEntity ? customer.customer_id : customer.id, product_id: params.productId }; if (product) { result.status = product.status; } if (isEntity) { result.entity_id = customer.id; } return result; }; var openDialog = ({ result, params, context }) => { let open = result?.allowed === false && params.dialog && context; if (!open) return; const isInRenderCycle = (() => { const stack = new Error().stack || ""; return stack.includes("renderWithHooks") || stack.includes("updateFunctionComponent") || stack.includes("beginWork") || stack.includes("performUnitOfWork") || stack.includes("workLoop") || stack.includes("Component.render") || stack.includes("FunctionComponent"); })(); if (isInRenderCycle) { context.paywallRef.current = { component: params.dialog, open: true, props: params }; } else { context.paywallDialog.setComponent(params.dialog); context.paywallDialog.setProps(params); context.paywallDialog.setOpen(true); } }; var handleCheck2 = ({ customer, isEntity, params, context }) => { if (!customer) { return { data: { allowed: false, feature_id: "", customer_id: "", required_balance: 0 }, error: null }; } if (!params.featureId && !params.productId) { throw new Error("allowed() requires either featureId or productId"); } let result; if (params.featureId) result = handleFeatureCheck({ customer, params, isEntity }); if (params.productId) result = handleProductCheck({ customer, params, isEntity }); return { data: result, error: null }; }; // src/libraries/react/errorUtils/logAuthError.ts var logAuthError = async (response) => { if (response.status === 401) { let clonedResponse = response.clone(); let data = await clonedResponse.json(); if (data.message.includes("Missing authorization header")) { console.error(`[Autumn] Missing authorization header. Use the getBearerToken prop in <AutumnProvider /> to set the authorization header. https://docs.useautumn.com/quickstart/quickstart#5-set-up-autumnprovider`); return true; } } return false; }; // src/libraries/react/errorUtils/logFetchError.ts var logFetchError = ({ method, backendUrl, path, error }) => { console.error(`[Autumn] Fetch failed: ${method} ${backendUrl}${path} 1. Check that backendUrl in <AutumnProvider/> is correctly set. 2. Check that autumnHandler is correctly registered on your backend.`); }; // src/libraries/react/client/clientCusMethods.ts var createCustomerMethod = async ({ client, params }) => { let result = await client.post(`${client.prefix}/customers`, params); return result; }; // src/utils/entityUtils.tsx var getEntityExpandStr = (expand) => { if (!expand) { return ""; } return `expand=${expand.join(",")}`; }; // src/libraries/react/client/clientEntityMethods.ts async function createEntityMethod(params) { const res = await this.post(`${this.prefix}/entities`, params); return res; } async function getEntityMethod(entityId, params) { const expand = getEntityExpandStr(params?.expand); const res = await this.get(`${this.prefix}/entities/${entityId}?${expand}`); return res; } async function deleteEntityMethod(entityId) { const res = await this.delete(`${this.prefix}/entities/${entityId}`); return res; } // src/libraries/react/client/clientGenMethods.ts async function checkoutMethod(params) { const res = await this.post(`${this.prefix}/checkout`, params); return res; } async function attachMethod(params) { const res = await this.post(`${this.prefix}/attach`, params); return res; } async function setupPaymentMethod(params) { const res = await this.post(`${this.prefix}/setup_payment`, params); return res; } async function cancelMethod(params) { const res = await this.post(`${this.prefix}/cancel`, params); return res; } async function checkMethod(params) { const noDialogParams = { ...params, dialog: void 0 }; const res = await this.post(`${this.prefix}/check`, noDialogParams); return res; } async function trackMethod(params) { const res = await this.post(`${this.prefix}/track`, params); return res; } async function openBillingPortalMethod(params) { const res = await this.post(`${this.prefix}/billing_portal`, params || {}); return res; } async function queryMethod(params) { const res = await this.post(`${this.prefix}/query`, params); return res; } // src/libraries/react/client/clientProdMethods.ts async function listProductsMethod() { const res = await this.get(`${this.prefix}/products`); return res; } // src/libraries/react/client/clientReferralMethods.ts async function createCode(params) { const res = await this.post(`${this.prefix}/referrals/code`, params); return res; } async function redeemCode(params) { const res = await this.post(`${this.prefix}/referrals/redeem`, params); return res; } // src/libraries/react/client/ReactAutumnClient.tsx var AutumnClient = class { backendUrl; getBearerToken; customerData; includeCredentials; prefix; camelCase; headers; framework; constructor({ backendUrl, getBearerToken, customerData, includeCredentials, betterAuthUrl, headers }) { this.backendUrl = backendUrl; this.getBearerToken = getBearerToken; this.customerData = customerData; this.includeCredentials = includeCredentials; this.prefix = "/api/autumn"; let camelCase = false; if (betterAuthUrl) { this.prefix = "/api/auth/autumn"; this.backendUrl = betterAuthUrl; camelCase = true; } this.headers = headers; if (betterAuthUrl) camelCase = true; this.camelCase = camelCase; } /** * Detects if the backend supports CORS credentials by making an OPTIONS request */ async detectCors() { if (this.prefix?.includes("/api/auth")) { return { valid: true, includeCredentials: true }; } const testEndpoint = `${this.backendUrl}/api/autumn/cors`; try { await fetch(testEndpoint, { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify({}) }); return { valid: true, includeCredentials: true }; } catch (_) { try { await fetch(testEndpoint, { method: "POST", credentials: "omit", headers: { "Content-Type": "application/json" }, body: JSON.stringify({}) }); return { valid: true, includeCredentials: false }; } catch (_2) { return { valid: false, includeCredentials: void 0 }; } } } /** * Automatically determines whether to include credentials based on CORS detection */ async shouldIncludeCredentials() { if (this.includeCredentials !== void 0) { return this.includeCredentials; } try { const corsResult = await this.detectCors(); if (corsResult.valid) { console.warn( `[Autumn] Detected CORS credentials: ${corsResult.includeCredentials}` ); console.warn( `[Autumn] To disable this warning, you can set includeCredentials={${corsResult.includeCredentials ? "true" : "false"}} in <AutumnProvider />` ); this.includeCredentials = corsResult.includeCredentials; return corsResult.includeCredentials || false; } console.warn(`[Autumn] CORS detection failed, defaulting to false`); return false; } catch (error) { console.error(`[Autumn] Error detecting CORS: ${error.message}`); return false; } } async getHeaders() { let headers = { "Content-Type": "application/json" }; if (this.getBearerToken) { try { const token = await this.getBearerToken(); headers.Authorization = `Bearer ${token}`; } catch (_) { console.error(`Failed to call getToken() in AutumnProvider`); } } if (this.headers) { headers = { ...headers, ...this.headers }; } return headers; } async handleFetch({ path, method, body }) { body = method === "POST" ? { ...body, [this.camelCase ? "customerData" : "customer_data"]: this.customerData || void 0 } : void 0; const includeCredentials = await this.shouldIncludeCredentials(); try { const response = await fetch(`${this.backendUrl}${path}`, { method, body: body ? JSON.stringify(body) : void 0, headers: await this.getHeaders(), credentials: includeCredentials ? "include" : "omit" }); const loggedError = await logAuthError(response); return await toContainerResult({ response, logger: console, logError: !loggedError }); } catch (error) { logFetchError({ method, backendUrl: this.backendUrl || "", path, error }); return { data: null, error: new AutumnError({ message: error instanceof Error ? error.message : JSON.stringify(error), code: "fetch_failed" }) }; } } async post(path, body) { return await this.handleFetch({ path, method: "POST", body }); } async get(path) { return await this.handleFetch({ path, method: "GET" }); } async delete(path) { return await this.handleFetch({ path, method: "DELETE" }); } async createCustomer(params) { return await createCustomerMethod({ client: this, params }); } attach = attachMethod.bind(this); checkout = checkoutMethod.bind(this); cancel = cancelMethod.bind(this); check = checkMethod.bind(this); track = trackMethod.bind(this); openBillingPortal = openBillingPortalMethod.bind(this); setupPayment = setupPaymentMethod.bind(this); query = queryMethod.bind(this); entities = { create: createEntityMethod.bind(this), get: getEntityMethod.bind(this), delete: deleteEntityMethod.bind(this) }; referrals = { createCode: createCode.bind(this), redeemCode: redeemCode.bind(this) }; products = { list: listProductsMethod.bind(this) }; }; // src/libraries/react/AutumnContext.tsx var import_react2 = require("react"); var AutumnContext = (0, import_react2.createContext)({ initialized: false, disableDialogs: false, client: new AutumnClient({ backendUrl: "" }), paywallDialog: { props: null, setProps: () => { }, open: false, setOpen: () => { }, setComponent: () => { } }, attachDialog: { props: null, setProps: () => { }, open: false, setOpen: () => { }, setComponent: () => { } }, paywallRef: { current: null } }); var useAutumnContext = ({ AutumnContext: AutumnContext2, name, errorIfNotInitialized = true }) => { const context = (0, import_react2.useContext)(AutumnContext2); if (!context.initialized && errorIfNotInitialized) { throw new Error(`${name} must be used within <AutumnProvider />`); } return context; }; // src/libraries/react/hooks/usePricingTableBase.tsx var import_swr = __toESM(require("swr")); var mergeProductDetails = (products, productDetails) => { if (!products) { return null; } if (!productDetails) { return products.map((product) => { if (product.base_variant_id) { let baseProduct = products.find( (p) => p.id === product.base_variant_id ); if (baseProduct) { return { ...product, name: baseProduct.name }; } } return product; }); } let fetchedProducts = structuredClone(products); let mergedProducts = []; for (const overrideDetails of productDetails) { if (!overrideDetails.id) { let properties = {}; let overrideItems2 = overrideDetails.items?.map((item) => ({ display: { primary_text: item.primaryText, secondary_text: item.secondaryText } })); let overridePrice2 = overrideDetails.price; if (overrideDetails.price) { properties.is_free = false; overrideItems2 = [ { display: { primary_text: overridePrice2?.primaryText, secondary_text: overridePrice2?.secondaryText } }, ...overrideItems2 || [] ]; } if (!overrideItems2 || overrideItems2.length === 0) { overrideItems2 = [ { display: { primary_text: "" } } ]; } mergedProducts.push({ display: { name: overrideDetails.name, description: overrideDetails.description, button_text: overrideDetails.buttonText, recommend_text: overrideDetails.recommendText, everything_from: overrideDetails.everythingFrom, button_url: overrideDetails.buttonUrl }, items: overrideItems2, properties }); continue; } let fetchedProduct = fetchedProducts.find( (p) => p.id === overrideDetails.id ); if (!fetchedProduct) { continue; } let displayName = fetchedProduct.name; let baseVariantId = fetchedProduct.base_variant_id; if (baseVariantId) { let baseProduct = fetchedProducts.find((p) => p.id === baseVariantId); if (baseProduct) { displayName = baseProduct.name; } } displayName = overrideDetails.name || displayName; const originalIsFree = fetchedProduct.properties?.is_free; let overrideProperties = fetchedProduct.properties || {}; let overrideItems = overrideDetails.items; let overridePrice = overrideDetails.price; let mergedItems = []; if (overridePrice) { overrideProperties.is_free = false; if (originalIsFree || overrideItems !== void 0) { mergedItems.push({ display: { primary_text: overridePrice.primaryText, secondary_text: overridePrice.secondaryText } }); } else { fetchedProduct.items[0].display = { primary_text: overridePrice.primaryText, secondary_text: overridePrice.secondaryText }; } } else { if (overrideItems && !originalIsFree) { mergedItems.push(fetchedProduct.items[0]); } } if (overrideItems) { for (const overrideItem of overrideItems) { if (!overrideItem.featureId) { mergedItems.push({ display: { primary_text: overrideItem.primaryText, secondary_text: overrideItem.secondaryText } }); } else { let fetchedItem = fetchedProduct.items.find( (i) => i.feature_id === overrideItem.featureId ); if (!fetchedItem) { console.error( `Feature with id ${overrideItem.featureId} not found for product ${fetchedProduct.id}` ); continue; } mergedItems.push({ ...fetchedItem, display: { primary_text: overrideItem.primaryText || fetchedItem.display?.primary_text, secondary_text: overrideItem.secondaryText || fetchedItem.display?.secondary_text } }); } } } else { mergedItems = fetchedProduct.items; } const mergedProduct = { ...fetchedProduct, items: mergedItems, properties: overrideProperties, display: { name: displayName, description: overrideDetails.description, button_text: overrideDetails.buttonText, recommend_text: overrideDetails.recommendText, everything_from: overrideDetails.everythingFrom, button_url: overrideDetails.buttonUrl } }; mergedProducts.push(mergedProduct); } return mergedProducts; }; var defaultSWRConfig = { refreshInterval: 0 }; var usePricingTableBase = ({ client, params }) => { const fetcher = async () => { try { const { data: data2, error: error2 } = await client.products.list(); if (error2) throw error2; return data2?.list || []; } catch (error2) { throw new AutumnError({ message: "Failed to fetch pricing table products", code: "failed_to_fetch_pricing_table_products" }); } }; const { data, error, mutate } = (0, import_swr.default)( ["pricing-table", client.backendUrl], fetcher, { ...defaultSWRConfig } ); return { products: mergeProductDetails(data || [], params?.productDetails), isLoading: !error && !data, error, refetch: mutate }; }; // src/libraries/react/hooks/helpers/useAutumnBase.tsx var useAutumnBase = ({ // AutumnContext, context, client, refetchCustomer }) => { const { attachDialog, paywallDialog } = context || {}; const { refetch: refetchPricingTable } = usePricingTableBase({ client }); const attachWithoutDialog = async (params) => { const result = await client.attach(params); if (result.error) { return result; } let data = result.data; if (data?.checkout_url && typeof window !== "undefined") { if (params.openInNewTab) { window.open(data.checkout_url, "_blank"); } else