autumn-js
Version:
Autumn JS Library
1,708 lines (1,668 loc) • 57.7 kB
JavaScript
"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