@alexasomba/better-auth-paystack
Version:
Production-ready Paystack billing plugin for Better Auth. Supports subscriptions, one-time payments, organization billing, secure webhooks and more
1 lines • 253 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","names":["getAllowedSubscriptionChannels","subCode"],"sources":["../src/billing-store.ts","../src/paystack-sdk.ts","../src/utils.ts","../src/reference-access.ts","../src/middleware.ts","../src/limits.ts","../src/subscription-lifecycle.ts","../src/reconciliation.ts","../src/route-modules/checkout.ts","../src/route-modules/catalog.ts","../src/route-modules/subscriptions.ts","../src/route-modules/webhook.ts","../src/route-modules/shared.ts","../src/routes.ts","../src/schema.ts","../src/customer.ts","../src/operations.ts","../src/index.ts"],"sourcesContent":["import type { GenericEndpointContext } from \"better-auth\";\n\nimport type {\n Member,\n PaystackOrganization,\n PaystackPlan,\n PaystackProduct,\n PaystackTransaction,\n Subscription,\n User,\n} from \"./types\";\n\ntype Adapter = GenericEndpointContext[\"context\"][\"adapter\"];\ntype WhereValue = string | number | boolean | null;\ntype WhereClause = { field: string; value: WhereValue }[];\n\nexport interface BillingStore {\n findSubscriptionById(id: string): Promise<Subscription | null>;\n findSubscriptionByCode(subscriptionCode: string): Promise<Subscription | null>;\n findSubscriptionsByReference(referenceId: string): Promise<Subscription[]>;\n findCurrentSubscription(\n referenceId: string,\n groupId?: string | null,\n ): Promise<Subscription | null>;\n retireCompetingSubscriptions(\n referenceId: string,\n groupId: string | null,\n exceptId: string,\n ): Promise<void>;\n findSubscriptionsByTransactionReference(reference: string): Promise<Subscription[]>;\n createSubscription(data: Partial<Subscription> & Record<string, unknown>): Promise<Subscription>;\n updateSubscription(\n id: string,\n update: Partial<Subscription> & Record<string, unknown>,\n ): Promise<Subscription | null>;\n updateSubscriptionByCode(\n subscriptionCode: string,\n update: Partial<Subscription> & Record<string, unknown>,\n ): Promise<Subscription | null>;\n createTransaction(\n data: Partial<PaystackTransaction> & Record<string, unknown>,\n ): Promise<PaystackTransaction>;\n findTransactionByReference(reference: string): Promise<PaystackTransaction | null>;\n updateTransactionByReference(\n reference: string,\n update: Partial<PaystackTransaction> & Record<string, unknown>,\n ): Promise<PaystackTransaction | null>;\n listTransactions(referenceId: string): Promise<PaystackTransaction[]>;\n listProducts(): Promise<PaystackProduct[]>;\n findProductByName(name: string): Promise<PaystackProduct | null>;\n findProductBySlug(slug: string): Promise<PaystackProduct | null>;\n updateProduct(\n id: string,\n update: Partial<PaystackProduct> & Record<string, unknown>,\n ): Promise<void>;\n upsertProductByPaystackId(\n paystackId: string,\n data: Partial<PaystackProduct> & Record<string, unknown>,\n ): Promise<void>;\n listPlans(): Promise<PaystackPlan[]>;\n findPlanByName(name: string): Promise<PaystackPlan | null>;\n findPlanByCode(planCode: string): Promise<PaystackPlan | null>;\n upsertPlanByPaystackId(\n paystackId: string,\n data: Partial<PaystackPlan> & Record<string, unknown>,\n ): Promise<void>;\n findUser(id: string): Promise<User | null>;\n findOrganization(id: string): Promise<PaystackOrganization | null>;\n findOrganizationOwner(organizationId: string): Promise<Member | null>;\n listMembers(organizationId: string): Promise<Member[]>;\n listTeams(organizationId: string): Promise<unknown[]>;\n saveCustomerCode(\n referenceId: string,\n customerCode: string,\n isOrganization: boolean,\n ): Promise<void>;\n}\n\nfunction sortSubscriptionsForCurrent(subscriptions: Subscription[]): Subscription[] {\n const statusRank = new Map([\n [\"active\", 0],\n [\"trialing\", 1],\n [\"incomplete\", 2],\n [\"past_due\", 3],\n [\"canceled\", 4],\n ]);\n\n return [...subscriptions].sort((a, b) => {\n const rankA = statusRank.get(a.status) ?? 99;\n const rankB = statusRank.get(b.status) ?? 99;\n if (rankA !== rankB) return rankA - rankB;\n return new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime();\n });\n}\n\nexport function createBillingStore(ctx: GenericEndpointContext): BillingStore {\n return createBillingStoreFromAdapter(ctx.context.adapter);\n}\n\nexport function createBillingStoreFromAdapter(adapter: Adapter): BillingStore {\n const findOne = async <T>(model: string, where: WhereClause): Promise<T | null> =>\n (await adapter.findOne<T>({ model, where })) ?? null;\n\n const findMany = async <T>(model: string, where?: WhereClause): Promise<T[]> =>\n (await adapter.findMany<T>({ model, ...(where ? { where } : {}) })) ?? [];\n\n return {\n findSubscriptionById: (id) =>\n findOne<Subscription>(\"subscription\", [{ field: \"id\", value: id }]),\n findSubscriptionByCode: (subscriptionCode) =>\n findOne<Subscription>(\"subscription\", [\n { field: \"paystackSubscriptionCode\", value: subscriptionCode },\n ]),\n findSubscriptionsByReference: (referenceId) =>\n findMany<Subscription>(\"subscription\", [{ field: \"referenceId\", value: referenceId }]),\n async findCurrentSubscription(referenceId, groupId) {\n const subscriptions = await this.findSubscriptionsByReference(referenceId);\n const scoped =\n groupId === undefined\n ? subscriptions\n : subscriptions.filter((subscription) =>\n groupId === null\n ? subscription.groupId === undefined ||\n subscription.groupId === null ||\n subscription.groupId === \"\"\n : subscription.groupId === groupId,\n );\n return sortSubscriptionsForCurrent(scoped)[0] ?? null;\n },\n async retireCompetingSubscriptions(referenceId, groupId, exceptId) {\n const subscriptions = await this.findSubscriptionsByReference(referenceId);\n const competitors = subscriptions.filter(\n (subscription) =>\n subscription.id !== exceptId &&\n (subscription.status === \"active\" || subscription.status === \"trialing\") &&\n (groupId === null\n ? subscription.groupId === undefined ||\n subscription.groupId === null ||\n subscription.groupId === \"\"\n : subscription.groupId === groupId),\n );\n const now = new Date();\n for (const subscription of competitors) {\n await this.updateSubscription(subscription.id, {\n status: \"canceled\",\n cancelAtPeriodEnd: false,\n canceledAt: now,\n endedAt: now,\n updatedAt: now,\n });\n }\n },\n findSubscriptionsByTransactionReference: (reference) =>\n findMany<Subscription>(\"subscription\", [\n { field: \"paystackTransactionReference\", value: reference },\n ]),\n createSubscription: async (data) =>\n await adapter.create({\n model: \"subscription\",\n data: data as Omit<Subscription, \"id\">,\n }),\n updateSubscription: (id, update) =>\n adapter.update<Subscription>({\n model: \"subscription\",\n update,\n where: [{ field: \"id\", value: id }],\n }),\n updateSubscriptionByCode: (subscriptionCode, update) =>\n adapter.update<Subscription>({\n model: \"subscription\",\n update,\n where: [{ field: \"paystackSubscriptionCode\", value: subscriptionCode }],\n }),\n createTransaction: async (data) =>\n await adapter.create({\n model: \"paystackTransaction\",\n data: data as Omit<PaystackTransaction, \"id\">,\n }),\n findTransactionByReference: (reference) =>\n findOne<PaystackTransaction>(\"paystackTransaction\", [\n { field: \"reference\", value: reference },\n ]),\n updateTransactionByReference: (reference, update) =>\n adapter.update<PaystackTransaction>({\n model: \"paystackTransaction\",\n update,\n where: [{ field: \"reference\", value: reference }],\n }),\n async listTransactions(referenceId) {\n const transactions = await findMany<PaystackTransaction>(\"paystackTransaction\", [\n { field: \"referenceId\", value: referenceId },\n ]);\n return transactions.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());\n },\n async listProducts() {\n const products = await findMany<PaystackProduct>(\"paystackProduct\");\n return products.sort((a, b) => a.name.localeCompare(b.name));\n },\n findProductByName: (name) =>\n findOne<PaystackProduct>(\"paystackProduct\", [{ field: \"name\", value: name }]),\n findProductBySlug: (slug) =>\n findOne<PaystackProduct>(\"paystackProduct\", [{ field: \"slug\", value: slug }]),\n async updateProduct(id, update) {\n await adapter.update({\n model: \"paystackProduct\",\n update,\n where: [{ field: \"id\", value: id }],\n });\n },\n async upsertProductByPaystackId(paystackId, data) {\n const existing = await findOne<PaystackProduct>(\"paystackProduct\", [\n { field: \"paystackId\", value: paystackId },\n ]);\n if (existing?.id !== undefined) {\n const { createdAt: _createdAt, ...update } = data;\n await adapter.update({\n model: \"paystackProduct\",\n update,\n where: [{ field: \"id\", value: String(existing.id) }],\n });\n return;\n }\n await adapter.create({ model: \"paystackProduct\", data });\n },\n listPlans: () => findMany<PaystackPlan>(\"paystackPlan\"),\n findPlanByName: (name) =>\n findOne<PaystackPlan>(\"paystackPlan\", [{ field: \"name\", value: name }]),\n findPlanByCode: (planCode) =>\n findOne<PaystackPlan>(\"paystackPlan\", [{ field: \"planCode\", value: planCode }]),\n async upsertPlanByPaystackId(paystackId, data) {\n const existing = await findOne<PaystackPlan>(\"paystackPlan\", [\n { field: \"paystackId\", value: paystackId },\n ]);\n if (existing?.id !== undefined) {\n const { createdAt: _createdAt, ...update } = data;\n await adapter.update({\n model: \"paystackPlan\",\n update,\n where: [{ field: \"id\", value: existing.id }],\n });\n return;\n }\n await adapter.create({ model: \"paystackPlan\", data });\n },\n findUser: (id) => findOne<User>(\"user\", [{ field: \"id\", value: id }]),\n findOrganization: (id) =>\n findOne<PaystackOrganization>(\"organization\", [{ field: \"id\", value: id }]),\n findOrganizationOwner: (organizationId) =>\n findOne<Member>(\"member\", [\n { field: \"organizationId\", value: organizationId },\n { field: \"role\", value: \"owner\" },\n ]),\n listMembers: (organizationId) =>\n findMany<Member>(\"member\", [{ field: \"organizationId\", value: organizationId }]),\n listTeams: (organizationId) =>\n findMany(\"team\", [{ field: \"organizationId\", value: organizationId }]),\n async saveCustomerCode(referenceId, customerCode, isOrganization) {\n await adapter.update({\n model: isOrganization ? \"organization\" : \"user\",\n update: { paystackCustomerCode: customerCode },\n where: [{ field: \"id\", value: referenceId }],\n });\n },\n };\n}\n","import { APIError } from \"better-auth/api\";\nimport {\n PaystackError,\n PaystackResponse,\n type CustomerCreatePayload,\n type CustomerUpdatePayload,\n} from \"@alexasomba/paystack-node\";\nimport type { components } from \"@alexasomba/paystack-node\";\nimport type { PaystackClientLike } from \"./types\";\n\n/**\n * Interface for checking if a result is a PaystackResponse from the SDK v1.9.1+\n */\nfunction IsPaystackResponse(value: unknown): value is PaystackResponse<unknown> {\n return value instanceof PaystackResponse;\n}\n\n/**\n * Unwraps a Paystack SDK result, extracting the data or throwing an APIError if the request failed.\n * Leverages the native .unwrap() method in SDK v1.9.1+ if available.\n */\nexport function unwrapSdkResult<T = unknown>(result: unknown): T {\n if (IsPaystackResponse(result)) {\n try {\n return result.unwrap() as T;\n } catch (e: unknown) {\n if (e instanceof PaystackError) {\n throw new APIError(\"BAD_REQUEST\", {\n message: e.message,\n status: e.status,\n });\n }\n\n throw new APIError(\"BAD_REQUEST\", {\n message: (e as Error)?.message ?? \"Paystack API error\",\n });\n }\n }\n\n // Fallback for custom or legacy structures (e.g. from mocks in tests)\n let current = result;\n\n // Handle nested { data: { data: ... } } or { status: true, data: ... }\n while (current !== null && current !== undefined && typeof current === \"object\") {\n const body = current as Record<string, unknown>;\n\n // Check for Paystack Error shape\n if (body.status === false) {\n throw new APIError(\"BAD_REQUEST\", {\n message: (body.message as string | undefined) ?? \"Paystack API error\",\n });\n }\n\n // Stop if we have found the actual transaction/subscription payload properties\n if (\"authorization_url\" in body || \"reference\" in body || \"customer_code\" in body) {\n break;\n }\n\n // If there's a data property, unwrap it and continue checking\n if (\n \"data\" in body &&\n body.data !== undefined &&\n body.data !== null &&\n typeof body.data === \"object\"\n ) {\n current = body.data;\n continue;\n }\n break;\n }\n\n return current as T;\n}\n\n/**\n * Returns the operations object from a Paystack client.\n * For v1.9.1+, the client itself uses the grouped structure.\n */\nexport function getPaystackOps(client?: PaystackClientLike): PaystackClientLike | undefined {\n return client;\n}\n\ninterface ChargeAuthorizationPayload {\n email: string;\n amount: number;\n authorization_code: string;\n reference: string;\n metadata?: string;\n}\n\ninterface CreateSubscriptionPayload {\n customer: string;\n plan: string;\n authorization?: string;\n start_date?: string;\n}\n\nexport interface PaystackAdapter {\n initializeTransaction(\n body: components[\"schemas\"][\"TransactionInitialize\"],\n ): Promise<components[\"schemas\"][\"TransactionInitializeResponse\"][\"data\"]>;\n verifyTransaction(reference: string): Promise<unknown>;\n chargeAuthorization(body: ChargeAuthorizationPayload): Promise<unknown>;\n createCustomer(body: CustomerCreatePayload): Promise<unknown>;\n fetchCustomer(emailOrCode: string): Promise<unknown>;\n updateCustomer(\n emailOrCode: string,\n body: CustomerUpdatePayload & { email?: string },\n ): Promise<unknown>;\n listProducts(): Promise<components[\"schemas\"][\"ProductListsResponseArray\"][]>;\n fetchProduct(productId: number): Promise<unknown>;\n listPlans(): Promise<components[\"schemas\"][\"PlanListResponseArray\"][]>;\n createSubscription(body: CreateSubscriptionPayload): Promise<unknown>;\n fetchSubscription(subscriptionCode: string): Promise<unknown>;\n disableSubscription(body: { code: string; token: string }): Promise<unknown>;\n enableSubscription(body: { code: string; token: string }): Promise<unknown>;\n manageSubscriptionLink(subscriptionCode: string): Promise<{ link: string }>;\n}\n\nexport function createPaystackAdapter(client?: PaystackClientLike): PaystackAdapter {\n const requireClient = (): PaystackClientLike => {\n if (client === undefined || client === null) {\n throw new APIError(\"BAD_REQUEST\", { message: \"Paystack client is not configured\" });\n }\n return client;\n };\n\n return {\n async initializeTransaction(\n body: components[\"schemas\"][\"TransactionInitialize\"],\n ): Promise<components[\"schemas\"][\"TransactionInitializeResponse\"][\"data\"]> {\n const raw = await requireClient().transaction?.initialize({ body });\n return unwrapSdkResult<components[\"schemas\"][\"TransactionInitializeResponse\"][\"data\"]>(raw);\n },\n async verifyTransaction(reference: string): Promise<unknown> {\n const raw = await requireClient().transaction?.verify(reference);\n return unwrapSdkResult(raw);\n },\n async chargeAuthorization(body: ChargeAuthorizationPayload): Promise<unknown> {\n const raw = await requireClient().transaction?.chargeAuthorization({ body });\n return unwrapSdkResult(raw);\n },\n async createCustomer(body: CustomerCreatePayload): Promise<unknown> {\n const raw = await requireClient().customer?.create({ body });\n return unwrapSdkResult(raw);\n },\n async fetchCustomer(emailOrCode: string): Promise<unknown> {\n const raw = await requireClient().customer?.fetch(emailOrCode);\n return unwrapSdkResult(raw);\n },\n async updateCustomer(\n emailOrCode: string,\n body: CustomerUpdatePayload & { email?: string },\n ): Promise<unknown> {\n const raw = await requireClient().customer?.update(emailOrCode, {\n body: body,\n });\n return unwrapSdkResult(raw);\n },\n async listProducts(): Promise<components[\"schemas\"][\"ProductListsResponseArray\"][]> {\n const raw = await requireClient().product?.list({});\n return unwrapSdkResult<components[\"schemas\"][\"ProductListsResponseArray\"][]>(raw);\n },\n async fetchProduct(productId: number): Promise<unknown> {\n const raw = await requireClient().product?.fetch(productId);\n return unwrapSdkResult(raw);\n },\n async listPlans(): Promise<components[\"schemas\"][\"PlanListResponseArray\"][]> {\n const raw = await requireClient().plan?.list();\n return unwrapSdkResult<components[\"schemas\"][\"PlanListResponseArray\"][]>(raw);\n },\n async createSubscription(body: CreateSubscriptionPayload): Promise<unknown> {\n const raw = await requireClient().subscription?.create({ body });\n return unwrapSdkResult(raw);\n },\n async fetchSubscription(subscriptionCode: string): Promise<unknown> {\n const raw = await requireClient().subscription?.fetch(subscriptionCode);\n return unwrapSdkResult(raw);\n },\n async disableSubscription(body: { code: string; token: string }): Promise<unknown> {\n const raw = await requireClient().subscription?.disable({ body });\n return unwrapSdkResult(raw);\n },\n async enableSubscription(body: { code: string; token: string }): Promise<unknown> {\n const raw = await requireClient().subscription?.enable({ body });\n return unwrapSdkResult(raw);\n },\n async manageSubscriptionLink(subscriptionCode: string): Promise<{ link: string }> {\n const raw = await requireClient().subscription?.manageLink(subscriptionCode);\n return unwrapSdkResult<{ link: string }>(raw);\n },\n };\n}\n","import type { GenericEndpointContext } from \"better-auth\";\n\nimport type {\n AnyPaystackOptions,\n PaystackClientLike,\n PaystackPlan,\n PaystackProduct,\n Subscription,\n PaystackProductResponse,\n} from \"./types\";\nimport { createBillingStore } from \"./billing-store\";\nimport { createPaystackAdapter } from \"./paystack-sdk\";\n\nexport function getPlanSeatAmount(plan: PaystackPlan): number | undefined {\n if (plan.seatAmount !== undefined) {\n if (typeof plan.seatAmount === \"number\" && Number.isFinite(plan.seatAmount)) {\n return plan.seatAmount;\n }\n throw new Error(`Invalid seatAmount for plan '${plan.name}'. Expected a finite number.`);\n }\n\n if (plan.seatPriceId === undefined || plan.seatPriceId === null || plan.seatPriceId === \"\") {\n return undefined;\n }\n\n const parsed = typeof plan.seatPriceId === \"string\" ? Number(plan.seatPriceId) : plan.seatPriceId;\n if (typeof parsed === \"number\" && Number.isFinite(parsed)) {\n return parsed;\n }\n\n throw new Error(\n `Invalid seatPriceId for plan '${plan.name}'. Expected a numeric amount in the smallest currency unit.`,\n );\n}\n\nexport function calculatePlanAmount(plan: PaystackPlan, quantity: number): number {\n return (plan.amount ?? 0) + quantity * (getPlanSeatAmount(plan) ?? 0);\n}\n\nexport function normalizeSubscriptionGroup(group: string | undefined | null): string | null {\n const normalized = group?.trim().toLowerCase();\n return normalized === undefined || normalized === \"\" ? null : normalized;\n}\n\nexport function isLocalSubscriptionCode(subscriptionCode: string | undefined | null): boolean {\n return (\n typeof subscriptionCode === \"string\" &&\n (subscriptionCode.startsWith(\"LOC_\") || subscriptionCode.startsWith(\"sub_local_\"))\n );\n}\n\nexport function isLocallyManagedSubscription(\n subscription: Pick<Subscription, \"paystackSubscriptionCode\" | \"paystackPlanCode\">,\n): boolean {\n if (isLocalSubscriptionCode(subscription.paystackSubscriptionCode)) {\n return true;\n }\n\n if (\n typeof subscription.paystackSubscriptionCode === \"string\" &&\n subscription.paystackSubscriptionCode !== \"\"\n ) {\n return false;\n }\n\n return (\n subscription.paystackPlanCode === undefined ||\n subscription.paystackPlanCode === null ||\n subscription.paystackPlanCode === \"\"\n );\n}\n\nexport function assertLocallyManagedSubscription(\n subscription: Pick<Subscription, \"paystackSubscriptionCode\" | \"paystackPlanCode\">,\n action: string,\n): void {\n if (!isLocallyManagedSubscription(subscription)) {\n throw new Error(\n `Paystack-managed subscriptions do not support ${action}. Use local billing for seat-based or prorated subscription changes.`,\n );\n }\n}\n\nexport async function getPlans(\n subscriptionOptions: AnyPaystackOptions[\"subscription\"],\n): Promise<PaystackPlan[]> {\n if (subscriptionOptions?.enabled === true) {\n return typeof subscriptionOptions.plans === \"function\"\n ? subscriptionOptions.plans()\n : subscriptionOptions.plans;\n }\n throw new Error(\"Subscriptions are not enabled in the Paystack options.\");\n}\n\nexport const getPlan: (\n options: AnyPaystackOptions,\n planId: string,\n) => Promise<PaystackPlan | null> = async (options, planId) => {\n if (options.subscription?.enabled === true) {\n const plans = await getPlans(options.subscription);\n return plans.find((plan) => plan.name === planId) ?? null;\n }\n return null;\n};\n\nexport async function getPlanByName(\n options: AnyPaystackOptions,\n name: string,\n): Promise<PaystackPlan | null> {\n if (typeof name !== \"string\" || name.trim() === \"\") {\n return null;\n }\n if (options.subscription?.enabled === true) {\n const plans = await getPlans(options.subscription);\n const normalizedName = name.toLowerCase();\n return (\n plans.find(\n (plan) => typeof plan.name === \"string\" && plan.name.toLowerCase() === normalizedName,\n ) ?? null\n );\n }\n return null;\n}\n\nexport async function getPlanByPriceId(\n options: AnyPaystackOptions,\n priceId: string,\n): Promise<PaystackPlan | null> {\n if (options.subscription?.enabled === true) {\n const plans = await getPlans(options.subscription);\n return plans.find((plan) => plan.name === priceId) ?? null;\n }\n return null;\n}\n\nexport async function getProducts(\n productOptions: AnyPaystackOptions[\"products\"],\n): Promise<PaystackProduct[]> {\n if (productOptions?.products) {\n return typeof productOptions.products === \"function\"\n ? await productOptions.products()\n : productOptions.products;\n }\n return [];\n}\n\nexport async function getProductByName(\n options: AnyPaystackOptions,\n name: string,\n): Promise<PaystackProduct | null> {\n return await getProducts(options.products).then((products) =>\n products !== undefined && products !== null\n ? (products.find((product) => product.name.toLowerCase() === name.toLowerCase()) ?? null)\n : null,\n );\n}\n\nexport function getNextPeriodEnd(startDate: Date, interval: string): Date {\n const date = new Date(startDate);\n switch (interval) {\n case \"daily\":\n date.setDate(date.getDate() + 1);\n break;\n case \"weekly\":\n date.setDate(date.getDate() + 7);\n break;\n case \"monthly\":\n date.setMonth(date.getMonth() + 1);\n break;\n case \"quarterly\":\n date.setMonth(date.getMonth() + 3);\n break;\n case \"biannually\":\n date.setMonth(date.getMonth() + 6);\n break;\n case \"annually\":\n date.setFullYear(date.getFullYear() + 1);\n break;\n default:\n // Default to monthly if unknown\n date.setMonth(date.getMonth() + 1);\n }\n return date;\n}\n\n/**\n * Validates if the amount meets Paystack's minimum transaction requirements.\n * Amounts should be in the smallest currency unit (e.g., kobo, cents).\n */\nexport function validateMinAmount(amount: number, currency: string): boolean {\n const minAmounts: Record<string, number> = {\n NGN: 5000, // 50.00\n GHS: 10, // 0.10\n ZAR: 100, // 1.00\n KES: 300, // 3.00\n USD: 200, // 2.00\n XOF: 100, // 1.00\n };\n const min = minAmounts[currency.toUpperCase()];\n return min !== undefined ? amount >= min : true;\n}\n\nexport async function syncProductQuantityFromPaystack(\n ctx: GenericEndpointContext,\n productName: string,\n paystackClient: PaystackClientLike,\n): Promise<void> {\n const store = createBillingStore(ctx);\n // Find the local product record (by name or slug)\n let localProduct = await store.findProductByName(productName);\n\n localProduct ??= await store.findProductBySlug(productName.toLowerCase().replace(/\\s+/g, \"-\"));\n\n if (\n localProduct?.paystackId === undefined ||\n localProduct.paystackId === null ||\n localProduct.paystackId === \"\"\n ) {\n // No local record with a Paystack ID - fall back to local decrement\n if (\n localProduct?.id !== undefined &&\n localProduct.unlimited !== true &&\n typeof localProduct.quantity === \"number\" &&\n localProduct.quantity > 0\n ) {\n await store.updateProduct(localProduct.id, {\n quantity: localProduct.quantity - 1,\n updatedAt: new Date(),\n });\n }\n return;\n }\n\n // Fetch the latest quantity from Paystack\n try {\n const paystackProductId = Number(localProduct.paystackId);\n if (!Number.isFinite(paystackProductId)) {\n return;\n }\n const sdkRes = (await createPaystackAdapter(paystackClient).fetchProduct(\n paystackProductId,\n )) as PaystackProductResponse;\n const remoteQuantity = sdkRes?.quantity;\n\n if (remoteQuantity !== undefined && localProduct.id !== undefined) {\n await store.updateProduct(localProduct.id, {\n quantity: remoteQuantity,\n updatedAt: new Date(),\n });\n }\n } catch {\n // If API call fails, fall back to local decrement\n if (\n localProduct?.id !== undefined &&\n localProduct.unlimited !== true &&\n typeof localProduct.quantity === \"number\" &&\n localProduct.quantity > 0\n ) {\n await store.updateProduct(localProduct.id, {\n quantity: localProduct.quantity - 1,\n updatedAt: new Date(),\n });\n }\n }\n}\n\nexport async function decrementProductQuantity(\n ctx: GenericEndpointContext,\n productName: string,\n): Promise<void> {\n const store = createBillingStore(ctx);\n let product = await store.findProductByName(productName);\n\n product ??= await store.findProductBySlug(productName.toLowerCase().replace(/\\s+/g, \"-\"));\n\n if (product !== undefined && product !== null) {\n if (\n product.unlimited !== true &&\n typeof product.quantity === \"number\" &&\n product.quantity > 0 &&\n product.id !== undefined\n ) {\n await store.updateProduct(product.id, {\n quantity: product.quantity - 1,\n updatedAt: new Date(),\n });\n }\n }\n}\n\nexport async function syncSubscriptionSeats(\n ctx: GenericEndpointContext,\n organizationId: string,\n options: AnyPaystackOptions,\n): Promise<void> {\n if (options.subscription?.enabled !== true) return;\n\n const store = createBillingStore(ctx);\n const subscriptions = (await store.findSubscriptionsByReference(organizationId)).filter(\n (subscription) => subscription.status === \"active\" || subscription.status === \"trialing\",\n );\n const seatSubscriptions: Subscription[] = [];\n for (const candidate of subscriptions) {\n const candidatePlan = await getPlanByName(options, candidate.plan);\n if (candidatePlan !== null && getPlanSeatAmount(candidatePlan) !== undefined) {\n seatSubscriptions.push(candidate);\n }\n }\n const members = await store.listMembers(organizationId);\n const quantity = members.length;\n for (const subscription of seatSubscriptions) {\n if (\n subscription.paystackSubscriptionCode === undefined ||\n subscription.paystackSubscriptionCode === null ||\n subscription.paystackSubscriptionCode === \"\"\n )\n continue;\n try {\n assertLocallyManagedSubscription(subscription, \"automatic seat sync\");\n\n // Locally managed subscriptions renew via saved authorizations, so seat count lives in our DB.\n await store.updateSubscription(subscription.id, {\n seats: quantity,\n updatedAt: new Date(),\n });\n } catch (e: unknown) {\n ctx.context.logger.error(\"Failed to sync subscription seats\", e);\n }\n }\n}\n","import type { GenericEndpointContext } from \"better-auth\";\nimport { APIError } from \"better-auth/api\";\n\nimport type { AnyPaystackOptions, Session, User } from \"./types\";\n\nexport type BillingReferenceAction =\n | \"initialize-transaction\"\n | \"verify-transaction\"\n | \"list-subscriptions\"\n | \"list-transactions\"\n | \"disable-subscription\"\n | \"enable-subscription\"\n | \"get-subscription-manage-link\";\n\nconst DEFAULT_BILLING_ORG_ROLES = [\"owner\", \"admin\"] as const;\n\nfunction normalizeBillingRoles(roles: readonly string[]): Set<string> {\n return new Set(roles.map((value) => value.trim()).filter((value) => value !== \"\"));\n}\n\nexport function getBillingRoles(options: AnyPaystackOptions): readonly string[] {\n return options.organization?.billingRoles ?? DEFAULT_BILLING_ORG_ROLES;\n}\n\nexport function hasBillingRole(\n role: unknown,\n billingRoles: readonly string[] = DEFAULT_BILLING_ORG_ROLES,\n): boolean {\n const allowedRoles = normalizeBillingRoles(billingRoles);\n if (Array.isArray(role)) {\n return role.some((value) => hasBillingRole(value, billingRoles));\n }\n if (typeof role !== \"string\") {\n return false;\n }\n return role\n .split(\",\")\n .map((value) => value.trim())\n .some((value) => allowedRoles.has(value));\n}\n\nexport function resolveBillingReferenceId(input: {\n body?: unknown;\n query?: unknown;\n requestUrl?: string;\n fallbackUserId: string;\n}): string {\n const body = (input.body ?? {}) as Record<string, unknown>;\n const query = (input.query ?? {}) as Record<string, unknown>;\n const requestQueryReferenceId =\n typeof input.requestUrl === \"string\"\n ? (new URL(input.requestUrl).searchParams.get(\"referenceId\") ?? undefined)\n : undefined;\n\n return (\n (body.referenceId as string | undefined) ??\n (query.referenceId as string | undefined) ??\n requestQueryReferenceId ??\n input.fallbackUserId\n );\n}\n\nexport async function authorizeBillingReference(\n ctx: GenericEndpointContext,\n options: AnyPaystackOptions,\n data: {\n user: User;\n session: Session;\n referenceId: string;\n action: BillingReferenceAction;\n },\n): Promise<void> {\n if (data.referenceId === data.user.id) return;\n\n if (\n options.subscription?.enabled === true &&\n typeof options.subscription.authorizeReference === \"function\"\n ) {\n const authorized = await options.subscription.authorizeReference(\n {\n user: data.user,\n session: data.session,\n referenceId: data.referenceId,\n action: data.action,\n },\n ctx,\n );\n if (authorized === true) return;\n throw new APIError(\"UNAUTHORIZED\");\n }\n\n if (options.organization?.enabled === true) {\n const member = await ctx.context.adapter.findOne({\n model: \"member\",\n where: [\n { field: \"userId\", value: data.user.id },\n { field: \"organizationId\", value: data.referenceId },\n ],\n });\n\n if (\n member !== null &&\n member !== undefined &&\n hasBillingRole((member as { role?: unknown }).role, getBillingRoles(options))\n ) {\n return;\n }\n }\n\n throw new APIError(\"UNAUTHORIZED\");\n}\n","import { APIError, createAuthMiddleware, type AuthMiddleware } from \"better-auth/api\";\n\nimport type { PaystackOptions } from \"./types\";\nimport {\n authorizeBillingReference,\n type BillingReferenceAction,\n resolveBillingReferenceId,\n} from \"./reference-access\";\n\nexport { hasBillingRole } from \"./reference-access\";\n\nexport const referenceMiddleware = (\n options: PaystackOptions,\n action: BillingReferenceAction,\n): AuthMiddleware =>\n createAuthMiddleware(async (ctx) => {\n const session = ctx.context.session;\n\n if (session === null || session === undefined) {\n throw new APIError(\"UNAUTHORIZED\");\n }\n const referenceId = resolveBillingReferenceId({\n body: ctx.body,\n query: ctx.query,\n requestUrl: ctx.request?.url,\n fallbackUserId: session.user.id,\n });\n\n await authorizeBillingReference(ctx, options, {\n user: session.user,\n session: session.session,\n referenceId,\n action,\n });\n\n return {\n context: {\n ...ctx.context,\n referenceId,\n },\n };\n });\n","import type { GenericEndpointContext } from \"better-auth\";\nimport { APIError } from \"better-auth/api\";\n\nimport type { AnyPaystackOptions, Subscription } from \"./types\";\nimport { createBillingStore } from \"./billing-store\";\nimport { getPlanByName } from \"./utils\";\n\nexport const getOrganizationSubscription = async (\n ctx: GenericEndpointContext,\n organizationId: string,\n groupId?: string | null,\n): Promise<Subscription | null> => {\n return createBillingStore(ctx).findCurrentSubscription(organizationId, groupId);\n};\n\nexport const checkSeatLimit = async (\n ctx: GenericEndpointContext,\n organizationId: string,\n seatsToAdd = 1,\n): Promise<boolean> => {\n const store = createBillingStore(ctx);\n const subscriptions = (await store.findSubscriptionsByReference(organizationId)).filter(\n (subscription) => subscription.status === \"active\" || subscription.status === \"trialing\",\n );\n const seatLimit = subscriptions.reduce<number | undefined>(\n (maximum, subscription) =>\n typeof subscription.seats === \"number\"\n ? Math.max(maximum ?? subscription.seats, subscription.seats)\n : maximum,\n undefined,\n );\n const members = await store.listMembers(organizationId);\n\n if (seatLimit === undefined) {\n return true; // No subscription, no specific limit enforcement here (or maybe allow depending on config)\n }\n\n if (members.length + seatsToAdd > seatLimit) {\n throw new APIError(\"FORBIDDEN\", {\n message: `Organization member limit reached. Used: ${members.length}, Max: ${seatLimit}`,\n });\n }\n\n return true;\n};\n\nexport async function getOrganizationEntitlements(\n ctx: GenericEndpointContext,\n organizationId: string,\n options: AnyPaystackOptions,\n): Promise<{ limits: Record<string, number>; features: string[] }> {\n const subscriptions = (\n await createBillingStore(ctx).findSubscriptionsByReference(organizationId)\n ).filter(\n (subscription) => subscription.status === \"active\" || subscription.status === \"trialing\",\n );\n const limits: Record<string, number> = {};\n const features = new Set<string>();\n for (const subscription of subscriptions) {\n const plan = await getPlanByName(options, subscription.plan);\n for (const [name, value] of Object.entries(plan?.limits ?? {})) {\n if (typeof value === \"number\" && Number.isFinite(value)) {\n limits[name] = Math.max(limits[name] ?? value, value);\n }\n }\n for (const feature of plan?.features ?? []) features.add(feature);\n }\n return { limits, features: [...features] };\n}\n\nexport const checkTeamLimit = async (\n ctx: GenericEndpointContext,\n organizationId: string,\n maxTeams: number,\n): Promise<boolean> => {\n const teams = await createBillingStore(ctx).listTeams(organizationId);\n\n if (teams.length >= maxTeams) {\n throw new APIError(\"FORBIDDEN\", {\n message: `Organization team limit reached. Max teams: ${maxTeams}`,\n });\n }\n\n return true;\n};\n","import type { GenericEndpointContext } from \"better-auth\";\nimport { APIError } from \"better-auth/api\";\nimport type { components } from \"@alexasomba/paystack-node\";\n\nimport { createBillingStore } from \"./billing-store\";\nimport { getOrganizationSubscription } from \"./limits\";\nimport { createPaystackAdapter } from \"./paystack-sdk\";\nimport {\n assertLocallyManagedSubscription,\n calculatePlanAmount,\n getPlanByName,\n getPlanSeatAmount,\n normalizeSubscriptionGroup,\n} from \"./utils\";\nimport type {\n AnyPaystackOptions,\n PaystackChargeAuthorizationResponse,\n PaystackCheckoutChannel,\n PaystackInitializeResult,\n PaystackPlan,\n Subscription,\n User,\n} from \"./types\";\nimport { createProrationMetadata, stringifyPaystackMetadata } from \"./metadata\";\n\nexport type ProratedUpgradeOutcome =\n | Extract<PaystackInitializeResult, { kind: \"prorated\" }>\n | {\n kind: \"checkout\";\n url: string | undefined;\n reference: string | undefined;\n accessCode: string | undefined;\n redirect: true;\n };\n\nexport interface TrialLifecycleDecision {\n trialStart?: Date;\n trialEnd?: Date;\n requestedDays: number;\n requested: boolean;\n granted: boolean;\n deniedReason?: \"already_used\";\n}\n\nexport async function scheduleSubscriptionLifecycleChange(\n ctx: GenericEndpointContext,\n input: {\n referenceId: string;\n subscriptionId?: string;\n plan?: PaystackPlan;\n scheduleAtPeriodEnd?: boolean;\n cancelAtPeriodEnd?: boolean;\n },\n): Promise<Extract<PaystackInitializeResult, { kind: \"scheduled\" }> | null> {\n const groupId = normalizeSubscriptionGroup(input.plan?.group);\n if (input.plan !== undefined && input.scheduleAtPeriodEnd === true) {\n const existingSub =\n input.subscriptionId === undefined\n ? await getOrganizationSubscription(ctx, input.referenceId, groupId)\n : await createBillingStore(ctx).findSubscriptionById(input.subscriptionId);\n if (existingSub?.status === \"active\") {\n await ctx.context.adapter.update({\n model: \"subscription\",\n where: [{ field: \"id\", value: existingSub.id }],\n update: {\n pendingPlan: input.plan.name,\n updatedAt: new Date(),\n },\n });\n return {\n kind: \"scheduled\",\n status: \"success\",\n message: \"Plan change scheduled at period end.\",\n scheduled: true,\n };\n }\n }\n\n if (input.cancelAtPeriodEnd === true) {\n const existingSub =\n input.subscriptionId === undefined\n ? await getOrganizationSubscription(\n ctx,\n input.referenceId,\n input.plan === undefined ? undefined : groupId,\n )\n : await createBillingStore(ctx).findSubscriptionById(input.subscriptionId);\n if (existingSub?.status === \"active\") {\n await ctx.context.adapter.update({\n model: \"subscription\",\n where: [{ field: \"id\", value: existingSub.id }],\n update: {\n cancelAtPeriodEnd: true,\n cancelAt: existingSub.periodEnd ?? null,\n canceledAt: new Date(),\n updatedAt: new Date(),\n },\n });\n\n return {\n kind: \"scheduled\",\n status: \"success\",\n message: \"Subscription cancellation scheduled at period end.\",\n scheduled: true,\n };\n }\n }\n\n return null;\n}\n\nexport async function resolveTrialLifecycle(\n ctx: GenericEndpointContext,\n input: {\n referenceId: string;\n plan?: PaystackPlan;\n },\n): Promise<TrialLifecycleDecision> {\n const requestedDays =\n input.plan?.freeTrial?.days !== undefined && input.plan.freeTrial.days > 0\n ? input.plan.freeTrial.days\n : 0;\n const requested = requestedDays > 0;\n if (!requested) {\n return {\n requestedDays,\n requested: false,\n granted: false,\n };\n }\n\n const previousTrials = await ctx.context.adapter.findMany<Subscription>({\n model: \"subscription\",\n where: [{ field: \"referenceId\", value: input.referenceId }],\n });\n const hadTrial = previousTrials?.some(\n (subscription) =>\n (subscription.trialStart !== undefined && subscription.trialStart !== null) ||\n (subscription.trialEnd !== undefined && subscription.trialEnd !== null) ||\n subscription.status === \"trialing\",\n );\n\n if (hadTrial === true) {\n return {\n requestedDays,\n requested,\n granted: false,\n deniedReason: \"already_used\",\n };\n }\n\n const trialStart = new Date();\n const trialEnd = new Date();\n trialEnd.setDate(trialEnd.getDate() + requestedDays);\n\n return {\n trialStart,\n trialEnd,\n requestedDays,\n requested,\n granted: true,\n };\n}\n\nexport async function resolveCheckoutTargetEmail(\n ctx: GenericEndpointContext,\n options: AnyPaystackOptions,\n input: {\n email?: string;\n referenceId: string;\n user: User;\n },\n): Promise<string> {\n const targetEmail = input.email ?? input.user.email;\n\n if (\n options.organization?.enabled !== true ||\n input.referenceId === input.user.id ||\n input.referenceId === \"\"\n ) {\n return targetEmail;\n }\n\n const org = await ctx.context.adapter.findOne({\n model: \"organization\",\n where: [{ field: \"id\", value: input.referenceId }],\n });\n if (org === undefined || org === null) {\n return targetEmail;\n }\n\n const orgWithEmail = org as { email?: string | null };\n if (\n orgWithEmail.email !== undefined &&\n orgWithEmail.email !== null &&\n orgWithEmail.email !== \"\"\n ) {\n return orgWithEmail.email;\n }\n\n const ownerMember = await ctx.context.adapter.findOne({\n model: \"member\",\n where: [\n { field: \"organizationId\", value: input.referenceId },\n { field: \"role\", value: \"owner\" },\n ],\n });\n\n if (ownerMember === undefined || ownerMember === null) {\n return targetEmail;\n }\n\n const ownerUser = await ctx.context.adapter.findOne<User>({\n model: \"user\",\n where: [{ field: \"id\", value: (ownerMember as { userId: string }).userId }],\n });\n\n return ownerUser?.email !== undefined && ownerUser.email !== \"\" ? ownerUser.email : targetEmail;\n}\n\nexport async function handleProratedUpgrade(\n ctx: GenericEndpointContext,\n options: AnyPaystackOptions,\n input: {\n plan: PaystackPlan;\n referenceId: string;\n subscriptionId?: string;\n quantity?: number;\n targetEmail: string;\n userId: string;\n finalCurrency: string;\n callbackURL?: string;\n allowedSubscriptionChannels?: PaystackCheckoutChannel[];\n },\n): Promise<ProratedUpgradeOutcome | null> {\n const store = createBillingStore(ctx);\n const existingSub =\n input.subscriptionId === undefined\n ? await store.findCurrentSubscription(\n input.referenceId,\n normalizeSubscriptionGroup(input.plan.group),\n )\n : await store.findSubscriptionById(input.subscriptionId);\n if (\n existingSub?.status !== \"active\" ||\n existingSub.paystackSubscriptionCode === undefined ||\n existingSub.paystackSubscriptionCode === null ||\n existingSub.paystackSubscriptionCode === \"\" ||\n existingSub.periodEnd === undefined ||\n existingSub.periodEnd === null ||\n existingSub.periodStart === undefined ||\n existingSub.periodStart === null\n ) {\n return null;\n }\n\n const now = new Date();\n const periodEnd = new Date(existingSub.periodEnd);\n const periodStart = new Date(existingSub.periodStart);\n\n const totalDays = Math.max(\n 1,\n Math.ceil((periodEnd.getTime() - periodStart.getTime()) / (1000 * 60 * 60 * 24)),\n );\n const remainingDays = Math.max(\n 0,\n Math.ceil((periodEnd.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)),\n );\n\n let oldAmount = 0;\n if (existingSub.plan !== \"\") {\n const oldPlan =\n (await getPlanByName(options, existingSub.plan)) ??\n (await store.findPlanByName(existingSub.plan));\n if (oldPlan !== undefined && oldPlan !== null) {\n oldAmount = calculatePlanAmount(oldPlan, existingSub.seats);\n }\n }\n\n let membersCount = 1;\n let newSeatCount: number;\n let newAmount: number;\n try {\n assertLocallyManagedSubscription(existingSub, \"plan or seat changes\");\n if (getPlanSeatAmount(input.plan) !== undefined) {\n const members = await store.listMembers(input.referenceId);\n membersCount = members.length > 0 ? members.length : 1;\n }\n newSeatCount = input.quantity ?? existingSub.seats ?? membersCount;\n newAmount = calculatePlanAmount(input.plan, newSeatCount);\n } catch (error: unknown) {\n throw new APIError(\"BAD_REQUEST\", {\n message: error instanceof Error ? error.message : \"Invalid seat configuration for plan.\",\n });\n }\n\n const costDifference = newAmount - oldAmount;\n const prorationMetadata = createProrationMetadata({\n subscriptionId: existingSub.id,\n referenceId: input.referenceId,\n newPlan: input.plan.name.toLowerCase(),\n oldPlan: existingSub.plan,\n newSeatCount,\n remainingDays,\n });\n const serializedProrationMetadata = stringifyPaystackMetadata(prorationMetadata);\n let completedProrationReference: string | undefined;\n\n if (costDifference > 0 && remainingDays > 0) {\n const proratedAmount = Math.round((costDifference / totalDays) * remainingDays);\n if (proratedAmount < 5000) {\n throw new APIError(\"BAD_REQUEST\", {\n message:\n \"Prorated upgrade amount is below Paystack's minimum charge. Schedule the change for period end instead.\",\n status: 400,\n });\n }\n\n const paystack = createPaystackAdapter(options.paystackClient);\n if (\n existingSub.paystackAuthorizationCode !== undefined &&\n existingSub.paystackAuthorizationCode !== null &&\n existingSub.paystackAuthorizationCode !== \"\"\n ) {\n const sdkRes = (await paystack.chargeAuthorization({\n email: input.targetEmail,\n amount: proratedAmount,\n authorization_code: existingSub.paystackAuthorizationCode,\n reference: `upg_${existingSub.id}_${Date.now()}_${Math.random().toString(36).substring(7)}`,\n metadata: serializedProrationMetadata,\n })) as PaystackChargeAuthorizationResponse;\n\n if (sdkRes?.status !== \"success\") {\n throw new APIError(\"BAD_REQUEST\", {\n message: \"Failed to process prorated charge via saved authorization.\",\n });\n }\n\n await store.createTransaction({\n reference: sdkRes.reference ?? \"\",\n paystackId: sdkRes.id !== undefined && sdkRes.id !== null ? String(sdkRes.id) : undefined,\n referenceId: input.referenceId,\n userId: input.userId,\n amount: sdkRes.amount ?? proratedAmount,\n currency: sdkRes.currency ?? input.finalCurrency,\n status: \"success\",\n plan: input.plan.name.toLowerCase(),\n metadata: serializedProrationMetadata,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n completedProrationReference = sdkRes.reference ?? undefined;\n } else {\n const initRes = await paystack.initializeTransaction({\n email: input.targetEmail,\n amount: proratedAmount,\n currency: input.finalCurrency,\n callback_url: input.callbackURL ?? undefined,\n metadata: serializedProrationMetadata,\n ...(input.allowedSubscriptionChannels !== undefined\n ? { channels: input.allowedSubscriptionChannels }\n : {}),\n } as components[\"schemas\"][\"TransactionInitialize\"]);\n\n await store.createTransaction({\n reference: initRes?.reference ?? \"\",\n referenceId: input.referenceId,\n userId: input.userId,\n amount: proratedAmount,\n currency: input.finalCurrency,\n status: \"pending\",\n plan: input.plan.name.toLowerCase(),\n metadata: serializedProrationMetadata,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n\n return {\n kind: \"checkout\",\n url: initRes?.authorization_url,\n reference: initRes?.reference,\n accessCode: initRes?.access_code,\n redirect: true,\n };\n }\n }\n\n await store.updateSubscription(existingSub.id, {\n plan: input.plan.name,\n seats: newSeatCount,\n ...(completedProrationReference !== undefined\n ? { paystackTransactionReference: completedProrationReference }\n : {}),\n updatedAt: new Date(),\n });\n\n return {\n kind: \"prorated\",\n status: \"success\",\n message: \"Subscription successfully upgraded with prorated charge.\",\n prorated: true,\n };\n}\n","import type { GenericEndpointContext } from \"better-auth\";\nimport { APIError } from \"better-auth/api\";\nimport type { components } from \"@alexasomba/paystack-node\";\n\nimport { createBillingStore } from \"./billing-store\";\nimport { authorizeBillingReference } from \"./reference-access\";\nimport { getPaystackOps, unwrapSdkResult } from \"./paystack-sdk\";\nimport { getPlans, syncProductQuantityFromPaystack } from \"./utils\";\nimport {\n getMetadataBoolean,\n getMetadataNumber,\n getMetadataString,\n parsePaystackMetadata,\n} from \"./metadata\";\nimport type {\n AnyPaystackOptions,\n PaystackCheckoutChannel,\n PaystackTransaction,\n PaystackTransactionResponse,\n PaystackWebhookPayload,\n Session,\n Subscription,\n User,\n} from \"./types\";\n\nexport type PaystackReconciliationSource = \"webhook\" | \"queue\" | \"admin\" | \"server\" | \"browser\";\n\nexport interface ReconcilePaystackTransactionInput {\n reference: string;\n source?: PaystackReconciliationSource;\n referenceId?: string;\n actor?: {\n user: User;\n session: Session;\n };\n throwOnError?: boolean;\n}\n\nexport interface PaystackReconciliationError {\n code: string;\n message: string;\n status?: number;\n}\n\nexport interface PaystackReconciliationSummary {\n transaction: {\n found: boolean;\n updated: boolean;\n referenceId?: string;\n previousStatus?: string;\n status?: string;\n };\n subscription: {\n found: boolean;\n updated: boolean;\n id?: string;\n status?: string;\n prorationApplied: boolean;\n };\n customer: {\n saved: boolean;\n referenceId?: string;\n customerCode?: string;\n model?: \"user\" | \"organization\";\n };\n product: {\n synced: boolean;\n name?: string;\n };\n}\n\nexport interface ReconcilePaystackTransactionSuccess extends PaystackReconciliationSummary {\n ok: true;\n source: PaystackReconciliationSource;\n status: string;\n reference: string;\n data: PaystackTransactionResponse;\n error?: undefined;\n}\n\nexport interface ReconcilePaystackTransactionFailure extends PaystackReconciliationSummary {\n ok: false;\n source: PaystackReconciliationSource;\n status: string;\n reference: string;\n data: PaystackTransactionResponse | null;\n error: PaystackReconciliationError;\n}\n\nexport type ReconcilePaystackTransactionResult =\n | ReconcilePaystackTransactionSuccess\n | ReconcilePaystackTransactionFailure;\n\nfunction getAllowedSubscriptionChannels(\n options: AnyPaystackOptions,\n): PaystackCheckoutChannel[] | undefined {\n const channels = options.subscription?.allowedPaymentChannels;\n return Array.isArray(channels) && channels.length > 0 ? channels : undefined;\n}\n\nfunction isAllowedSubscriptionChannel(\n channel: string | null | undefined,\n allowedChannels: readonly PaystackCheckoutChannel[] | undefined,\n): boolean {\n if (allowedChannels === undefined) return true;\n return channel !== undefined && channel !== null && allowedChannels.includes(channel as never);\n}\n\nfunction createSummary(): PaystackReconciliationSummary {\n return {\n transaction: {\n found: false,\n updated: false,\n },\n subscription: {\n found: false,\n updated: false,\n prorationApplied: false,\n },\n customer: {\n saved: false,\n },\n product: {\n synced: false,\n },\n };\n}\n\nfunction getErrorMessage(error: unknown, fallback: string): string {\n return error instanceof Error && error.message !== \"\" ? error.message : fallback;\n}\n\nfunction createFailureResult(input: {\n source: PaystackReconciliationSource;\n status: string;\n reference: string;\n data: PaystackTransactionResponse | null;\n summary: PaystackReconciliationSummary;\n error: PaystackReconciliationError;\n}): ReconcilePaystackTransactionFailure {\n return {\n ok: false,\n source: input.source,\n status: input.status,\n reference: input.reference,\n data: input.data,\n error: input.error,\n ...input.summary,\n };\n}\n\nfunction throwOrReturnFailure(\n input: {\n throwOnError: boolean;\n apiStatus: \"BAD_REQUEST\" | \"UNAUTHORIZED\";\n } & Parameters<typeof createFailureResult>[0],\n): ReconcilePaystackTransactionFailure {\n if (input.throwOnError) {\n throw new APIError(input.apiStatus, {\n code: input.error.code,\n message: input.error.message,\n status: input.error.status,\n });\n }\n\n return createFailureResult(input);\n}\n\nfunction hasReferenceMismatch(input: {\n expectedReferenceId?: string;\n transactionReferenceId?: string | null;\n}): boolean {\n return (\n input.expectedReferenceId !== undefined &&\n input.expectedReferenceId !== \"\" &&\n input.transactionReferenceId !== undefined &&\n input.transactionReferenceId !== null &&\n input.transactionReferenceId !== \"\" &&\n input.expectedReferenceId !== input.transactionReferenceId\n );\n}\n\nfunction getNonEmptyString(value: unknown): string | undefined {\n return typeof value === \"string\" && value !== \"\" ? value : undefined;\n}\n\nexport async function reconcilePaystackTransaction(\n ctx: GenericEndpointContext,\n options: AnyPaystackOptions,\n input: ReconcilePaystackTransactionInput,\n): Promise<ReconcilePaystackTransactionResult> {\n const source = input.source ?? \"server\";\n const throwOnError = input.throwOnError === true;\n const summary = createSummary();\n const paystack = getPaystackOps(options.paystackClient);\n let data: PaystackTransactionResponse | undefined;\n\n try {\n const verifyRaw = await paystack?.transaction?.verify(input.reference);\n data = unwrapSdkResult<PaystackTransactionResponse>(verifyRaw);\n } catch (error: unknown) {\n ctx.context.logger.error(\"Failed to verify Paystack transaction\", error);\n return throwOrReturnFailure({\n throwOnError,\n apiStatus: \"BAD_REQUEST\",\n source,\n status: \"error\",\n reference: input.reference,\n data: null,\n summary,\n error: {\n code: \"FAILED_TO_VERIFY_TRANSACTION\",\n message: getErrorMessage(error, \"Failed to verify transaction\"),\n status: 400,\n },\n });\n }\n\n if (data === undefined || data === null) {\n return throwOrReturnFailure({\n throwOnError,\n apiStatus: \"BAD_REQUEST\",\n source,\n status: \"error\",\n reference: input.reference,\n data: null,\n summary,\n error: {\n code: \"FAILED_TO_VERIFY_TRANSACTION\",\n message: \"Failed to fetch transaction data from Paystack.\",\n status: 400,\n },\n });\n }\n\n const status = data.status ?? \"failed\";\n const reference = data.reference ?? input.reference;\n const paystackIdRaw = (data as { id?: number | string | null }).id;\n const paystackId =\n paystackIdRaw !== undefined && paystackIdRaw !== null ? String(paystackIdRaw) : undefined;\n const authorizationCode = (data.authorization as { authorization_code?: string | null } | null)\n ?.authorization_code;\n const store = createBillingStore(ctx);\n const txRecord = await store.findTransactionByReference(reference);\n summary.transaction.found = txRecord !== null;\n summary.transaction.previousStatus = txRecord?.status;\n\n if (\n hasReferenceMismatch({\n expectedReferenceId: input.referenceId,\n transactionReferenceId: txRecord?.referenceId,\n })\n ) {\n return throwOrReturnFailure({\n throwOnError,\n apiStatus: \"UNAUTHORIZED\",\n source,\n status,\n reference,\n data,\n summary,\n error: {\n code: \"REFERENCE_ID_MISMATCH\",\n message: \"Transaction reference does not belong to the expected billing reference.\",\n status: 401,\n },\n });\n }\n\n const referenceId =\n input.referenceId ??\n getNonEmptyString(txRecord?.referenceId) ??\n getNonEmptyString(input.actor?.user.id);\n summary.transaction.referenceId = referenceId;\n\n if (\n input.actor !== undefined &&\n referenceId !== undefined &&\n referenceId !== input.actor.user.id\n ) {\n try {\n await authorizeBillingReference(ctx, options, {\n user: input.actor.user,\n session: input.actor.session,\n referenceId,\n action: \"verify-transaction\",\n });\n } catch (error: unknown) {\n return throwOrReturnFailure({\n throwOnError,\n apiStatus: \"UNAUTHORIZED\",\n source,\n status,\n reference,\n data,\n summary,\n error: {\n code: \"UNAUTHORIZED\",\n message: getErrorMessage(error, \"Not authorized to reconcile this transaction.\"),\n status: 401,\n },\n });\n }\n }\n\n const transactionUpdate: Partial<PaystackTransaction> & Record<string, unknown> = {\n status,\n paystackId,\n amount: data.amount,\n currency: data.currency,\n updatedAt: new Date(),\n };\n const updatedTransaction = await store.updateTransactionByReference(reference, transactionUpdate);\n summary.transaction.updated = updatedTransaction !== null;\n summary.transaction.status = status;\n\n if (status !== \"success\") {\n return {\n ok: true,\n source,\n status,\n reference,\n data,\n ...summary,\n };\n }\n\n const allowedSubscriptionChannels = getAllowedSubscriptionChannels(options);\n const isSubscriptionFlow =\n (txRecord?.plan !== undefined && txRecord.plan !== null && txRecord.plan !== \"\") ||\n Boolean((data as { plan?: unknown }).plan);\n\n if (\n isSubscriptionFlow &&\n isAllowedSubscriptionChannel(data.channel ?? undefined, allowedSubscriptionChannels) === false\n ) {\n await store.updateTransactionByReference(reference, {\n ...transactionUpdate,\n status: \"failed\",\n });\n summary.transaction.updated = true;\n summary.transaction.status = \"failed\";\n\n return throwOrReturnFailure({\n throwOnError,\n apiStatus: \"BAD_REQUEST\",\n source,\n status: \"failed\",\n reference,\n data,\n summary,\n error: {\n code: \"SUBSCRIPTION_PAYMENT_CHANNEL_NOT_ALLOWED\",\n message: `This subscription requires one of: ${allowedSubscriptionChannels?.join(\", \") ?? \"allowed channels\"}.`,\n status: 400,\n },\n });\n }\n\n const paystackCustomerCodeFromPaystack = data.customer?.customer_code;\n if (\n paystackCustomerCodeFromPaystack !== undefined &&\n paystackCustomerCodeFromPaystack !== null &&\n paystackCustomerCodeFromPaystack !== \"\" &&\n referenceId !== undefined &&\n referenceId !== \"\"\n ) {\n let isOrganization =\n options.organization?.enabled === true &&\n typeof referenceId === \"string\" &&\n referenceId.startsWith(\"org_\");\n if (isOrganization === false && options.organization?.enabled === true) {\n const organization = await store.findOrganization(referenceId);\n isOrganization = organization !== null;\n }\n\n await store.saveCustomerCode(referenceId, paystackCustomerCodeFromPaystack, isOrganization);\n summary.customer.saved = true;\n summary.customer.referenceId = referenceId;\n summary.customer.customerCode = paystackCustomerCodeFromPaystack;\n summary.customer.model = isOrganization ? \"organization\" : \"user\";\n }\n\n const transaction = updatedTransaction ?? (await store.findTransactionByReference(reference));\n if (\n transaction !== undefined &&\n transaction !== null &&\n transaction.product !== undefined &&\n transaction.product !== null &&\n transaction.product !== \"\" &&\n options.paystackClient !== undefined &&\n options.paystackClient !== null\n ) {\n await syncProductQuantityFromPaystack(ctx, transaction.product, options.paystackClient);\n summary.product.synced = true;\n summary.product.name = transaction.product;\n }\n\n if (options.subscription?.enabled !== true) {\n return {\n ok: true,\n source,\n status,\n reference,\n data,\n ...summary,\n };\n }\n\n const metadataObj = parsePaystackMetadata(data.metadata);\n const isTrial = getMetadataBoolean(metadataObj, \"isTrial\");\n const trialEnd = getMetadataString(metadataObj, \"trialEnd\");\n const targetPlan = getMetadataString(metadataObj, \"plan\");\n\n if (metadataObj.type === \"proration\") {\n const subscriptionId = getMetadataString(metadataObj, \"subscriptionId\");\n const newPlan = getMetadataString(metadataObj, \"newPlan\");\n const newSeatCount = getMetadataNumber(metadataObj, \"newSeatCount\");\n\n if (\n subscriptionId !== undefined &&\n subscriptionId !== \"\" &&\n newPlan !== undefined &&\n newPlan !== \"\"\n ) {\n const updatedSubscription = await store.updateSubscription(subscriptionId, {\n plan: newPlan,\n ...(typeof newSeatCount === \"number\" ? { seats: newSeatCount } : {}),\n paystackTransactionReference: reference,\n ...(authorizationCode !== undefined && authorizationCode !== null\n ? { paystackAuthorizationCode: authorizationCode }\n : {}),\n updatedAt: new Date(),\n });\n summary.subscription.found = updatedSubscription !== null;\n summary.subscription.updated = updatedSubscription !== null;\n summary.subscription.id = updatedSubscription?.id ?? subscriptionId;\n summary.subscription.status = updatedSubscription?.status;\n summary.subscription.prorationApplied = updatedSubscription !== null;\n }\n\n return {\n ok: true,\n source,\n status,\n reference,\n data,\n ...summary,\n };\n }\n\n let paystackSubscriptionCode: string | undefined;\n const existingSubs = await store.findSubscriptionsByTransactionReference(reference);\n const targetSub = existingSubs.find(\n (subscription) =>\n referenceId === undefined || referenceId === \"\" || subscription.referenceId === referenceId,\n );\n summary.subscription.found = targetSub !== undefined;\n summary.subscription.id = targetSub?.id;\n summary.subscription.status = targetSub?.status;\n\n if (isTrial && targetPlan !== undefined && trialEnd !== undefined) {\n const email = data.customer?.email;\n const plans = await getPlans(options.subscription);\n const planConfig = plans.find((plan) => plan.name.toLowerCase() === targetPlan.toLowerCase());\n\n if (\n planConfig !== undefined &&\n planConfig !== null &&\n (planConfig.planCode === undefined ||\n planConfig.planCode === null ||\n planConfig.planCode === \"\")\n ) {\n paystackSubscriptionCode = `LOC_${reference}`;\n } else if (\n targetSub?.paystackSubscriptionCode !== undefined &&\n targetSub.paystackSubscriptionCode !== null &&\n targetSub.paystackSubscriptionCode !== \"\"\n ) {\n paystackSubscriptionCode = targetSub.paystackSubscriptionCode;\n } else if (\n authorizationCode !== undefined &&\n authorizationCode !== null &&\n email !== undefined &&\n email !== null &&\n email !== \"\" &&\n planConfig?.planCode !== undefined &&\n planConfig.planCode !== null &&\n planConfig.planCode !== \"\"\n ) {\n const subResRaw = await paystack?.subscription?.create({\n body: {\n customer: email,\n plan: planConfig.planCode,\n authorization: authorizationCode,\n start_date: trialEnd,\n },\n });\n const subRes =\n unwrapSdkResult<components[\"schemas\"][\"SubscriptionListResponseArray\"]>(subResRaw);\n paystackSubscriptionCode = subRes?.subscription_code;\n }\n } else if (isTrial === false) {\n const planCodeFromPaystack = (data as { plan?: { plan_code?: string | null } }).plan?.plan_code;\n if (\n planCodeFromPaystack === undefined ||\n planCodeFromPaystack === null ||\n planCodeFromPaystack === \"\"\n ) {\n paystackSubscriptionCode = `LOC_${reference}`;\n } else {\n paystackSubscriptionCode =\n (data as { subscription?: { subscription_code?: string | null } }).subscription\n ?.subscription_code ?? undefined;\n }\n }\n\n let updatedSubscription: Subscription | null = null;\n if (targetSub !== undefined && targetSub !== null) {\n const plans = await getPlans(options.subscription);\n const resolvedPlan = plans.find(\n (candidate) => candidate.name.toLowerCase() === targetSub.plan.toLowerCase(),\n );\n updatedSubscription = await store.updateSubscription(targetSub.id, {\n status: isTrial ? \"trialing\" : \"active\",\n billingInterval: resolvedPlan?.interval ?? targetSub.billingInterval ?? null,\n periodStart: new Date(),\n updatedAt: new Date(),\n ...(isTrial && trialEnd !== undefined\n ? {\n trialStart: new Date(),\n trialEnd: new Date(trialEnd),\n periodEnd: new Date(trialEnd),\n }\n : {}),\n ...(paystackSubscriptionCode !== undefined ? { paystackSubscriptionCode } : {}),\n ...(authorizationCode !== undefined && authorizationCode !== null\n ? { paystackAuthorizationCode: authorizationCode }\n : {}),\n });\n summary.subscription.updated = updatedSubscription !== null;\n summary.subscription.id = updatedSubscription?.id ?? targetSub.id;\n summary.subscription.status = updatedSubscription?.status ?? targetSub.status;\n if (\n updatedSubscription !== null &&\n (updatedSubscription.status === \"active\" || updatedSubscription.status === \"trialing\")\n ) {\n await store.retireCompetingSubscriptions(\n updatedSubscription.referenceId,\n updatedSubscription.groupId ?? null,\n updatedSubscription.id,\n );\n }\n }\n\n if (updatedSubscription !== undefined && updatedSubscription !== null) {\n const plans = await getPlans(options.subscription);\n const plan = plans.find(\n (candidate) => candidate.name.toLowerCase() === updatedSubscription.plan.toLowerCase(),\n );\n if (plan !== undefined) {\n const callbackData = {\n event: data as unknown as PaystackWebhookPayload,\n subscription: updatedSubscription,\n plan,\n };\n for (const callback of [\n options.subscription?.onSubscriptionComplete,\n options.subscription?.onSubscriptionUpdate,\n ]) {\n try {\n await callback?.(callbackData, ctx);\n } catch (error) {\n ctx.context.logger.error(\"Paystack subscription callback failed\", error);\n }\n }\n if (targetSub?.status === \"trialing\" && updatedSubscription.status === \"active\") {\n try {\n await plan.freeTrial?.onTrialEnd?.(updatedSubscription);\n } catch (error) {\n ctx.context.logger.error(\"Paystack trial end callback failed\", error);\n }\n }\n }\n }\n\n return {\n ok: true,\n source,\n status,\n reference,\n data,\n ...summary,\n };\n}\n","/* oxlint-disable no-restricted-imports */\nimport { z } from \"zod\";\n\nexport const initializeTransactionBodySchema: z.ZodObject<{\n plan: z.ZodOptional<z.ZodString>;\n product: z.ZodOptional<z.ZodString>;\n amount: z.ZodOptional<z.ZodNumber>;\n currency: z.ZodOptional<z.ZodString>;\n email: z.ZodOptional<z.ZodString>;\n metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;\n referenceId: z.ZodOptional<z.ZodString>;\n subscriptionId: z.ZodOptional<z.ZodString>;\n callbackURL: z.ZodOptional<z.ZodString>;\n quantity: z.ZodOptional<z.ZodNumber>;\n scheduleAtPeriodEnd: z.ZodOptional<z.ZodBoolean>;\n cancelAtPeriodEnd: z.ZodOptional<z.ZodBoolean>;\n prorateAndCharge: z.ZodOptional<z.ZodBoolean>;\n}> = z.object({\n plan: z.string().optional(),\n product: z.string().optional(),\n amount: z.number().int().positive().optional(),\n currency: z.string().optional(),\n email: z.string().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n referenceId: z.string().optional(),\n subscriptionId: z.string().optional(),\n callbackURL: z.string().optional(),\n quantity: z.number().int().positive().optional(),\n scheduleAtPeriodEnd: z.boolean().optional(),\n cancelAtPeriodEnd: z.boolean().optional(),\n prorateAndCharge: z.boolean().optional(),\n});\n","import type { GenericEndpointContext } from \"better-auth\";\n\nimport { createBillingStore } from \"../billing-store\";\nimport { getPlans, getProducts } from \"../utils\";\nimport type { AnyPaystackOptions, PaystackPlan, PaystackProduct } from \"../types\";\n\nexport async function listStoredProducts(ctx: GenericEndpointContext): Promise<PaystackProduct[]> {\n return createBillingStore(ctx).listProducts();\n}\n\nexport async function listStoredPlans(ctx: GenericEndpointContext): Promise<PaystackPlan[]> {\n return createBillingStore(ctx).listPlans();\n}\n\nexport async function getConfiguredCatalog(options: AnyPaystackOptions): Promise<{\n plans: PaystackPlan[];\n products: PaystackProduct[];\n}> {\n const plans = options.subscription?.enabled === true ? await getPlans(options.subscription) : [];\n const products = await getProducts(options.products);\n return { plans, products };\n}\n","/* oxlint-disable no-restricted-imports */\nimport { z } from \"zod\";\n\nexport const enableDisableBodySchema: z.ZodObject<{\n referenceId: z.ZodOptional<z.ZodString>;\n subscriptionCode: z.ZodString;\n emailToken: z.ZodOptional<z.ZodString>;\n atPeriodEnd: z.ZodOptional<z.ZodBoolean>;\n}> = z.object({\n referenceId: z.string().optional(),\n subscriptionCode: z.string(),\n emailToken: z.string().optional(),\n atPeriodEnd: z.boolean().optional(),\n});\n\nexport function decodeBase64UrlToString(value: string): string {\n const normalized = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padded = normalized + \"===\".slice((normalized.length + 3) % 4);\n const binaryString = atob(padded);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return new TextDecoder().decode(bytes);\n}\n\nexport function tryGetEmailTokenFromSubscriptionManageLink(link: string): string | undefined {\n try {\n const url = new URL(link);\n const subscriptionToken = url.searchParams.get(\"subscription_token\");\n if (subscriptionToken === undefined || subscriptionToken === null || subscriptionToken === \"\")\n return undefined;\n const parts = subscriptionToken.split(\".\");\n if (parts.length < 2) return undefined;\n const payloadJson = decodeBase64UrlToString(parts[1] ?? \"\");\n const payload = JSON.parse(payloadJson) as Record<string, unknown>;\n return typeof payload.email_token === \"string\" ? payload.email_token : undefined;\n } catch {\n return undefined;\n }\n}\n","import type { GenericEndpointContext } from \"better-auth\";\n\nexport function getWebhookRequest(ctx: GenericEndpointContext): Request | undefined {\n return (\n (ctx as unknown as { requestClone?: Request }).requestClone ??\n (ctx as { request?: Request }).request\n );\n}\n\nexport function getWebhookHeaders(ctx: GenericEndpointContext): Headers | undefined {\n return (\n (ctx as GenericEndpointContext & { headers?: Headers }).headers ??\n (ctx.request as unknown as { headers?: Headers })?.headers\n );\n}\n\nexport function getWebhookClientIP(\n ctx: GenericEndpointContext,\n headers: Headers | undefined,\n): string | undefined {\n return (\n headers?.get(\"x-forwarded-for\")?.split(\",\")[0]?.trim() ??\n headers?.get(\"x-real-ip\") ??\n (ctx.request as unknown as { ip?: string }).ip\n );\n}\n","import { defineErrorCodes } from \"better-auth\";\nimport type { RawError } from \"better-auth\";\n\nimport type { AnyPaystackOptions, PaystackCheckoutChannel } from \"../types\";\n\nexport const PAYSTACK_ERROR_CODES: {\n SUBSCRIPTION_NOT_FOUND: RawError<\"SUBSCRIPTION_NOT_FOUND\">;\n SUBSCRIPTION_PLAN_NOT_FOUND: RawError<\"SUBSCRIPTION_PLAN_NOT_FOUND\">;\n UNABLE_TO_CREATE_CUSTOMER: RawError<\"UNABLE_TO_CREATE_CUSTOMER\">;\n FAILED_TO_INITIALIZE_TRANSACTION: RawError<\"FAILED_TO_INITIALIZE_TRANSACTION\">;\n FAILED_TO_VERIFY_TRANSACTION: RawError<\"FAILED_TO_VERIFY_TRANSACTION\">;\n FAILED_TO_DISABLE_SUBSCRIPTION: RawError<\"FAILED_TO_DISABLE_SUBSCRIPTION\">;\n FAILED_TO_ENABLE_SUBSCRIPTION: RawError<\"FAILED_TO_ENABLE_SUBSCRIPTION\">;\n EMAIL_VERIFICATION_REQUIRED: RawError<\"EMAIL_VERIFICATION_REQUIRED\">;\n SUBSCRIPTION_PAYMENT_CHANNEL_NOT_ALLOWED: RawError<\"SUBSCRIPTION_PAYMENT_CHANNEL_NOT_ALLOWED\">;\n} = defineErrorCodes({\n SUBSCRIPTION_NOT_FOUND: \"Subscription not found\",\n SUBSCRIPTION_PLAN_NOT_FOUND: \"Subscription plan not found\",\n UNABLE_TO_CREATE_CUSTOMER: \"Unable to create customer\",\n FAILED_TO_INITIALIZE_TRANSACTION: \"Failed to initialize transaction\",\n FAILED_TO_VERIFY_TRANSACTION: \"Failed to verify transaction\",\n FAILED_TO_DISABLE_SUBSCRIPTION: \"Failed to disable subscription\",\n FAILED_TO_ENABLE_SUBSCRIPTION: \"Failed to enable subscription\",\n EMAIL_VERIFICATION_REQUIRED: \"Email verification is required before you can subscribe to a plan\",\n SUBSCRIPTION_PAYMENT_CHANNEL_NOT_ALLOWED:\n \"This subscription only supports specific payment channels\",\n});\n\nexport function getAllowedSubscriptionChannels(\n options: AnyPaystackOptions,\n): PaystackCheckoutChannel[] | undefined {\n const channels = options.subscription?.allowedPaymentChannels;\n return Array.isArray(channels) && channels.length > 0 ? channels : undefined;\n}\n\nexport async function hmacSha512Hex(secret: string, message: string): Promise<string> {\n const encoder = new TextEncoder();\n const keyData = encoder.encode(secret);\n const msgData = encoder.encode(message);\n\n const crypto = globalThis.crypto;\n if (crypto !== undefined && crypto !== null && \"subtle\" in crypto) {\n const subtle = crypto.subtle;\n const key = await subtle.importKey(\"raw\", keyData, { name: \"HMAC\", hash: \"SHA-512\" }, false, [\n \"sign\",\n ]);\n const signature = await subtle.sign(\"HMAC\", key, msgData);\n return Array.from(new Uint8Array(signature))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n }\n\n const { createHmac } = await import(\"node:crypto\");\n return createHmac(\"sha512\", secret).update(message).digest(\"hex\");\n}\n","import { HIDE_METADATA } from \"better-auth\";\nimport { APIError, getSessionFromCtx, originCheck, sessionMiddleware } from \"better-auth/api\";\nimport { createAuthEndpoint } from \"better-auth/api\";\n/* oxlint-disable no-restricted-imports */\nimport { z } from \"zod\";\nimport type { components } from \"@alexasomba/paystack-node\";\nimport type {\n GenericEndpointContext,\n MiddlewareInputContext,\n MiddlewareOptions,\n StrictEndpoint,\n} from \"better-auth\";\n\nimport type {\n InputPaystackProduct,\n PaystackTransaction,\n AnyPaystackOptions,\n PaystackProduct,\n Subscription,\n Member,\n PaystackOrganization,\n PaystackPlan,\n PaystackWebhookPayload,\n User,\n PaystackUser,\n PaystackCheckoutChannel,\n PaystackInitializeResult,\n} from \"./types\";\nimport {\n createCheckoutMetadata,\n hasPaystackMetadata,\n parsePaystackMetadata,\n stringifyPaystackMetadata,\n} from \"./metadata\";\nimport {\n syncProductQuantityFromPaystack,\n getPlanByName,\n getPlans,\n getProductByName,\n getPlanSeatAmount,\n calculatePlanAmount,\n isLocalSubscriptionCode,\n normalizeSubscriptionGroup,\n} from \"./utils\";\nimport { referenceMiddleware } from \"./middleware\";\nimport { authorizeBillingReference } from \"./reference-access\";\nimport { getPaystackOps, unwrapSdkResult } from \"./paystack-sdk\";\nimport { createBillingStore } from \"./billing-store\";\nimport {\n handleProratedUpgrade,\n resolveCheckoutTargetEmail,\n resolveTrialLifecycle,\n scheduleSubscriptionLifecycleChange,\n} from \"./subscription-lifecycle\";\nimport { reconcilePaystackTransaction } from \"./reconciliation\";\nimport { initializeTransactionBodySchema } from \"./route-modules/checkout\";\nimport { getConfiguredCatalog, listStoredPlans, listStoredProducts } from \"./route-modules/catalog\";\nimport {\n enableDisableBodySchema,\n tryGetEmailTokenFromSubscriptionManageLink,\n} from \"./route-modules/subscriptions\";\nimport { getWebhookClientIP, getWebhookHeaders, getWebhookRequest } from \"./route-modules/webhook\";\nimport {\n getAllowedSubscriptionChannels,\n hmacSha512Hex,\n PAYSTACK_ERROR_CODES,\n} from \"./route-modules/shared\";\n\nexport const paystackWebhook = <P extends string = \"/webhook\">(\n options: AnyPaystackOptions,\n path: P = \"/webhook\" as P,\n): StrictEndpoint<\n P,\n {\n method: \"POST\";\n metadata: {\n openapi: {\n operationId: string;\n };\n scope: \"server\";\n };\n cloneRequest: true;\n disableBody: true;\n },\n {\n received: boolean;\n }\n> => {\n return createAuthEndpoint(\n path,\n {\n method: \"POST\",\n metadata: {\n ...HIDE_METADATA,\n openapi: {\n operationId: \"handlePaystackWebhook\",\n },\n },\n cloneRequest: true,\n disableBody: true,\n },\n async (ctx) => {\n const request = getWebhookRequest(ctx as GenericEndpointContext);\n if (request === undefined || request === null) {\n throw new APIError(\"BAD_REQUEST\", {\n message: \"Request object is missing from context\",\n });\n }\n const payload = await request.text();\n const headers = getWebhookHeaders(ctx as GenericEndpointContext);\n const signature = headers?.get(\"x-paystack-signature\");\n\n if (options.webhook?.verifyIP === true) {\n const trustedIPs = options.webhook.trustedIPs ?? [\n \"52.31.139.75\",\n \"52.49.173.169\",\n \"52.214.14.220\",\n ];\n const clientIP = getWebhookClientIP(ctx as GenericEndpointContext, headers);\n\n if (\n clientIP !== undefined &&\n clientIP !== null &&\n trustedIPs.includes(clientIP) === false\n ) {\n throw new APIError(\"UNAUTHORIZED\", {\n message: `Forbidden IP: ${clientIP}`,\n status: 401,\n });\n }\n }\n\n if (signature === undefined || signature === null || signature === \"\") {\n throw new APIError(\"UNAUTHORIZED\", {\n message: \"Missing x-paystack-signature header\",\n status: 401,\n });\n }\n\n const expected = await hmacSha512Hex(options.secretKey, payload);\n if (expected !== signature) {\n throw new APIError(\"UNAUTHORIZED\", {\n message: \"Invalid Paystack webhook signature\",\n status: 401,\n });\n }\n\n const event = JSON.parse(payload) as PaystackWebhookPayload;\n const eventName = event.event;\n const data = event.data;\n\n // Core Transaction Status Sync (Applies to both one-time and recurring)\n if (eventName === \"charge.success\") {\n const reference = (data as { reference?: string | null })?.reference;\n const paystackIdRaw = (data as { id?: number | string | null })?.id;\n const paystackId =\n paystackIdRaw !== undefined && paystackIdRaw !== null ? String(paystackIdRaw) : undefined;\n\n if (reference !== undefined && reference !== null && reference !== \"\") {\n try {\n await ctx.context.adapter.update({\n model: \"paystackTransaction\",\n update: {\n status: \"success\",\n paystackId,\n updatedAt: new Date(),\n },\n where: [{ field: \"reference\", value: reference }],\n });\n } catch (e) {\n ctx.context.logger.warn(\"Failed to update transaction status for charge.success\", e);\n }\n\n // Sync product quantity from Paystack after successful charge\n try {\n const transaction = await ctx.context.adapter.findOne<PaystackTransaction>({\n model: \"paystackTransaction\",\n where: [{ field: \"reference\", value: reference }],\n });\n if (\n transaction !== undefined &&\n transaction !== null &&\n transaction.product !== undefined &&\n transaction.product !== null &&\n transaction.product !== \"\"\n ) {\n if (options.paystackClient !== undefined && options.paystackClient !== null) {\n await syncProductQuantityFromPaystack(\n ctx,\n transaction.product,\n options.paystackClient,\n );\n }\n }\n } catch (e) {\n ctx.context.logger.warn(\"Failed to sync product quantity\", e);\n }\n }\n }\n\n if ((eventName as string) === \"charge.failure\") {\n const reference = (data as { reference?: string })?.reference;\n if (reference !== undefined && reference !== null && reference !== \"\") {\n try {\n await ctx.context.adapter.update({\n model: \"paystackTransaction\",\n update: {\n status: \"failed\",\n updatedAt: new Date(),\n },\n where: [{ field: \"reference\", value: reference }],\n });\n } catch (e) {\n ctx.context.logger.warn(\"Failed to update transaction status for charge.failure\", e);\n }\n }\n }\n\n // Best-effort local state sync for subscription lifecycle.\n if (options.subscription?.enabled === true) {\n try {\n if (eventName === \"subscription.create\") {\n const subscriptionData =\n data as unknown as components[\"schemas\"][\"SubscriptionListResponseArray\"];\n const subscriptionCode = subscriptionData.subscription_code ?? \"\";\n const customerCode = (\n subscriptionData.customer as { customer_code?: string | null } | undefined\n )?.customer_code;\n const planCode = (subscriptionData.plan as { plan_code?: string | null } | undefined)\n ?.plan_code;\n\n const metadataObj = parsePaystackMetadata(\n (subscriptionData as unknown as { metadata?: unknown }).metadata,\n );\n const referenceIdFromMetadata =\n typeof metadataObj.referenceId === \"string\" ? metadataObj.referenceId : undefined;\n let planNameFromMetadata =\n typeof metadataObj.plan === \"string\" ? metadataObj.plan : undefined;\n if (typeof planNameFromMetadata === \"string\") {\n planNameFromMetadata = planNameFromMetadata.toLowerCase();\n }\n\n const plans = await getPlans(options.subscription);\n const planFromCode =\n planCode !== undefined && planCode !== null && planCode !== \"\"\n ? plans.find((p) => p.planCode === planCode)\n : undefined;\n const groupIdFromMetadata =\n typeof metadataObj.groupId === \"string\"\n ? normalizeSubscriptionGroup(metadataObj.groupId)\n : normalizeSubscriptionGroup(planFromCode?.group);\n const planPart = planFromCode?.name ?? planNameFromMetadata;\n const planName =\n planPart !== undefined && planPart !== null && planPart !== \"\"\n ? planPart.toLowerCase()\n : undefined;\n\n if (\n subscriptionCode !== undefined &&\n subscriptionCode !== null &&\n subscriptionCode !== \"\"\n ) {\n const where: { field: string; value: string | number | boolean | null }[] = [];\n if (\n referenceIdFromMetadata !== undefined &&\n referenceIdFromMetadata !== null &&\n referenceIdFromMetadata !== \"\"\n ) {\n where.push({ field: \"referenceId\", value: referenceIdFromMetadata });\n } else if (\n customerCode !== undefined &&\n customerCode !== null &&\n customerCode !== \"\"\n ) {\n where.push({ field: \"paystackCustomerCode\", value: customerCode });\n }\n if (planName !== undefined && planName !== null && planName !== \"\") {\n where.push({ field: \"plan\", value: planName });\n }\n\n if (where.length > 0) {\n const matches = await ctx.context.adapter.findMany<Subscription>({\n model: \"subscription\",\n where: where,\n });\n const subscription = matches?.find((candidate) =>\n groupIdFromMetadata === null\n ? candidate.groupId === undefined ||\n candidate.groupId === null ||\n candidate.groupId === \"\"\n : candidate.groupId === groupIdFromMetadata,\n );\n if (subscription !== undefined && subscription !== null) {\n const plan =\n planFromCode ??\n (planName !== undefined && planName !== null && planName !== \"\"\n ? await getPlanByName(options, planName)\n : undefined);\n const now = new Date();\n const persistedSubscription: Subscription = {\n ...subscription,\n paystackSubscriptionCode: subscriptionCode,\n status: \"active\",\n billingInterval: plan?.interval ?? subscription.billingInterval ?? null,\n periodEnd:\n subscriptionData.next_payment_date !== undefined &&\n subscriptionData.next_payment_date !== null\n ? new Date(subscriptionData.next_payment_date)\n : subscription.periodEnd,\n updatedAt: now,\n };\n await ctx.context.adapter.update({\n model: \"subscription\",\n update: {\n paystackSubscriptionCode: persistedSubscription.paystackSubscriptionCode,\n status: persistedSubscription.status,\n billingInterval: persistedSubscription.billingInterval,\n periodEnd: persistedSubscription.periodEnd,\n updatedAt: persistedSubscription.updatedAt,\n },\n where: [{ field: \"id\", value: subscription.id }],\n });\n await createBillingStore(ctx).retireCompetingSubscriptions(\n subscription.referenceId,\n subscription.groupId ?? null,\n subscription.id,\n );\n\n if (plan !== undefined && plan !== null) {\n const callbackData = { event, subscription: persistedSubscription, plan };\n for (const callback of [\n options.subscription.onSubscriptionComplete,\n options.subscription.onSubscriptionCreated,\n options.subscription.onSubscriptionUpdate,\n ]) {\n try {\n await callback?.(callbackData, ctx as GenericEndpointContext);\n } catch (error) {\n ctx.context.logger.error(\"Paystack subscription callback failed\", error);\n }\n }\n if (subscription.status === \"trialing\") {\n try {\n await plan.freeTrial?.onTrialEnd?.(persistedSubscription);\n } catch (error) {\n ctx.context.logger.error(\"Paystack trial end callback failed\", error);\n }\n }\n }\n }\n }\n }\n }\n\n if (eventName === \"subscription.disable\" || eventName === \"subscription.not_renew\") {\n const subscriptionData =\n data as unknown as components[\"schemas\"][\"SubscriptionListResponseArray\"];\n const subscriptionCode = subscriptionData.subscription_code ?? \"\";\n if (subscriptionCode !== \"\") {\n const existing = await ctx.context.adapter.findOne<Subscription>({\n model: \"subscription\",\n where: [{ field: \"paystackSubscriptionCode\", value: subscriptionCode }],\n });\n\n let newStatus = \"canceled\";\n const nextPaymentDate = subscriptionData.next_payment_date;\n const periodEnd =\n nextPaymentDate !== undefined && nextPaymentDate !== null && nextPaymentDate !== \"\"\n ? new Date(nextPaymentDate)\n : existing?.periodEnd !== undefined && existing.periodEnd !== null\n ? new Date(existing.periodEnd)\n : undefined;\n\n if (periodEnd !== undefined && periodEnd.getTime() > Date.now()) {\n newStatus = \"active\";\n }\n\n const now = new Date();\n const persistedSubscription =\n existing === null || existing === undefined\n ? undefined\n : ({\n ...existing,\n status: newStatus,\n cancelAtPeriodEnd: newStatus === \"active\",\n cancelAt: newStatus === \"active\" ? (periodEnd ?? null) : null,\n canceledAt: now,\n endedAt: newStatus === \"canceled\" ? now : null,\n ...(periodEnd ? { periodEnd } : {}),\n updatedAt: now,\n } as Subscription);\n await ctx.context.adapter.update({\n model: \"subscription\",\n update: {\n status: newStatus,\n cancelAtPeriodEnd: newStatus === \"active\",\n cancelAt: newStatus === \"active\" ? (periodEnd ?? null) : null,\n canceledAt: now,\n endedAt: newStatus === \"canceled\" ? now : null,\n ...(periodEnd ? { periodEnd } : {}),\n updatedAt: now,\n },\n where: [{ field: \"paystackSubscriptionCode\", value: subscriptionCode }],\n });\n\n if (persistedSubscription !== undefined) {\n try {\n await options.subscription.onSubscriptionCancel?.(\n { event, subscription: persistedSubscription },\n ctx as GenericEndpointContext,\n );\n } catch (error) {\n ctx.context.logger.error(\"Paystack subscription cancel callback failed\", error);\n }\n const plan = await getPlanByName(options, persistedSubscription.plan);\n if (plan !== undefined && plan !== null) {\n try {\n await options.subscription.onSubscriptionUpdate?.(\n { event, subscription: persistedSubscription, plan },\n ctx as GenericEndpointContext,\n );\n } catch (error) {\n ctx.context.logger.error(\"Paystack subscription update callback failed\", error);\n }\n if (existing?.status === \"trialing\" && newStatus === \"canceled\") {\n try {\n await plan.freeTrial?.onTrialExpired?.(persistedSubscription);\n } catch (error) {\n ctx.context.logger.error(\"Paystack trial expiry callback failed\", error);\n }\n }\n }\n }\n }\n }\n\n // Handle plan changes on renewal\n if (eventName === \"charge.success\" || eventName === \"invoice.update\") {\n const subData = (data as { subscription?: { subscription_code?: string | null } })\n ?.subscription;\n const subscriptionCodeRaw =\n subData?.subscription_code ??\n (data as { subscription_code?: string | null })?.subscription_code;\n const subscriptionCode =\n subscriptionCodeRaw !== undefined &&\n subscriptionCodeRaw !== null &&\n subscriptionCodeRaw !== \"\"\n ? subscriptionCodeRaw\n : undefined;\n\n if (subscriptionCode !== undefined) {\n const existingSub = await ctx.context.adapter.findOne<Subscription>({\n model: \"subscription\",\n where: [{ field: \"paystackSubscriptionCode\", value: subscriptionCode }],\n });\n\n if (\n existingSub !== undefined &&\n existingSub !== null &&\n existingSub.pendingPlan !== undefined &&\n existingSub.pendingPlan !== null &&\n existingSub.pendingPlan !== \"\"\n ) {\n await ctx.context.adapter.update({\n model: \"subscription\",\n update: {\n plan: existingSub.pendingPlan,\n pendingPlan: null,\n updatedAt: new Date(),\n },\n where: [{ field: \"id\", value: existingSub.id }],\n });\n }\n }\n }\n } catch (_e: unknown) {\n ctx.context.logger.error(\"Failed to sync Paystack webhook event\", _e);\n }\n }\n\n await options.onEvent?.(event);\n return ctx.json({ received: true });\n },\n );\n};\n\nexport const initializeTransaction = <P extends string = \"/initialize-transaction\">(\n options: AnyPaystackOptions,\n path: P = \"/initialize-transaction\" as P,\n): StrictEndpoint<\n P,\n {\n method: \"POST\";\n body: z.ZodObject<\n {\n plan: z.ZodOptional<z.ZodString>;\n product: z.ZodOptional<z.ZodString>;\n amount: z.ZodOptional<z.ZodNumber>;\n currency: z.ZodOptional<z.ZodString>;\n email: z.ZodOptional<z.ZodString>;\n metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;\n referenceId: z.ZodOptional<z.ZodString>;\n subscriptionId: z.ZodOptional<z.ZodString>;\n callbackURL: z.ZodOptional<z.ZodString>;\n quantity: z.ZodOptional<z.ZodNumber>;\n scheduleAtPeriodEnd: z.ZodOptional<z.ZodBoolean>;\n cancelAtPeriodEnd: z.ZodOptional<z.ZodBoolean>;\n prorateAndCharge: z.ZodOptional<z.ZodBoolean>;\n },\n z.core.$strip\n >;\n use: (\n | ((\n getValue: (ctx: GenericEndpointContext) => string | string[],\n ) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>)\n | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>)\n )[];\n },\n PaystackInitializeResult | undefined\n> => {\n const subscriptionOptions = options.subscription;\n const useMiddlewares =\n subscriptionOptions?.enabled === true\n ? [sessionMiddleware, originCheck, referenceMiddleware(options, \"initialize-transaction\")]\n : [sessionMiddleware, originCheck];\n\n return createAuthEndpoint(\n path,\n {\n method: \"POST\",\n body: initializeTransactionBodySchema,\n use: useMiddlewares,\n },\n async (ctx) => {\n const paystack = getPaystackOps(options.paystackClient);\n const {\n plan: planName,\n product: productName,\n amount: bodyAmount,\n currency,\n email,\n metadata: extraMetadata,\n callbackURL,\n quantity,\n scheduleAtPeriodEnd,\n cancelAtPeriodEnd,\n prorateAndCharge,\n subscriptionId,\n } = ctx.body;\n\n // 1. Validate Callback URL validation (same as before)\n if (callbackURL !== undefined && callbackURL !== null && callbackURL !== \"\") {\n const checkTrusted = () => {\n try {\n if ((callbackURL as string | undefined)?.startsWith(\"/\") === true) return true;\n const baseUrl =\n ((ctx.context as Record<string, unknown>)?.baseURL as string | undefined) ??\n (ctx.request as unknown as { url?: string })?.url ??\n \"\";\n if (baseUrl === \"\") return false;\n const baseOrigin = new URL(baseUrl).origin;\n return new URL(callbackURL).origin === baseOrigin;\n } catch {\n return false;\n }\n };\n if (checkTrusted() === false) {\n throw new APIError(\"FORBIDDEN\", {\n message: \"callbackURL is not a trusted origin.\",\n status: 403,\n });\n }\n }\n\n // 2. Get User & Session\n const session = await getSessionFromCtx(ctx);\n if (session === undefined || session === null) throw new APIError(\"UNAUTHORIZED\");\n const user = session.user;\n\n // 3. Email Verification Check (only if subscription options enforce it)\n if (\n subscriptionOptions?.enabled === true &&\n subscriptionOptions.requireEmailVerification === true &&\n user.emailVerified !== true\n ) {\n throw new APIError(\"BAD_REQUEST\", {\n code: \"EMAIL_VERIFICATION_REQUIRED\",\n message: PAYSTACK_ERROR_CODES.EMAIL_VERIFICATION_REQUIRED.message,\n });\n }\n\n // 4. Determine Payment Mode: Subscription (Plan) vs Product vs One-Time (Amount)\n let plan: PaystackPlan | undefined;\n let product: PaystackProduct | InputPaystackProduct | undefined;\n\n if (planName !== undefined && planName !== null && planName !== \"\") {\n if (subscriptionOptions?.enabled !== true) {\n throw new APIError(\"BAD_REQUEST\", { message: \"Subscriptions are not enabled.\" });\n }\n plan = (await getPlanByName(options, planName)) ?? undefined;\n if (plan === undefined || plan === null) {\n try {\n // Fallback: Check database for synced plans when that model exists.\n const nativePlan = await ctx.context.adapter.findOne<PaystackPlan>({\n model: \"paystackPlan\",\n where: [{ field: \"name\", value: planName }],\n });\n if (nativePlan !== undefined && nativePlan !== null) {\n plan = nativePlan;\n } else {\n const nativePlanByCode = await ctx.context.adapter.findOne<PaystackPlan>({\n model: \"paystackPlan\",\n where: [{ field: \"planCode\", value: planName }],\n });\n plan = nativePlanByCode ?? undefined;\n }\n } catch {\n plan = undefined;\n }\n }\n if (plan === undefined || plan === null) {\n throw new APIError(\"BAD_REQUEST\", {\n code: \"SUBSCRIPTION_PLAN_NOT_FOUND\",\n message: PAYSTACK_ERROR_CODES.SUBSCRIPTION_PLAN_NOT_FOUND.message,\n status: 400,\n });\n }\n } else if (productName !== undefined && productName !== null && productName !== \"\") {\n if (typeof productName === \"string\") {\n product = (await getProductByName(options, productName)) ?? undefined;\n // Fallback: Check database for synced products\n product ??=\n (await ctx.context.adapter.findOne<PaystackProduct>({\n model: \"paystackProduct\",\n where: [{ field: \"name\", value: productName }],\n })) ?? undefined;\n }\n if (product === undefined || product === null) {\n throw new APIError(\"BAD_REQUEST\", {\n message: `Product '${productName}' not found.`,\n status: 400,\n });\n }\n } else if (bodyAmount === undefined || bodyAmount === null) {\n throw new APIError(\"BAD_REQUEST\", {\n message: \"Either 'plan', 'product', or 'amount' is required to initialize a transaction.\",\n status: 400,\n });\n }\n\n let amount =\n bodyAmount ??\n (product as PaystackProduct)?.price ??\n (product as InputPaystackProduct)?.amount;\n const finalCurrency =\n currency ??\n (product as PaystackProduct)?.currency ??\n (product as InputPaystackProduct)?.currency ??\n plan?.currency ??\n \"NGN\";\n\n const referenceIdFromCtx = (ctx.context as Record<string, unknown>).referenceId as\n | string\n | undefined;\n const referenceId =\n ctx.body.referenceId ?? referenceIdFromCtx ?? (session.user as { id: string }).id;\n const groupId = normalizeSubscriptionGroup(plan?.group);\n if (subscriptionId !== undefined) {\n const selectedSubscription =\n await createBillingStore(ctx).findSubscriptionById(subscriptionId);\n if (\n selectedSubscription === null ||\n selectedSubscription.referenceId !== referenceId ||\n normalizeSubscriptionGroup(selectedSubscription.groupId) !== groupId\n ) {\n throw new APIError(\"BAD_REQUEST\", {\n message: \"Subscription does not belong to the authorized reference and plan group.\",\n });\n }\n }\n\n const scheduledChange = await scheduleSubscriptionLifecycleChange(ctx, {\n referenceId,\n subscriptionId,\n plan,\n scheduleAtPeriodEnd,\n cancelAtPeriodEnd,\n });\n if (scheduledChange !== null) {\n return ctx.json(scheduledChange);\n }\n\n // Calculate final amount considering seats if applicable\n if (plan !== undefined) {\n try {\n if (getPlanSeatAmount(plan) !== undefined) {\n const members = await ctx.context.adapter.findMany<Member>({\n model: \"member\",\n where: [{ field: \"organizationId\", value: referenceId }],\n });\n const seatCount = members.length > 0 ? members.length : 1;\n const quantityToUse = quantity ?? seatCount;\n amount = calculatePlanAmount(plan, quantityToUse);\n }\n } catch (error: unknown) {\n throw new APIError(\"BAD_REQUEST\", {\n message:\n error instanceof Error ? error.message : \"Invalid seat configuration for plan.\",\n });\n }\n }\n\n let url: string | undefined;\n let reference: string | undefined;\n let accessCode: string | undefined;\n\n const trial = await resolveTrialLifecycle(ctx, { referenceId, plan });\n const { trialStart, trialEnd } = trial;\n\n try {\n const targetEmail = await resolveCheckoutTargetEmail(ctx, options, {\n email,\n referenceId,\n user: user as User,\n });\n\n const allowedSubscriptionChannels = plan\n ? getAllowedSubscriptionChannels(options)\n : undefined;\n\n // Construct Metadata\n const metadata = stringifyPaystackMetadata(\n createCheckoutMetadata({\n referenceId,\n userId: user.id,\n plan: plan !== undefined ? plan.name.toLowerCase() : undefined,\n groupId,\n product: product !== undefined ? product.name.toLowerCase() : undefined,\n extra: extraMetadata,\n trial: {\n isTrial: trialStart !== undefined,\n requested: trial.requested,\n granted: trial.granted,\n deniedReason: trial.deniedReason,\n endsAt: trialEnd,\n },\n }),\n );\n\n const initBody: {\n email: string;\n callback_url?: string;\n metadata?: string;\n currency: string;\n quantity?: number;\n amount?: number;\n plan?: string;\n channels?: PaystackCheckoutChannel[];\n [key: string]: unknown;\n } = {\n email: targetEmail,\n callback_url: callbackURL ?? undefined,\n metadata,\n // If plan/product exists, use its currency; otherwise fallback to provided or default\n currency: finalCurrency,\n quantity,\n };\n\n if (allowedSubscriptionChannels !== undefined) {\n initBody.channels = allowedSubscriptionChannels;\n }\n\n // Handle prorateAndCharge for existing active subscriptions\n if (plan !== undefined && prorateAndCharge === true) {\n const proration = await handleProratedUpgrade(ctx, options, {\n plan,\n referenceId,\n subscriptionId,\n quantity,\n targetEmail,\n userId: user.id,\n finalCurrency,\n callbackURL,\n allowedSubscriptionChannels,\n });\n\n if (proration?.kind === \"checkout\") {\n return ctx.json({\n kind: \"checkout\",\n url: proration.url ?? \"\",\n reference: proration.reference ?? \"\",\n accessCode: proration.accessCode ?? \"\",\n redirect: proration.redirect,\n } satisfies PaystackInitializeResult);\n }\n\n if (proration?.kind === \"prorated\") {\n return ctx.json({\n kind: \"prorated\",\n status: proration.status,\n message: proration.message,\n prorated: proration.prorated,\n } satisfies PaystackInitializeResult);\n }\n }\n\n if (plan !== undefined) {\n // Subscription Flow\n if (trialStart !== undefined) {\n // Trial Flow: Authorize card with minimum amount, don't start sub yet\n initBody.amount = 5000; // 50 NGN (minimum allowed)\n } else {\n // Standard Flow\n initBody.plan = plan.planCode;\n // SDK might use different field names, but keeping DX consistency\n (initBody as Record<string, unknown>).invoice_limit = plan.invoiceLimit;\n\n let finalAmount: number;\n if (amount !== undefined && amount !== null) {\n finalAmount = amount;\n initBody.quantity = 1;\n } else {\n finalAmount = (plan.amount ?? 0) * (quantity ?? 1);\n }\n initBody.amount = Math.max(Math.round(finalAmount), 5000);\n }\n } else {\n // One-Time Payment Flow\n if (amount === undefined || amount === null)\n throw new APIError(\"BAD_REQUEST\", {\n message: \"Amount is required for one-time payments\",\n });\n initBody.amount = Math.round(amount);\n }\n\n const initRaw = await paystack?.transaction?.initialize({\n body: initBody as components[\"schemas\"][\"TransactionInitialize\"],\n });\n const sdkRes =\n unwrapSdkResult<components[\"schemas\"][\"TransactionInitializeResponse\"][\"data\"]>(initRaw);\n\n url = sdkRes?.authorization_url;\n reference = sdkRes?.reference;\n accessCode = sdkRes?.access_code;\n } catch (error: unknown) {\n ctx.context.logger.error(\"Failed to initialize Paystack transaction\", error);\n const errorMessage =\n error instanceof Error\n ? error.message\n : PAYSTACK_ERROR_CODES.FAILED_TO_INITIALIZE_TRANSACTION.message;\n throw new APIError(\"BAD_REQUEST\", {\n code: \"FAILED_TO_INITIALIZE_TRANSACTION\",\n message: errorMessage,\n });\n }\n\n // 6. Record Transaction & Subscription\n await ctx.context.adapter.create({\n model: \"paystackTransaction\",\n data: {\n reference: reference ?? \"\",\n referenceId,\n userId: user.id,\n amount: amount ?? 0,\n currency: plan?.currency ?? currency ?? \"NGN\",\n status: \"pending\",\n plan: plan !== undefined ? plan.name.toLowerCase() : undefined,\n product: product !== undefined ? product.name.toLowerCase() : undefined,\n metadata: hasPaystackMetadata(extraMetadata)\n ? stringifyPaystackMetadata(extraMetadata)\n : undefined,\n createdAt: new Date(),\n updatedAt: new Date(),\n },\n });\n\n if (plan !== undefined) {\n let storedCustomerCode = (user as PaystackUser).paystackCustomerCode;\n if (options.organization?.enabled === true && referenceId !== user.id) {\n const org = await ctx.context.adapter.findOne({\n model: \"organization\",\n where: [{ field: \"id\", value: referenceId }],\n });\n if (org !== undefined && org !== null) {\n const paystackOrg = org as PaystackOrganization;\n if (\n paystackOrg.paystackCustomerCode !== undefined &&\n paystackOrg.paystackCustomerCode !== null &&\n paystackOrg.paystackCustomerCode !== \"\"\n ) {\n storedCustomerCode = paystackOrg.paystackCustomerCode;\n }\n }\n }\n\n const newSubscription = await ctx.context.adapter.create<Subscription>({\n model: \"subscription\",\n data: {\n plan: plan.name.toLowerCase(),\n groupId,\n referenceId,\n userId: user.id,\n paystackCustomerCode: storedCustomerCode ?? \"\",\n paystackSubscriptionCode: \"\",\n paystackPlanCode: plan.planCode,\n paystackAuthorizationCode: \"\",\n paystackTransactionReference: reference ?? \"\",\n status: trialStart !== undefined ? \"trialing\" : \"incomplete\",\n billingInterval: plan.interval ?? null,\n seats: quantity ?? 1,\n periodStart: new Date(),\n periodEnd: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000), // Default 30 days\n cancelAtPeriodEnd: false,\n trialStart,\n trialEnd,\n createdAt: new Date(),\n updatedAt: new Date(),\n },\n });\n\n // Call trial start hook if trial was granted\n if (\n trialStart !== undefined &&\n newSubscription !== undefined &&\n newSubscription !== null &&\n plan.freeTrial?.onTrialStart !== undefined\n ) {\n await plan.freeTrial.onTrialStart(newSubscription);\n }\n }\n\n return ctx.json({\n kind: \"checkout\",\n url: url ?? \"\",\n reference: reference ?? \"\",\n accessCode: accessCode ?? \"\",\n redirect: true,\n } satisfies PaystackInitializeResult);\n },\n );\n};\n\n// Aliases for Client DX Parity\nexport const createSubscription = <P extends string = \"/create-subscription\">(\n options: AnyPaystackOptions,\n path: P = \"/create-subscription\" as P,\n): StrictEndpoint<\n P,\n {\n method: \"POST\";\n body: z.ZodObject<\n {\n plan: z.ZodOptional<z.ZodString>;\n product: z.ZodOptional<z.ZodString>;\n amount: z.ZodOptional<z.ZodNumber>;\n currency: z.ZodOptional<z.ZodString>;\n email: z.ZodOptional<z.ZodString>;\n metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;\n referenceId: z.ZodOptional<z.ZodString>;\n subscriptionId: z.ZodOptional<z.ZodString>;\n callbackURL: z.ZodOptional<z.ZodString>;\n quantity: z.ZodOptional<z.ZodNumber>;\n scheduleAtPeriodEnd: z.ZodOptional<z.ZodBoolean>;\n cancelAtPeriodEnd: z.ZodOptional<z.ZodBoolean>;\n prorateAndCharge: z.ZodOptional<z.ZodBoolean>;\n },\n z.core.$strip\n >;\n use: (\n | ((\n getValue: (ctx: GenericEndpointContext) => string | string[],\n ) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>)\n | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>)\n )[];\n },\n PaystackInitializeResult | undefined\n> => initializeTransaction(options, path);\n\nexport const upgradeSubscription = <P extends string = \"/upgrade-subscription\">(\n options: AnyPaystackOptions,\n path: P = \"/upgrade-subscription\" as P,\n): StrictEndpoint<\n P,\n {\n method: \"POST\";\n body: z.ZodObject<\n {\n plan: z.ZodOptional<z.ZodString>;\n product: z.ZodOptional<z.ZodString>;\n amount: z.ZodOptional<z.ZodNumber>;\n currency: z.ZodOptional<z.ZodString>;\n email: z.ZodOptional<z.ZodString>;\n metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;\n referenceId: z.ZodOptional<z.ZodString>;\n subscriptionId: z.ZodOptional<z.ZodString>;\n callbackURL: z.ZodOptional<z.ZodString>;\n quantity: z.ZodOptional<z.ZodNumber>;\n scheduleAtPeriodEnd: z.ZodOptional<z.ZodBoolean>;\n cancelAtPeriodEnd: z.ZodOptional<z.ZodBoolean>;\n prorateAndCharge: z.ZodOptional<z.ZodBoolean>;\n },\n z.core.$strip\n >;\n use: (\n | ((\n getValue: (ctx: GenericEndpointContext) => string | string[],\n ) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>)\n | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>)\n )[];\n },\n PaystackInitializeResult | undefined\n> => initializeTransaction(options, path);\n\nexport const cancelSubscription = <P extends string = \"/cancel-subscription\">(\n options: AnyPaystackOptions,\n path: P = \"/cancel-subscription\" as P,\n): StrictEndpoint<\n P,\n {\n method: \"POST\";\n body: z.ZodObject<\n {\n referenceId: z.ZodOptional<z.ZodString>;\n subscriptionCode: z.ZodString;\n emailToken: z.ZodOptional<z.ZodString>;\n atPeriodEnd: z.ZodOptional<z.ZodBoolean>;\n },\n z.core.$strip\n >;\n use: (\n | ((\n getValue: (ctx: GenericEndpointContext) => string | string[],\n ) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>)\n | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>)\n )[];\n },\n {\n status: string;\n }\n> => disablePaystackSubscription(options, path);\n\nexport const restoreSubscription = <P extends string = \"/restore-subscription\">(\n options: AnyPaystackOptions,\n path: P = \"/restore-subscription\" as P,\n): StrictEndpoint<\n P,\n {\n method: \"POST\";\n body: z.ZodObject<\n {\n referenceId: z.ZodOptional<z.ZodString>;\n subscriptionCode: z.ZodString;\n emailToken: z.ZodOptional<z.ZodString>;\n atPeriodEnd: z.ZodOptional<z.ZodBoolean>;\n },\n z.core.$strip\n >;\n use: (\n | ((\n getValue: (ctx: GenericEndpointContext) => string | string[],\n ) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>)\n | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>)\n )[];\n },\n {\n status: string;\n }\n> => enablePaystackSubscription(options, path);\n\nexport const verifyTransaction = <P extends string = \"/verify-transaction\">(\n options: AnyPaystackOptions,\n path: P = \"/verify-transaction\" as P,\n): StrictEndpoint<\n P,\n {\n method: \"POST\";\n body: z.ZodObject<\n {\n reference: z.ZodString;\n },\n z.core.$strip\n >;\n use: (\n | ((\n getValue: (ctx: GenericEndpointContext) => string | string[],\n ) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>)\n | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>)\n )[];\n },\n {\n status: string;\n reference: string;\n data: {\n id: number;\n domain: string;\n status: string;\n reference: string;\n receipt_number: string | null;\n amount: number;\n message: string | null;\n gateway_response: string;\n channel: string;\n currency: string;\n ip_address: string | null;\n metadata: (string | Record<string, never> | number) | null;\n log: {\n start_time: number;\n time_spent: number;\n attempts: number;\n errors: number;\n success: boolean;\n mobile: boolean;\n input: unknown[];\n history: {\n type: string;\n message: string;\n time: number;\n }[];\n } | null;\n fees: number | null;\n fees_split: unknown;\n authorization: {\n authorization_code?: string;\n bin?: string | null;\n last4?: string;\n exp_month?: string;\n exp_year?: string;\n channel?: string;\n card_type?: string;\n bank?: string;\n country_code?: string;\n brand?: string;\n reusable?: boolean;\n signature?: string;\n account_name?: string | null;\n receiver_bank_account_number?: string | null;\n receiver_bank?: string | null;\n };\n customer: {\n id: number;\n first_name: string | null;\n last_name: string | null;\n email: string;\n customer_code: string;\n phone: string | null;\n metadata: Record<string, never> | null;\n risk_action: string;\n international_format_phone?: string | null;\n };\n plan: (string | Record<string, never>) | null;\n split: Record<string, never> | null;\n order_id: unknown;\n paidAt: string | null;\n createdAt: string;\n requested_amount: number;\n pos_transaction_data: unknown;\n source: unknown;\n fees_breakdown: unknown;\n connect: unknown;\n transaction_date: string;\n plan_object: {\n id?: number;\n name?: string;\n plan_code?: string;\n description?: unknown;\n amount?: number;\n interval?: string;\n send_invoices?: boolean;\n send_sms?: boolean;\n currency?: string;\n };\n subaccount: Record<string, never> | null;\n };\n }\n> => {\n const verifyBodySchema = z.object({\n reference: z.string(),\n });\n\n const subscriptionOptions = options.subscription;\n const useMiddlewares =\n subscriptionOptions?.enabled === true\n ? [sessionMiddleware, originCheck, referenceMiddleware(options, \"verify-transaction\")]\n : [sessionMiddleware, originCheck];\n\n return createAuthEndpoint(\n path,\n {\n method: \"POST\",\n body: verifyBodySchema,\n use: useMiddlewares,\n },\n async (ctx) => {\n const session = await getSessionFromCtx(ctx);\n const result = await reconcilePaystackTransaction(ctx as GenericEndpointContext, options, {\n reference: ctx.body.reference,\n source: \"browser\",\n actor:\n session !== undefined && session !== null\n ? {\n user: session.user as User,\n session: session.session,\n }\n : undefined,\n throwOnError: true,\n });\n\n if (!result.ok || result.data === null) {\n throw new APIError(\"BAD_REQUEST\", {\n code: result.error?.code ?? \"FAILED_TO_VERIFY_TRANSACTION\",\n message:\n result.error?.message ?? PAYSTACK_ERROR_CODES.FAILED_TO_VERIFY_TRANSACTION.message,\n status: result.error?.status,\n });\n }\n\n return ctx.json({\n status: result.status,\n reference: result.reference,\n data: result.data,\n });\n },\n );\n};\n\nexport const listSubscriptions = <P extends string = \"/list-subscriptions\">(\n options: AnyPaystackOptions,\n path: P = \"/list-subscriptions\" as P,\n): StrictEndpoint<\n P,\n {\n method: \"GET\";\n query: z.ZodObject<\n {\n referenceId: z.ZodOptional<z.ZodString>;\n },\n z.core.$strip\n >;\n use: (\n | ((\n getValue: (ctx: GenericEndpointContext) => string | string[],\n ) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>)\n | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>)\n )[];\n },\n {\n subscriptions: Subscription[];\n }\n> => {\n const listQuerySchema = z.object({\n referenceId: z.string().optional(),\n });\n\n const subscriptionOptions = options.subscription;\n const useMiddlewares =\n subscriptionOptions?.enabled === true\n ? [sessionMiddleware, originCheck, referenceMiddleware(options, \"list-subscriptions\")]\n : [sessionMiddleware, originCheck];\n\n return createAuthEndpoint(\n path,\n {\n method: \"GET\",\n query: listQuerySchema,\n use: useMiddlewares,\n },\n async (ctx) => {\n if (subscriptionOptions?.enabled !== true) {\n throw new APIError(\"BAD_REQUEST\", {\n message: \"Subscriptions are not enabled in the Paystack options.\",\n });\n }\n const session = await getSessionFromCtx(ctx);\n if (session === undefined || session === null) throw new APIError(\"UNAUTHORIZED\");\n const store = createBillingStore(ctx);\n const referenceIdPart = (ctx.context as Record<string, unknown>).referenceId as\n | string\n | undefined;\n const queryRefId =\n ctx.query?.referenceId ??\n (typeof ctx.request?.url === \"string\"\n ? (new URL(ctx.request.url).searchParams.get(\"referenceId\") ?? undefined)\n : undefined);\n const userId = (session.user as { id: string }).id;\n if (queryRefId !== undefined && queryRefId !== userId && referenceIdPart !== queryRefId) {\n await authorizeBillingReference(ctx, options, {\n user: session.user as User,\n session: session.session,\n referenceId: queryRefId,\n action: \"list-subscriptions\",\n });\n }\n const referenceId = queryRefId ?? referenceIdPart ?? userId;\n const res = await store.findSubscriptionsByReference(referenceId);\n return ctx.json({ subscriptions: res });\n },\n );\n};\n\nexport const listTransactions = <P extends string = \"/list-transactions\">(\n options: AnyPaystackOptions,\n path: P = \"/list-transactions\" as P,\n): StrictEndpoint<\n P,\n {\n method: \"GET\";\n query: z.ZodObject<\n {\n referenceId: z.ZodOptional<z.ZodString>;\n },\n z.core.$strip\n >;\n use: (\n | ((\n getValue: (ctx: GenericEndpointContext) => string | string[],\n ) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>)\n | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>)\n )[];\n },\n {\n transactions: PaystackTransaction[];\n }\n> => {\n const listQuerySchema = z.object({\n referenceId: z.string().optional(),\n });\n\n const subscriptionOptions = options.subscription;\n const useMiddlewares =\n subscriptionOptions?.enabled === true\n ? [sessionMiddleware, originCheck, referenceMiddleware(options, \"list-transactions\")]\n : [sessionMiddleware, originCheck];\n\n return createAuthEndpoint(\n path,\n {\n method: \"GET\",\n query: listQuerySchema,\n use: useMiddlewares,\n },\n async (ctx) => {\n const session = await getSessionFromCtx(ctx);\n if (session === undefined || session === null) throw new APIError(\"UNAUTHORIZED\");\n const store = createBillingStore(ctx);\n const referenceIdPart = (ctx.context as Record<string, unknown>).referenceId as\n | string\n | undefined;\n const queryRefId =\n ctx.query?.referenceId ??\n (typeof ctx.request?.url === \"string\"\n ? (new URL(ctx.request.url).searchParams.get(\"referenceId\") ?? undefined)\n : undefined);\n const userId = (session.user as { id: string }).id;\n if (queryRefId !== undefined && queryRefId !== userId && referenceIdPart !== queryRefId) {\n await authorizeBillingReference(ctx, options, {\n user: session.user as User,\n session: session.session,\n referenceId: queryRefId,\n action: \"list-transactions\",\n });\n }\n const referenceId = queryRefId ?? referenceIdPart ?? userId;\n const transactions = await store.listTransactions(referenceId);\n return ctx.json({ transactions });\n },\n );\n};\n\nexport const disablePaystackSubscription = <P extends string = \"/disable-subscription\">(\n options: AnyPaystackOptions,\n path: P = \"/disable-subscription\" as P,\n): StrictEndpoint<\n P,\n {\n method: \"POST\";\n body: z.ZodObject<\n {\n referenceId: z.ZodOptional<z.ZodString>;\n subscriptionCode: z.ZodString;\n emailToken: z.ZodOptional<z.ZodString>;\n atPeriodEnd: z.ZodOptional<z.ZodBoolean>;\n },\n z.core.$strip\n >;\n use: (\n | ((\n getValue: (ctx: GenericEndpointContext) => string | string[],\n ) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>)\n | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>)\n )[];\n },\n {\n status: string;\n }\n> => {\n const subscriptionOptions = options.subscription;\n const useMiddlewares =\n subscriptionOptions?.enabled === true\n ? [sessionMiddleware, originCheck, referenceMiddleware(options, \"disable-subscription\")]\n : [sessionMiddleware, originCheck];\n\n return createAuthEndpoint(\n path,\n { method: \"POST\", body: enableDisableBodySchema, use: useMiddlewares },\n async (ctx) => {\n const { subscriptionCode, atPeriodEnd } = ctx.body;\n const paystack = getPaystackOps(options.paystackClient);\n try {\n const subCode = subscriptionCode;\n if (isLocalSubscriptionCode(subCode)) {\n const sub = await ctx.context.adapter.findOne<Subscription>({\n model: \"subscription\",\n where: [{ field: \"paystackSubscriptionCode\", value: subscriptionCode }],\n });\n\n if (sub !== null && sub !== undefined) {\n const now = new Date();\n const immediate = atPeriodEnd === false;\n await ctx.context.adapter.update({\n model: \"subscription\",\n update: {\n status: immediate ? \"canceled\" : \"active\",\n cancelAtPeriodEnd: !immediate,\n cancelAt: immediate ? null : (sub.periodEnd ?? null),\n canceledAt: now,\n endedAt: immediate ? now : null,\n updatedAt: now,\n },\n where: [{ field: \"id\", value: sub.id }],\n });\n return ctx.json({ status: \"success\" });\n }\n throw new APIError(\"BAD_REQUEST\", { message: \"Subscription not found\" });\n }\n\n let emailToken = ctx.body.emailToken;\n let nextPaymentDate: string | undefined;\n\n try {\n const raw = await paystack?.subscription?.fetch(subscriptionCode);\n const fetchRes =\n unwrapSdkResult<components[\"schemas\"][\"SubscriptionListResponseArray\"]>(raw);\n\n if (fetchRes !== undefined && fetchRes !== null) {\n emailToken ??= fetchRes.email_token ?? undefined;\n nextPaymentDate = fetchRes.next_payment_date ?? undefined;\n }\n } catch {\n // ignore fetch failure\n }\n\n if (emailToken === undefined || emailToken === null || emailToken === \"\") {\n try {\n const raw = await paystack?.subscription?.manageLink(subscriptionCode);\n const linkRes = unwrapSdkResult<{ link: string }>(raw);\n const link = linkRes?.link;\n if (link !== undefined && link !== null && link !== \"\") {\n emailToken = tryGetEmailTokenFromSubscriptionManageLink(link);\n }\n } catch {\n // ignore\n }\n }\n\n if (emailToken === undefined || emailToken === null || emailToken === \"\") {\n throw new Error(\"Could not retrieve email_token for subscription disable.\");\n }\n\n await paystack?.subscription?.disable({\n body: { code: subscriptionCode, token: emailToken },\n });\n\n const periodEnd =\n nextPaymentDate !== undefined && nextPaymentDate !== null && nextPaymentDate !== \"\"\n ? new Date(nextPaymentDate)\n : undefined;\n\n const sub = await ctx.context.adapter.findOne<Subscription>({\n model: \"subscription\",\n where: [{ field: \"paystackSubscriptionCode\", value: subscriptionCode }],\n });\n\n if (sub !== undefined && sub !== null) {\n const now = new Date();\n const immediate = atPeriodEnd === false;\n await ctx.context.adapter.update({\n model: \"subscription\",\n update: {\n status: immediate ? \"canceled\" : \"active\",\n cancelAtPeriodEnd: !immediate,\n cancelAt: immediate ? null : (periodEnd ?? sub.periodEnd ?? null),\n canceledAt: now,\n endedAt: immediate ? now : null,\n periodEnd,\n updatedAt: now,\n },\n where: [{ field: \"id\", value: sub.id }],\n });\n } else {\n ctx.context.logger.warn(\n `Could not find subscription with code ${subscriptionCode} to disable`,\n );\n }\n\n return ctx.json({ status: \"success\" });\n } catch (error: unknown) {\n ctx.context.logger.error(\"Failed to disable subscription\", error);\n const errorMessage =\n error instanceof Error\n ? error.message\n : PAYSTACK_ERROR_CODES.FAILED_TO_DISABLE_SUBSCRIPTION.message;\n throw new APIError(\"BAD_REQUEST\", {\n code: \"FAILED_TO_DISABLE_SUBSCRIPTION\",\n message: errorMessage,\n });\n }\n },\n );\n};\n\nexport const enablePaystackSubscription = <P extends string = \"/enable-subscription\">(\n options: AnyPaystackOptions,\n path: P = \"/enable-subscription\" as P,\n): StrictEndpoint<\n P,\n {\n method: \"POST\";\n body: z.ZodObject<\n {\n referenceId: z.ZodOptional<z.ZodString>;\n subscriptionCode: z.ZodString;\n emailToken: z.ZodOptional<z.ZodString>;\n atPeriodEnd: z.ZodOptional<z.ZodBoolean>;\n },\n z.core.$strip\n >;\n use: (\n | ((\n getValue: (ctx: GenericEndpointContext) => string | string[],\n ) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>)\n | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>)\n )[];\n },\n {\n status: string;\n }\n> => {\n const subscriptionOptions = options.subscription;\n const useMiddlewares =\n subscriptionOptions?.enabled === true\n ? [sessionMiddleware, originCheck, referenceMiddleware(options, \"enable-subscription\")]\n : [sessionMiddleware, originCheck];\n\n return createAuthEndpoint(\n path,\n { method: \"POST\", body: enableDisableBodySchema, use: useMiddlewares },\n async (ctx) => {\n const { subscriptionCode } = ctx.body;\n const paystack = getPaystackOps(options.paystackClient);\n try {\n let emailToken = ctx.body.emailToken;\n if (emailToken === undefined || emailToken === null || emailToken === \"\") {\n try {\n const raw = await paystack?.subscription?.fetch(subscriptionCode);\n const fetchRes =\n unwrapSdkResult<components[\"schemas\"][\"SubscriptionListResponseArray\"]>(raw);\n if (fetchRes !== undefined && fetchRes !== null) {\n emailToken = fetchRes.email_token ?? undefined;\n }\n } catch {\n // ignore\n }\n }\n\n if (emailToken === undefined || emailToken === null || emailToken === \"\") {\n try {\n const raw = await paystack?.subscription?.manageLink(subscriptionCode);\n const linkRes = unwrapSdkResult<{ link: string }>(raw);\n const link = linkRes?.link;\n if (link !== undefined && link !== null && link !== \"\") {\n emailToken = tryGetEmailTokenFromSubscriptionManageLink(link);\n }\n } catch {\n // ignore\n }\n }\n\n if (emailToken === undefined || emailToken === null || emailToken === \"\") {\n throw new APIError(\"BAD_REQUEST\", {\n message: \"Could not retrieve email_token for subscription enable.\",\n });\n }\n\n await paystack?.subscription?.enable({\n body: { code: subscriptionCode, token: emailToken },\n });\n\n // Update local status immediately\n await ctx.context.adapter.update({\n model: \"subscription\",\n update: {\n status: \"active\",\n cancelAtPeriodEnd: false,\n cancelAt: null,\n canceledAt: null,\n endedAt: null,\n updatedAt: new Date(),\n },\n where: [{ field: \"paystackSubscriptionCode\", value: subscriptionCode }],\n });\n\n return ctx.json({ status: \"success\" });\n } catch (error: unknown) {\n ctx.context.logger.error(\"Failed to enable subscription\", error);\n const errorMessage =\n error instanceof Error\n ? error.message\n : PAYSTACK_ERROR_CODES.FAILED_TO_ENABLE_SUBSCRIPTION.message;\n throw new APIError(\"BAD_REQUEST\", {\n code: \"FAILED_TO_ENABLE_SUBSCRIPTION\",\n message: errorMessage,\n });\n }\n },\n );\n};\n\nexport const getSubscriptionManageLink = <P extends string = \"/subscription-manage-link\">(\n options: AnyPaystackOptions,\n path: P = \"/subscription-manage-link\" as P,\n): StrictEndpoint<\n P,\n {\n method: \"GET\";\n query: z.ZodObject<\n {\n subscriptionCode: z.ZodString;\n },\n z.core.$strip\n >;\n use: (\n | ((\n getValue: (ctx: GenericEndpointContext) => string | string[],\n ) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>)\n | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>)\n )[];\n },\n {\n link: string | null;\n }\n> => {\n const manageLinkQuerySchema = z.object({\n subscriptionCode: z.string(),\n });\n const subscriptionOptions = options.subscription;\n const useMiddlewares =\n subscriptionOptions?.enabled === true\n ? [\n sessionMiddleware,\n originCheck,\n referenceMiddleware(options, \"get-subscription-manage-link\"),\n ]\n : [sessionMiddleware, originCheck];\n\n const handler = async (ctx: GenericEndpointContext) => {\n const { subscriptionCode } = ctx.query;\n\n if (isLocalSubscriptionCode(subscriptionCode as string)) {\n return ctx.json({ link: null, message: \"Local subscriptions cannot be managed on Paystack\" });\n }\n\n const paystack = getPaystackOps(options.paystackClient);\n try {\n const raw = await paystack?.subscription?.manageLink(subscriptionCode as string);\n const res = unwrapSdkResult<{ link: string }>(raw);\n return ctx.json({ link: res?.link || null });\n } catch (error: unknown) {\n ctx.context.logger.error(\"Failed to get subscription manage link\", error);\n const errorMessage =\n error instanceof Error ? error.message : \"Failed to get subscription manage link\";\n throw new APIError(\"BAD_REQUEST\", {\n message: errorMessage,\n });\n }\n };\n\n return createAuthEndpoint(\n path,\n {\n method: \"GET\",\n query: manageLinkQuerySchema,\n use: useMiddlewares,\n },\n handler,\n );\n};\n\nexport const listProducts = <P extends string = \"/list-products\">(\n _options: AnyPaystackOptions,\n path: P = \"/list-products\" as P,\n): StrictEndpoint<\n P,\n {\n method: \"GET\";\n metadata: {\n openapi: {\n operationId: string;\n };\n };\n },\n {\n products: PaystackProduct[];\n }\n> => {\n return createAuthEndpoint(\n path,\n {\n method: \"GET\",\n metadata: {\n openapi: {\n operationId: \"listPaystackProducts\",\n },\n },\n },\n async (ctx) => {\n const products = await listStoredProducts(ctx);\n return ctx.json({ products });\n },\n );\n};\n\nexport const listPlans = <P extends string = \"/list-plans\">(\n _options: AnyPaystackOptions,\n path: P = \"/list-plans\" as P,\n): StrictEndpoint<\n P,\n {\n method: \"GET\";\n metadata: {\n scope: \"server\";\n };\n use: ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<{\n session: {\n session: Record<string, unknown> & {\n id: string;\n createdAt: Date;\n updatedAt: Date;\n userId: string;\n expiresAt: Date;\n token: string;\n ipAddress?: string | null | undefined;\n userAgent?: string | null | undefined;\n };\n user: Record<string, unknown> & {\n id: string;\n createdAt: Date;\n updatedAt: Date;\n email: string;\n emailVerified: boolean;\n name: string;\n image?: string | null | undefined;\n };\n };\n }>)[];\n },\n {\n plans: PaystackPlan[];\n }\n> => {\n return createAuthEndpoint(\n path,\n {\n method: \"GET\",\n metadata: { ...HIDE_METADATA },\n use: [sessionMiddleware],\n },\n async (ctx) => {\n try {\n const plans = await listStoredPlans(ctx);\n return ctx.json({ plans });\n } catch (error: unknown) {\n ctx.context.logger.error(\"Failed to list plans\", error);\n const errorMessage = error instanceof Error ? error.message : \"Failed to list plans\";\n throw new APIError(\"BAD_REQUEST\", {\n message: errorMessage,\n });\n }\n },\n );\n};\n\nexport const getConfig = <P extends string = \"/get-config\">(\n options: AnyPaystackOptions,\n path: P = \"/get-config\" as P,\n): StrictEndpoint<\n P,\n {\n method: \"GET\";\n metadata: {\n openapi: {\n operationId: string;\n };\n };\n },\n {\n plans: PaystackPlan[];\n products: PaystackProduct[];\n }\n> => {\n return createAuthEndpoint(\n path,\n {\n method: \"GET\",\n metadata: {\n openapi: {\n operationId: \"getPaystackConfig\",\n },\n },\n },\n async (ctx: GenericEndpointContext) => {\n return ctx.json(await getConfiguredCatalog(options));\n },\n );\n};\n\nexport { PAYSTACK_ERROR_CODES };\n","import { mergeSchema, type BetterAuthPluginDBSchema, type DBFieldAttribute } from \"better-auth/db\";\n\nimport type { PaystackOptions } from \"./types\";\n\ntype PluginSchemaTable<TableName extends string, FieldName extends string> = Record<\n TableName,\n {\n fields: Record<FieldName, DBFieldAttribute>;\n disableMigration?: boolean;\n modelName?: string;\n }\n>;\n\ntype TransactionsSchema = PluginSchemaTable<\n \"paystackTransaction\",\n | \"reference\"\n | \"paystackId\"\n | \"referenceId\"\n | \"userId\"\n | \"amount\"\n | \"currency\"\n | \"status\"\n | \"plan\"\n | \"product\"\n | \"metadata\"\n | \"createdAt\"\n | \"updatedAt\"\n>;\n\ntype SubscriptionsSchema = PluginSchemaTable<\n \"subscription\",\n | \"plan\"\n | \"referenceId\"\n | \"paystackCustomerCode\"\n | \"paystackSubscriptionCode\"\n | \"paystackTransactionReference\"\n | \"paystackAuthorizationCode\"\n | \"paystackEmailToken\"\n | \"status\"\n | \"periodStart\"\n | \"periodEnd\"\n | \"trialStart\"\n | \"trialEnd\"\n | \"cancelAtPeriodEnd\"\n | \"cancelAt\"\n | \"canceledAt\"\n | \"endedAt\"\n | \"billingInterval\"\n | \"groupId\"\n | \"seats\"\n | \"pendingPlan\"\n>;\n\ntype UserSchema = PluginSchemaTable<\"user\", \"paystackCustomerCode\">;\n\ntype OrganizationSchema = PluginSchemaTable<\"organization\", \"paystackCustomerCode\" | \"email\">;\n\ntype ProductsSchema = PluginSchemaTable<\n \"paystackProduct\",\n | \"name\"\n | \"description\"\n | \"price\"\n | \"currency\"\n | \"quantity\"\n | \"unlimited\"\n | \"paystackId\"\n | \"slug\"\n | \"metadata\"\n | \"createdAt\"\n | \"updatedAt\"\n>;\n\ntype PlansSchema = PluginSchemaTable<\n \"paystackPlan\",\n | \"name\"\n | \"description\"\n | \"amount\"\n | \"currency\"\n | \"interval\"\n | \"group\"\n | \"planCode\"\n | \"paystackId\"\n | \"metadata\"\n | \"createdAt\"\n | \"updatedAt\"\n>;\n\nexport type PaystackPluginSchema = SubscriptionsSchema &\n TransactionsSchema &\n UserSchema &\n OrganizationSchema &\n ProductsSchema &\n PlansSchema;\n\nconst transactionsSchema: TransactionsSchema = {\n paystackTransaction: {\n fields: {\n reference: {\n type: \"string\",\n required: true,\n unique: true,\n },\n paystackId: {\n type: \"string\",\n required: false,\n },\n referenceId: {\n type: \"string\",\n required: true,\n index: true,\n },\n userId: {\n type: \"string\",\n required: true,\n index: true,\n },\n amount: {\n type: \"number\",\n required: true,\n },\n currency: {\n type: \"string\",\n required: true,\n },\n status: {\n type: \"string\",\n required: true,\n },\n plan: {\n type: \"string\",\n required: false,\n },\n product: {\n type: \"string\",\n required: false,\n },\n metadata: {\n type: \"string\",\n required: false,\n },\n createdAt: {\n type: \"date\",\n required: true,\n },\n updatedAt: {\n type: \"date\",\n required: true,\n },\n },\n },\n} satisfies BetterAuthPluginDBSchema;\n\nexport const transactions: typeof transactionsSchema = transactionsSchema;\n\nconst subscriptionsSchema: SubscriptionsSchema = {\n subscription: {\n fields: {\n plan: {\n type: \"string\",\n required: true,\n index: true,\n },\n referenceId: {\n type: \"string\",\n required: true,\n index: true,\n },\n paystackCustomerCode: {\n type: \"string\",\n required: false,\n index: true,\n },\n paystackSubscriptionCode: {\n type: \"string\",\n required: false,\n unique: true,\n },\n paystackTransactionReference: {\n type: \"string\",\n required: false,\n index: true,\n },\n paystackAuthorizationCode: {\n type: \"string\",\n required: false,\n },\n paystackEmailToken: {\n type: \"string\",\n required: false,\n },\n status: {\n type: \"string\",\n defaultValue: \"incomplete\",\n },\n periodStart: {\n type: \"date\",\n required: false,\n },\n periodEnd: {\n type: \"date\",\n required: false,\n },\n trialStart: {\n type: \"date\",\n required: false,\n },\n trialEnd: {\n type: \"date\",\n required: false,\n },\n cancelAtPeriodEnd: {\n type: \"boolean\",\n required: false,\n defaultValue: false,\n },\n cancelAt: {\n type: \"date\",\n required: false,\n },\n canceledAt: {\n type: \"date\",\n required: false,\n },\n endedAt: {\n type: \"date\",\n required: false,\n },\n billingInterval: {\n type: \"string\",\n required: false,\n },\n groupId: {\n type: \"string\",\n required: false,\n },\n seats: {\n type: \"number\",\n required: false,\n },\n pendingPlan: {\n type: \"string\",\n required: false,\n },\n },\n },\n} satisfies BetterAuthPluginDBSchema;\n\nexport const subscriptions: typeof subscriptionsSchema = subscriptionsSchema;\n\nconst userSchema: UserSchema = {\n user: {\n fields: {\n paystackCustomerCode: {\n type: \"string\",\n required: false,\n index: true,\n },\n },\n },\n} satisfies BetterAuthPluginDBSchema;\n\nexport const user: typeof userSchema = userSchema;\n\nconst organizationSchema: OrganizationSchema = {\n organization: {\n fields: {\n paystackCustomerCode: {\n type: \"string\",\n required: false,\n index: true,\n },\n email: {\n type: \"string\",\n required: false,\n },\n },\n },\n} satisfies BetterAuthPluginDBSchema;\n\nexport const organization: typeof organizationSchema = organizationSchema;\n\nconst productsSchema: ProductsSchema = {\n paystackProduct: {\n fields: {\n name: {\n type: \"string\",\n required: true,\n },\n description: {\n type: \"string\",\n required: false,\n },\n price: {\n type: \"number\",\n required: true,\n },\n currency: {\n type: \"string\",\n required: true,\n },\n quantity: {\n type: \"number\",\n required: false,\n defaultValue: 0,\n },\n unlimited: {\n type: \"boolean\",\n required: false,\n defaultValue: true,\n },\n paystackId: {\n type: \"string\",\n required: false,\n unique: true,\n },\n slug: {\n type: \"string\",\n required: true,\n unique: true,\n },\n metadata: {\n type: \"string\",\n required: false,\n },\n createdAt: {\n type: \"date\",\n required: true,\n },\n updatedAt: {\n type: \"date\",\n required: true,\n },\n },\n },\n} satisfies BetterAuthPluginDBSchema;\n\nexport const products: typeof productsSchema = productsSchema;\n\nconst plansSchema: PlansSchema = {\n paystackPlan: {\n fields: {\n name: {\n type: \"string\",\n required: true,\n },\n description: {\n type: \"string\",\n required: false,\n },\n amount: {\n type: \"number\",\n required: true,\n },\n currency: {\n type: \"string\",\n required: true,\n },\n interval: {\n type: \"string\",\n required: true,\n },\n group: {\n type: \"string\",\n required: false,\n },\n planCode: {\n type: \"string\",\n required: true,\n unique: true,\n },\n paystackId: {\n type: \"string\",\n required: true,\n unique: true,\n },\n metadata: {\n type: \"string\",\n required: false,\n },\n createdAt: {\n type: \"date\",\n required: true,\n },\n updatedAt: {\n type: \"date\",\n required: true,\n },\n },\n },\n} satisfies BetterAuthPluginDBSchema;\n\nexport const plans: typeof plansSchema = plansSchema;\n\nconst paystackPluginSchemaDefinition: PaystackPluginSchema = {\n ...subscriptions,\n ...transactions,\n ...user,\n ...organization,\n ...products,\n ...plans,\n} satisfies BetterAuthPluginDBSchema;\n\nexport const paystackPluginSchema: typeof paystackPluginSchemaDefinition =\n paystackPluginSchemaDefinition;\n\nexport const getSchema = (options: PaystackOptions): BetterAuthPluginDBSchema => {\n let baseSchema: BetterAuthPluginDBSchema;\n const optionSchema = options.schema as Parameters<typeof mergeSchema>[1];\n\n if (options.subscription?.enabled === true) {\n baseSchema = {\n ...subscriptions,\n ...transactions,\n ...user,\n ...products,\n ...plans,\n };\n } else {\n baseSchema = {\n ...user,\n ...transactions,\n ...products,\n ...plans,\n };\n }\n\n // Add organization schema if organization support is enabled\n if (options.organization?.enabled === true) {\n baseSchema = {\n ...baseSchema,\n ...organization,\n };\n }\n\n if (\n options.schema !== undefined &&\n options.subscription?.enabled !== true &&\n \"subscription\" in options.schema\n ) {\n const { subscription: _subscription, ...restSchema } = optionSchema ?? {};\n return mergeSchema(baseSchema, restSchema);\n }\n\n return mergeSchema(baseSchema, optionSchema);\n};\n","import { createBillingStoreFromAdapter } from \"./billing-store\";\nimport { parsePaystackMetadata, stringifyPaystackMetadata } from \"./metadata\";\nimport type {\n PaystackClientLike,\n PaystackCustomerResponse,\n PaystackOrganization,\n User,\n} from \"./types\";\nimport { createPaystackAdapter } from \"./paystack-sdk\";\n\ninterface Logger {\n error(message: string, error?: unknown): void;\n}\ntype Adapter = Parameters<typeof createBillingStoreFromAdapter>[0];\n\ninterface BillingReference {\n id: string;\n type: \"user\" | \"organization\";\n email: string;\n name?: string | null;\n emailVerified?: boolean;\n paystackCustomerCode?: string | null;\n}\n\nfunction isNotFound(error: unknown): boolean {\n if (error === null || typeof error !== \"object\") return false;\n const candidate = error as Record<string, unknown>;\n return candidate.status === 404 || candidate.statusCode === 404;\n}\n\nfunction customerCode(customer: unknown): string | undefined {\n if (customer === null || typeof customer !== \"object\") return undefined;\n const code = (customer as Record<string, unknown>).customer_code;\n return typeof code === \"string\" && code !== \"\" ? code : undefined;\n}\n\nfunction ownsCustomer(customer: unknown, reference: BillingReference): boolean {\n if (customer === null || typeof customer !== \"object\") return false;\n const metadata = parsePaystackMetadata((customer as Record<string, unknown>).metadata);\n const expectedIdKey = reference.type === \"user\" ? \"userId\" : \"organizationId\";\n const otherIdKey = reference.type === \"user\" ? \"organizationId\" : \"userId\";\n return (\n metadata[expectedIdKey] === reference.id &&\n metadata[otherIdKey] === undefined &&\n (metadata.customerType === undefined || metadata.customerType === reference.type)\n );\n}\n\nfunction hasOwner(customer: unknown): boolean {\n if (customer === null || typeof customer !== \"object\") return false;\n const metadata = parsePaystackMetadata((customer as Record<string, unknown>).metadata);\n return (\n typeof metadata.userId === \"string\" ||\n typeof metadata.organizationId === \"string\" ||\n typeof metadata.customerType === \"string\"\n );\n}\n\nfunction ownershipMetadata(reference: BillingReference, existing?: unknown): string | undefined {\n return stringifyPaystackMetadata({\n ...parsePaystackMetadata(existing),\n customerType: reference.type,\n ...(reference.type === \"user\" ? { userId: reference.id } : { organizationId: reference.id }),\n });\n}\n\nexport async function resolvePaystackCustomer(input: {\n adapter: Adapter;\n client: PaystackClientLike;\n logger: Logger;\n reference: BillingReference;\n createParams?: Record<string, unknown>;\n}): Promise<{ customer: PaystackCustomerResponse; created: boolean } | null> {\n const { adapter, client, logger, reference } = input;\n const store = createBillingStoreFromAdapter(adapter);\n const persisted: User | PaystackOrganization | null =\n reference.type === \"user\"\n ? await store.findUser(reference.id)\n : await store.findOrganization(reference.id);\n const existingCode =\n reference.paystackCustomerCode ??\n (persisted as { paystackCustomerCode?: string | null } | null)?.paystackCustomerCode;\n if (typeof existingCode === \"string\" && existingCode !== \"\") return null;\n\n const sdk = createPaystackAdapter(client);\n let existing: PaystackCustomerResponse | null = null;\n if (typeof client.customer?.fetch === \"function\") {\n try {\n existing =\n ((await sdk.fetchCustomer(reference.email)) as PaystackCustomerResponse | undefined) ??\n null;\n } catch (error: unknown) {\n if (!isNotFound(error)) {\n logger.error(\"Failed to look up Paystack customer; customer creation was skipped\", error);\n return null;\n }\n }\n }\n\n if (existing !== null) {\n const code = customerCode(existing);\n if (code === undefined) {\n logger.error(\"Paystack customer lookup returned no customer code\");\n return null;\n }\n\n const owned = ownsCustomer(existing, reference);\n const canClaimLegacy =\n reference.type === \"user\" && reference.emailVerified === true && !hasOwner(existing);\n if (!owned && !canClaimLegacy) {\n logger.error(\"Paystack customer belongs to another billing reference\");\n return null;\n }\n\n const existingMetadata = (existing as unknown as Record<string, unknown>).metadata;\n if (canClaimLegacy || parsePaystackMetadata(existingMetadata).customerType !== reference.type) {\n await sdk.updateCustomer(code, {\n metadata: ownershipMetadata(reference, existingMetadata),\n });\n }\n await store.saveCustomerCode(reference.id, code, reference.type === \"organization\");\n return { customer: existing, created: false };\n }\n\n const customer = (await sdk.createCustomer({\n ...input.createParams,\n email: reference.email,\n first_name: reference.name ?? undefined,\n metadata: ownershipMetadata(reference),\n })) as PaystackCustomerResponse;\n const code = customerCode(customer);\n if (code === undefined) return null;\n await store.saveCustomerCode(reference.id, code, reference.type === \"organization\");\n return { customer, created: true };\n}\n","import { APIError } from \"better-auth/api\";\nimport type { GenericEndpointContext } from \"better-auth\";\n\nimport { createBillingStore } from \"./billing-store\";\nimport { createPaystackAdapter } from \"./paystack-sdk\";\nimport { getNextPeriodEnd, getPlans, validateMinAmount } from \"./utils\";\nimport { createRenewalMetadata, stringifyPaystackMetadata } from \"./metadata\";\nimport type {\n AnyPaystackOptions,\n ChargeRecurringSubscriptionInput,\n ChargeRecurringSubscriptionResult,\n PaystackSyncResult,\n PaystackChargeAuthorizationResponse,\n} from \"./types\";\n\nexport async function syncPaystackProducts(\n ctx: GenericEndpointContext,\n options: AnyPaystackOptions,\n): Promise<PaystackSyncResult> {\n const paystack = createPaystackAdapter(options.paystackClient);\n const store = createBillingStore(ctx);\n try {\n const productsData = await paystack.listProducts();\n\n if (!Array.isArray(productsData)) {\n return { status: \"success\", count: 0 };\n }\n\n for (const product of productsData) {\n const paystackId = String(product.id);\n const productFields = {\n name: product.name ?? \"\",\n description: product.description ?? \"\",\n price: product.price ?? 0,\n currency: product.currency ?? \"\",\n quantity: product.quantity ?? 0,\n unlimited:\n product.unlimited !== undefined &&\n product.unlimited !== null &&\n product.unlimited !== false,\n paystackId,\n slug:\n (product as { slug?: string }).slug ??\n product.name?.toLowerCase().replace(/\\s+/g, \"-\") ??\n \"\",\n metadata: stringifyPaystackMetadata((product as { metadata?: unknown }).metadata),\n updatedAt: new Date(),\n };\n\n await store.upsertProductByPaystackId(paystackId, {\n ...productFields,\n createdAt: new Date(),\n });\n }\n\n return { status: \"success\", count: productsData.length };\n } catch (error: unknown) {\n ctx.context.logger.error(\"Failed to sync products\", error);\n const errorMessage = error instanceof Error ? error.message : \"Failed to sync products\";\n throw new APIError(\"BAD_REQUEST\", {\n message: errorMessage,\n });\n }\n}\n\nexport async function syncPaystackPlans(\n ctx: GenericEndpointContext,\n options: AnyPaystackOptions,\n): Promise<PaystackSyncResult> {\n const paystack = createPaystackAdapter(options.paystackClient);\n const store = createBillingStore(ctx);\n try {\n const plansData = await paystack.listPlans();\n\n if (!Array.isArray(plansData)) {\n return { status: \"success\", count: 0 };\n }\n\n for (const plan of plansData) {\n const paystackId = String(plan.id);\n const planData = {\n name: plan.name ?? \"\",\n description: typeof plan.description === \"string\" ? plan.description : \"\",\n amount: plan.amount ?? 0,\n currency: plan.currency ?? \"\",\n interval: plan.interval ?? \"\",\n planCode: plan.plan_code ?? \"\",\n paystackId,\n metadata: stringifyPaystackMetadata((plan as { metadata?: unknown }).metadata),\n updatedAt: new Date(),\n };\n\n await store.upsertPlanByPaystackId(paystackId, {\n ...planData,\n createdAt: new Date(),\n });\n }\n\n return { status: \"success\", count: plansData.length };\n } catch (error: unknown) {\n ctx.context.logger.error(\"Failed to sync plans\", error);\n const errorMessage = error instanceof Error ? error.message : \"Failed to sync plans\";\n throw new APIError(\"BAD_REQUEST\", {\n message: errorMessage,\n });\n }\n}\n\nexport async function chargeSubscriptionRenewal(\n ctx: GenericEndpointContext,\n options: AnyPaystackOptions,\n input: ChargeRecurringSubscriptionInput,\n): Promise<ChargeRecurringSubscriptionResult> {\n const { subscriptionId, amount: bodyAmount } = input;\n const store = createBillingStore(ctx);\n const subscription = await store.findSubscriptionById(subscriptionId);\n\n if (subscription === undefined || subscription === null) {\n throw new APIError(\"NOT_FOUND\", { message: \"Subscription not found\" });\n }\n\n if (\n subscription.paystackAuthorizationCode === undefined ||\n subscription.paystackAuthorizationCode === null ||\n subscription.paystackAuthorizationCode === \"\"\n ) {\n throw new APIError(\"BAD_REQUEST\", {\n message: \"No authorization code found for this subscription\",\n });\n }\n\n const plans = await getPlans(options.subscription);\n const plan = plans.find(\n (candidate) => candidate.name.toLowerCase() === subscription.plan.toLowerCase(),\n );\n\n if (plan === undefined || plan === null) {\n throw new APIError(\"NOT_FOUND\", { message: \"Plan not found\" });\n }\n\n const amount = bodyAmount ?? plan.amount;\n if (amount === undefined || amount === null) {\n throw new APIError(\"BAD_REQUEST\", { message: \"Plan amount is not defined\" });\n }\n\n let email: string | undefined;\n let billingUserId = subscription.userId;\n const referenceId = subscription.referenceId;\n if (referenceId !== undefined && referenceId !== null && referenceId !== \"\") {\n const user = await store.findUser(referenceId);\n if (user !== undefined && user !== null) {\n email = user.email;\n billingUserId = user.id;\n } else if (options.organization?.enabled === true) {\n const ownerMember = await store.findOrganizationOwner(referenceId);\n if (ownerMember !== undefined && ownerMember !== null) {\n const ownerUser = await store.findUser(ownerMember.userId);\n email = ownerUser?.email;\n billingUserId = ownerUser?.id ?? ownerMember.userId;\n }\n }\n }\n\n if (email === undefined || email === null || email === \"\") {\n throw new APIError(\"NOT_FOUND\", { message: \"User email not found\" });\n }\n\n const finalCurrency = plan.currency ?? \"NGN\";\n if (!validateMinAmount(amount, finalCurrency)) {\n throw new APIError(\"BAD_REQUEST\", {\n message: `Amount ${amount} is less than the minimum required for ${finalCurrency}.`,\n status: 400,\n });\n }\n\n const paystack = createPaystackAdapter(options.paystackClient);\n const renewalMetadata = createRenewalMetadata({\n subscriptionId,\n referenceId,\n });\n const serializedRenewalMetadata = stringifyPaystackMetadata(renewalMetadata);\n\n const chargeData = await paystack.chargeAuthorization({\n email,\n amount,\n authorization_code: subscription.paystackAuthorizationCode,\n reference: `rec_${subscription.id}_${Date.now()}`,\n metadata: serializedRenewalMetadata,\n });\n\n const typedChargeData = chargeData as PaystackChargeAuthorizationResponse;\n if (typedChargeData?.status === \"success\" && typedChargeData.reference !== undefined) {\n const now = new Date();\n const nextPeriodEnd = getNextPeriodEnd(now, plan.interval ?? \"monthly\");\n\n await store.createTransaction({\n reference: typedChargeData.reference,\n paystackId:\n typedChargeData.id !== undefined && typedChargeData.id !== null\n ? String(typedChargeData.id)\n : undefined,\n referenceId,\n userId: billingUserId,\n amount: typedChargeData.amount,\n currency: typedChargeData.currency,\n status: \"success\",\n plan: plan.name.toLowerCase(),\n metadata: serializedRenewalMetadata,\n createdAt: now,\n updatedAt: now,\n });\n\n await store.updateSubscription(subscription.id, {\n periodStart: now,\n periodEnd: nextPeriodEnd,\n updatedAt: now,\n paystackTransactionReference: typedChargeData.reference,\n });\n\n return { status: \"success\", data: typedChargeData };\n }\n\n return { status: \"failed\", data: typedChargeData };\n}\n","import {\n defineErrorCodes,\n type AuthContext,\n type BetterAuthPlugin,\n type GenericEndpointContext,\n} from \"better-auth\";\nimport { APIError } from \"better-auth/api\";\nimport { defu } from \"defu\";\n\nimport {\n disablePaystackSubscription,\n enablePaystackSubscription,\n initializeTransaction,\n listSubscriptions,\n listTransactions,\n paystackWebhook,\n verifyTransaction,\n getConfig,\n getSubscriptionManageLink,\n PAYSTACK_ERROR_CODES,\n createSubscription,\n upgradeSubscription,\n cancelSubscription,\n restoreSubscription,\n listProducts,\n listPlans,\n} from \"./routes\";\nimport { getSchema } from \"./schema\";\nimport { checkSeatLimit, checkTeamLimit, getOrganizationEntitlements } from \"./limits\";\nimport { syncSubscriptionSeats } from \"./utils\";\nimport type { PaystackClientLike, PaystackOptions, AnyPaystackOptions, User } from \"./types\";\nimport { createPaystackAdapter } from \"./paystack-sdk\";\nimport { PACKAGE_VERSION } from \"./version\";\nimport { createBillingStoreFromAdapter } from \"./billing-store\";\nimport { resolvePaystackCustomer } from \"./customer\";\n\nexport {\n createCheckoutMetadata,\n createProrationMetadata,\n createRenewalMetadata,\n getMetadataBoolean,\n getMetadataNumber,\n getMetadataString,\n hasPaystackMetadata,\n parsePaystackMetadata,\n stringifyPaystackMetadata,\n} from \"./metadata\";\nexport type { PaystackMetadata } from \"./metadata\";\nexport type { PaystackInitializeResult } from \"./types\";\n\ndeclare module \"better-auth\" {\n interface BetterAuthPluginRegistry<AuthOptions, Options> {\n paystack: {\n creator: typeof paystack;\n };\n }\n}\n\nconst INTERNAL_ERROR_CODES: ReturnType<typeof defineErrorCodes> = defineErrorCodes(\n Object.fromEntries(\n Object.entries(PAYSTACK_ERROR_CODES).map(([key, value]) => [\n key,\n typeof value === \"string\" ? value : (value as { message: string }).message,\n ]),\n ),\n);\n\n/**\n * Must stay a `type` rather than an `interface`.\n *\n * `BetterAuthPlugin[\"endpoints\"]` is `{ [key: string]: Endpoint }`, and only object literal\n * *type aliases* get TypeScript's implicit index signature — interfaces do not. Declaring\n * this as `interface ... extends Record<string, Endpoint>` satisfies that constraint but\n * gives the plugin a real string index signature. Better Auth merges every plugin's\n * endpoints into `auth.api`, so that signature spreads across the whole API surface and,\n * under `noUncheckedIndexedAccess`, makes *every* `auth.api.*` call possibly `undefined`.\n */\n// oxlint-disable-next-line typescript/consistent-type-definitions\ntype PaystackPluginEndpoints = {\n initializeTransaction: ReturnType<typeof initializeTransaction>;\n verifyTransaction: ReturnType<typeof verifyTransaction>;\n listSubscriptions: ReturnType<typeof listSubscriptions>;\n paystackWebhook: ReturnType<typeof paystackWebhook>;\n listTransactions: ReturnType<typeof listTransactions>;\n getConfig: ReturnType<typeof getConfig>;\n disableSubscription: ReturnType<typeof disablePaystackSubscription>;\n enableSubscription: ReturnType<typeof enablePaystackSubscription>;\n getSubscriptionManageLink: ReturnType<typeof getSubscriptionManageLink>;\n subscriptionManageLink: ReturnType<typeof getSubscriptionManageLink>;\n createSubscription: ReturnType<typeof createSubscription>;\n upgradeSubscription: ReturnType<typeof upgradeSubscription>;\n cancelSubscription: ReturnType<typeof cancelSubscription>;\n restoreSubscription: ReturnType<typeof restoreSubscription>;\n listProducts: ReturnType<typeof listProducts>;\n listPlans: ReturnType<typeof listPlans>;\n};\n\ntype PaystackHookHandler = (...args: unknown[]) => unknown;\n\ninterface PaystackPluginInitResult {\n options: {\n databaseHooks: Record<string, unknown> & {\n organization: {\n create: {\n after: PaystackHookHandler;\n };\n };\n };\n };\n}\n\ntype PaystackPluginInit = ((ctx: AuthContext) => PaystackPluginInitResult) &\n NonNullable<BetterAuthPlugin[\"init\"]>;\n\ntype PaystackPluginInstance<O extends AnyPaystackOptions> = Omit<\n BetterAuthPlugin,\n \"id\" | \"version\" | \"endpoints\" | \"schema\" | \"init\" | \"$ERROR_CODES\" | \"options\"\n> & {\n id: \"paystack\";\n version: typeof PACKAGE_VERSION;\n endpoints: PaystackPluginEndpoints;\n schema: ReturnType<typeof getSchema>;\n init: PaystackPluginInit;\n $ERROR_CODES: typeof INTERNAL_ERROR_CODES;\n options: NoInfer<O>;\n};\n\nconst createPaystackPlugin = <\n TPaystackClient extends PaystackClientLike = PaystackClientLike,\n O extends PaystackOptions<TPaystackClient> = PaystackOptions<TPaystackClient>,\n>(\n options: O,\n): PaystackPluginInstance<O> => {\n const routeOptions = {\n ...(options as unknown as AnyPaystackOptions),\n webhook: options.webhook,\n } satisfies AnyPaystackOptions;\n return {\n id: \"paystack\",\n version: PACKAGE_VERSION as typeof PACKAGE_VERSION,\n endpoints: {\n initializeTransaction: initializeTransaction(\n routeOptions,\n \"/paystack/initialize-transaction\",\n ),\n verifyTransaction: verifyTransaction(routeOptions, \"/paystack/verify-transaction\"),\n listSubscriptions: listSubscriptions(routeOptions, \"/paystack/list-subscriptions\"),\n paystackWebhook: paystackWebhook(routeOptions, \"/paystack/webhook\"),\n listTransactions: listTransactions(routeOptions, \"/paystack/list-transactions\"),\n getConfig: getConfig(routeOptions, \"/paystack/config\"),\n disableSubscription: disablePaystackSubscription(\n routeOptions,\n \"/paystack/disable-subscription\",\n ),\n enableSubscription: enablePaystackSubscription(routeOptions, \"/paystack/enable-subscription\"),\n getSubscriptionManageLink: getSubscriptionManageLink(\n routeOptions,\n \"/paystack/subscription-manage-link\",\n ),\n subscriptionManageLink: getSubscriptionManageLink(\n routeOptions,\n \"/paystack/subscription/manage-link\",\n ),\n createSubscription: createSubscription(routeOptions, \"/paystack/create-subscription\"),\n upgradeSubscription: upgradeSubscription(routeOptions, \"/paystack/upgrade-subscription\"),\n cancelSubscription: cancelSubscription(routeOptions, \"/paystack/cancel-subscription\"),\n restoreSubscription: restoreSubscription(routeOptions, \"/paystack/restore-subscription\"),\n listProducts: listProducts(routeOptions, \"/paystack/list-products\"),\n listPlans: listPlans(routeOptions, \"/paystack/list-plans\"),\n },\n schema: getSchema(options),\n init: ((ctx: AuthContext) => {\n const organizationPluginAvailable = ctx.hasPlugin(\"organization\");\n if (options.organization?.enabled === true && !organizationPluginAvailable) {\n ctx.logger.error(\n \"Paystack organization billing is enabled, but the Better Auth organization plugin was not found. Organization billing hooks will be skipped.\",\n );\n }\n\n return {\n options: {\n databaseHooks: {\n user: {\n create: {\n async after(\n user: {\n id: string;\n email?: string | null;\n name?: string | null;\n emailVerified?: boolean;\n paystackCustomerCode?: string | null;\n },\n hookCtx?: GenericEndpointContext | null,\n ) {\n if (\n !hookCtx ||\n options.createCustomerOnSignUp !== true ||\n user.email === null ||\n user.email === undefined ||\n user.email === \"\"\n )\n return;\n\n try {\n const result = await resolvePaystackCustomer({\n adapter: ctx.adapter,\n client: options.paystackClient as PaystackClientLike,\n logger: ctx.logger,\n reference: {\n id: user.id,\n type: \"user\",\n email: user.email,\n name: user.name,\n emailVerified: user.emailVerified,\n paystackCustomerCode: user.paystackCustomerCode,\n },\n });\n const customerCode = result?.customer.customer_code;\n\n if (\n result?.created === true &&\n typeof customerCode === \"string\" &&\n typeof options.onCustomerCreate === \"function\"\n ) {\n await options.onCustomerCreate(\n {\n paystackCustomer: result.customer,\n user: {\n ...(user as User),\n paystackCustomerCode: customerCode,\n },\n },\n hookCtx,\n );\n }\n } catch (error: unknown) {\n ctx.logger.error(\"Failed to create Paystack customer for user\", error);\n }\n },\n },\n update: {\n async after(user: {\n id: string;\n email?: string | null;\n paystackCustomerCode?: string | null;\n }) {\n const persisted = await createBillingStoreFromAdapter(ctx.adapter).findUser(\n user.id,\n );\n const customerCode =\n user.paystackCustomerCode ??\n (persisted as { paystackCustomerCode?: string | null } | null)\n ?.paystackCustomerCode;\n if (\n typeof customerCode !== \"string\" ||\n customerCode === \"\" ||\n typeof user.email !== \"string\" ||\n user.email === \"\"\n )\n return;\n try {\n await createPaystackAdapter(options.paystackClient).updateCustomer(\n customerCode,\n { email: user.email },\n );\n } catch (error: unknown) {\n ctx.logger.error(\"Failed to synchronize Paystack customer email\", error);\n }\n },\n },\n },\n organization:\n options.organization?.enabled === true && organizationPluginAvailable\n ? {\n create: {\n async after(\n org: { id: string; name: string; email?: string | null },\n hookCtx: GenericEndpointContext | null,\n ) {\n try {\n const extraCreateParams =\n typeof options.organization?.getCustomerCreateParams === \"function\"\n ? await (\n options.organization.getCustomerCreateParams as (\n org: Record<string, unknown>,\n hookCtx: GenericEndpointContext,\n ) => Promise<Record<string, unknown>>\n )(org, hookCtx!)\n : {};\n\n let targetEmail = org.email;\n if (targetEmail === undefined || targetEmail === null) {\n const store = createBillingStoreFromAdapter(ctx.adapter);\n const ownerMember = await store.findOrganizationOwner(org.id);\n if (ownerMember !== null && ownerMember !== undefined) {\n const ownerUser = await store.findUser(ownerMember.userId);\n targetEmail = ownerUser?.email;\n }\n }\n\n if (targetEmail === undefined || targetEmail === null) return;\n\n const result = await resolvePaystackCustomer({\n adapter: ctx.adapter,\n client: options.paystackClient as PaystackClientLike,\n logger: ctx.logger,\n reference: {\n id: org.id,\n type: \"organization\",\n email: targetEmail,\n name: org.name,\n paystackCustomerCode: (\n org as { paystackCustomerCode?: string | null }\n ).paystackCustomerCode,\n },\n createParams: defu({}, extraCreateParams),\n });\n const customerCode = result?.customer.customer_code;\n\n if (\n result?.created === true &&\n typeof customerCode === \"string\" &&\n typeof options.organization?.onCustomerCreate === \"function\"\n ) {\n await options.organization.onCustomerCreate(\n {\n paystackCustomer: result.customer,\n organization: {\n ...org,\n paystackCustomerCode: customerCode,\n },\n },\n hookCtx!,\n );\n }\n } catch (error: unknown) {\n ctx.logger.error(\n \"Failed to create Paystack customer for organization\",\n error,\n );\n }\n },\n },\n update: {\n async after(\n org: {\n id: string;\n name?: string | null;\n email?: string | null;\n paystackCustomerCode?: string | null;\n },\n hookCtx?: GenericEndpointContext | null,\n ) {\n const persisted = await createBillingStoreFromAdapter(\n ctx.adapter,\n ).findOrganization(org.id);\n const customerCode =\n org.paystackCustomerCode ?? persisted?.paystackCustomerCode;\n if (typeof customerCode !== \"string\" || customerCode === \"\") return;\n try {\n const configured =\n typeof options.organization?.getCustomerCreateParams === \"function\" &&\n hookCtx\n ? await options.organization.getCustomerCreateParams(\n {\n id: org.id,\n name: org.name ?? persisted?.name ?? \"\",\n email:\n org.email ??\n (persisted as typeof persisted & { email?: string | null })\n ?.email,\n },\n hookCtx,\n )\n : {};\n const configuredEmail =\n typeof configured.email === \"string\" && configured.email !== \"\"\n ? configured.email\n : undefined;\n await createPaystackAdapter(options.paystackClient).updateCustomer(\n customerCode,\n {\n ...(configuredEmail !== undefined ||\n (typeof org.email === \"string\" && org.email !== \"\")\n ? { email: configuredEmail ?? org.email ?? undefined }\n : {}),\n ...(typeof org.name === \"string\" && org.name !== \"\"\n ? { first_name: org.name }\n : {}),\n },\n );\n } catch (error: unknown) {\n ctx.logger.error(\n \"Failed to synchronize Paystack organization customer\",\n error,\n );\n }\n },\n },\n delete: {\n async before(org: { id: string; paystackCustomerCode?: string | null }) {\n const store = createBillingStoreFromAdapter(ctx.adapter);\n const subscriptions = await store.findSubscriptionsByReference(org.id);\n if (\n subscriptions.some(\n (subscription) =>\n subscription.status === \"active\" ||\n subscription.status === \"trialing\",\n )\n ) {\n throw new APIError(\"BAD_REQUEST\", {\n message:\n \"Organization cannot be deleted while it has an active subscription\",\n });\n }\n\n const persisted = await store.findOrganization(org.id);\n const customerCode =\n org.paystackCustomerCode ?? persisted?.paystackCustomerCode;\n if (typeof customerCode !== \"string\" || customerCode === \"\") return;\n try {\n const customer = (await createPaystackAdapter(\n options.paystackClient,\n ).fetchCustomer(customerCode)) as {\n subscriptions?: { status?: string }[];\n };\n if (\n customer.subscriptions?.some(\n (subscription) =>\n subscription.status === \"active\" ||\n subscription.status === \"trialing\",\n ) === true\n ) {\n throw new APIError(\"BAD_REQUEST\", {\n message:\n \"Organization cannot be deleted while it has an active subscription\",\n });\n }\n } catch (error: unknown) {\n if (error instanceof APIError) throw error;\n ctx.logger.error(\n \"Failed to check Paystack subscriptions before organization deletion\",\n error,\n );\n throw new APIError(\"BAD_REQUEST\", {\n message:\n \"Organization deletion could not verify its Paystack subscriptions\",\n });\n }\n },\n },\n }\n : undefined,\n member: organizationPluginAvailable\n ? {\n create: {\n before: async (\n member: { organizationId: string },\n ctx: GenericEndpointContext | null | undefined,\n ) => {\n if (\n options.subscription?.enabled === true &&\n member.organizationId &&\n ctx !== null &&\n ctx !== undefined\n ) {\n await checkSeatLimit(ctx, member.organizationId);\n }\n },\n after: async (\n member: { organizationId: string | undefined },\n ctx: GenericEndpointContext | null | undefined,\n ) => {\n if (\n options.subscription?.enabled === true &&\n typeof member?.organizationId === \"string\" &&\n ctx\n ) {\n await syncSubscriptionSeats(ctx, member.organizationId, routeOptions);\n }\n },\n },\n delete: {\n after: async (\n member: { organizationId: string | undefined },\n ctx: GenericEndpointContext | null | undefined,\n ) => {\n if (\n options.subscription?.enabled === true &&\n typeof member?.organizationId === \"string\" &&\n ctx\n ) {\n await syncSubscriptionSeats(ctx, member.organizationId, routeOptions);\n }\n },\n },\n }\n : undefined,\n invitation: organizationPluginAvailable\n ? {\n create: {\n before: async (\n invitation: { organizationId: string },\n ctx: GenericEndpointContext | null | undefined,\n ) => {\n if (\n options.subscription?.enabled === true &&\n invitation.organizationId &&\n ctx !== null &&\n ctx !== undefined\n ) {\n await checkSeatLimit(ctx, invitation.organizationId);\n }\n },\n after: async (\n invitation: { organizationId: string | undefined },\n ctx: GenericEndpointContext | null | undefined,\n ) => {\n if (\n options.subscription?.enabled === true &&\n typeof invitation?.organizationId === \"string\" &&\n ctx\n ) {\n await syncSubscriptionSeats(ctx, invitation.organizationId, routeOptions);\n }\n },\n },\n delete: {\n after: async (\n invitation: { organizationId: string | undefined },\n ctx: GenericEndpointContext | null | undefined,\n ) => {\n if (\n options.subscription?.enabled === true &&\n typeof invitation?.organizationId === \"string\" &&\n ctx\n ) {\n await syncSubscriptionSeats(ctx, invitation.organizationId, routeOptions);\n }\n },\n },\n }\n : undefined,\n team: organizationPluginAvailable\n ? {\n create: {\n before: async (\n team: { organizationId: string },\n ctx: GenericEndpointContext | null | undefined,\n ) => {\n if (options.subscription?.enabled === true && team.organizationId && ctx) {\n const entitlements = await getOrganizationEntitlements(\n ctx,\n team.organizationId,\n routeOptions,\n );\n const maxTeams = entitlements.limits.teams;\n if (typeof maxTeams === \"number\") {\n await checkTeamLimit(ctx, team.organizationId, maxTeams);\n }\n }\n },\n },\n }\n : undefined,\n },\n },\n };\n }) as PaystackPluginInit,\n $ERROR_CODES: INTERNAL_ERROR_CODES,\n options: options,\n } satisfies BetterAuthPlugin;\n};\n\nexport const paystack: typeof createPaystackPlugin = createPaystackPlugin;\n\nexport type PaystackPlugin<\n TPaystackClient extends PaystackClientLike = PaystackClientLike,\n O extends PaystackOptions<TPaystackClient> = PaystackOptions<TPaystackClient>,\n> = ReturnType<typeof paystack<TPaystackClient, O>>;\n\nexport { chargeSubscriptionRenewal, syncPaystackPlans, syncPaystackProducts } from \"./operations\";\nexport { getOrganizationEntitlements } from \"./limits\";\nexport { reconcilePaystackTransaction } from \"./reconciliation\";\nexport type {\n PaystackReconciliationError,\n PaystackReconciliationSource,\n PaystackReconciliationSummary,\n ReconcilePaystackTransactionFailure,\n ReconcilePaystackTransactionInput,\n ReconcilePaystackTransactionResult,\n ReconcilePaystackTransactionSuccess,\n} from \"./reconciliation\";\nexport type {\n Subscription,\n SubscriptionOptions,\n PaystackPlan,\n PaystackOptions,\n PaystackProduct,\n PaystackTransactionResponse,\n PaystackClientLike,\n ChargeRecurringSubscriptionResult,\n PaystackSyncResult,\n} from \"./types\";\n"],"mappings":"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"}