@alexasomba/better-auth-paystack 1.2.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/paystack-sdk.ts","../src/utils.ts","../src/middleware.ts","../src/limits.ts","../src/routes.ts","../src/schema.ts","../src/index.ts"],"sourcesContent":["import type {\n\tPaystackClientLike,\n\tPaystackCustomerCreateInput,\n\tPaystackCustomerUpdateInput,\n\tPaystackNodeClient,\n\tPaystackOpenApiFetchResponse,\n\tPaystackSubscriptionFetchInit,\n\tPaystackSubscriptionCreateInput,\n\tPaystackSubscriptionToggleInput,\n\tPaystackTransactionInitializeInput,\n\tPaystackTransactionChargeAuthorizationInput,\n} from \"./types\";\n\nfunction isOpenApiFetchResponse(\n\tvalue: unknown,\n): value is PaystackOpenApiFetchResponse {\n\treturn (\n\t\tvalue !== null &&\n\t\tvalue !== undefined &&\n\t\ttypeof value === \"object\" &&\n\t\t(\"data\" in value || \"error\" in value || \"response\" in value)\n\t);\n}\n\nexport function unwrapSdkResult<T = unknown>(result: unknown): T {\n\tif (isOpenApiFetchResponse(result)) {\n\t\tif (result.error !== undefined && result.error !== null) {\n\t\t\tthrow new Error(typeof result.error === \"string\" ? result.error : JSON.stringify(result.error));\n\t\t}\n\t\treturn (result.data as T) ?? (result as T);\n\t}\n\tif (result !== null && result !== undefined && typeof result === \"object\" && \"data\" in result) {\n\t\tconst data = (result as { data: unknown }).data;\n\t\t// If data is also an object with a data property, unwrap it (legacy SDK style)\n\t\tif (data !== null && typeof data === \"object\" && \"data\" in data) {\n\t\t\treturn (data as { data: T }).data;\n\t\t}\n\t\treturn data as T;\n\t}\n\treturn result as T;\n}\n\n\n\n\n\ntype TransactionInitializeBody = Parameters<PaystackNodeClient[\"transaction_initialize\"]>[0] extends {\n\tbody?: infer B;\n}\n\t? B\n\t: never;\n\nexport function getPaystackOps(\n\tpaystackClient: PaystackClientLike,\n) {\n\treturn {\n\t\tcustomerCreate: (params: PaystackCustomerCreateInput) => {\n\t\t\tif (paystackClient?.customer_create !== undefined) {\n\t\t\t\treturn paystackClient.customer_create({ body: params as unknown as NonNullable<Parameters<PaystackNodeClient[\"customer_create\"]>[0]>[\"body\"] });\n\t\t\t}\n\t\t\treturn paystackClient?.customer?.create?.(params);\n\t\t},\n\t\tcustomerUpdate: (code: string, params: PaystackCustomerUpdateInput) => {\n\t\t\tif (paystackClient?.customer_update !== undefined) {\n\t\t\t\treturn paystackClient.customer_update({\n\t\t\t\t\tparams: { path: { code } },\n\t\t\t\t\tbody: params as unknown as NonNullable<Parameters<PaystackNodeClient[\"customer_update\"]>[0]>[\"body\"],\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn paystackClient?.customer?.update?.(code, params);\n\t\t},\n\t\ttransactionInitialize: (body: PaystackTransactionInitializeInput) => {\n\t\t\tif (paystackClient?.transaction_initialize !== undefined) {\n\t\t\t\treturn paystackClient.transaction_initialize({\n\t\t\t\t\tbody: body as TransactionInitializeBody,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn paystackClient?.transaction?.initialize?.(body);\n\t\t},\n\t\ttransactionVerify: (reference: string) => {\n\t\t\tif (paystackClient?.transaction_verify !== undefined) {\n\t\t\t\treturn paystackClient.transaction_verify({\n\t\t\t\t\tparams: { path: { reference } },\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn paystackClient?.transaction?.verify?.(reference);\n\t\t},\n\t\tsubscriptionCreate: (body: PaystackSubscriptionCreateInput) => {\n\t\t\tif (paystackClient?.subscription_create !== undefined) {\n\t\t\t\treturn paystackClient.subscription_create({ body });\n\t\t\t}\n\t\t\treturn paystackClient?.subscription?.create?.(body);\n\t\t},\n\t\tsubscriptionDisable: (body: PaystackSubscriptionToggleInput) => {\n\t\t\tif (paystackClient?.subscription_disable !== undefined) {\n\t\t\t\treturn paystackClient.subscription_disable({ body });\n\t\t\t}\n\t\t\treturn paystackClient?.subscription?.disable?.(body);\n\t\t},\n\t\tsubscriptionEnable: (body: PaystackSubscriptionToggleInput) => {\n\t\t\tif (paystackClient?.subscription_enable !== undefined) {\n\t\t\t\treturn paystackClient.subscription_enable({ body });\n\t\t\t}\n\t\t\treturn paystackClient?.subscription?.enable?.(body);\n\t\t},\n\t\tsubscriptionFetch: async (idOrCode: string) => {\n\t\t\tif (paystackClient?.subscription_fetch !== undefined) {\n\t\t\t\ttry {\n\t\t\t\t\treturn await paystackClient.subscription_fetch({\n\t\t\t\t\t\tparams: { path: { code: idOrCode } },\n\t\t\t\t\t});\n\t\t\t\t} catch {\n\t\t\t\t\tconst compatFetch = paystackClient.subscription_fetch as unknown as (\n\t\t\t\t\t\tinit: PaystackSubscriptionFetchInit,\n\t\t\t\t\t) => Promise<unknown>;\n\t\t\t\t\treturn compatFetch({\n\t\t\t\t\t\tparams: { path: { id_or_code: idOrCode } },\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn paystackClient?.subscription?.fetch?.(idOrCode);\n\t\t},\n\t\tsubscriptionManageLink: (code: string) => {\n\t\t\tif (paystackClient?.subscription_manageLink !== undefined) {\n\t\t\t\treturn paystackClient.subscription_manageLink({\n\t\t\t\t\tparams: { path: { code } },\n\t\t\t\t});\n\t\t\t}\n\t\t\t// Fallback for snake_case if older SDK version or different generator\n\t\t\tif (paystackClient?.subscription_manage_link !== undefined) {\n\t\t\t\treturn paystackClient.subscription_manage_link({\n\t\t\t\t\tparams: { path: { code } },\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn paystackClient?.subscription?.manage?.link?.(code);\n\t\t},\n\t\tsubscriptionManageEmail: (code: string, email: string) => {\n\t\t\tif (paystackClient?.subscription_manageEmail !== undefined) {\n\t\t\t\treturn paystackClient.subscription_manageEmail({\n\t\t\t\t\tparams: { path: { code } },\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn paystackClient?.subscription?.manage?.email?.(code, email);\n\t\t},\n\t\tsubscriptionUpdate: (params: { code: string; plan?: string; authorization?: string; amount?: number }) => {\n\t\t\tif (paystackClient?.subscription_update !== undefined) {\n\t\t\t\treturn (paystackClient.subscription_update as unknown as (args: Record<string, unknown>) => Promise<unknown>)({\n\t\t\t\t\tparams: { path: { code: params.code } },\n\t\t\t\t\tbody: {\n\t\t\t\t\t\tplan: params.plan,\n\t\t\t\t\t\tauthorization: params.authorization,\n\t\t\t\t\t\tamount: params.amount,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\treturn (paystackClient as any)?.subscription?.update?.(params.code, params);\n\t\t},\n\t\ttransactionChargeAuthorization: (body: PaystackTransactionChargeAuthorizationInput) => {\n\t\t\tif (paystackClient?.transaction_chargeAuthorization !== undefined) {\n\t\t\t\treturn paystackClient.transaction_chargeAuthorization({\n\n\t\t\t\t\t// casting to avoid deep type issues with metadata\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t\t\tbody: body as any, // casting to avoid deep type issues with metadata\n\t\t\t\t});\n\t\t\t}\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\treturn paystackClient?.transaction?.chargeAuthorization?.(body as any);\n\t\t},\n\t\tproductList: () => {\n\t\t\tif (paystackClient?.product_list !== undefined) {\n\t\t\t\treturn paystackClient.product_list();\n\t\t\t}\n\t\t\treturn paystackClient?.product?.list?.();\n\t\t},\n\t\tproductFetch: (idOrCode: string) => {\n\t\t\tif (paystackClient?.product_fetch !== undefined) {\n\t\t\t\treturn paystackClient.product_fetch({\n\t\t\t\t\tparams: { path: { id_or_code: idOrCode } },\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn paystackClient?.product?.fetch?.(idOrCode);\n\t\t},\n\t\tproductCreate: (params: Record<string, unknown>) => {\n\t\t\tif (paystackClient?.product_create !== undefined) {\n\t\t\t\treturn paystackClient.product_create({ body: params });\n\t\t\t}\n\t\t\treturn paystackClient?.product?.create?.(params);\n\t\t},\n\t\tproductUpdate: (idOrCode: string, params: Record<string, unknown>) => {\n\t\t\tif (paystackClient?.product_update !== undefined) {\n\t\t\t\treturn paystackClient.product_update({\n\t\t\t\t\tparams: { path: { id_or_code: idOrCode } },\n\t\t\t\t\tbody: params,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn paystackClient?.product?.update?.(idOrCode, params);\n\t\t},\n\t\tproductDelete: (idOrCode: string) => {\n\t\t\tif (paystackClient?.product_delete !== undefined) {\n\t\t\t\treturn paystackClient.product_delete({\n\t\t\t\t\tparams: { path: { id_or_code: idOrCode } },\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn paystackClient?.product?.delete?.(idOrCode);\n\t\t},\n\t\tplanList: () => {\n\t\t\tif (paystackClient?.plan_list !== undefined) {\n\t\t\t\treturn paystackClient.plan_list();\n\t\t\t}\n\t\t\treturn paystackClient?.plan?.list?.();\n\t\t},\n\t};\n}\n","import type { GenericEndpointContext } from \"better-auth\";\n\nimport type { AnyPaystackOptions, PaystackClientLike, PaystackProduct, Subscription, PaystackProductResponse } from \"./types\";\nimport { getPaystackOps, unwrapSdkResult } from \"./paystack-sdk\";\n\nexport async function getPlans(subscriptionOptions: AnyPaystackOptions[\"subscription\"]) {\n\tif (subscriptionOptions?.enabled === true) {\n\t\treturn typeof subscriptionOptions.plans === \"function\"\n\t\t\t? subscriptionOptions.plans()\n\t\t\t: subscriptionOptions.plans;\n\t}\n\tthrow new Error(\"Subscriptions are not enabled in the Paystack options.\");\n}\n\nexport const getPlan = async (options: AnyPaystackOptions, planId: string) => {\n\tif (options.subscription?.enabled === true) {\n\t\tconst plans = await getPlans(options.subscription);\n\t\treturn plans.find((plan) => plan.name === planId) ?? null;\n\t}\n\treturn null;\n};\n\nexport async function getPlanByName(options: AnyPaystackOptions, name: string) {\n\tif (options.subscription?.enabled === true) {\n\t\tconst plans = await getPlans(options.subscription);\n\t\treturn plans.find(\n\t\t\t(plan) => plan.name.toLowerCase() === name.toLowerCase(),\n\t\t) ?? null;\n\t}\n\treturn null;\n}\n\nexport async function getPlanByPriceId(options: AnyPaystackOptions, priceId: string) {\n\tif (options.subscription?.enabled === true) {\n\t\tconst plans = await getPlans(options.subscription);\n\t\treturn plans.find((plan) => plan.name === priceId) ?? null;\n\t}\n\treturn null;\n}\n\n\nexport async function getProducts(productOptions: AnyPaystackOptions[\"products\"]) {\n\tif (productOptions?.products) {\n\t\treturn typeof productOptions.products === \"function\"\n\t\t\t? await productOptions.products()\n\t\t\t: productOptions.products;\n\t}\n\treturn [];\n}\n\nexport async function getProductByName(options: AnyPaystackOptions, name: string) {\n\treturn await getProducts(options.products).then((products) =>\n\t\tproducts?.find((product) => product.name.toLowerCase() === name.toLowerCase()) ?? null,\n\t);\n}\n\nexport function getNextPeriodEnd(startDate: Date, interval: string): Date {\n\tconst date = new Date(startDate);\n\tswitch (interval) {\n\tcase \"daily\":\n\t\tdate.setDate(date.getDate() + 1);\n\t\tbreak;\n\tcase \"weekly\":\n\t\tdate.setDate(date.getDate() + 7);\n\t\tbreak;\n\tcase \"monthly\":\n\t\tdate.setMonth(date.getMonth() + 1);\n\t\tbreak;\n\tcase \"quarterly\":\n\t\tdate.setMonth(date.getMonth() + 3);\n\t\tbreak;\n\tcase \"biannually\":\n\t\tdate.setMonth(date.getMonth() + 6);\n\t\tbreak;\n\tcase \"annually\":\n\t\tdate.setFullYear(date.getFullYear() + 1);\n\t\tbreak;\n\tdefault:\n\t\t// Default to monthly if unknown\n\t\tdate.setMonth(date.getMonth() + 1);\n\t}\n\treturn 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\tconst minAmounts: Record<string, number> = {\n\t\tNGN: 5000, // 50.00\n\t\tGHS: 10, // 0.10\n\t\tZAR: 100, // 1.00\n\t\tKES: 300, // 3.00\n\t\tUSD: 200, // 2.00\n\t\tXOF: 100, // 1.00\n\t};\n\tconst min = minAmounts[currency.toUpperCase()];\n\treturn min !== undefined ? amount >= min : true;\n}\n\nexport async function syncProductQuantityFromPaystack(\n\tctx: GenericEndpointContext,\n\tproductName: string,\n\tpaystackClient: PaystackClientLike,\n): Promise<void> {\n\t// Find the local product record (by name or slug)\n\tlet localProduct = await ctx.context.adapter.findOne<PaystackProduct>({\n\t\tmodel: \"paystackProduct\",\n\t\twhere: [{ field: \"name\", value: productName }],\n\t});\n\n\tlocalProduct ??= await ctx.context.adapter.findOne<PaystackProduct>({\n\t\tmodel: \"paystackProduct\",\n\t\twhere: [{ field: \"slug\", value: productName.toLowerCase().replace(/\\s+/g, \"-\") }],\n\t});\n\n\tif (localProduct?.paystackId === undefined || localProduct.paystackId === null || localProduct.paystackId === \"\") {\n\t\t// No local record with a Paystack ID — fall back to local decrement\n\t\tif (localProduct !== null && localProduct.unlimited !== true && typeof localProduct.quantity === \"number\" && localProduct.quantity > 0) {\n\t\t\tawait ctx.context.adapter.update({\n\t\t\t\tmodel: \"paystackProduct\",\n\t\t\t\tupdate: { quantity: localProduct.quantity - 1, updatedAt: new Date() },\n\t\t\t\twhere: [{ field: \"id\", value: localProduct.id }],\n\t\t\t});\n\t\t}\n\t\treturn;\n\t}\n\n\t// Fetch the latest quantity from Paystack\n\ttry {\n\t\tconst ops = getPaystackOps(paystackClient);\n\t\tconst raw = await ops.productFetch(localProduct.paystackId);\n\t\tconst sdkRes = unwrapSdkResult<PaystackProductResponse>(raw);\n\t\tconst remoteQuantity = sdkRes?.quantity;\n\n\t\tif (remoteQuantity !== undefined) {\n\t\t\tawait ctx.context.adapter.update({\n\t\t\t\tmodel: \"paystackProduct\",\n\t\t\t\tupdate: { quantity: remoteQuantity, updatedAt: new Date() },\n\t\t\t\twhere: [{ field: \"id\", value: localProduct.id }],\n\t\t\t});\n\t\t}\n\t} catch {\n\t\t// If API call fails, fall back to local decrement\n\t\tif (localProduct !== null && localProduct.unlimited !== true && typeof localProduct.quantity === \"number\" && localProduct.quantity > 0) {\n\t\t\tawait ctx.context.adapter.update({\n\t\t\t\tmodel: \"paystackProduct\",\n\t\t\t\tupdate: { quantity: localProduct.quantity - 1, updatedAt: new Date() },\n\t\t\t\twhere: [{ field: \"id\", value: localProduct.id }],\n\t\t\t});\n\t\t}\n\t}\n}\n\nexport async function decrementProductQuantity(ctx: GenericEndpointContext, productName: string) {\n\tlet product = await ctx.context.adapter.findOne<PaystackProduct>({\n\t\tmodel: \"paystackProduct\",\n\t\twhere: [{ field: \"name\", value: productName }],\n\t});\n\n\tproduct ??= await ctx.context.adapter.findOne<PaystackProduct>({\n\t\tmodel: \"paystackProduct\",\n\t\twhere: [{ field: \"slug\", value: productName.toLowerCase().replace(/\\s+/g, \"-\") }],\n\t});\n\n\tif (product) {\n\t\tif (product.unlimited !== true && typeof product.quantity === \"number\" && product.quantity > 0) {\n\t\t\tawait ctx.context.adapter.update({\n\t\t\t\tmodel: \"paystackProduct\",\n\t\t\t\tupdate: {\n\t\t\t\t\tquantity: product.quantity - 1,\n\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t},\n\t\t\t\twhere: [{ field: \"id\", value: product.id }],\n\t\t\t});\n\t\t}\n\t}\n}\n\nexport async function syncSubscriptionSeats(\n\tctx: GenericEndpointContext,\n\torganizationId: string,\n\toptions: AnyPaystackOptions,\n): Promise<void> {\n\tif (options.subscription?.enabled !== true) return;\n\n\tconst adapter = ctx.context.adapter;\n\tconst subscription = await adapter.findOne<Subscription>({\n\t\tmodel: \"subscription\",\n\t\twhere: [{ field: \"referenceId\", value: organizationId }],\n\t});\n\n\tif (subscription?.paystackSubscriptionCode === undefined || subscription.paystackSubscriptionCode === null || subscription.paystackSubscriptionCode === \"\") return;\n\tconst plan = await getPlanByName(options, subscription.plan);\n\tif (plan === null) return;\n\tif (plan.seatAmount === undefined && plan.seatPlanCode === undefined) return;\n\n\tconst members = await (adapter).findMany({\n\t\tmodel: \"member\",\n\t\twhere: [{ field: \"organizationId\", value: organizationId }],\n\t});\n\n\tconst quantity = members.length;\n\tlet totalAmount = plan.amount ?? 0;\n\n\tif (plan.seatAmount !== undefined && plan.seatAmount !== null && typeof plan.seatAmount === \"number\") {\n\t\ttotalAmount += (quantity * plan.seatAmount);\n\t}\n\n\tconst ops = getPaystackOps(options.paystackClient);\n\ttry {\n\t\t// Paystack subscription update doesn't natively support quantity in the same way as Stripe\n\t\t// but we can update the amount or the plan.\n\t\tawait ops.subscriptionUpdate({\n\t\t\tcode: subscription.paystackSubscriptionCode,\n\t\t\tamount: totalAmount,\n\t\t});\n\n\t\t// Update local DB to reflect current seat count\n\t\tawait (adapter).update({\n\t\t\tmodel: \"subscription\",\n\t\t\twhere: [{ field: \"id\", value: subscription.id }],\n\t\t\tupdate: {\n\t\t\t\tseats: quantity,\n\t\t\t\tupdatedAt: new Date(),\n\t\t\t},\n\t\t});\n\t} catch (e: unknown) {\n\t\tconst log = ctx.context.logger;\n\t\tif (log !== undefined && log !== null) {\n\t\t\tlog.error(\"Failed to sync subscription seats with Paystack\", e);\n\t\t}\n\t}\n}\n","import { createAuthMiddleware } from \"@better-auth/core/api\";\nimport { logger } from \"better-auth\";\nimport { APIError } from \"better-auth/api\";\n\nimport type { PaystackClientLike, PaystackOptions, Session, User } from \"./types\";\n\nexport const referenceMiddleware = (\n\toptions: PaystackOptions<PaystackClientLike>,\n\taction:\n | \"initialize-transaction\"\n | \"verify-transaction\"\n | \"list-subscriptions\"\n | \"list-transactions\"\n | \"disable-subscription\"\n | \"enable-subscription\"\n | \"get-subscription-manage-link\",\n) =>\n\tcreateAuthMiddleware(async (ctx) => {\n\t\tconst session = ctx.context.session as {\n\t\t\tuser: User;\n\t\t\tsession: Session;\n\t\t} | null;\n\n\t\tif (session === null || session === undefined) {\n\t\t\tthrow new APIError(\"UNAUTHORIZED\");\n\t\t}\n\t\tconst body = (ctx.body ?? {}) as Record<string, unknown>;\n\t\tconst query = (ctx.query ?? {}) as Record<string, unknown>;\n\t\tconst referenceId =\n (body.referenceId as string | undefined) ?? (query.referenceId as string | undefined) ?? session.user.id;\n \n\t\tconst subscriptionOptions = options.subscription;\n\n\n\n\t\tif (referenceId === session.user.id) {\n\t\t\treturn {\n\t\t\t\treferenceId,\n\t\t\t};\n\t\t}\n\n\n \n\t\t// 1. Try custom authorization first if provided\n\t\tif (subscriptionOptions?.enabled === true && 'authorizeReference' in subscriptionOptions && subscriptionOptions.authorizeReference) {\n\t\t\tconst authorized = await subscriptionOptions.authorizeReference(\n\t\t\t\t{\n\t\t\t\t\tuser: session.user,\n\t\t\t\t\tsession: session.session,\n\t\t\t\t\treferenceId,\n\t\t\t\t\taction,\n\t\t\t\t},\n\t\t\t\tctx,\n\t\t\t);\n\t\t\tif (authorized === true) {\n\t\t\t\treturn {\n\t\t\t\t\treferenceId,\n\t\t\t\t};\n\t\t\t}\n\t\t\t// If explicit authorizeReference returns false, do we fail immediately?\n\t\t\t// Usually yes, but maybe we fallback to org check?\n\t\t\t// Let's assume authorizeReference overrides everything.\n\t\t\tthrow new APIError(\"UNAUTHORIZED\");\n\t\t}\n\n\t\t// 2. Fallback: Organization Check\n\t\tif (options.organization?.enabled === true) {\n\t\t\t// Check if referenceId indicates an organization the user is a member of\n\t\t\tconst member = await ctx.context.adapter.findOne({\n\t\t\t\tmodel: \"member\",\n\t\t\t\twhere: [\n\t\t\t\t\t{ field: \"userId\", value: session.user.id },\n\t\t\t\t\t{ field: \"organizationId\", value: referenceId }\n\t\t\t\t]\n\t\t\t});\n \n\t\t\tif (member !== null && member !== undefined) {\n\t\t\t\tlogger.debug(\"DEBUG MIDDLEWARE MEMBER FOUND:\", member);\n\t\t\t\t// User is a member of the organization.\n\t\t\t\t// We could check roles here, but for now allow any member.\n\t\t\t\treturn {\n\t\t\t\t\treferenceId,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tlogger.error(\n\t\t\t`Passing referenceId into a subscription action isn't allowed if subscription.authorizeReference isn't defined in your paystack plugin config and matches no organization membership.`,\n\t\t);\n\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\tmessage:\n \"Passing referenceId isn't allowed without subscription.authorizeReference or valid organization membership.\",\n\t\t});\n\t});\n","import type { GenericEndpointContext } from \"better-auth\";\nimport { APIError } from \"better-auth/api\";\n\nimport type { Subscription } from \"./types\";\n\nexport const getOrganizationSubscription = async (\n\tctx: GenericEndpointContext,\n\torganizationId: string\n): Promise<Subscription | null> => {\n\tconst subscription = await ctx.context.adapter.findOne<Subscription>({\n\t\tmodel: \"subscription\",\n\t\twhere: [{ field: \"referenceId\", value: organizationId }],\n\t});\n\treturn subscription;\n};\n\nexport const checkSeatLimit = async (\n\tctx: GenericEndpointContext,\n\torganizationId: string,\n\tseatsToAdd = 1\n) => {\n\tconst subscription = await getOrganizationSubscription(ctx, organizationId);\n \n\tif (subscription?.seats === undefined || subscription.seats === null) {\n\t\treturn true; // No explicit seat limit found\n\t}\n\n\tconst members = await ctx.context.adapter.findMany({\n\t\tmodel: \"member\",\n\t\twhere: [{ field: \"organizationId\", value: organizationId }],\n\t});\n\n\tif (members.length + seatsToAdd > subscription.seats) {\n\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\tmessage: `Organization member limit reached. Used: ${members.length}, Max: ${subscription.seats}`\n\t\t});\n\t}\n\n\treturn true;\n};\n\nexport const checkTeamLimit = async (\n\tctx: GenericEndpointContext,\n\torganizationId: string,\n\tmaxTeams: number\n) => {\n\tconst teams = await ctx.context.adapter.findMany({\n\t\tmodel: \"team\",\n\t\twhere: [{ field: \"organizationId\", value: organizationId }],\n\t});\n\n\tif (teams.length >= maxTeams) {\n\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\tmessage: `Organization team limit reached. Max teams: ${maxTeams}`\n\t\t});\n\t}\n\n\treturn true;\n};\n","import { createAuthEndpoint } from \"@better-auth/core/api\";\nimport { defineErrorCodes } from \"@better-auth/core/utils/error-codes\";\nimport { HIDE_METADATA } from \"better-auth\";\nimport {\n\tAPIError,\n\tgetSessionFromCtx,\n\toriginCheck,\n\tsessionMiddleware,\n} from \"better-auth/api\";\nimport * as z from \"zod/v4\";\nimport type { GenericEndpointContext } from \"better-auth\";\n\nimport type {\n\tInputPaystackProduct,\n\tPaystackTransaction,\n\tAnyPaystackOptions,\n\tPaystackProduct,\n\tSubscription,\n\tPaystackWebhookPayload,\n\tPaystackPlan,\n\tPaystackSubscriptionResponse,\n\tPaystackTransactionResponse,\n\tPaystackCurrency,\n\tUser,\n\tMember,\n} from \"./types\";\nimport {\n\tsyncProductQuantityFromPaystack,\n\tgetPlanByName,\n\tgetPlans,\n\tgetProductByName,\n\tgetProducts,\n\tvalidateMinAmount,\n\tgetNextPeriodEnd,\n} from \"./utils\";\nimport { referenceMiddleware } from \"./middleware\";\nimport { getPaystackOps, unwrapSdkResult } from \"./paystack-sdk\";\nimport { getOrganizationSubscription } from \"./limits\";\n\nconst PAYSTACK_ERROR_CODES = defineErrorCodes({\n\tSUBSCRIPTION_NOT_FOUND: \"Subscription not found\",\n\tSUBSCRIPTION_PLAN_NOT_FOUND: \"Subscription plan not found\",\n\tUNABLE_TO_CREATE_CUSTOMER: \"Unable to create customer\",\n\tFAILED_TO_INITIALIZE_TRANSACTION: \"Failed to initialize transaction\",\n\tFAILED_TO_VERIFY_TRANSACTION: \"Failed to verify transaction\",\n\tFAILED_TO_DISABLE_SUBSCRIPTION: \"Failed to disable subscription\",\n\tFAILED_TO_ENABLE_SUBSCRIPTION: \"Failed to enable subscription\",\n\tEMAIL_VERIFICATION_REQUIRED:\n\t\t\"Email verification is required before you can subscribe to a plan\",\n});\n\nasync function hmacSha512Hex(secret: string, message: string): Promise<string> {\n\tconst encoder = new TextEncoder();\n\tconst keyData = encoder.encode(secret);\n\tconst msgData = encoder.encode(message);\n\n\tconst crypto = globalThis.crypto;\n\tif (crypto !== undefined && crypto !== null && \"subtle\" in crypto) {\n\t\tconst subtle = crypto.subtle;\n\t\tconst key = await subtle.importKey(\n\t\t\t\"raw\",\n\t\t\tkeyData,\n\t\t\t{ name: \"HMAC\", hash: \"SHA-512\" },\n\t\t\tfalse,\n\t\t\t[\"sign\"],\n\t\t);\n\t\tconst signature = await subtle.sign(\"HMAC\", key, msgData);\n\t\treturn Array.from(new Uint8Array(signature))\n\t\t\t.map((b) => b.toString(16).padStart(2, \"0\"))\n\t\t\t.join(\"\");\n\t}\n\n\tconst { createHmac } = await import(\"node:crypto\");\n\treturn createHmac(\"sha512\", secret).update(message).digest(\"hex\");\n}\n\nexport const paystackWebhook = (options: AnyPaystackOptions) => {\n\treturn createAuthEndpoint(\n\t\t\"/paystack/webhook\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"handlePaystackWebhook\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tcloneRequest: true,\n\t\t\tdisableBody: true,\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst request = (ctx as unknown as { requestClone?: Request }).requestClone ?? (ctx as { request: Request }).request;\n\t\t\tif (request === undefined || request === null) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"Request object is missing from context\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst payload = await request.text();\n\t\t\tconst headers = (ctx as GenericEndpointContext & { headers?: Headers }).headers ?? (ctx.request as unknown as { headers: Headers })?.headers;\n\t\t\tconst signature = headers?.get(\"x-paystack-signature\") as\n\t\t\t\t| string\n\t\t\t\t| null\n\t\t\t\t| undefined;\n\n\t\t\tif (signature === undefined || signature === null || signature === \"\") {\n\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\tmessage: \"Missing x-paystack-signature header\",\n\t\t\t\t\tstatus: 401,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst expected = await hmacSha512Hex(options.paystackWebhookSecret, payload);\n\t\t\tif (expected !== signature) {\n\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\tmessage: \"Invalid Paystack webhook signature\",\n\t\t\t\t\tstatus: 401,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst event = JSON.parse(payload) as PaystackWebhookPayload;\n\t\t\tconst eventName = event.event;\n\t\t\tconst data = event.data;\n\n\t\t\t// Core Transaction Status Sync (Applies to both one-time and recurring)\n\t\t\tif (eventName === \"charge.success\") {\n\t\t\t\tconst reference = (data as Record<string, unknown> | undefined)?.reference as string | undefined;\n\t\t\t\tconst paystackId = (data as Record<string, unknown> | undefined)?.id !== undefined && (data as Record<string, unknown> | undefined)?.id !== null ? String((data).id) : undefined;\n\t\t\t\tif (reference !== undefined && reference !== null && reference !== \"\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\t\tmodel: \"paystackTransaction\",\n\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\t\t\t\tpaystackId,\n\t\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\twhere: [{ field: \"reference\", value: reference }],\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t// Transaction record might not exist yet (e.g. webhook arrives before local record)\n\t\t\t\t\t\tctx.context.logger.warn(\"Failed to update transaction status for charge.success\", e);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Sync product quantity from Paystack after successful charge\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst transaction = await ctx.context.adapter.findOne<PaystackTransaction>({\n\t\t\t\t\t\t\tmodel: \"paystackTransaction\",\n\t\t\t\t\t\t\twhere: [{ field: \"reference\", value: reference }],\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (transaction?.product !== undefined && transaction.product !== null && transaction.product !== \"\") {\n\t\t\t\t\t\t\tawait syncProductQuantityFromPaystack(ctx, transaction.product, options.paystackClient);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tctx.context.logger.warn(\"Failed to sync product quantity\", e);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (eventName === \"charge.failure\") {\n\t\t\t\tconst reference = (data as Record<string, unknown> | undefined)?.reference as string | undefined;\n\t\t\t\tif (reference !== undefined && reference !== null && reference !== \"\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\t\tmodel: \"paystackTransaction\",\n\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\tstatus: \"failed\",\n\t\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\twhere: [{ field: \"reference\", value: reference }],\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tctx.context.logger.warn(\"Failed to update transaction status for charge.failure\", e);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Best-effort local state sync for subscription lifecycle.\n\t\t\tif (options.subscription?.enabled === true) {\n\t\t\t\ttry {\n\n\t\t\t\t\tif (eventName === \"subscription.create\") {\n\t\t\t\t\t\tconst payloadData = data as PaystackSubscriptionResponse | undefined;\n\t\t\t\t\t\tconst subscriptionCode =\n\t\t\t\t\t\t\tpayloadData?.subscription_code ??\n\t\t\t\t\t\t\t(payloadData as { subscription?: { subscription_code?: string } } | undefined)?.subscription?.subscription_code ??\n\t\t\t\t\t\t\t(payloadData as { code?: string } | undefined)?.code;\n\t\t\t\t\t\tconst customerCode =\n\t\t\t\t\t\t\tpayloadData?.customer?.customer_code ??\n\t\t\t\t\t\t\t(payloadData as { customer_code?: string } | undefined)?.customer_code ??\n\t\t\t\t\t\t\t(payloadData as { customer?: { code?: string } } | undefined)?.customer?.code;\n\t\t\t\t\t\tconst planCode =\n\t\t\t\t\t\t\tpayloadData?.plan?.plan_code ?? (payloadData as { plan_code?: string } | undefined)?.plan_code ?? (payloadData as { plan?: string } | undefined)?.plan;\n\n\t\t\t\t\t\tlet metadata: unknown = payloadData?.metadata;\n\t\t\t\t\t\tif (typeof metadata === \"string\") {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tmetadata = JSON.parse(metadata);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// ignore\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst referenceIdFromMetadata =\n\t\t\t\t\t\t\ttypeof metadata === \"object\" && metadata !== null\n\t\t\t\t\t\t\t\t? ((metadata as Record<string, unknown>).referenceId as string | undefined)\n\t\t\t\t\t\t\t\t: undefined;\n\n\t\t\t\t\t\tlet planNameFromMetadata =\n\t\t\t\t\t\t\ttypeof metadata === \"object\" && metadata !== null\n\t\t\t\t\t\t\t\t? ((metadata as Record<string, unknown>).plan as string | undefined)\n\t\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\t\tif (typeof planNameFromMetadata === \"string\") {\n\t\t\t\t\t\t\tplanNameFromMetadata = planNameFromMetadata.toLowerCase();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst plans = await getPlans(options.subscription);\n\t\t\t\t\t\tconst planFromCode = (planCode !== undefined && planCode !== null && planCode !== \"\")\n\t\t\t\t\t\t\t? plans.find((p) => p.planCode !== undefined && p.planCode !== null && p.planCode === planCode)\n\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\t\tconst planPart = planFromCode?.name ?? planNameFromMetadata;\n\t\t\t\t\t\tconst planName = planPart !== undefined && planPart !== null && planPart !== \"\" ? planPart.toLowerCase() : undefined;\n\n\t\t\t\t\t\tif (subscriptionCode !== undefined && subscriptionCode !== null && subscriptionCode !== \"\") {\n\t\t\t\t\t\t\tconst where: { field: string; value: string | number | boolean | null }[] = [];\n\t\t\t\t\t\t\tif (referenceIdFromMetadata !== undefined && referenceIdFromMetadata !== null && referenceIdFromMetadata !== \"\") {\n\t\t\t\t\t\t\t\twhere.push({ field: \"referenceId\", value: referenceIdFromMetadata });\n\t\t\t\t\t\t\t} else if (customerCode !== undefined && customerCode !== null && customerCode !== \"\") {\n\t\t\t\t\t\t\t\twhere.push({ field: \"paystackCustomerCode\", value: customerCode });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (planName !== undefined && planName !== null && planName !== \"\") {\n\t\t\t\t\t\t\t\twhere.push({ field: \"plan\", value: planName });\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (where.length > 0) {\n\t\t\t\t\t\t\t\tconst matches = await ctx.context.adapter.findMany<Subscription>({\n\t\t\t\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\t\t\t\twhere: where as { field: string; value: string | number | boolean | null }[],\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tconst subscription = matches?.[0];\n\t\t\t\t\t\t\t\tif (subscription !== undefined && subscription !== null) {\n\t\t\t\t\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\t\t\t\tpaystackSubscriptionCode: subscriptionCode,\n\t\t\t\t\t\t\t\t\t\t\tstatus: \"active\",\n\t\t\t\t\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t\t\t\t\t\tperiodEnd: (payloadData?.next_payment_date !== undefined && payloadData.next_payment_date !== null && payloadData.next_payment_date !== \"\") ? new Date(payloadData.next_payment_date) : undefined,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\twhere: [{ field: \"id\", value: subscription.id }],\n\t\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\t\tconst plan = planFromCode ?? (planName !== undefined && planName !== null && planName !== \"\" ? await getPlanByName(options, planName) : undefined);\n\t\t\t\t\t\t\t\t\tif (plan !== undefined && plan !== null) {\n\t\t\t\t\t\t\t\t\t\tawait options.subscription.onSubscriptionComplete?.(\n\t\t\t\t\t\t\t\t\t\t\t{ event, subscription: { ...subscription, paystackSubscriptionCode: subscriptionCode, status: \"active\" }, plan },\n\t\t\t\t\t\t\t\t\t\t\tctx as GenericEndpointContext,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t// Also call onSubscriptionCreated for subscriptions created outside of checkout\n\t\t\t\t\t\t\t\t\t\tawait options.subscription.onSubscriptionCreated?.(\n\t\t\t\t\t\t\t\t\t\t\t{ event, subscription: { ...subscription, paystackSubscriptionCode: subscriptionCode, status: \"active\" }, plan },\n\t\t\t\t\t\t\t\t\t\t\tctx as GenericEndpointContext,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (eventName === \"subscription.disable\" || eventName === \"subscription.not_renew\") {\n\t\t\t\t\t\tconst payloadData = data as PaystackSubscriptionResponse | undefined;\n\t\t\t\t\t\tconst subscriptionCode =\n\t\t\t\t\t\t\tpayloadData?.subscription_code ??\n\t\t\t\t\t\t\t(payloadData as { subscription?: { subscription_code?: string } } | undefined)?.subscription?.subscription_code ??\n\t\t\t\t\t\t\t(payloadData as { code?: string } | undefined)?.code;\n\t\t\t\t\t\tif (subscriptionCode !== undefined && subscriptionCode !== null && subscriptionCode !== \"\") {\n\t\t\t\t\t\t\t// Find the subscription first to get full data for the hook\n\t\t\t\t\t\t\tconst existing = await ctx.context.adapter.findOne<Subscription>({\n\t\t\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\t\t\twhere: [{ field: \"paystackSubscriptionCode\", value: subscriptionCode }],\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tlet newStatus = \"canceled\";\n\t\t\t\t\t\t\tconst nextPaymentDate = (data as { next_payment_date?: string } | undefined)?.next_payment_date;\n\t\t\t\t\t\t\tconst periodEnd = (nextPaymentDate !== undefined && nextPaymentDate !== null && nextPaymentDate !== \"\") ? new Date(nextPaymentDate) : (existing?.periodEnd !== undefined ? new Date(existing.periodEnd) : undefined);\n\n\t\t\t\t\t\t\tif (periodEnd !== undefined && periodEnd > new Date()) {\n\t\t\t\t\t\t\t\tnewStatus = \"active\";\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\t\tstatus: newStatus,\n\t\t\t\t\t\t\t\t\tcancelAtPeriodEnd: true,\n\t\t\t\t\t\t\t\t\t...(periodEnd ? { periodEnd } : {}),\n\t\t\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t\t\t{ field: \"paystackSubscriptionCode\", value: subscriptionCode },\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tif (existing !== undefined && existing !== null) {\n\t\t\t\t\t\t\t\tawait options.subscription.onSubscriptionCancel?.(\n\t\t\t\t\t\t\t\t\t{ event, subscription: { ...existing, status: \"canceled\" } },\n\t\t\t\t\t\t\t\t\tctx as GenericEndpointContext,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Handle plan changes on renewal\n\t\t\t\t\tif (eventName === \"charge.success\" || eventName === \"invoice.update\") {\n\t\t\t\t\t\tconst payloadData = data as PaystackSubscriptionResponse | undefined;\n\t\t\t\t\t\tconst subscriptionCode = (payloadData as Record<string, Record<string, unknown>> | undefined)?.subscription?.subscription_code as string | undefined ?? payloadData?.subscription_code;\n\n\t\t\t\t\t\tif (subscriptionCode !== undefined && subscriptionCode !== null && subscriptionCode !== \"\") {\n\t\t\t\t\t\t\tconst existingSub = await ctx.context.adapter.findOne<Subscription>({\n\t\t\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\t\t\twhere: [{ field: \"paystackSubscriptionCode\", value: subscriptionCode }],\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tif (existingSub?.pendingPlan !== undefined && existingSub.pendingPlan !== null && existingSub.pendingPlan !== \"\") {\n\t\t\t\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\t\t\tplan: existingSub.pendingPlan,\n\t\t\t\t\t\t\t\t\t\tpendingPlan: null,\n\t\t\t\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\twhere: [{ field: \"id\", value: existingSub.id }],\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (_e: unknown) {\n\t\t\t\t\tctx.context.logger.error(\"Failed to sync Paystack webhook event\", _e);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait options.onEvent?.(event);\n\t\t\treturn ctx.json({ received: true });\n\t\t},\n\t);\n};\n\nconst initializeTransactionBodySchema = z.object({\n\tplan: z.string().optional(),\n\tproduct: z.string().optional(),\n\tamount: z.number().int().positive().optional(),\n\tcurrency: z.string().optional(),\n\temail: z.string().optional(),\n\tmetadata: z.record(z.string(), z.unknown()).optional(),\n\treferenceId: z.string().optional(),\n\tcallbackURL: z.string().optional(),\n\tquantity: z.number().int().positive().optional(),\n\tscheduleAtPeriodEnd: z.boolean().optional(),\n\tcancelAtPeriodEnd: z.boolean().optional(),\n\tprorateAndCharge: z.boolean().optional(),\n});\n\nexport const initializeTransaction = <P extends string = \"/paystack/initialize-transaction\">(options: AnyPaystackOptions, path: P = \"/paystack/initialize-transaction\" as P) => {\n\tconst subscriptionOptions = options.subscription;\n\t// However, for one-time payments, we might not strictly need subscription middleware\n\t// checking for existing subs, but let's keep it consistent for now.\n\tconst useMiddlewares = subscriptionOptions?.enabled === true\n\t\t? [sessionMiddleware, originCheck, referenceMiddleware(options, \"initialize-transaction\")]\n\t\t: [sessionMiddleware, originCheck];\n\n\treturn createAuthEndpoint(\n\t\tpath,\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tbody: initializeTransactionBodySchema,\n\t\t\tuse: useMiddlewares,\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst paystack = getPaystackOps(options.paystackClient);\n\t\t\tconst { plan: planName, product: productName, amount: bodyAmount, currency, email, metadata: extraMetadata, callbackURL, quantity, scheduleAtPeriodEnd, cancelAtPeriodEnd, prorateAndCharge } = ctx.body;\n\n\t\t\t// 1. Validate Callback URL validation (same as before)\n\t\t\tif (callbackURL !== undefined && callbackURL !== null && callbackURL !== \"\") {\n\t\t\t\tconst checkTrusted = () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (callbackURL === undefined || callbackURL === null || callbackURL === \"\") return false;\n\t\t\t\t\t\tif ((callbackURL as string).startsWith(\"/\")) return true;\n\t\t\t\t\t\tconst baseUrl =\n\t\t\t\t\t\t\t((ctx.context as Record<string, unknown>)?.baseURL as string | undefined) ??\n\t\t\t\t\t\t\t((ctx.request as unknown as { url?: string })?.url) ??\n\t\t\t\t\t\t\t\"\";\n\t\t\t\t\t\tif (!baseUrl) return false;\n\t\t\t\t\t\tconst baseOrigin = new URL(baseUrl).origin;\n\t\t\t\t\t\treturn new URL(callbackURL).origin === baseOrigin;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tif (checkTrusted() !== true) {\n\t\t\t\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\t\t\t\tmessage: \"callbackURL is not a trusted origin.\",\n\t\t\t\t\t\tstatus: 403,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 2. Get User & Session\n\t\t\tconst session = await getSessionFromCtx(ctx);\n\t\t\tif (!session) throw new APIError(\"UNAUTHORIZED\");\n\t\t\tconst user = session.user;\n\n\t\t\t// 3. Email Verification Check (only if subscription options enforce it)\n\t\t\tif (subscriptionOptions?.enabled === true && subscriptionOptions.requireEmailVerification === true && user.emailVerified !== true) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tcode: \"EMAIL_VERIFICATION_REQUIRED\",\n\t\t\t\t\tmessage: PAYSTACK_ERROR_CODES.EMAIL_VERIFICATION_REQUIRED.message,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// 4. Determine Payment Mode: Subscription (Plan) vs Product vs One-Time (Amount)\n\t\t\tlet plan: PaystackPlan | null | undefined;\n\t\t\tlet product: PaystackProduct | InputPaystackProduct | undefined;\n\n\t\t\tif (planName !== undefined && planName !== null && planName !== \"\") {\n\t\t\t\tif (subscriptionOptions?.enabled !== true) {\n\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", { message: \"Subscriptions are not enabled.\" });\n\t\t\t\t}\n\t\t\t\tplan = await getPlanByName(options, planName) ?? undefined;\n\t\t\t\tif (plan === null || plan === undefined) {\n\t\t\t\t\t// Fallback: Check database for synced plans\n\t\t\t\t\tconst nativePlan = await ctx.context.adapter.findOne<PaystackPlan>({\n\t\t\t\t\t\tmodel: \"paystackPlan\",\n\t\t\t\t\t\twhere: [{ field: \"name\", value: planName }],\n\t\t\t\t\t});\n\t\t\t\t\tif (nativePlan !== undefined && nativePlan !== null) {\n\t\t\t\t\t\tplan = nativePlan;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Try checking by planCode as well\n\t\t\t\t\t\tconst nativePlanByCode = await ctx.context.adapter.findOne<PaystackPlan>({\n\t\t\t\t\t\t\tmodel: \"paystackPlan\",\n\t\t\t\t\t\t\twhere: [{ field: \"planCode\", value: planName }],\n\t\t\t\t\t\t});\n\t\t\t\t\t\tplan = nativePlanByCode ?? undefined;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (plan === null || plan === undefined) {\n\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\tcode: \"SUBSCRIPTION_PLAN_NOT_FOUND\",\n\t\t\t\t\t\tmessage: PAYSTACK_ERROR_CODES.SUBSCRIPTION_PLAN_NOT_FOUND.message,\n\t\t\t\t\t\tstatus: 400\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else if (productName !== undefined && productName !== null && productName !== \"\") {\n\t\t\t\tif (typeof productName === 'string') {\n\t\t\t\t\tproduct ??= await getProductByName(options, productName) ?? undefined;\n\t\t\t\t\t// Fallback: Check database for synced products\n\t\t\t\t\tproduct ??= (await ctx.context.adapter.findOne<PaystackProduct>({\n\t\t\t\t\t\tmodel: \"paystackProduct\",\n\t\t\t\t\t\twhere: [{ field: \"name\", value: productName }],\n\t\t\t\t\t})) ?? undefined;\n\t\t\t\t}\n\t\t\t\tif (product === null || product === undefined) {\n\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\tmessage: `Product '${productName}' not found.`,\n\t\t\t\t\t\tstatus: 400\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else if (bodyAmount === undefined || bodyAmount === null || bodyAmount === 0) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"Either 'plan', 'product', or 'amount' is required to initialize a transaction.\",\n\t\t\t\t\tstatus: 400\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tlet amount = bodyAmount ?? (product)?.price;\n\t\t\tconst finalCurrency = currency ?? (product)?.currency ?? plan?.currency ?? \"NGN\";\n\n\t\t\tconst referenceIdFromCtx = (ctx.context as Record<string, unknown>).referenceId as string | undefined;\n\t\t\tconst referenceId = (ctx.body.referenceId !== undefined && ctx.body.referenceId !== null && ctx.body.referenceId !== \"\")\n\t\t\t\t? ctx.body.referenceId\n\t\t\t\t: (referenceIdFromCtx !== undefined && referenceIdFromCtx !== null && referenceIdFromCtx !== \"\")\n\t\t\t\t\t? referenceIdFromCtx\n\t\t\t\t\t: (session.user as unknown as { id: string }).id;\n\n\t\t\t// Handle scheduleAtPeriodEnd for existing subscriptions\n\t\t\tif (plan && scheduleAtPeriodEnd === true) {\n\t\t\t\tconst existingSub = await getOrganizationSubscription(ctx, referenceId);\n\t\t\t\tif (existingSub?.status === \"active\") {\n\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\twhere: [{ field: \"id\", value: existingSub.id }],\n\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\tpendingPlan: plan.name,\n\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\t\tmessage: \"Plan change scheduled at period end.\",\n\t\t\t\t\t\tscheduled: true,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Handle cancelAtPeriodEnd for existing subscriptions\n\t\t\tif (cancelAtPeriodEnd === true) {\n\t\t\t\tconst existingSub = await getOrganizationSubscription(ctx, referenceId);\n\t\t\t\tif (existingSub?.status === \"active\") {\n\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\twhere: [{ field: \"id\", value: existingSub.id }],\n\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\tcancelAtPeriodEnd: true,\n\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\t\tmessage: \"Subscription cancellation scheduled at period end.\",\n\t\t\t\t\t\tscheduled: true,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Calculate final amount considering seats if applicable\n\t\t\t// Calculate final amount considering seats if applicable\n\t\t\tif (plan !== null && plan !== undefined && (plan.seatAmount !== undefined || 'seatPriceId' in plan)) {\n\n\t\t\t\tconst members = await ctx.context.adapter.findMany<Member>({\n\t\t\t\t\tmodel: \"member\",\n\t\t\t\t\twhere: [{ field: \"organizationId\", value: referenceId }],\n\t\t\t\t});\n\t\t\t\tconst seatCount = members.length > 0 ? members.length : 1;\n\t\t\t\tconst quantityToUse = quantity ?? seatCount;\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t\tamount = (plan.amount ?? 0) + (quantityToUse * (plan.seatAmount ?? (plan as Record<string, any>).seatPriceId ?? 0));\n\t\t\t}\n\n\t\t\tlet url: string | undefined;\n\t\t\tlet reference: string | undefined;\n\t\t\tlet accessCode: string | undefined;\n\n\t\t\t// Check trial eligibility - prevent trial abuse\n\t\t\tlet trialStart: Date | undefined;\n\t\t\tlet trialEnd: Date | undefined;\n\t\t\tif (plan?.freeTrial?.days !== undefined && plan.freeTrial.days !== null && plan.freeTrial.days > 0) {\n\t\t\t\t// Check if user/referenceId has ever had a trial\n\t\t\t\tconst previousTrials = await ctx.context.adapter.findMany<Subscription>({\n\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\twhere: [{ field: \"referenceId\", value: referenceId }],\n\t\t\t\t});\n\t\t\t\tconst hadTrial = previousTrials?.some(\n\t\t\t\t\t(sub: Subscription) => (sub.trialStart !== undefined && sub.trialStart !== null) || (sub.trialEnd !== undefined && sub.trialEnd !== null) || sub.status === \"trialing\"\n\t\t\t\t);\n\n\t\t\t\tif (hadTrial !== true) {\n\t\t\t\t\ttrialStart = new Date();\n\t\t\t\t\ttrialEnd = new Date();\n\t\t\t\t\ttrialEnd.setDate(trialEnd.getDate() + plan.freeTrial.days);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t// Determine Customer Email & Code (Organization support)\n\t\t\t\tlet targetEmail = (email !== undefined && email !== null && email !== \"\") ? email : user.email;\n\t\t\t\tlet paystackCustomerCode = (user as unknown as { paystackCustomerCode?: string }).paystackCustomerCode;\n\n\t\t\t\tif (options.organization?.enabled === true && referenceId !== undefined && referenceId !== null && referenceId !== \"\" && referenceId !== user.id) {\n\t\t\t\t\tconst org = await ctx.context.adapter.findOne({\n\t\t\t\t\t\tmodel: \"organization\",\n\t\t\t\t\t\twhere: [{ field: \"id\", value: referenceId }],\n\t\t\t\t\t});\n\t\t\t\t\tif (org !== undefined && org !== null) {\n\t\t\t\t\t\t// Prefer organization's existing Paystack customer code\n\t\t\t\t\t\tif (org.paystackCustomerCode !== undefined && org.paystackCustomerCode !== null && org.paystackCustomerCode !== \"\") {\n\t\t\t\t\t\t\tpaystackCustomerCode = org.paystackCustomerCode;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (org.email !== undefined && org.email !== null && org.email !== \"\") {\n\t\t\t\t\t\t\ttargetEmail = org.email;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Fallback: Use Organization Owner Email\n\t\t\t\t\t\t\tconst ownerMember = await ctx.context.adapter.findOne<Member>({\n\t\t\t\t\t\t\t\tmodel: \"member\",\n\t\t\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t\t\t{ field: \"organizationId\", value: referenceId },\n\t\t\t\t\t\t\t\t\t{ field: \"role\", value: \"owner\" }\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tif (ownerMember !== undefined && ownerMember !== null) {\n\t\t\t\t\t\t\t\tconst ownerUser = await ctx.context.adapter.findOne<User>({\n\t\t\t\t\t\t\t\t\tmodel: \"user\",\n\t\t\t\t\t\t\t\t\twhere: [{ field: \"id\", value: ownerMember.userId }]\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\tif (ownerUser?.email !== undefined && ownerUser?.email !== null && ownerUser?.email !== \"\") {\n\t\t\t\t\t\t\t\t\ttargetEmail = ownerUser.email;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Construct Metadata\n\t\t\t\tconst metadata = JSON.stringify({\n\t\t\t\t\treferenceId,\n\t\t\t\t\tuserId: user.id,\n\t\t\t\t\tplan: plan?.name.toLowerCase(), // Undefined for one-time\n\t\t\t\t\tproduct: product?.name.toLowerCase(),\n\t\t\t\t\tisTrial: trialStart !== undefined && trialStart !== null,\n\t\t\t\t\ttrialEnd: trialEnd?.toISOString(),\n\t\t\t\t\t...extraMetadata,\n\t\t\t\t});\n\n\t\t\t\tconst initBody: Record<string, unknown> & { email?: string; amount?: number; plan?: string; invoice_limit?: number } = {\n\t\t\t\t\temail: targetEmail,\n\t\t\t\t\tcallback_url: callbackURL,\n\t\t\t\t\tmetadata,\n\t\t\t\t\t// If plan/product exists, use its currency; otherwise fallback to provided or default\n\t\t\t\t\tcurrency: finalCurrency,\n\t\t\t\t\tquantity,\n\t\t\t\t};\n\n\t\t\t\t// Sync/Update Customer: ensure email matches if code exists\n\t\t\t\tif (paystackCustomerCode !== undefined && paystackCustomerCode !== null && paystackCustomerCode !== \"\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst ops = getPaystackOps(options.paystackClient);\n\t\t\t\t\t\t// Only update if email is present\n\t\t\t\t\t\tif (initBody.email !== undefined && initBody.email !== null && initBody.email !== \"\") {\n\t\t\t\t\t\t\tawait ops.customerUpdate(paystackCustomerCode, { email: initBody.email });\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (_e: unknown) {\n\t\t\t\t\t\t// Ignore sync errors\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Handle prorateAndCharge for existing active subscriptions\n\t\t\t\tif (plan !== undefined && plan !== null && prorateAndCharge === true) {\n\t\t\t\t\tconst existingSub = await getOrganizationSubscription(ctx, referenceId);\n\t\t\t\t\tif (existingSub?.status === \"active\" && existingSub.paystackAuthorizationCode !== null && existingSub.paystackAuthorizationCode !== undefined && existingSub.paystackSubscriptionCode !== null && existingSub.paystackSubscriptionCode !== undefined) {\n\t\t\t\t\t\t// 1. Calculate remaining days\n\t\t\t\t\t\tconst now = new Date();\n\t\t\t\t\t\tconst periodEndLocal = existingSub.periodEnd ? new Date(existingSub.periodEnd) : new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000); // fallback 30 days\n\t\t\t\t\t\tconst periodStartLocal = existingSub.periodStart ? new Date(existingSub.periodStart) : now;\n\n\t\t\t\t\t\tconst totalDays = Math.max(1, Math.ceil((periodEndLocal.getTime() - periodStartLocal.getTime()) / (1000 * 60 * 60 * 24)));\n\t\t\t\t\t\tconst remainingDays = Math.max(0, Math.ceil((periodEndLocal.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)));\n\n\t\t\t\t\t\t// 2. Fetch old plan/amount\n\t\t\t\t\t\tlet oldAmount = 0;\n\t\t\t\t\t\tif (existingSub.plan !== undefined && existingSub.plan !== null && existingSub.plan !== \"\") {\n\t\t\t\t\t\t\tconst oldPlan = (await getPlanByName(options, existingSub.plan)) ?? (await ctx.context.adapter.findOne<PaystackPlan>({ model: \"paystackPlan\", where: [{ field: \"name\", value: existingSub.plan }] }));\n\t\t\t\t\t\t\tif (oldPlan !== null && oldPlan !== undefined) {\n\t\t\t\t\t\t\t\tconst oldSeatCount = existingSub.seats ?? 1;\n\t\t\t\t\t\t\t\toldAmount = (oldPlan.amount ?? 0) + (oldSeatCount * (oldPlan.seatAmount ?? (oldPlan as { seatPriceId?: number }).seatPriceId ?? 0));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// 3. Calculate new total amount\n\t\t\t\t\t\tlet membersCount = 1;\n\t\t\t\t\t\tif (plan.seatAmount !== undefined || (plan as { seatPriceId?: string | number }).seatPriceId !== undefined) {\n\t\t\t\t\t\t\tconst members = await ctx.context.adapter.findMany<Member>({\n\t\t\t\t\t\t\t\tmodel: \"member\",\n\t\t\t\t\t\t\t\twhere: [{ field: \"organizationId\", value: referenceId }],\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tmembersCount = members.length > 0 ? members.length : 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst newSeatCount = quantity ?? existingSub.seats ?? membersCount;\n\t\t\t\t\t\tconst newAmount = (plan.amount ?? 0) + (newSeatCount * (plan.seatAmount ?? (plan as { seatPriceId?: number }).seatPriceId ?? 0));\n\n\t\t\t\t\t\t// 4. Calculate Difference & Charge\n\t\t\t\t\t\tconst costDifference = newAmount - oldAmount;\n\t\t\t\t\t\tif (costDifference > 0 && remainingDays > 0) {\n\t\t\t\t\t\t\tconst proratedAmount = Math.round((costDifference / totalDays) * remainingDays);\n\t\t\t\t\t\t\t// Ensure minimum Paystack charge limit is met (50 NGN -> 5000)\n\t\t\t\t\t\t\tif (proratedAmount >= 5000) {\n\t\t\t\t\t\t\t\tconst ops = getPaystackOps(options.paystackClient);\n\t\t\t\t\t\t\t\tconst chargeResRaw = await ops.transactionChargeAuthorization({\n\t\t\t\t\t\t\t\t\temail: targetEmail,\n\t\t\t\t\t\t\t\t\tamount: proratedAmount,\n\t\t\t\t\t\t\t\t\tauthorization_code: existingSub.paystackAuthorizationCode,\n\t\t\t\t\t\t\t\t\treference: `prorate_${Date.now()}_${Math.random().toString(36).substring(7)}`,\n\t\t\t\t\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t\t\t\t\ttype: \"proration\",\n\t\t\t\t\t\t\t\t\t\treferenceId,\n\t\t\t\t\t\t\t\t\t\tnewPlan: plan.name,\n\t\t\t\t\t\t\t\t\t\toldPlan: existingSub.plan,\n\t\t\t\t\t\t\t\t\t\tremainingDays,\n\t\t\t\t\t\t\t\t\t} as Record<string, unknown>,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tconst sdkRes = unwrapSdkResult<PaystackTransactionResponse>(chargeResRaw);\n\n\t\t\t\t\t\t\t\tconst actualStatus = sdkRes?.status;\n\n\t\t\t\t\t\t\t\tif (actualStatus !== \"success\") {\n\t\t\t\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", { message: \"Failed to process prorated charge via saved authorization.\" });\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// 5. Update Subscription Future Cycle in Paystack\n\t\t\t\t\t\tconst ops = getPaystackOps(options.paystackClient);\n\t\t\t\t\t\tawait ops.subscriptionUpdate({\n\t\t\t\t\t\t\tcode: existingSub.paystackSubscriptionCode,\n\t\t\t\t\t\t\tamount: newAmount,\n\t\t\t\t\t\t\tplan: plan.planCode,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// 6. Update Local DB\n\t\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\t\twhere: [{ field: \"id\", value: existingSub.id }],\n\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\tplan: plan.name,\n\t\t\t\t\t\t\t\tseats: newSeatCount,\n\t\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\t\t\tmessage: \"Subscription successfully upgraded with prorated charge.\",\n\t\t\t\t\t\t\tprorated: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (plan !== undefined && plan !== null) {\n\t\t\t\t\t// Subscription Flow\n\t\t\t\t\tif (trialStart !== undefined && trialStart !== null) {\n\t\t\t\t\t\t// Trial Flow: Authorize card with minimum amount, don't start sub yet\n\t\t\t\t\t\tinitBody.amount = 5000; // 50 NGN (minimum allowed)\n\t\t\t\t\t\t// Do NOT set initBody.plan\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Standard Flow\n\t\t\t\t\t\tinitBody.plan = plan.planCode;\n\t\t\t\t\t\tinitBody.invoice_limit = plan.invoiceLimit;\n\t\t\t\t\t\t// Paystack requires amount even with planCode (it uses plan's stored amount)\n\t\t\t\t\t\t// For local plans without planCode, use finalAmount; for planCode plans, use plan.amount or override\n\t\t\t\t\t\tlet finalAmount: number;\n\t\t\t\t\t\tif (amount !== undefined && amount !== null) {\n\t\t\t\t\t\t\t// amount was calculated via seat-based logic or provided as override\n\t\t\t\t\t\t\tfinalAmount = amount;\n\t\t\t\t\t\t\t// We force quantity to 1 in the Paystack call because our amount already includes the quantity multiplier\n\t\t\t\t\t\t\tinitBody.quantity = 1;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Standard Flow: Plan Price * Quantity\n\t\t\t\t\t\t\tfinalAmount = (plan.amount ?? 0) * (quantity ?? 1);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tinitBody.amount = Math.max(Math.round(finalAmount), 5000);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// One-Time Payment Flow\n\t\t\t\t\tif (amount === undefined || amount === null || amount === 0) throw new APIError(\"BAD_REQUEST\", { message: \"Amount is required for one-time payments\" });\n\t\t\t\t\tinitBody.amount = Math.round(amount);\n\t\t\t\t}\n\n\t\t\t\tconst initRaw = await paystack.transactionInitialize(initBody as unknown as Parameters<typeof paystack.transactionInitialize>[0]);\n\t\t\t\tconst sdkRes = unwrapSdkResult<PaystackTransactionResponse>(initRaw);\n\n\t\t\t\turl = (sdkRes as { authorization_url?: string } | undefined)?.authorization_url ?? (sdkRes as unknown as { data: { authorization_url?: string } } | undefined)?.data?.authorization_url;\n\t\t\t\treference = (sdkRes as { reference?: string } | undefined)?.reference ?? (sdkRes as unknown as { data: { reference?: string } } | undefined)?.data?.reference;\n\t\t\t\taccessCode = (sdkRes as { access_code?: string } | undefined)?.access_code ?? (sdkRes as unknown as { data: { access_code?: string } } | undefined)?.data?.access_code;\n\t\t\t} catch (error: unknown) {\n\t\t\t\t(ctx as unknown as { context: { logger: { error: (msg: string, err: unknown) => void } } }).context.logger.error(\"Failed to initialize Paystack transaction\", error);\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tcode: \"FAILED_TO_INITIALIZE_TRANSACTION\",\n\t\t\t\t\tmessage: (error as Error)?.message ?? PAYSTACK_ERROR_CODES.FAILED_TO_INITIALIZE_TRANSACTION.message,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// 6. Record Transaction & Subscription\n\t\t\tawait ctx.context.adapter.create({\n\t\t\t\tmodel: \"paystackTransaction\",\n\t\t\t\tdata: {\n\t\t\t\t\treference: reference!,\n\t\t\t\t\treferenceId,\n\t\t\t\t\tuserId: user.id,\n\t\t\t\t\tamount: amount ?? 0,\n\t\t\t\t\tcurrency: plan?.currency ?? currency ?? \"NGN\",\n\t\t\t\t\tstatus: \"pending\",\n\t\t\t\t\tplan: plan?.name.toLowerCase(),\n\t\t\t\t\tproduct: product?.name.toLowerCase(),\n\t\t\t\t\tmetadata: (extraMetadata !== undefined && extraMetadata !== null && Object.keys(extraMetadata).length > 0) ? JSON.stringify(extraMetadata) : undefined,\n\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tif (plan !== undefined && plan !== null) {\n\t\t\t\t// Re-fetch customer code if it wasn't available before (though we didn't force-create it here)\n\t\t\t\t// For now, use what we have (user's or org's)\n\t\t\t\tlet storedCustomerCode = (user as unknown as { paystackCustomerCode?: string }).paystackCustomerCode;\n\t\t\t\tif (options.organization?.enabled === true && referenceId !== user.id) {\n\t\t\t\t\tconst org = await ctx.context.adapter.findOne({\n\t\t\t\t\t\tmodel: \"organization\",\n\t\t\t\t\t\twhere: [{ field: \"id\", value: referenceId }],\n\t\t\t\t\t});\n\t\t\t\t\tif (org?.paystackCustomerCode !== undefined && org.paystackCustomerCode !== null && org.paystackCustomerCode !== \"\") {\n\t\t\t\t\t\tstoredCustomerCode = org.paystackCustomerCode;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst newSubscription = await ctx.context.adapter.create<Subscription>({\n\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tplan: plan.name.toLowerCase(),\n\t\t\t\t\t\treferenceId,\n\t\t\t\t\t\tpaystackCustomerCode: storedCustomerCode,\n\t\t\t\t\t\tpaystackTransactionReference: reference,\n\t\t\t\t\t\tstatus: (trialStart !== undefined && trialStart !== null) ? \"trialing\" : \"incomplete\",\n\t\t\t\t\t\tseats: quantity,\n\t\t\t\t\t\ttrialStart,\n\t\t\t\t\t\ttrialEnd,\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\t// Call trial start hook if trial was granted\n\t\t\t\tif ((trialStart !== undefined && trialStart !== null) && newSubscription !== null && plan.freeTrial?.onTrialStart !== undefined && plan.freeTrial?.onTrialStart !== null) {\n\t\t\t\t\tawait plan.freeTrial.onTrialStart(newSubscription);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn ctx.json({\n\t\t\t\turl,\n\t\t\t\treference,\n\t\t\t\taccessCode,\n\t\t\t\tredirect: true,\n\t\t\t});\n\t\t},\n\t);\n};\n\n// Aliases for Client DX Parity\nexport const createSubscription = (options: AnyPaystackOptions) =>\n\tinitializeTransaction(options, \"/paystack/create-subscription\");\nexport const upgradeSubscription = (options: AnyPaystackOptions) =>\n\tinitializeTransaction(options, \"/paystack/upgrade-subscription\");\nexport const restoreSubscription = (options: AnyPaystackOptions) => {\n\t// Alias for enable\n\treturn enablePaystackSubscription(options, \"/paystack/restore-subscription\");\n};\nexport const cancelSubscription = (options: AnyPaystackOptions) => {\n\t// Alias for disable\n\treturn disablePaystackSubscription(options, \"/paystack/cancel-subscription\");\n};\n\n\nexport const verifyTransaction = <P extends string = \"/paystack/verify-transaction\">(options: AnyPaystackOptions, path: P = \"/paystack/verify-transaction\" as P) => {\n\tconst verifyBodySchema = z.object({\n\t\treference: z.string(),\n\t});\n\n\tconst subscriptionOptions = options.subscription;\n\tconst useMiddlewares = subscriptionOptions?.enabled === true\n\t\t? [sessionMiddleware, originCheck, referenceMiddleware(options, \"verify-transaction\")]\n\t\t: [sessionMiddleware, originCheck];\n\n\treturn createAuthEndpoint(\n\t\tpath,\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tbody: verifyBodySchema,\n\t\t\tuse: useMiddlewares,\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst paystack = getPaystackOps(options.paystackClient);\n\t\t\tlet verifyRes: unknown;\n\t\t\ttry {\n\t\t\t\tconst verifyRaw = await paystack.transactionVerify(ctx.body.reference);\n\t\t\t\tverifyRes = unwrapSdkResult<Record<string, unknown>>(verifyRaw);\n\t\t\t} catch (error: unknown) {\n\t\t\t\tctx.context.logger.error(\"Failed to verify Paystack transaction\", error);\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tcode: \"FAILED_TO_VERIFY_TRANSACTION\",\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t(error as Error)?.message ?? PAYSTACK_ERROR_CODES.FAILED_TO_VERIFY_TRANSACTION.message,\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst dataRaw = unwrapSdkResult<PaystackTransactionResponse>(verifyRes);\n\t\t\tconst data = (dataRaw as { data?: unknown } | undefined)?.data ?? dataRaw;\n\t\t\tconst status = (data as { status?: string } | undefined)?.status;\n\t\t\tconst reference = (data as { reference?: string } | undefined)?.reference ?? ctx.body.reference;\n\t\t\tconst paystackId = (data as { id?: string | number } | undefined)?.id !== undefined && (data as { id?: string | number } | undefined)?.id !== null ? String((data as { id: string | number }).id) : undefined;\n\t\t\tconst authorizationCode = ((data as { authorization?: { authorization_code?: string } } | undefined)?.authorization)?.authorization_code;\n\n\t\t\tif (status === \"success\") {\n\t\t\t\tconst session = await getSessionFromCtx(ctx);\n\n\t\t\t\t// Get the local transaction record to know the intended referenceId (Org or User)\n\t\t\t\tconst txRecord = await ctx.context.adapter.findOne<PaystackTransaction & { referenceId?: string }>({\n\t\t\t\t\tmodel: \"paystackTransaction\",\n\t\t\t\t\twhere: [{ field: \"reference\", value: reference }],\n\t\t\t\t});\n\n\t\t\t\t// Trust the referenceId from the record, fallback to session user if missing\n\t\t\t\tconst referenceId = txRecord?.referenceId ?? (session?.user as unknown as { id: string })?.id;\n\n\t\t\t\t// Authorization check: ensure the current user has access to this referenceId\n\t\t\t\tif (session !== null && session !== undefined && referenceId !== session.user.id) {\n\t\t\t\t\tconst authRef = (subscriptionOptions as unknown as { authorizeReference?: (data: unknown, ctx: unknown) => Promise<boolean> })?.authorizeReference;\n\t\t\t\t\tlet authorized = false;\n\t\t\t\t\tif (authRef !== undefined) {\n\t\t\t\t\t\tauthorized = await authRef(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tuser: session.user,\n\t\t\t\t\t\t\t\tsession,\n\t\t\t\t\t\t\t\treferenceId,\n\t\t\t\t\t\t\t\taction: \"verify-transaction\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tctx as GenericEndpointContext,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (authorized !== true) {\n\t\t\t\t\t\tif (options.organization?.enabled === true) {\n\t\t\t\t\t\t\tconst member = await ctx.context.adapter.findOne<Member>({\n\t\t\t\t\t\t\t\tmodel: \"member\",\n\t\t\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t\t\t{ field: \"userId\", value: session.user.id },\n\t\t\t\t\t\t\t\t\t{ field: \"organizationId\", value: referenceId }\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (member !== undefined && member !== null) authorized = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!authorized) {\n\t\t\t\t\t\tthrow new APIError(\"UNAUTHORIZED\");\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\tmodel: \"paystackTransaction\",\n\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\t\t\tpaystackId,\n\t\t\t\t\t\t\t// Update with actual amount/currency from Paystack (for planCode subscriptions)\n\t\t\t\t\t\t\t...((data as { amount?: number } | undefined)?.amount !== undefined && (data as { amount?: number } | undefined)?.amount !== null ? { amount: (data as { amount: number }).amount } : {}),\n\t\t\t\t\t\t\t...((data as { currency?: string } | undefined)?.currency !== undefined && (data as { currency?: string } | undefined)?.currency !== null && (data as { currency?: string } | undefined)?.currency !== \"\" ? { currency: (data as { currency: string }).currency } : {}),\n\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t},\n\t\t\t\t\t\twhere: [{ field: \"reference\", value: reference }],\n\t\t\t\t\t});\n\n\n\t\t\t\t\tconst customer = (data as PaystackTransactionResponse | undefined)?.customer;\n\t\t\t\t\tconst paystackCustomerCodeFromPaystack = (customer !== undefined && customer !== null && typeof customer === \"object\")\n\t\t\t\t\t\t? (customer as Record<string, unknown>).customer_code as string | undefined\n\t\t\t\t\t\t: undefined;\n\t\t\t\t\tif (paystackCustomerCodeFromPaystack !== undefined && paystackCustomerCodeFromPaystack !== null && paystackCustomerCodeFromPaystack !== \"\" && referenceId !== undefined && referenceId !== null && referenceId !== \"\") {\n\t\t\t\t\t\tlet isOrg = (options.organization?.enabled === true && typeof referenceId === \"string\" && referenceId.startsWith(\"org_\"));\n\t\t\t\t\t\tif (!isOrg && options.organization?.enabled === true) {\n\t\t\t\t\t\t\tconst org = (await ctx.context.adapter.findOne({\n\t\t\t\t\t\t\t\tmodel: \"organization\",\n\t\t\t\t\t\t\t\twhere: [{ field: \"id\", value: referenceId }],\n\t\t\t\t\t\t\t}));\n\t\t\t\t\t\t\tisOrg = org !== null && org !== undefined;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (isOrg === true) {\n\t\t\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\t\t\tmodel: \"organization\",\n\t\t\t\t\t\t\t\tupdate: { paystackCustomerCode: paystackCustomerCodeFromPaystack },\n\t\t\t\t\t\t\t\twhere: [{ field: \"id\", value: referenceId }],\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\t\t\tmodel: \"user\",\n\t\t\t\t\t\t\t\tupdate: { paystackCustomerCode: paystackCustomerCodeFromPaystack },\n\t\t\t\t\t\t\t\twhere: [{ field: \"id\", value: referenceId }],\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Decrement product quantity if applicable\n\t\t\t\t\tconst transaction = await ctx.context.adapter.findOne<PaystackTransaction>({\n\t\t\t\t\t\tmodel: \"paystackTransaction\",\n\t\t\t\t\t\twhere: [{ field: \"reference\", value: reference }],\n\t\t\t\t\t});\n\t\t\t\t\tif (transaction?.product !== undefined && transaction?.product !== null && transaction?.product !== \"\") {\n\t\t\t\t\t\tawait syncProductQuantityFromPaystack(ctx, transaction.product, options.paystackClient);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check for trial activation\n\t\t\t\t\tlet isTrial = false;\n\t\t\t\t\tlet trialEnd: string | undefined;\n\t\t\t\t\tlet targetPlan: string | undefined;\n\n\t\t\t\t\tif ((data as { metadata?: unknown } | undefined)?.metadata !== undefined && (data as { metadata?: unknown } | undefined)?.metadata !== null) {\n\t\t\t\t\t\tconst metaRaw = (data as { metadata: unknown }).metadata;\n\t\t\t\t\t\tconst meta = typeof metaRaw === \"string\" ? JSON.parse(metaRaw) : metaRaw as Record<string, unknown>;\n\t\t\t\t\t\tisTrial = meta.isTrial === true || meta.isTrial === \"true\";\n\n\t\t\t\t\t\ttrialEnd = meta.trialEnd as string | undefined;\n\n\t\t\t\t\t\ttargetPlan = meta.plan as string | undefined;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet paystackSubscriptionCode: string | undefined;\n\n\t\t\t\t\tif (isTrial === true && (targetPlan !== undefined && targetPlan !== null && targetPlan !== \"\") && (trialEnd !== undefined && trialEnd !== null && trialEnd !== \"\")) {\n\t\t\t\t\t\t// Trial Flow: Create subscription with future start date using auth code\n\t\t\t\t\t\tconst email = ((data as { customer?: unknown }).customer as { email?: string })?.email;\n\n\t\t\t\t\t\t// We need the planCode. We have the plan NAME in metadata (lowercased).\n\t\t\t\t\t\tconst plans = await getPlans(subscriptionOptions);\n\t\t\t\t\t\tconst planConfig = plans.find(p => p.name.toLowerCase() === targetPlan?.toLowerCase());\n\n\t\t\t\t\t\t// For local plans (no planCode), generate a local subscription code\n\t\t\t\t\t\tif (planConfig !== undefined && planConfig !== null && (planConfig.planCode === undefined || planConfig.planCode === null || planConfig.planCode === \"\")) {\n\t\t\t\t\t\t\tpaystackSubscriptionCode = `LOC_${reference}`;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (authorizationCode !== undefined && authorizationCode !== null && authorizationCode !== \"\" && email !== undefined && email !== null && email !== \"\" && planConfig?.planCode !== undefined && planConfig.planCode !== null && planConfig.planCode !== \"\") {\n\t\t\t\t\t\t\tconst subResRaw = await paystack.subscriptionCreate({\n\t\t\t\t\t\t\t\tcustomer: email,\n\t\t\t\t\t\t\t\tplan: planConfig.planCode,\n\t\t\t\t\t\t\t\tauthorization: authorizationCode,\n\t\t\t\t\t\t\t\tstart_date: trialEnd\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tconst subRes = unwrapSdkResult<PaystackSubscriptionResponse>(subResRaw);\n\t\t\t\t\t\t\tconst cleanSubData = (subRes as { data?: unknown } | undefined)?.data ?? subRes;\n\n\t\t\t\t\t\t\tpaystackSubscriptionCode = (cleanSubData as { subscription_code?: string } | undefined)?.subscription_code;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (isTrial !== true) {\n\t\t\t\t\t\tconst planFromPaystack = (data as { plan?: unknown } | undefined)?.plan;\n\t\t\t\t\t\tconst planCodeFromPaystack = (planFromPaystack as { plan_code?: string } | undefined)?.plan_code;\n\n\t\t\t\t\t\tif (planCodeFromPaystack === undefined || planCodeFromPaystack === null || planCodeFromPaystack === \"\") {\n\t\t\t\t\t\t\t// Local Plan\n\t\t\t\t\t\t\tpaystackSubscriptionCode = `LOC_${reference}`;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Native Paystack subscription (if created during charge)\n\t\t\t\t\t\t\tpaystackSubscriptionCode = ((data as { subscription?: { subscription_code?: string } } | undefined)?.subscription)?.subscription_code;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\n\t\t\t\t\tconst existingSubs = await ctx.context.adapter.findMany<Subscription>({\n\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\twhere: [{ field: \"paystackTransactionReference\", value: reference }],\n\t\t\t\t\t});\n\t\t\t\t\tlet targetSub: Subscription | undefined;\n\t\t\t\t\tif (existingSubs !== null && existingSubs !== undefined && existingSubs.length > 0) {\n\t\t\t\t\t\ttargetSub = existingSubs.find((s: Subscription) =>\n\t\t\t\t\t\t\t(referenceId === undefined || referenceId === null || referenceId === \"\") || s.referenceId === referenceId\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet updatedSubscription: Subscription | null = null;\n\t\t\t\t\tif (targetSub !== undefined && targetSub !== null) {\n\t\t\t\t\t\tupdatedSubscription = await ctx.context.adapter.update<Subscription>({\n\t\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\tstatus: isTrial ? \"trialing\" : \"active\",\n\t\t\t\t\t\t\t\tperiodStart: new Date(),\n\t\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t\t\t...(isTrial === true && trialEnd !== undefined && trialEnd !== null ? {\n\t\t\t\t\t\t\t\t\ttrialStart: new Date(),\n\t\t\t\t\t\t\t\t\ttrialEnd: new Date(trialEnd),\n\t\t\t\t\t\t\t\t\tperiodEnd: new Date(trialEnd),\n\t\t\t\t\t\t\t\t} : {}),\n\t\t\t\t\t\t\t\t...(paystackSubscriptionCode !== undefined && paystackSubscriptionCode !== null && paystackSubscriptionCode !== \"\" ? { paystackSubscriptionCode } : {}),\n\t\t\t\t\t\t\t\t...(authorizationCode !== undefined && authorizationCode !== null && authorizationCode !== \"\" ? { paystackAuthorizationCode: authorizationCode } : {}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\twhere: [{ field: \"id\", value: targetSub.id }],\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tif (updatedSubscription && subscriptionOptions?.enabled === true && \"onSubscriptionComplete\" in subscriptionOptions && typeof (subscriptionOptions as unknown as Record<string, unknown>).onSubscriptionComplete === \"function\") {\n\t\t\t\t\t\tconst subOpts = subscriptionOptions;\n\t\t\t\t\t\tconst plans = await getPlans(subOpts);\n\t\t\t\t\t\tconst plan = plans.find(p => p.name.toLowerCase() === updatedSubscription.plan.toLowerCase());\n\t\t\t\t\t\tif (plan) {\n\t\t\t\t\t\t\tawait (subscriptionOptions as unknown as { onSubscriptionComplete: (data: unknown, ctx: unknown) => Promise<void> }).onSubscriptionComplete({\n\t\t\t\t\t\t\t\tevent: data,\n\t\t\t\t\t\t\t\tsubscription: updatedSubscription,\n\t\t\t\t\t\t\t\tplan\n\t\t\t\t\t\t\t}, ctx);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (e: unknown) {\n\t\t\t\t\tctx.context.logger.error(\n\t\t\t\t\t\t\"Failed to update transaction/subscription after verification\",\n\t\t\t\t\t\te,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn ctx.json({\n\t\t\t\tstatus,\n\t\t\t\treference,\n\t\t\t\tdata,\n\t\t\t});\n\t\t},\n\t);\n};\n\nexport const listSubscriptions = (options: AnyPaystackOptions) => {\n\tconst listQuerySchema = z.object({\n\t\treferenceId: z.string().optional(),\n\t});\n\n\tconst subscriptionOptions = options.subscription;\n\tconst useMiddlewares = subscriptionOptions?.enabled === true\n\t\t? [sessionMiddleware, originCheck, referenceMiddleware(options, \"list-subscriptions\")]\n\t\t: [sessionMiddleware, originCheck];\n\n\treturn createAuthEndpoint(\n\t\t\"/paystack/list-subscriptions\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tquery: listQuerySchema,\n\t\t\tuse: useMiddlewares,\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tif (subscriptionOptions?.enabled !== true) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"Subscriptions are not enabled in the Paystack options.\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst session = await getSessionFromCtx(ctx);\n\t\t\tif (!session) throw new APIError(\"UNAUTHORIZED\");\n\t\t\tconst referenceIdPart = (ctx.context as Record<string, unknown>).referenceId as string | undefined;\n\t\t\tconst queryRefId = ctx.query?.referenceId;\n\t\t\tconst referenceId = referenceIdPart ?? queryRefId ?? (session.user as { id: string }).id;\n\t\t\tconst res = await ctx.context.adapter.findMany<Subscription>({\n\t\t\t\tmodel: \"subscription\",\n\t\t\t\twhere: [{ field: \"referenceId\", value: referenceId }],\n\t\t\t});\n\t\t\treturn ctx.json({ subscriptions: res });\n\t\t},\n\t);\n};\n\nexport const listTransactions = <P extends string = \"/paystack/list-transactions\">(options: AnyPaystackOptions, path: P = \"/paystack/list-transactions\" as P) => {\n\tconst listQuerySchema = z.object({\n\t\treferenceId: z.string().optional(),\n\t});\n\n\tconst subscriptionOptions = options.subscription;\n\tconst useMiddlewares = subscriptionOptions?.enabled === true\n\t\t? [sessionMiddleware, originCheck, referenceMiddleware(options, \"list-transactions\")]\n\t\t: [sessionMiddleware, originCheck];\n\n\treturn createAuthEndpoint(\n\t\tpath,\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tquery: listQuerySchema,\n\t\t\tuse: useMiddlewares,\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst session = await getSessionFromCtx(ctx);\n\t\t\tif (!session) throw new APIError(\"UNAUTHORIZED\");\n\t\t\tconst referenceId =\n\t\t\t\t((ctx.context as Record<string, unknown>).referenceId as string | undefined) ??\n\t\t\t\t(ctx.query?.referenceId) ??\n\t\t\t\t(session.user as { id: string }).id;\n\t\t\tconst res = await ctx.context.adapter.findMany<PaystackTransaction>({\n\t\t\t\tmodel: \"paystackTransaction\",\n\t\t\t\twhere: [{ field: \"referenceId\", value: referenceId }],\n\t\t\t});\n\t\t\t// Sort by createdAt desc locally if adapter doesn't support it well,\n\t\t\t// but Better Auth adapters usually return in insertion order.\n\t\t\t// Let's sort to be sure.\n\t\t\tconst sorted = res.sort((a: PaystackTransaction, b: PaystackTransaction) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());\n\t\t\treturn ctx.json({ transactions: sorted });\n\t\t},\n\t);\n};\n\nconst enableDisableBodySchema = z.object({\n\treferenceId: z.string().optional(),\n\tsubscriptionCode: z.string(),\n\temailToken: z.string().optional(),\n\tatPeriodEnd: z.boolean().optional(),\n});\n\nfunction decodeBase64UrlToString(value: string): string {\n\tconst normalized = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n\tconst padded = normalized + \"===\".slice((normalized.length + 3) % 4);\n\tif (typeof (globalThis as unknown as { atob: unknown }).atob === \"function\") {\n\t\treturn ((globalThis as unknown as { atob: (v: string) => string }).atob)(padded);\n\t}\n\t// eslint-disable-next-line no-restricted-globals\n\treturn Buffer.from(padded, \"base64\").toString(\"utf8\");\n}\n\nfunction tryGetEmailTokenFromSubscriptionManageLink(link: string): string | undefined {\n\ttry {\n\t\tconst url = new URL(link);\n\t\tconst subscriptionToken = url.searchParams.get(\"subscription_token\");\n\t\tif (subscriptionToken === undefined || subscriptionToken === null || subscriptionToken === \"\") return undefined;\n\t\tconst parts = subscriptionToken.split(\".\");\n\t\tif (parts.length < 2) return undefined;\n\t\tconst payloadJson = decodeBase64UrlToString(parts[1]);\n\t\tconst payload = JSON.parse(payloadJson);\n\t\treturn typeof payload?.email_token === \"string\" ? payload.email_token : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nexport const disablePaystackSubscription = <P extends string = \"/paystack/disable-subscription\">(options: AnyPaystackOptions, path: P = \"/paystack/disable-subscription\" as P) => {\n\tconst subscriptionOptions = options.subscription;\n\tconst useMiddlewares = subscriptionOptions?.enabled === true\n\t\t? [sessionMiddleware, originCheck, referenceMiddleware(options, \"disable-subscription\")]\n\t\t: [sessionMiddleware, originCheck];\n\n\treturn createAuthEndpoint(\n\t\tpath,\n\t\t{ method: \"POST\", body: enableDisableBodySchema, use: useMiddlewares },\n\t\tasync (ctx) => {\n\t\t\tconst { subscriptionCode, atPeriodEnd } = ctx.body;\n\t\t\tconst paystack = getPaystackOps(options.paystackClient);\n\t\t\ttry {\n\t\t\t\tif ((subscriptionCode as string).startsWith(\"LOC_\")) {\n\t\t\t\t\tconst sub = await ctx.context.adapter.findOne<Subscription>({\n\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\twhere: [{ field: \"paystackSubscriptionCode\", value: subscriptionCode }],\n\t\t\t\t\t});\n\n\t\t\t\t\tif (sub !== null && sub !== undefined) {\n\t\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\tstatus: atPeriodEnd === false ? \"canceled\" : \"active\",\n\t\t\t\t\t\t\t\tcancelAtPeriodEnd: atPeriodEnd !== false,\n\t\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\twhere: [{ field: \"id\", value: sub.id }],\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn ctx.json({ status: \"success\" });\n\t\t\t\t\t}\n\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", { message: \"Subscription not found\" });\n\t\t\t\t}\n\n\t\t\t\tlet emailToken = ctx.body.emailToken;\n\t\t\t\tlet nextPaymentDate: string | undefined;\n\n\t\t\t\t// Always fetch subscription to get next_payment_date even if we have emailToken (unless passed? no, next_payment_date comes from paystack)\n\t\t\t\t// We need next_payment_date for cancelAtPeriodEnd logic\n\t\t\t\ttry {\n\t\t\t\t\tconst raw = await paystack.subscriptionFetch(subscriptionCode);\n\t\t\t\t\tconst fetchRes = unwrapSdkResult<PaystackSubscriptionResponse>(raw);\n\t\t\t\t\tconst data = (fetchRes as { data?: unknown } | undefined)?.data ?? fetchRes;\n\n\t\t\t\t\tif (emailToken === undefined || emailToken === null || emailToken === \"\") {\n\t\t\t\t\t\temailToken = (data as Record<string, unknown>)?.email_token as string | undefined;\n\t\t\t\t\t}\n\t\t\t\t\tnextPaymentDate = (data as Record<string, unknown>)?.next_payment_date as string | undefined;\n\t\t\t\t} catch {\n\t\t\t\t\t// ignore fetch failure? If we can't fetch, we might miss next_payment_date.\n\t\t\t\t}\n\n\t\t\t\tif (emailToken === undefined || emailToken === null || emailToken === \"\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst raw = await paystack.subscriptionManageLink(subscriptionCode);\n\t\t\t\t\t\tconst linkRes = unwrapSdkResult<Record<string, unknown>>(raw);\n\t\t\t\t\t\tconst data = (linkRes as Record<string, unknown> | undefined)?.data ?? linkRes;\n\t\t\t\t\t\tconst link = typeof data === \"string\" ? data : (data as Record<string, unknown>).link;\n\n\t\t\t\t\t\tif (typeof link === \"string\" && link !== \"\") {\n\t\t\t\t\t\t\temailToken = tryGetEmailTokenFromSubscriptionManageLink(link);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// ignore\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (emailToken === undefined || emailToken === null || emailToken === \"\") {\n\t\t\t\t\tthrow new Error(\"Could not retrieve email_token for subscription disable.\");\n\t\t\t\t}\n\n\t\t\t\tawait paystack.subscriptionDisable({ code: subscriptionCode, token: emailToken });\n\n\t\t\t\t// Implement Cancel at Period End logic\n\t\t\t\t// Paystack \"disable\" stops future charges.\n\t\t\t\t// We keep status as \"active\" but set cancelAtPeriodEnd = true\n\n\t\t\t\tconst periodEnd = (nextPaymentDate !== undefined && nextPaymentDate !== null && nextPaymentDate !== \"\") ? new Date(nextPaymentDate) : undefined;\n\n\t\t\t\tconst sub = await ctx.context.adapter.findOne<Subscription>({\n\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\twhere: [{ field: \"paystackSubscriptionCode\", value: subscriptionCode }],\n\t\t\t\t});\n\n\t\t\t\tif (sub !== undefined && sub !== null) {\n\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\tstatus: atPeriodEnd === false ? \"canceled\" : \"active\",\n\t\t\t\t\t\t\tcancelAtPeriodEnd: atPeriodEnd !== false,\n\t\t\t\t\t\t\tperiodEnd,\n\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t},\n\t\t\t\t\t\twhere: [{ field: \"id\", value: sub.id }],\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\t// This is unexpected if we are disabling a subscription that should exist\n\t\t\t\t\tctx.context.logger.warn(`Could not find subscription with code ${subscriptionCode} to disable`);\n\t\t\t\t}\n\n\t\t\t\treturn ctx.json({ status: \"success\" });\n\t\t\t} catch (error: unknown) {\n\t\t\t\tctx.context.logger.error(\"Failed to disable subscription\", error);\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tcode: \"FAILED_TO_DISABLE_SUBSCRIPTION\",\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t(error as Error)?.message ?? PAYSTACK_ERROR_CODES.FAILED_TO_DISABLE_SUBSCRIPTION.message,\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t);\n};\n\nexport const enablePaystackSubscription = <P extends string = \"/paystack/enable-subscription\">(options: AnyPaystackOptions, path: P = \"/paystack/enable-subscription\" as P) => {\n\tconst subscriptionOptions = options.subscription;\n\tconst useMiddlewares = subscriptionOptions?.enabled === true\n\t\t? [sessionMiddleware, originCheck, referenceMiddleware(options, \"enable-subscription\")]\n\t\t: [sessionMiddleware, originCheck];\n\n\treturn createAuthEndpoint(\n\t\tpath,\n\t\t{ method: \"POST\", body: enableDisableBodySchema, use: useMiddlewares },\n\t\tasync (ctx) => {\n\t\t\tconst { subscriptionCode } = ctx.body;\n\t\t\tconst paystack = getPaystackOps(options.paystackClient);\n\t\t\ttry {\n\t\t\t\tlet emailToken = ctx.body.emailToken;\n\t\t\t\tif (emailToken === undefined || emailToken === null || emailToken === \"\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst raw = await paystack.subscriptionFetch(subscriptionCode);\n\t\t\t\t\t\tconst fetchRes = unwrapSdkResult<PaystackSubscriptionResponse>(raw);\n\t\t\t\t\t\tconst data = (fetchRes as { data?: unknown } | undefined)?.data ?? fetchRes;\n\t\t\t\t\t\temailToken = (data as { email_token?: string })?.email_token;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// ignore; try manage-link fallback below\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (emailToken === undefined || emailToken === null || emailToken === \"\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst raw = await paystack.subscriptionManageLink(subscriptionCode);\n\t\t\t\t\t\tconst linkRes = unwrapSdkResult<Record<string, unknown>>(raw);\n\t\t\t\t\t\tconst data = (linkRes as Record<string, unknown> | undefined)?.data ?? linkRes;\n\t\t\t\t\t\tconst link = typeof data === \"string\" ? data : (data as Record<string, unknown>).link;\n\n\t\t\t\t\t\tif (typeof link === \"string\" && link !== \"\") {\n\t\t\t\t\t\t\temailToken = tryGetEmailTokenFromSubscriptionManageLink(link);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// ignore\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (emailToken === undefined || emailToken === null || emailToken === \"\") {\n\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", { message: \"Could not retrieve email_token for subscription enable.\" });\n\t\t\t\t}\n\n\t\t\t\tawait paystack.subscriptionEnable({ code: subscriptionCode, token: emailToken });\n\n\t\t\t\t// Update local status immediately\n\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tstatus: \"active\",\n\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t},\n\t\t\t\t\twhere: [{ field: \"paystackSubscriptionCode\", value: subscriptionCode }],\n\t\t\t\t});\n\n\t\t\t\treturn ctx.json({ status: \"success\" });\n\t\t\t} catch (error: unknown) {\n\t\t\t\tctx.context.logger.error(\"Failed to enable subscription\", error);\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tcode: \"FAILED_TO_ENABLE_SUBSCRIPTION\",\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t(error as Error)?.message ?? PAYSTACK_ERROR_CODES.FAILED_TO_ENABLE_SUBSCRIPTION.message,\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t);\n};\n\nexport const getSubscriptionManageLink = <P extends string = \"/paystack/get-subscription-manage-link\">(options: AnyPaystackOptions, path: P = \"/paystack/get-subscription-manage-link\" as P) => {\n\tconst manageLinkQuerySchema = z.object({\n\t\tsubscriptionCode: z.string(),\n\t});\n\tconst subscriptionOptions = options.subscription;\n\tconst useMiddlewares = subscriptionOptions?.enabled === true\n\t\t? [sessionMiddleware, originCheck, referenceMiddleware(options, \"get-subscription-manage-link\")]\n\t\t: [sessionMiddleware, originCheck];\n\n\tconst handler = async (ctx: GenericEndpointContext) => {\n\t\tconst { subscriptionCode } = ctx.query;\n\n\t\t// If it's a local mock subscription, return null link instead of error\n\t\tif ((subscriptionCode as string).startsWith(\"LOC_\") || (subscriptionCode as string).startsWith(\"sub_local_\")) {\n\t\t\treturn ctx.json({ link: null, message: \"Local subscriptions cannot be managed on Paystack\" });\n\t\t}\n\n\t\tconst paystack = getPaystackOps(options.paystackClient);\n\t\ttry {\n\t\t\tconst raw = await paystack.subscriptionManageLink(subscriptionCode);\n\t\t\tconst res = unwrapSdkResult<Record<string, unknown>>(raw);\n\t\t\tconst data = (res as Record<string, unknown> | undefined)?.data ?? res;\n\t\t\tconst link = typeof data === \"string\" ? data : (data as Record<string, unknown>).link;\n\n\t\t\treturn ctx.json({ link: typeof link === \"string\" ? link : null });\n\t\t} catch (error: unknown) {\n\t\t\tctx.context.logger.error(\"Failed to get subscription manage link\", error);\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: (error as Error)?.message ?? \"Failed to get subscription manage link\",\n\t\t\t});\n\t\t}\n\t};\n\n\treturn createAuthEndpoint(\n\t\tpath,\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tquery: manageLinkQuerySchema,\n\t\t\tuse: useMiddlewares,\n\t\t},\n\t\thandler,\n\t);\n};\n\nexport const syncProducts = (options: AnyPaystackOptions) => {\n\treturn createAuthEndpoint(\n\t\t\"/paystack/sync-products\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t},\n\t\t\tdisableBody: true,\n\t\t\tuse: [sessionMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst paystack = getPaystackOps(options.paystackClient);\n\t\t\ttry {\n\t\t\t\tconst raw = await paystack.productList();\n\t\t\t\tconst dataRaw = unwrapSdkResult<Record<string, unknown>>(raw);\n\t\t\t\t// Standardise access to avoid any warnings\n\t\t\t\tconst productsDataRaw = (dataRaw as { data?: unknown } | undefined)?.data ?? dataRaw;\n\t\t\t\tif (!Array.isArray(productsDataRaw)) {\n\t\t\t\t\treturn ctx.json({ products: [] });\n\t\t\t\t}\n\t\t\t\tconst productsData = productsDataRaw as Record<string, unknown>[];\n\t\t\t\tfor (const productRaw of productsData) {\n\t\t\t\t\tconst product = productRaw as {\n\t\t\t\t\t\tid: number | string;\n\t\t\t\t\t\tname?: string;\n\t\t\t\t\t\tdescription?: string;\n\t\t\t\t\t\tprice?: number;\n\t\t\t\t\t\tcurrency?: string;\n\t\t\t\t\t\tquantity?: number;\n\t\t\t\t\t\tunlimited?: boolean;\n\t\t\t\t\t\tslug?: string;\n\t\t\t\t\t\tmetadata?: Record<string, unknown>;\n\t\t\t\t\t};\n\t\t\t\t\tconst paystackId = String(product.id);\n\t\t\t\t\tconst existing = await ctx.context.adapter.findOne<PaystackProduct>({\n\t\t\t\t\t\tmodel: \"paystackProduct\",\n\t\t\t\t\t\twhere: [{ field: \"paystackId\", value: paystackId }],\n\t\t\t\t\t});\n\n\t\t\t\t\tconst productFields = {\n\t\t\t\t\t\tname: typeof product.name === \"string\" ? product.name : \"\",\n\t\t\t\t\t\tdescription: typeof product.description === \"string\" ? product.description : \"\",\n\t\t\t\t\t\tprice: typeof product.price === \"number\" ? product.price : 0,\n\t\t\t\t\t\tcurrency: typeof product.currency === \"string\" ? product.currency : \"\",\n\t\t\t\t\t\tquantity: typeof product.quantity === \"number\" ? product.quantity : 0,\n\t\t\t\t\t\tunlimited: product.unlimited === true,\n\t\t\t\t\t\tpaystackId,\n\t\t\t\t\t\tslug: (typeof product.slug === \"string\" && product.slug !== \"\") ? product.slug : (typeof product.name === \"string\" ? product.name.toLowerCase().replace(/\\s+/g, \"-\") : \"\"),\n\t\t\t\t\t\tmetadata: (product.metadata !== undefined && product.metadata !== null) ? JSON.stringify(product.metadata) : undefined,\n\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t};\n\n\t\t\t\t\tif (existing !== null && existing !== undefined) {\n\t\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\t\tmodel: \"paystackProduct\",\n\t\t\t\t\t\t\tupdate: productFields,\n\t\t\t\t\t\t\twhere: [{ field: \"id\", value: existing.id }],\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tawait ctx.context.adapter.create({\n\t\t\t\t\t\t\tmodel: \"paystackProduct\",\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t...productFields,\n\t\t\t\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn ctx.json({ status: \"success\", count: productsData.length });\n\t\t\t} catch (error: unknown) {\n\t\t\t\tctx.context.logger.error(\"Failed to sync products\", error);\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: (error as Error)?.message ?? \"Failed to sync products\",\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t);\n};\n\nexport const listProducts = (_options: AnyPaystackOptions) => {\n\treturn createAuthEndpoint(\n\t\t\"/paystack/list-products\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"listPaystackProducts\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst res = await ctx.context.adapter.findMany<PaystackProduct>({\n\t\t\t\tmodel: \"paystackProduct\",\n\t\t\t});\n\t\t\tconst sorted = res.sort((a: PaystackProduct, b: PaystackProduct) => a.name.localeCompare(b.name));\n\t\t\treturn ctx.json({ products: sorted });\n\t\t}\n\t);\n};\n\n\nexport const syncPlans = (options: AnyPaystackOptions) => {\n\treturn createAuthEndpoint(\n\t\t\"/paystack/sync-plans\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t},\n\t\t\tdisableBody: true,\n\t\t\tuse: [sessionMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst paystack = getPaystackOps(options.paystackClient);\n\t\t\ttry {\n\t\t\t\tconst raw = await paystack.planList();\n\t\t\t\tconst res = unwrapSdkResult<Record<string, unknown>>(raw);\n\t\t\t\tconst plansData = (res as { data?: unknown } | undefined)?.data ?? res;\n\n\t\t\t\tif (!Array.isArray(plansData)) {\n\t\t\t\t\treturn ctx.json({ status: \"success\", count: 0 });\n\t\t\t\t}\n\n\t\t\t\tfor (const plan of plansData) {\n\t\t\t\t\tconst paystackId = String(plan.id);\n\t\t\t\t\tconst existing = await ctx.context.adapter.findOne<PaystackPlan>({\n\t\t\t\t\t\tmodel: \"paystackPlan\",\n\t\t\t\t\t\twhere: [{ field: \"paystackId\", value: paystackId }],\n\t\t\t\t\t});\n\n\t\t\t\t\tconst planData = {\n\t\t\t\t\t\tname: plan.name,\n\t\t\t\t\t\tdescription: plan.description,\n\t\t\t\t\t\tamount: plan.amount,\n\t\t\t\t\t\tcurrency: plan.currency,\n\t\t\t\t\t\tinterval: plan.interval,\n\t\t\t\t\t\tplanCode: plan.plan_code,\n\t\t\t\t\t\tpaystackId,\n\t\t\t\t\t\tmetadata: (plan.metadata !== undefined && plan.metadata !== null) ? JSON.stringify(plan.metadata) : undefined,\n\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t};\n\n\t\t\t\t\tif (existing !== undefined && existing !== null) {\n\t\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\t\tmodel: \"paystackPlan\",\n\t\t\t\t\t\t\tupdate: planData,\n\t\t\t\t\t\t\twhere: [{ field: \"id\", value: existing.id }],\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tawait ctx.context.adapter.create({\n\t\t\t\t\t\t\tmodel: \"paystackPlan\",\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t...planData,\n\t\t\t\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn ctx.json({ status: \"success\", count: plansData.length });\n\t\t\t} catch (error: unknown) {\n\t\t\t\tctx.context.logger.error(\"Failed to sync plans\", error);\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: (error as Error)?.message ?? \"Failed to sync plans\",\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t);\n};\n\nexport const listPlans = (_options: AnyPaystackOptions) => {\n\treturn createAuthEndpoint(\n\t\t\"/paystack/list-plans\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t},\n\t\t\tuse: [sessionMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\ttry {\n\t\t\t\tconst plans = await ctx.context.adapter.findMany<PaystackPlan>({\n\t\t\t\t\tmodel: \"paystackPlan\",\n\t\t\t\t});\n\t\t\t\treturn ctx.json({ plans });\n\t\t\t} catch (error: unknown) {\n\t\t\t\tctx.context.logger.error(\"Failed to list plans\", error);\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: (error as Error)?.message ?? \"Failed to list plans\",\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t);\n};\n\nexport const getConfig = (options: AnyPaystackOptions) => {\n\treturn createAuthEndpoint(\n\t\t\"/paystack/get-config\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"getPaystackConfig\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tasync (ctx: GenericEndpointContext) => {\n\t\t\tconst plans = options.subscription?.enabled === true\n\t\t\t\t? await getPlans(options.subscription)\n\t\t\t\t: [];\n\t\t\tconst products = await getProducts(options.products);\n\t\t\treturn ctx.json({\n\t\t\t\tplans,\n\t\t\t\tproducts,\n\t\t\t});\n\t\t}\n\t);\n};\n\nexport { PAYSTACK_ERROR_CODES };\nexport const chargeRecurringSubscription = (options: AnyPaystackOptions) => {\n\treturn createAuthEndpoint(\n\t\t\"/paystack/charge-recurring\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tbody: z.object({\n\t\t\t\tsubscriptionId: z.string(),\n\t\t\t\tamount: z.number().optional(),\n\t\t\t}),\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst { subscriptionId, amount: bodyAmount } = ctx.body;\n\t\t\tconst subscription = await ctx.context.adapter.findOne<Subscription>({\n\t\t\t\tmodel: \"subscription\",\n\t\t\t\twhere: [{ field: \"id\", value: subscriptionId }],\n\t\t\t});\n\n\t\t\tif (subscription === undefined || subscription === null) {\n\t\t\t\tthrow new APIError(\"NOT_FOUND\", { message: \"Subscription not found\" });\n\t\t\t}\n\n\t\t\tif (subscription.paystackAuthorizationCode === undefined || subscription.paystackAuthorizationCode === null || subscription.paystackAuthorizationCode === \"\") {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", { message: \"No authorization code found for this subscription\" });\n\t\t\t}\n\n\t\t\tconst plans = await getPlans(options.subscription);\n\t\t\tconst plan = plans.find((p) => p.name.toLowerCase() === subscription.plan.toLowerCase());\n\n\t\t\tif (!plan) {\n\t\t\t\tthrow new APIError(\"NOT_FOUND\", { message: \"Plan not found\" });\n\t\t\t}\n\n\t\t\tconst amount = bodyAmount ?? plan.amount;\n\t\t\tif (amount === undefined || amount === null) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", { message: \"Plan amount is not defined\" });\n\t\t\t}\n\n\t\t\tlet email: string | null | undefined;\n\t\t\tif (subscription.referenceId !== undefined && subscription.referenceId !== null && subscription.referenceId !== \"\") {\n\t\t\t\t// Try to find user or org\n\t\t\t\tconst user = await ctx.context.adapter.findOne<User>({\n\t\t\t\t\tmodel: \"user\",\n\t\t\t\t\twhere: [{ field: \"id\", value: subscription.referenceId }],\n\t\t\t\t});\n\t\t\t\tif (user !== undefined && user !== null) {\n\t\t\t\t\temail = user.email;\n\t\t\t\t} else if (options.organization?.enabled === true) {\n\t\t\t\t\t// Check org owner email if referenceId is organizationId\n\t\t\t\t\tconst ownerMember = await ctx.context.adapter.findOne<Member>({\n\t\t\t\t\t\tmodel: \"member\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{ field: \"organizationId\", value: subscription.referenceId },\n\t\t\t\t\t\t\t{ field: \"role\", value: \"owner\" },\n\t\t\t\t\t\t],\n\t\t\t\t\t});\n\t\t\t\t\tif (ownerMember !== undefined && ownerMember !== null) {\n\t\t\t\t\t\tconst ownerUser = await ctx.context.adapter.findOne<User>({\n\t\t\t\t\t\t\tmodel: \"user\",\n\t\t\t\t\t\t\twhere: [{ field: \"id\", value: ownerMember.userId }],\n\t\t\t\t\t\t});\n\t\t\t\t\t\temail = ownerUser?.email;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// No fallback needed since referenceId is required and handled above\n\t\t\tif (email === undefined || email === null || email === \"\") {\n\t\t\t\tthrow new APIError(\"NOT_FOUND\", { message: \"User email not found\" });\n\t\t\t}\n\n\t\t\tconst finalCurrency = plan.currency ?? \"NGN\";\n\t\t\tif (!validateMinAmount(amount, finalCurrency)) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: `Amount ${amount} is less than the minimum required for ${finalCurrency}.`,\n\t\t\t\t\tstatus: 400\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst paystack = getPaystackOps(options.paystackClient);\n\t\t\tconst chargeResRaw = await paystack.transactionChargeAuthorization({\n\t\t\t\temail,\n\t\t\t\tamount,\n\t\t\t\tauthorization_code: subscription.paystackAuthorizationCode,\n\t\t\t\tcurrency: plan.currency as PaystackCurrency,\n\t\t\t\tmetadata: {\n\t\t\t\t\tsubscriptionId,\n\t\t\t\t\treferenceId: subscription.referenceId,\n\t\t\t\t\tplan: plan.name,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tconst dataRaw = unwrapSdkResult<PaystackTransactionResponse>(chargeResRaw);\n\t\t\tconst chargeData = (dataRaw as Record<string, unknown> | undefined)?.data ?? dataRaw;\n\n\t\t\tif ((chargeData as Record<string, unknown> | undefined)?.status === \"success\" || (dataRaw as Record<string, unknown> | undefined)?.status === \"success\") {\n\t\t\t\tconst now = new Date();\n\t\t\t\tconst nextPeriodEnd = getNextPeriodEnd(now, plan.interval ?? \"monthly\");\n\n\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tperiodStart: now,\n\t\t\t\t\t\tperiodEnd: nextPeriodEnd,\n\t\t\t\t\t\tupdatedAt: now,\n\t\t\t\t\t\t// Record the last transaction reference if available\n\t\t\t\t\t\tpaystackTransactionReference: (chargeData as Record<string, unknown> | undefined)?.reference as string | undefined ?? (dataRaw as Record<string, unknown> | undefined)?.reference as string | undefined,\n\t\t\t\t\t},\n\t\t\t\t\twhere: [{ field: \"id\", value: subscription.id }],\n\t\t\t\t});\n\n\t\t\t\treturn ctx.json({ status: \"success\", data: chargeData });\n\t\t\t}\n\n\t\t\treturn ctx.json({ status: \"failed\", data: chargeData }, { status: 400 });\n\t\t},\n\t);\n};\n","import type { BetterAuthPluginDBSchema } from \"@better-auth/core/db\";\nimport { mergeSchema } from \"better-auth/db\";\n\nimport type { PaystackClientLike, PaystackOptions } from \"./types\";\n\nexport const transactions = {\n\tpaystackTransaction: {\n\t\tfields: {\n\t\t\treference: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t\tunique: true,\n\t\t\t},\n\t\t\tpaystackId: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\treferenceId: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t\tindex: true,\n\t\t\t},\n\t\t\tuserId: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t\tindex: true,\n\t\t\t},\n\t\t\tamount: {\n\t\t\t\ttype: \"number\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tcurrency: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tstatus: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tplan: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tproduct: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tmetadata: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tcreatedAt: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tupdatedAt: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t},\n\t},\n} satisfies BetterAuthPluginDBSchema;\n\nexport const subscriptions = {\n\tsubscription: {\n\t\tfields: {\n\t\t\tplan: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t\tindex: true,\n\t\t\t},\n\t\t\treferenceId: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t\tindex: true,\n\t\t\t},\n\t\t\tpaystackCustomerCode: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t\tindex: true,\n\t\t\t},\n\t\t\tpaystackSubscriptionCode: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t\tunique: true,\n\t\t\t},\n\t\t\tpaystackTransactionReference: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t\tindex: true,\n\t\t\t},\n\t\t\tpaystackAuthorizationCode: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tpaystackEmailToken: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tstatus: {\n\t\t\t\ttype: \"string\",\n\t\t\t\tdefaultValue: \"incomplete\",\n\t\t\t},\n\t\t\tperiodStart: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tperiodEnd: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\ttrialStart: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\ttrialEnd: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tcancelAtPeriodEnd: {\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trequired: false,\n\t\t\t\tdefaultValue: false,\n\t\t\t},\n\t\t\tgroupId: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tseats: {\n\t\t\t\ttype: \"number\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tpendingPlan: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t},\n\t},\n} satisfies BetterAuthPluginDBSchema;\n\nexport const user = {\n\tuser: {\n\t\tfields: {\n\t\t\tpaystackCustomerCode: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t\tindex: true,\n\t\t\t},\n\t\t},\n\t},\n} satisfies BetterAuthPluginDBSchema;\n\nexport const organization = {\n\torganization: {\n\t\tfields: {\n\t\t\tpaystackCustomerCode: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t\tindex: true,\n\t\t\t},\n\t\t\temail: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t},\n\t},\n} satisfies BetterAuthPluginDBSchema;\n\nexport const products = {\n\tpaystackProduct: {\n\t\tfields: {\n\t\t\tname: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tdescription: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tprice: {\n\t\t\t\ttype: \"number\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tcurrency: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tquantity: {\n\t\t\t\ttype: \"number\",\n\t\t\t\trequired: false,\n\t\t\t\tdefaultValue: 0,\n\t\t\t},\n\t\t\tunlimited: {\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trequired: false,\n\t\t\t\tdefaultValue: true,\n\t\t\t},\n\t\t\tpaystackId: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t\tunique: true,\n\t\t\t},\n\t\t\tslug: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t\tunique: true,\n\t\t\t},\n\t\t\tmetadata: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tcreatedAt: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tupdatedAt: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t},\n\t},\n} satisfies BetterAuthPluginDBSchema;\n\nexport const plans = {\n\tpaystackPlan: {\n\t\tfields: {\n\t\t\tname: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tdescription: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tamount: {\n\t\t\t\ttype: \"number\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tcurrency: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tinterval: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tplanCode: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t\tunique: true,\n\t\t\t},\n\t\t\tpaystackId: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t\tunique: true,\n\t\t\t},\n\t\t\tmetadata: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tcreatedAt: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tupdatedAt: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t},\n\t},\n} satisfies BetterAuthPluginDBSchema;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const getSchema = (options: PaystackOptions<PaystackClientLike, any, any>) => {\n\tlet baseSchema: BetterAuthPluginDBSchema;\n\n\tif (options.subscription?.enabled === true) {\n\t\tbaseSchema = {\n\t\t\t...subscriptions,\n\t\t\t...transactions,\n\t\t\t...user,\n\t\t\t...products,\n\t\t\t...plans,\n\t\t};\n\t} else {\n\t\tbaseSchema = {\n\t\t\t...user,\n\t\t\t...transactions,\n\t\t\t...products,\n\t\t\t...plans,\n\t\t};\n\t}\n\n\t// Add organization schema if organization support is enabled\n\tif (options.organization?.enabled === true) {\n\t\tbaseSchema = {\n\t\t\t...baseSchema,\n\t\t\t...organization,\n\t\t};\n\t}\n\n\tif (\n\t\toptions.schema !== undefined &&\n\t\toptions.subscription?.enabled !== true &&\n\t\t\"subscription\" in options.schema\n\t) {\n\t\tconst { subscription: _subscription, ...restSchema } = options.schema as Record<string, unknown>;\n\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\treturn mergeSchema(baseSchema, restSchema as any);\n\t}\n\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\treturn mergeSchema(baseSchema, options.schema as any);\n};\n","import { defineErrorCodes } from \"@better-auth/core/utils/error-codes\";\nimport type { AuthContext, GenericEndpointContext } from \"better-auth\";\nimport { defu } from \"defu\";\n\nimport {\n\tdisablePaystackSubscription,\n\tenablePaystackSubscription,\n\tinitializeTransaction,\n\tlistSubscriptions,\n\tlistTransactions,\n\tpaystackWebhook,\n\tverifyTransaction,\n\tgetConfig,\n\tgetSubscriptionManageLink,\n\tPAYSTACK_ERROR_CODES,\n\tcreateSubscription,\n\tupgradeSubscription,\n\tcancelSubscription,\n\trestoreSubscription,\n\tchargeRecurringSubscription,\n\tsyncProducts,\n\tlistProducts,\n\tsyncPlans,\n\tlistPlans,\n} from \"./routes\";\nimport { getSchema } from \"./schema\";\nimport { checkSeatLimit, checkTeamLimit, getOrganizationSubscription } from \"./limits\";\nimport { getPlanByName, syncSubscriptionSeats } from \"./utils\";\nimport type {\n\tPaystackNodeClient,\n\tPaystackClientLike,\n\tPaystackOptions,\n\tPaystackPlan,\n\tSubscription,\n\tSubscriptionOptions,\n\tPaystackProduct,\n\tPaystackCustomerResponse,\n\tMember,\n\tAnyPaystackOptions,\n\tUser,\n} from \"./types\";\nimport { getPaystackOps, unwrapSdkResult } from \"./paystack-sdk\";\n\nconst INTERNAL_ERROR_CODES = defineErrorCodes({\n\t...Object.fromEntries(\n\t\tObject.entries(PAYSTACK_ERROR_CODES).map(([key, value]) => [\n\t\t\tkey,\n\t\t\ttypeof value === \"string\" ? value : (value as { message: string }).message,\n\t\t]),\n\t),\n});\n\nexport const paystack = <\n\tTPaystackClient extends PaystackClientLike = PaystackNodeClient,\n\tTMetadata extends Record<string, unknown> = Record<string, unknown>,\n\tTLimits extends Record<string, unknown> = Record<string, unknown>,\n\tO extends PaystackOptions<TPaystackClient, TMetadata, TLimits> = PaystackOptions<TPaystackClient, TMetadata, TLimits>,\n>(\n\t\toptions: O,\n\t) => {\n\tconst routeOptions = options as unknown as AnyPaystackOptions;\n\tconst res = {\n\t\tid: \"paystack\",\n\t\tendpoints: {\n\t\t\tinitializeTransaction: initializeTransaction(routeOptions),\n\t\t\tverifyTransaction: verifyTransaction(routeOptions),\n\t\t\tlistSubscriptions: listSubscriptions(routeOptions),\n\t\t\tpaystackWebhook: paystackWebhook(routeOptions),\n\t\t\tlistTransactions: listTransactions(routeOptions),\n\t\t\tgetConfig: getConfig(routeOptions),\n\t\t\tdisableSubscription: disablePaystackSubscription(routeOptions),\n\t\t\tenableSubscription: enablePaystackSubscription(routeOptions),\n\t\t\tgetSubscriptionManageLink: getSubscriptionManageLink(routeOptions),\n\t\t\tsubscriptionManageLink: getSubscriptionManageLink(routeOptions, \"/paystack/subscription/manage-link\"), // Historical alias\n\t\t\tcreateSubscription: createSubscription(routeOptions),\n\t\t\tupgradeSubscription: upgradeSubscription(routeOptions),\n\t\t\tcancelSubscription: cancelSubscription(routeOptions),\n\t\t\trestoreSubscription: restoreSubscription(routeOptions),\n\t\t\tchargeRecurringSubscription: chargeRecurringSubscription(routeOptions),\n\t\t\tsyncProducts: syncProducts(routeOptions),\n\t\t\tlistProducts: listProducts(routeOptions),\n\t\t\tsyncPlans: syncPlans(routeOptions),\n\t\t\tlistPlans: listPlans(routeOptions),\n\t\t},\n\t\tschema: getSchema(options),\n\t\tinit: (ctx: AuthContext) => {\n\t\t\treturn {\n\t\t\t\toptions: {\n\t\t\t\t\tdatabaseHooks: {\n\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\tcreate: {\n\t\t\t\t\t\t\t\tasync after(user: { id: string; email?: string | null; name?: string | null }, hookCtx?: GenericEndpointContext | null) {\n\t\t\t\t\t\t\t\t\tif (!hookCtx || options.createCustomerOnSignUp !== true || user.email === null || user.email === undefined || user.email === \"\") return;\n\n\t\t\t\t\t\t\t\t\tconst paystackOps = getPaystackOps(options.paystackClient as PaystackClientLike);\n\t\t\t\t\t\t\t\t\tconst raw = await paystackOps.customerCreate({\n\t\t\t\t\t\t\t\t\t\temail: user.email,\n\t\t\t\t\t\t\t\t\t\tfirst_name: user.name ?? undefined,\n\t\t\t\t\t\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t\t\t\t\t\tuserId: user.id,\n\t\t\t\t\t\t\t\t\t\t} as Record<string, unknown>,\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\tconst sdkRes = unwrapSdkResult<PaystackCustomerResponse>(raw);\n\t\t\t\t\t\t\t\t\tconst customerCode = (sdkRes?.customer_code as string | undefined)\n\t\t\t\t\t\t\t\t\t\t?? (sdkRes?.data as Record<string, unknown>)?.customer_code as string | undefined;\n\n\t\t\t\t\t\t\t\t\tif (customerCode === \"\" || customerCode === null || customerCode === undefined) {\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tawait ctx.adapter.update({\n\t\t\t\t\t\t\t\t\t\tmodel: \"user\",\n\t\t\t\t\t\t\t\t\t\twhere: [{ field: \"id\", value: user.id }],\n\t\t\t\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\t\t\t\tpaystackCustomerCode: customerCode,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\torganization: options.organization?.enabled === true\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tcreate: {\n\t\t\t\t\t\t\t\t\tasync after(org: { id: string; name: string; email?: string | null }, hookCtx: GenericEndpointContext | null) {\n\t\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t\tconst extraCreateParams = options.organization?.getCustomerCreateParams\n\t\t\t\t\t\t\t\t\t\t\t\t? await options.organization.getCustomerCreateParams(org, hookCtx!)\n\t\t\t\t\t\t\t\t\t\t\t\t: {};\n\n\t\t\t\t\t\t\t\t\t\t\tlet targetEmail = org.email;\n\t\t\t\t\t\t\t\t\t\t\tif (targetEmail === undefined || targetEmail === null) {\n\t\t\t\t\t\t\t\t\t\t\t\tconst ownerMember = await ctx.adapter.findOne<Member>({\n\t\t\t\t\t\t\t\t\t\t\t\t\tmodel: \"member\",\n\t\t\t\t\t\t\t\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{ field: \"organizationId\", value: org.id },\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{ field: \"role\", value: \"owner\" }\n\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t\t\tif (ownerMember) {\n\t\t\t\t\t\t\t\t\t\t\t\t\tconst ownerUser = await ctx.adapter.findOne<User>({\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tmodel: \"user\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\twhere: [{ field: \"id\", value: ownerMember.userId }]\n\t\t\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t\t\t\ttargetEmail = ownerUser?.email;\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\tif (targetEmail === undefined || targetEmail === null) return;\n\n\t\t\t\t\t\t\t\t\t\t\tconst params = defu(\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\temail: targetEmail,\n\t\t\t\t\t\t\t\t\t\t\t\t\tfirst_name: org.name,\n\t\t\t\t\t\t\t\t\t\t\t\t\tmetadata: { organizationId: org.id },\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\textraCreateParams,\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\tconst paystackOps = getPaystackOps(options.paystackClient as PaystackClientLike);\n\t\t\t\t\t\t\t\t\t\t\tconst raw = await paystackOps.customerCreate(params as unknown as Parameters<typeof paystackOps.customerCreate>[0]);\n\t\t\t\t\t\t\t\t\t\t\tconst sdkRes = unwrapSdkResult<PaystackCustomerResponse>(raw);\n\t\t\t\t\t\t\t\t\t\t\tconst customerCode = (sdkRes?.customer_code as string | undefined)\n\t\t\t\t\t\t\t\t\t\t\t\t?? (sdkRes?.data as Record<string, unknown>)?.customer_code as string | undefined;\n\n\t\t\t\t\t\t\t\t\t\t\tif (customerCode === \"\" || customerCode === null || customerCode === undefined || sdkRes === null || sdkRes === undefined) return;\n\n\t\t\t\t\t\t\t\t\t\t\tawait (ctx.internalAdapter as unknown as { updateOrganization: (id: string, data: Record<string, unknown>) => Promise<void> }).updateOrganization(org.id, {\n\t\t\t\t\t\t\t\t\t\t\t\tpaystackCustomerCode: customerCode,\n\t\t\t\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\t\t\t\tawait options.organization?.onCustomerCreate?.(\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tpaystackCustomer: sdkRes,\n\t\t\t\t\t\t\t\t\t\t\t\t\torganization: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t...org,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tpaystackCustomerCode: customerCode,\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\thookCtx!,\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t} catch (error: unknown) {\n\t\t\t\t\t\t\t\t\t\t\t(ctx as unknown as AuthContext).logger.error(\"Failed to create Paystack customer for organization\", error);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t},\n\t\t\t\t\tmember: {\n\t\t\t\t\t\tcreate: {\n\t\t\t\t\t\t\tbefore: async (member: { organizationId: string }, ctx: GenericEndpointContext | null | undefined) => {\n\t\t\t\t\t\t\t\tif (options.subscription?.enabled === true && member.organizationId && ctx !== null && ctx !== undefined) {\n\t\t\t\t\t\t\t\t\tawait checkSeatLimit(ctx, member.organizationId);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tafter: async (member: { organizationId: string | undefined }, ctx: GenericEndpointContext | null | undefined) => {\n\t\t\t\t\t\t\t\tif (options.subscription?.enabled === true && typeof member?.organizationId === \"string\" && ctx) {\n\t\t\t\t\t\t\t\t\tawait syncSubscriptionSeats(ctx, member.organizationId, routeOptions);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tdelete: {\n\t\t\t\t\t\t\tafter: async (member: { organizationId: string | undefined }, ctx: GenericEndpointContext | null | undefined) => {\n\t\t\t\t\t\t\t\tif (options.subscription?.enabled === true && typeof member?.organizationId === \"string\" && ctx) {\n\t\t\t\t\t\t\t\t\tawait syncSubscriptionSeats(ctx, member.organizationId, routeOptions);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tinvitation: {\n\t\t\t\t\t\tcreate: {\n\t\t\t\t\t\t\tbefore: async (invitation: { organizationId: string }, ctx: GenericEndpointContext | null | undefined) => {\n\t\t\t\t\t\t\t\tif (options.subscription?.enabled === true && invitation.organizationId && ctx !== null && ctx !== undefined) {\n\t\t\t\t\t\t\t\t\tawait checkSeatLimit(ctx, invitation.organizationId);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tafter: async (invitation: { organizationId: string | undefined }, ctx: GenericEndpointContext | null | undefined) => {\n\t\t\t\t\t\t\t\tif (options.subscription?.enabled === true && typeof invitation?.organizationId === \"string\" && ctx) {\n\t\t\t\t\t\t\t\t\tawait syncSubscriptionSeats(ctx, invitation.organizationId, routeOptions);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tdelete: {\n\t\t\t\t\t\t\tafter: async (invitation: { organizationId: string | undefined }, ctx: GenericEndpointContext | null | undefined) => {\n\t\t\t\t\t\t\t\tif (options.subscription?.enabled === true && typeof invitation?.organizationId === \"string\" && ctx) {\n\t\t\t\t\t\t\t\t\tawait syncSubscriptionSeats(ctx, invitation.organizationId, routeOptions);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tteam: {\n\t\t\t\t\t\tcreate: {\n\t\t\t\t\t\t\tbefore: async (team: { organizationId: string }, ctx: GenericEndpointContext | null | undefined) => {\n\t\t\t\t\t\t\t\tif (options.subscription?.enabled === true && team.organizationId && ctx) {\n\t\t\t\t\t\t\t\t\tconst subscription = await getOrganizationSubscription(ctx, team.organizationId);\n\t\t\t\t\t\t\t\t\tif (subscription) {\n\t\t\t\t\t\t\t\t\t\tconst plan = await getPlanByName(routeOptions, subscription.plan);\n\t\t\t\t\t\t\t\t\t\tconst limits = plan?.limits;\n\t\t\t\t\t\t\t\t\t\tconst maxTeams = limits?.teams as number | undefined;\n\n\t\t\t\t\t\t\t\t\t\tif (typeof maxTeams === \"number\") {\n\t\t\t\t\t\t\t\t\t\t\tawait checkTeamLimit(ctx, team.organizationId, maxTeams);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\t$ERROR_CODES: INTERNAL_ERROR_CODES,\n\t};\n\n\treturn res;\n};\n\nexport type PaystackPlugin<\n\tTPaystackClient extends PaystackClientLike = PaystackNodeClient,\n\tTMetadata extends Record<string, unknown> = Record<string, unknown>,\n\tTLimits extends Record<string, unknown> = Record<string, unknown>,\n\tO extends PaystackOptions<TPaystackClient, TMetadata, TLimits> = PaystackOptions<TPaystackClient, TMetadata, TLimits>,\n> = ReturnType<\n\ttypeof paystack<TPaystackClient, TMetadata, TLimits, O>\n>;\n\nexport type { Subscription, SubscriptionOptions, PaystackPlan, PaystackOptions, PaystackProduct };\n"],"mappings":"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N,UAAU;EACV;CACD,oBAAoB;EACnB,MAAM;EACN,UAAU;EACV;CACD,QAAQ;EACP,MAAM;EACN,cAAc;EACd;CACD,aAAa;EACZ,MAAM;EACN,UAAU;EACV;CACD,WAAW;EACV,MAAM;EACN,UAAU;EACV;CACD,YAAY;EACX,MAAM;EACN,UAAU;EACV;CACD,UAAU;EACT,MAAM;EACN,UAAU;EACV;CACD,mBAAmB;EAClB,MAAM;EACN,UAAU;EACV,cAAc;EACd;CACD,SAAS;EACR,MAAM;EACN,UAAU;EACV;CACD,OAAO;EACN,MAAM;EACN,UAAU;EACV;CACD,aAAa;EACZ,MAAM;EACN,UAAU;EACV;CACD,EACD,EACD;AAED,MAAa,OAAO,EACnB,MAAM,EACL,QAAQ,EACP,sBAAsB;CACrB,MAAM;CACN,UAAU;CACV,OAAO;CACP,EACD,EACD,EACD;AAED,MAAa,eAAe,EAC3B,cAAc,EACb,QAAQ;CACP,sBAAsB;EACrB,MAAM;EACN,UAAU;EACV,OAAO;EACP;CACD,OAAO;EACN,MAAM;EACN,UAAU;EACV;CACD,EACD,EACD;AAED,MAAa,WAAW,EACvB,iBAAiB,EAChB,QAAQ;CACP,MAAM;EACL,MAAM;EACN,UAAU;EACV;CACD,aAAa;EACZ,MAAM;EACN,UAAU;EACV;CACD,OAAO;EACN,MAAM;EACN,UAAU;EACV;CACD,UAAU;EACT,MAAM;EACN,UAAU;EACV;CACD,UAAU;EACT,MAAM;EACN,UAAU;EACV,cAAc;EACd;CACD,WAAW;EACV,MAAM;EACN,UAAU;EACV,cAAc;EACd;CACD,YAAY;EACX,MAAM;EACN,UAAU;EACV,QAAQ;EACR;CACD,MAAM;EACL,MAAM;EACN,UAAU;EACV,QAAQ;EACR;CACD,UAAU;EACT,MAAM;EACN,UAAU;EACV;CACD,WAAW;EACV,MAAM;EACN,UAAU;EACV;CACD,WAAW;EACV,MAAM;EACN,UAAU;EACV;CACD,EACD,EACD;AAED,MAAa,QAAQ,EACpB,cAAc,EACb,QAAQ;CACP,MAAM;EACL,MAAM;EACN,UAAU;EACV;CACD,aAAa;EACZ,MAAM;EACN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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/paystack-sdk.ts","../src/utils.ts","../src/middleware.ts","../src/limits.ts","../src/routes.ts","../src/schema.ts","../src/operations.ts","../src/index.ts"],"sourcesContent":["import { APIError } from \"better-auth/api\";\nimport { PaystackResponse } 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 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","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 { unwrapSdkResult } 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 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 // Find the local product record (by name or slug)\n let localProduct = await ctx.context.adapter.findOne<PaystackProduct>({\n model: \"paystackProduct\",\n where: [{ field: \"name\", value: productName }],\n });\n\n localProduct ??= await ctx.context.adapter.findOne<PaystackProduct>({\n model: \"paystackProduct\",\n where: [{ field: \"slug\", value: productName.toLowerCase().replace(/\\s+/g, \"-\") }],\n });\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 ctx.context.adapter.update({\n model: \"paystackProduct\",\n update: { quantity: localProduct.quantity - 1, updatedAt: new Date() },\n where: [{ field: \"id\", value: localProduct.id }],\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 raw = await paystackClient.product?.fetch(paystackProductId);\n const sdkRes = unwrapSdkResult<PaystackProductResponse>(raw);\n const remoteQuantity = sdkRes?.quantity;\n\n if (remoteQuantity !== undefined && localProduct.id !== undefined) {\n await ctx.context.adapter.update({\n model: \"paystackProduct\",\n update: { quantity: remoteQuantity, updatedAt: new Date() },\n where: [{ field: \"id\", value: localProduct.id }],\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 ctx.context.adapter.update({\n model: \"paystackProduct\",\n update: { quantity: localProduct.quantity - 1, updatedAt: new Date() },\n where: [{ field: \"id\", value: localProduct.id }],\n });\n }\n }\n}\n\nexport async function decrementProductQuantity(\n ctx: GenericEndpointContext,\n productName: string,\n): Promise<void> {\n let product = await ctx.context.adapter.findOne<PaystackProduct>({\n model: \"paystackProduct\",\n where: [{ field: \"name\", value: productName }],\n });\n\n product ??= await ctx.context.adapter.findOne<PaystackProduct>({\n model: \"paystackProduct\",\n where: [{ field: \"slug\", value: productName.toLowerCase().replace(/\\s+/g, \"-\") }],\n });\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 ctx.context.adapter.update({\n model: \"paystackProduct\",\n update: {\n quantity: product.quantity - 1,\n updatedAt: new Date(),\n },\n where: [{ field: \"id\", value: product.id }],\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 adapter = ctx.context.adapter;\n const subscription = await adapter.findOne<Subscription>({\n model: \"subscription\",\n where: [{ field: \"referenceId\", value: organizationId }],\n });\n\n if (\n subscription?.paystackSubscriptionCode === undefined ||\n subscription.paystackSubscriptionCode === null ||\n subscription.paystackSubscriptionCode === \"\"\n )\n return;\n if (subscription === null || subscription === undefined) return;\n const plan = await getPlanByName(options, subscription.plan);\n if (plan === null || plan === undefined) return;\n const seatAmount = getPlanSeatAmount(plan);\n if (seatAmount === undefined) return;\n\n const members = await adapter.findMany({\n model: \"member\",\n where: [{ field: \"organizationId\", value: organizationId }],\n });\n\n const quantity = members.length;\n\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 adapter.update({\n model: \"subscription\",\n where: [{ field: \"id\", value: subscription.id }],\n update: {\n seats: quantity,\n updatedAt: new Date(),\n },\n });\n } catch (e: unknown) {\n const log = ctx.context.logger;\n if (log !== undefined && log !== null) {\n log.error(\"Failed to sync subscription seats\", e);\n }\n }\n}\n","import { createAuthMiddleware, type AuthMiddleware } from \"@better-auth/core/api\";\nimport { logger } from \"better-auth\";\nimport { APIError } from \"better-auth/api\";\n\nimport type { PaystackOptions, Session, User } from \"./types\";\n\nexport const referenceMiddleware = (\n options: PaystackOptions,\n action:\n | \"initialize-transaction\"\n | \"verify-transaction\"\n | \"list-subscriptions\"\n | \"list-transactions\"\n | \"disable-subscription\"\n | \"enable-subscription\"\n | \"get-subscription-manage-link\",\n): AuthMiddleware =>\n createAuthMiddleware(async (ctx) => {\n const session = ctx.context.session as {\n user: User;\n session: Session;\n } | null;\n\n if (session === null || session === undefined) {\n throw new APIError(\"UNAUTHORIZED\");\n }\n const body = (ctx.body ?? {}) as Record<string, unknown>;\n const query = (ctx.query ?? {}) as Record<string, unknown>;\n const referenceId =\n (body.referenceId as string | undefined) ??\n (query.referenceId as string | undefined) ??\n session.user.id;\n\n const subscriptionOptions = options.subscription;\n\n if (referenceId === session.user.id) {\n return {\n referenceId,\n };\n }\n\n // 1. Try custom authorization first if provided\n if (\n subscriptionOptions?.enabled === true &&\n \"authorizeReference\" in subscriptionOptions &&\n typeof subscriptionOptions.authorizeReference === \"function\"\n ) {\n const authorized = await subscriptionOptions.authorizeReference(\n {\n user: session.user,\n session: session.session,\n referenceId,\n action,\n },\n ctx,\n );\n if (authorized === true) {\n return {\n referenceId,\n };\n }\n // If explicit authorizeReference returns false, do we fail immediately?\n // Usually yes, but maybe we fallback to org check?\n // Let's assume authorizeReference overrides everything.\n throw new APIError(\"UNAUTHORIZED\");\n }\n\n // 2. Fallback: Organization Check\n if (options.organization?.enabled === true) {\n // Check if referenceId indicates an organization the user is a member of\n const member = await ctx.context.adapter.findOne({\n model: \"member\",\n where: [\n { field: \"userId\", value: session.user.id },\n { field: \"organizationId\", value: referenceId },\n ],\n });\n\n if (member !== null && member !== undefined) {\n logger.debug(\"DEBUG MIDDLEWARE MEMBER FOUND:\", member);\n // User is a member of the organization.\n // We could check roles here, but for now allow any member.\n return {\n referenceId,\n };\n }\n }\n\n logger.error(\n `Passing referenceId into a subscription action isn't allowed if subscription.authorizeReference isn't defined in your paystack plugin config and matches no organization membership.`,\n );\n throw new APIError(\"BAD_REQUEST\", {\n message:\n \"Passing referenceId isn't allowed without subscription.authorizeReference or valid organization membership.\",\n });\n });\n","import type { GenericEndpointContext } from \"better-auth\";\nimport { APIError } from \"better-auth/api\";\n\nimport type { Subscription } from \"./types\";\n\nexport const getOrganizationSubscription = async (\n ctx: GenericEndpointContext,\n organizationId: string,\n): Promise<Subscription | null> => {\n const subscription = await ctx.context.adapter.findOne<Subscription>({\n model: \"subscription\",\n where: [{ field: \"referenceId\", value: organizationId }],\n });\n return subscription;\n};\n\nexport const checkSeatLimit = async (\n ctx: GenericEndpointContext,\n organizationId: string,\n seatsToAdd = 1,\n): Promise<boolean> => {\n const subscription = await getOrganizationSubscription(ctx, organizationId);\n\n if (subscription?.seats === null) {\n return true; // No explicit seat limit found\n }\n\n const members = await ctx.context.adapter.findMany({\n model: \"member\",\n where: [{ field: \"organizationId\", value: organizationId }],\n });\n\n if (!subscription) {\n return true; // No subscription, no specific limit enforcement here (or maybe allow depending on config)\n }\n\n if (members.length + seatsToAdd > subscription.seats) {\n throw new APIError(\"FORBIDDEN\", {\n message: `Organization member limit reached. Used: ${members.length}, Max: ${subscription.seats}`,\n });\n }\n\n return true;\n};\n\nexport const checkTeamLimit = async (\n ctx: GenericEndpointContext,\n organizationId: string,\n maxTeams: number,\n): Promise<boolean> => {\n const teams = await ctx.context.adapter.findMany({\n model: \"team\",\n where: [{ field: \"organizationId\", value: organizationId }],\n });\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 { createAuthEndpoint } from \"@better-auth/core/api\";\nimport { defineErrorCodes } from \"@better-auth/core/utils/error-codes\";\nimport { HIDE_METADATA } from \"better-auth\";\nimport { APIError, getSessionFromCtx, originCheck, sessionMiddleware } 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 RawError,\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 PaystackTransactionResponse,\n User,\n PaystackUser,\n PaystackCheckoutChannel,\n} from \"./types\";\nimport {\n syncProductQuantityFromPaystack,\n getPlanByName,\n getPlans,\n getProductByName,\n getProducts,\n validateMinAmount,\n getNextPeriodEnd,\n getPlanSeatAmount,\n calculatePlanAmount,\n assertLocallyManagedSubscription,\n isLocalSubscriptionCode,\n} from \"./utils\";\nimport { referenceMiddleware } from \"./middleware\";\nimport { getPaystackOps, unwrapSdkResult } from \"./paystack-sdk\";\nimport { getOrganizationSubscription } from \"./limits\";\n\nconst 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\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\nasync 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\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 =\n (ctx as unknown as { requestClone?: Request }).requestClone ??\n (ctx as { request: Request }).request;\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 =\n (ctx as GenericEndpointContext & { headers?: Headers }).headers ??\n (ctx.request as unknown as { headers: Headers })?.headers;\n const signature = headers?.get(\"x-paystack-signature\") as string | null | undefined;\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 =\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 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 webhookSecret =\n options.webhook?.secret ?? options.paystackWebhookSecret ?? options.secretKey;\n const expected = await hmacSha512Hex(webhookSecret, 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 metadataVal = (subscriptionData as unknown as { metadata?: unknown }).metadata;\n let metadata: unknown = metadataVal;\n if (typeof metadata === \"string\") {\n try {\n metadata = JSON.parse(metadata);\n } catch {\n // ignore\n }\n }\n\n const metadataObj =\n metadata !== undefined && metadata !== null && typeof metadata === \"object\"\n ? (metadata as Record<string, unknown>)\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 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 as unknown as {\n field: string;\n value: string | number | boolean | null;\n }[],\n });\n const subscription = matches?.[0];\n if (subscription !== undefined && subscription !== null) {\n await ctx.context.adapter.update({\n model: \"subscription\",\n update: {\n paystackSubscriptionCode: subscriptionCode,\n status: \"active\",\n updatedAt: new Date(),\n periodEnd:\n subscriptionData.next_payment_date !== undefined &&\n subscriptionData.next_payment_date !== null\n ? new Date(subscriptionData.next_payment_date)\n : undefined,\n },\n where: [{ field: \"id\", value: subscription.id }],\n });\n\n const plan =\n planFromCode ??\n (planName !== undefined && planName !== null && planName !== \"\"\n ? await getPlanByName(options, planName)\n : undefined);\n if (plan !== undefined && plan !== null) {\n await options.subscription.onSubscriptionComplete?.(\n {\n event,\n subscription: {\n ...subscription,\n paystackSubscriptionCode: subscriptionCode,\n status: \"active\",\n },\n plan,\n },\n ctx as GenericEndpointContext,\n );\n await options.subscription.onSubscriptionCreated?.(\n {\n event,\n subscription: {\n ...subscription,\n paystackSubscriptionCode: subscriptionCode,\n status: \"active\",\n },\n plan,\n },\n ctx as GenericEndpointContext,\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 await ctx.context.adapter.update({\n model: \"subscription\",\n update: {\n status: newStatus,\n cancelAtPeriodEnd: true,\n ...(periodEnd ? { periodEnd } : {}),\n updatedAt: new Date(),\n },\n where: [{ field: \"paystackSubscriptionCode\", value: subscriptionCode }],\n });\n\n if (existing !== null && existing !== undefined) {\n await options.subscription.onSubscriptionCancel?.(\n { event, subscription: { ...existing, status: \"canceled\" } as Subscription },\n ctx as GenericEndpointContext,\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\nconst initializeTransactionBodySchema = 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 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\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 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 | {\n status: string;\n message: string;\n scheduled: boolean;\n }\n | {\n status: string;\n message: string;\n prorated: boolean;\n }\n | {\n url: string;\n reference: string;\n accessCode: string;\n redirect: boolean;\n }\n | 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 } = 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\n // Handle scheduleAtPeriodEnd for existing subscriptions\n if (plan !== undefined && scheduleAtPeriodEnd === true) {\n const existingSub = await getOrganizationSubscription(ctx, referenceId);\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: plan.name,\n updatedAt: new Date(),\n },\n });\n return ctx.json({\n status: \"success\",\n message: \"Plan change scheduled at period end.\",\n scheduled: true,\n });\n }\n }\n\n // Handle cancelAtPeriodEnd for existing subscriptions\n if (cancelAtPeriodEnd === true) {\n const existingSub = await getOrganizationSubscription(ctx, referenceId);\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 updatedAt: new Date(),\n },\n });\n\n return ctx.json({\n status: \"success\",\n message: \"Subscription cancellation scheduled at period end.\",\n scheduled: true,\n });\n }\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 // Check trial eligibility - prevent trial abuse\n let trialStart: Date | undefined;\n let trialEnd: Date | undefined;\n const requestedTrialDays =\n plan?.freeTrial?.days !== undefined && plan.freeTrial.days > 0 ? plan.freeTrial.days : 0;\n const trialRequested = requestedTrialDays > 0;\n let trialGranted = false;\n let trialDeniedReason: \"already_used\" | undefined;\n if (trialRequested) {\n // Check if user/referenceId has ever had a trial\n const previousTrials = await ctx.context.adapter.findMany<Subscription>({\n model: \"subscription\",\n where: [{ field: \"referenceId\", value: referenceId }],\n });\n const hadTrial = previousTrials?.some(\n (sub: Subscription) =>\n (sub.trialStart !== undefined && sub.trialStart !== null) ||\n (sub.trialEnd !== undefined && sub.trialEnd !== null) ||\n sub.status === \"trialing\",\n );\n\n if (hadTrial === false) {\n trialStart = new Date();\n trialEnd = new Date();\n trialEnd.setDate(trialEnd.getDate() + requestedTrialDays);\n trialGranted = true;\n } else {\n trialDeniedReason = \"already_used\";\n }\n }\n\n try {\n // Determine Customer Email & Code (Organization support)\n let targetEmail = email ?? user.email;\n\n if (\n options.organization?.enabled === true &&\n referenceId !== undefined &&\n referenceId !== null &&\n referenceId !== user.id\n ) {\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 orgWithEmail = org as { email?: string | null };\n if (\n orgWithEmail.email !== undefined &&\n orgWithEmail.email !== null &&\n orgWithEmail.email !== \"\"\n ) {\n targetEmail = orgWithEmail.email;\n } else {\n // Fallback: Use Organization Owner Email\n const ownerMember = await ctx.context.adapter.findOne({\n model: \"member\",\n where: [\n { field: \"organizationId\", value: referenceId },\n { field: \"role\", value: \"owner\" },\n ],\n });\n\n if (ownerMember !== undefined && ownerMember !== null) {\n const ownerUser = (await ctx.context.adapter.findOne({\n model: \"user\",\n where: [{ field: \"id\", value: (ownerMember as Member).userId }],\n })) as User | null;\n\n if (\n ownerUser !== undefined &&\n ownerUser !== null &&\n ownerUser.email !== undefined &&\n ownerUser.email !== null &&\n ownerUser.email !== \"\"\n ) {\n targetEmail = ownerUser.email;\n }\n }\n }\n }\n }\n\n const allowedSubscriptionChannels = plan\n ? getAllowedSubscriptionChannels(options)\n : undefined;\n\n // Construct Metadata\n const metadata = JSON.stringify({\n referenceId,\n userId: user.id,\n plan: plan !== undefined ? plan.name.toLowerCase() : undefined, // Undefined for one-time\n product: product !== undefined ? product.name.toLowerCase() : undefined,\n ...extraMetadata,\n isTrial: trialStart !== undefined,\n trialRequested,\n trialGranted,\n trialDeniedReason,\n trialEnd: trialEnd !== undefined ? trialEnd.toISOString() : undefined,\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 existingSub = await getOrganizationSubscription(ctx, referenceId);\n if (\n existingSub?.status === \"active\" &&\n existingSub.paystackSubscriptionCode !== undefined &&\n existingSub.paystackSubscriptionCode !== null &&\n existingSub.paystackSubscriptionCode !== \"\"\n ) {\n if (\n existingSub.periodEnd !== undefined &&\n existingSub.periodEnd !== null &&\n existingSub.periodStart !== undefined &&\n existingSub.periodStart !== null\n ) {\n // 1. Calculate remaining days\n const now = new Date();\n const periodEndLocal = new Date(existingSub.periodEnd);\n const periodStartLocal = new Date(existingSub.periodStart);\n\n const totalDays = Math.max(\n 1,\n Math.ceil(\n (periodEndLocal.getTime() - periodStartLocal.getTime()) / (1000 * 60 * 60 * 24),\n ),\n );\n const remainingDays = Math.max(\n 0,\n Math.ceil((periodEndLocal.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)),\n );\n\n // 2. Fetch old plan/amount\n let oldAmount = 0;\n if (existingSub.plan !== \"\") {\n const oldPlan =\n (await getPlanByName(options, existingSub.plan)) ??\n (await ctx.context.adapter.findOne<PaystackPlan>({\n model: \"paystackPlan\",\n where: [{ field: \"name\", value: existingSub.plan }],\n })) ??\n undefined;\n if (oldPlan !== undefined && oldPlan !== null) {\n const oldSeatCount = existingSub.seats;\n oldAmount = calculatePlanAmount(oldPlan, oldSeatCount);\n }\n }\n\n // 3. Calculate new total amount\n let membersCount = 1;\n let newSeatCount = quantity ?? existingSub.seats ?? membersCount;\n let newAmount: number;\n try {\n assertLocallyManagedSubscription(existingSub, \"plan or seat changes\");\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 membersCount = members.length > 0 ? members.length : 1;\n }\n newSeatCount = quantity ?? existingSub.seats ?? membersCount;\n newAmount = calculatePlanAmount(plan, newSeatCount);\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 // 4. Calculate Difference & Charge\n const costDifference = newAmount - oldAmount;\n const prorationMetadata = {\n type: \"proration\",\n subscriptionId: existingSub.id,\n referenceId,\n newPlan: plan.name.toLowerCase(),\n oldPlan: existingSub.plan,\n newSeatCount,\n remainingDays,\n };\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 ops = getPaystackOps(options.paystackClient);\n if (ops === undefined || ops === null) {\n ctx.context.logger.error(\"Paystack client not configured for proration charge\");\n return;\n }\n\n if (\n existingSub.paystackAuthorizationCode !== undefined &&\n existingSub.paystackAuthorizationCode !== null &&\n existingSub.paystackAuthorizationCode !== \"\"\n ) {\n const chargeResRaw = await ops.transaction?.chargeAuthorization({\n body: {\n email: targetEmail,\n amount: proratedAmount,\n authorization_code: existingSub.paystackAuthorizationCode,\n reference: `upg_${existingSub.id}_${Date.now()}_${Math.random().toString(36).substring(7)}`,\n metadata: JSON.stringify(prorationMetadata),\n },\n });\n const sdkRes = unwrapSdkResult<PaystackTransactionResponse>(chargeResRaw);\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 ctx.context.adapter.create({\n model: \"paystackTransaction\",\n data: {\n reference: sdkRes.reference ?? \"\",\n paystackId:\n sdkRes.id !== undefined && sdkRes.id !== null\n ? String(sdkRes.id)\n : undefined,\n referenceId,\n userId: user.id,\n amount: sdkRes.amount ?? proratedAmount,\n currency: sdkRes.currency ?? finalCurrency,\n status: \"success\",\n plan: plan.name.toLowerCase(),\n metadata: JSON.stringify(prorationMetadata),\n createdAt: new Date(),\n updatedAt: new Date(),\n },\n });\n completedProrationReference = sdkRes.reference ?? undefined;\n } else {\n const initRaw = await ops.transaction?.initialize({\n body: {\n email: targetEmail,\n amount: proratedAmount,\n currency: finalCurrency,\n callback_url: callbackURL ?? undefined,\n metadata: JSON.stringify(prorationMetadata),\n ...(allowedSubscriptionChannels !== undefined\n ? { channels: allowedSubscriptionChannels }\n : {}),\n } as components[\"schemas\"][\"TransactionInitialize\"],\n });\n const initRes =\n unwrapSdkResult<components[\"schemas\"][\"TransactionInitializeResponse\"][\"data\"]>(\n initRaw,\n );\n\n await ctx.context.adapter.create({\n model: \"paystackTransaction\",\n data: {\n reference: initRes?.reference ?? \"\",\n referenceId,\n userId: user.id,\n amount: proratedAmount,\n currency: finalCurrency,\n status: \"pending\",\n plan: plan.name.toLowerCase(),\n metadata: JSON.stringify(prorationMetadata),\n createdAt: new Date(),\n updatedAt: new Date(),\n },\n });\n\n return ctx.json({\n url: initRes?.authorization_url,\n reference: initRes?.reference,\n accessCode: initRes?.access_code,\n redirect: true,\n });\n }\n }\n\n // 5. Update Local DB for locally managed subscriptions.\n await ctx.context.adapter.update({\n model: \"subscription\",\n where: [{ field: \"id\", value: existingSub.id }],\n update: {\n plan: plan.name,\n seats: newSeatCount,\n ...(completedProrationReference !== undefined\n ? { paystackTransactionReference: completedProrationReference }\n : {}),\n updatedAt: new Date(),\n },\n });\n\n return ctx.json({\n status: \"success\",\n message: \"Subscription successfully upgraded with prorated charge.\",\n prorated: true,\n });\n }\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:\n extraMetadata !== undefined && Object.keys(extraMetadata).length > 0\n ? JSON.stringify(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 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 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 url,\n reference,\n accessCode,\n redirect: true,\n });\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 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 | {\n status: string;\n message: string;\n scheduled: boolean;\n }\n | {\n status: string;\n message: string;\n prorated: boolean;\n }\n | {\n url: string;\n reference: string;\n accessCode: string;\n redirect: boolean;\n }\n | 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 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 | {\n status: string;\n message: string;\n scheduled: boolean;\n }\n | {\n status: string;\n message: string;\n prorated: boolean;\n }\n | {\n url: string;\n reference: string;\n accessCode: string;\n redirect: boolean;\n }\n | 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 paystack = getPaystackOps(options.paystackClient);\n let data: PaystackTransactionResponse | undefined;\n\n try {\n const verifyRaw = await paystack?.transaction?.verify(ctx.body.reference);\n // unwrapSdkResult might return the data field or the whole body depending on its impl.\n // But with PaystackResponse and ours, it should give us the 'data' part for success.\n data = unwrapSdkResult<PaystackTransactionResponse>(verifyRaw);\n } catch (error: unknown) {\n ctx.context.logger.error(\"Failed to verify Paystack transaction\", error);\n const errorMessage =\n error instanceof Error\n ? error.message\n : PAYSTACK_ERROR_CODES.FAILED_TO_VERIFY_TRANSACTION.message;\n throw new APIError(\"BAD_REQUEST\", {\n code: \"FAILED_TO_VERIFY_TRANSACTION\",\n message: errorMessage,\n });\n }\n\n if (data === undefined || data === null) {\n throw new APIError(\"BAD_REQUEST\", {\n message: \"Failed to fetch transaction data from Paystack.\",\n });\n }\n\n const status = data.status ?? \"failed\";\n const reference = data.reference ?? ctx.body.reference;\n const paystackIdRaw = data.id;\n const paystackId =\n paystackIdRaw !== undefined && paystackIdRaw !== null ? String(paystackIdRaw) : undefined;\n const authorizationCode = (data.authorization as { authorization_code?: string | null })\n ?.authorization_code;\n const allowedSubscriptionChannels = getAllowedSubscriptionChannels(options);\n\n if (status === \"success\") {\n const session = await getSessionFromCtx(ctx);\n\n // Get the local transaction record to know the intended referenceId (Org or User)\n const txRecord = await ctx.context.adapter.findOne<\n PaystackTransaction & { referenceId?: string }\n >({\n model: \"paystackTransaction\",\n where: [{ field: \"reference\", value: reference }],\n });\n\n // Trust the referenceId from the record, fallback to session user if missing\n const referenceId =\n txRecord !== undefined &&\n txRecord !== null &&\n txRecord.referenceId !== undefined &&\n txRecord.referenceId !== null &&\n txRecord.referenceId !== \"\"\n ? txRecord.referenceId\n : session !== undefined && session !== null\n ? session.user.id\n : undefined;\n\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) ===\n false\n ) {\n await ctx.context.adapter.update({\n model: \"paystackTransaction\",\n update: {\n status: \"failed\",\n paystackId,\n amount: data.amount,\n currency: data.currency,\n updatedAt: new Date(),\n },\n where: [{ field: \"reference\", value: reference }],\n });\n\n throw new APIError(\"BAD_REQUEST\", {\n code: \"SUBSCRIPTION_PAYMENT_CHANNEL_NOT_ALLOWED\",\n message: `This subscription requires one of: ${allowedSubscriptionChannels?.join(\", \") ?? \"allowed channels\"}.`,\n });\n }\n\n // Authorization check: ensure the current user has access to this referenceId\n if (\n session !== undefined &&\n session !== null &&\n referenceId !== undefined &&\n referenceId !== null &&\n referenceId !== \"\" &&\n referenceId !== session.user.id\n ) {\n const authRef = subscriptionOptions?.authorizeReference;\n let authorized = false;\n if (authRef !== undefined && authRef !== null) {\n authorized = await authRef(\n {\n user: session.user,\n session: session.session,\n referenceId,\n action: \"verify-transaction\",\n },\n ctx as GenericEndpointContext,\n );\n }\n if (authorized === false && options.organization?.enabled === true) {\n const member = await ctx.context.adapter.findOne<Member>({\n model: \"member\",\n where: [\n { field: \"userId\", value: session.user.id },\n { field: \"organizationId\", value: referenceId },\n ],\n });\n if (member !== undefined && member !== null) authorized = true;\n }\n\n if (authorized === false) {\n throw new APIError(\"UNAUTHORIZED\");\n }\n }\n\n try {\n await ctx.context.adapter.update({\n model: \"paystackTransaction\",\n update: {\n status: \"success\",\n paystackId,\n amount: data.amount,\n currency: data.currency,\n updatedAt: new Date(),\n },\n where: [{ field: \"reference\", value: reference }],\n });\n\n const paystackCustomerCodeFromPaystack = data.customer?.customer_code;\n if (\n paystackCustomerCodeFromPaystack !== undefined &&\n paystackCustomerCodeFromPaystack !== null &&\n paystackCustomerCodeFromPaystack !== \"\" &&\n referenceId !== undefined &&\n referenceId !== null &&\n referenceId !== \"\"\n ) {\n let isOrg =\n options.organization?.enabled === true &&\n typeof referenceId === \"string\" &&\n referenceId.startsWith(\"org_\");\n if (isOrg === false && options.organization?.enabled === true) {\n const org = await ctx.context.adapter.findOne({\n model: \"organization\",\n where: [{ field: \"id\", value: referenceId }],\n });\n isOrg = org !== undefined && org !== null;\n }\n\n if (isOrg) {\n await ctx.context.adapter.update({\n model: \"organization\",\n update: { paystackCustomerCode: paystackCustomerCodeFromPaystack },\n where: [{ field: \"id\", value: referenceId }],\n });\n } else {\n await ctx.context.adapter.update({\n model: \"user\",\n update: { paystackCustomerCode: paystackCustomerCodeFromPaystack },\n where: [{ field: \"id\", value: referenceId }],\n });\n }\n }\n\n // Decrement product quantity if applicable\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 options.paystackClient !== undefined &&\n options.paystackClient !== null\n ) {\n await syncProductQuantityFromPaystack(ctx, transaction.product, options.paystackClient);\n }\n\n // Check for trial activation\n let isTrial = false;\n let trialEnd: string | undefined;\n let targetPlan: string | undefined;\n let metadataObj: Record<string, unknown> = {};\n\n if (data.metadata !== undefined && data.metadata !== null && data.metadata !== \"\") {\n metadataObj = (\n typeof data.metadata === \"string\" ? JSON.parse(data.metadata) : data.metadata\n ) as Record<string, unknown>;\n isTrial = metadataObj.isTrial === true || metadataObj.isTrial === \"true\";\n trialEnd = metadataObj.trialEnd as string | undefined;\n targetPlan = metadataObj.plan as string | undefined;\n }\n\n if (metadataObj.type === \"proration\") {\n const subscriptionId = metadataObj.subscriptionId as string | undefined;\n const newPlan = metadataObj.newPlan as string | undefined;\n const newSeatCount = metadataObj.newSeatCount as number | undefined;\n\n if (\n subscriptionId !== undefined &&\n subscriptionId !== \"\" &&\n newPlan !== undefined &&\n newPlan !== \"\"\n ) {\n await ctx.context.adapter.update<Subscription>({\n model: \"subscription\",\n update: {\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 where: [{ field: \"id\", value: subscriptionId }],\n });\n }\n\n return ctx.json({ status, reference, data });\n }\n\n let paystackSubscriptionCode: string | undefined;\n\n if (isTrial && targetPlan !== undefined && trialEnd !== undefined) {\n // Trial Flow: Create subscription with future start date using auth code\n const email = data.customer?.email;\n\n const plans = await getPlans(subscriptionOptions);\n const planConfig = plans.find(\n (p) => p.name.toLowerCase() === targetPlan?.toLowerCase(),\n );\n\n // For local plans (no planCode), generate a local subscription code\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 }\n\n 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\n ?.plan_code;\n if (\n planCodeFromPaystack === undefined ||\n planCodeFromPaystack === null ||\n planCodeFromPaystack === \"\"\n ) {\n // Local Plan\n paystackSubscriptionCode = `LOC_${reference}`;\n } else {\n // Native Paystack subscription (if created during charge)\n paystackSubscriptionCode =\n (data as { subscription?: { subscription_code?: string | null } }).subscription\n ?.subscription_code ?? undefined;\n }\n }\n\n const existingSubs = await ctx.context.adapter.findMany<Subscription>({\n model: \"subscription\",\n where: [{ field: \"paystackTransactionReference\", value: reference }],\n });\n\n const targetSub = existingSubs?.find(\n (s) =>\n referenceId === undefined ||\n referenceId === null ||\n referenceId === \"\" ||\n s.referenceId === referenceId,\n );\n\n let updatedSubscription: Subscription | null = null;\n if (targetSub !== undefined && targetSub !== null) {\n updatedSubscription = await ctx.context.adapter.update<Subscription>({\n model: \"subscription\",\n update: {\n status: isTrial ? \"trialing\" : \"active\",\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 where: [{ field: \"id\", value: targetSub.id }],\n });\n }\n\n if (\n updatedSubscription !== undefined &&\n updatedSubscription !== null &&\n subscriptionOptions?.onSubscriptionComplete !== undefined\n ) {\n const plans = await getPlans(subscriptionOptions);\n const plan = plans.find(\n (p) => p.name.toLowerCase() === updatedSubscription.plan.toLowerCase(),\n );\n if (plan !== undefined) {\n await subscriptionOptions.onSubscriptionComplete(\n {\n event: data as unknown as PaystackWebhookPayload,\n subscription: updatedSubscription,\n plan,\n },\n ctx as GenericEndpointContext,\n );\n }\n }\n } catch (e: unknown) {\n ctx.context.logger.error(\n \"Failed to update transaction/subscription after verification\",\n e,\n );\n }\n }\n\n return ctx.json({ status, reference, data });\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 referenceIdPart = (ctx.context as Record<string, unknown>).referenceId as\n | string\n | undefined;\n const queryRefId = ctx.query?.referenceId;\n const referenceId = referenceIdPart ?? queryRefId ?? (session.user as { id: string }).id;\n const res = await ctx.context.adapter.findMany<Subscription>({\n model: \"subscription\",\n where: [{ field: \"referenceId\", value: referenceId }],\n });\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 referenceIdPart = (ctx.context as Record<string, unknown>).referenceId as\n | string\n | undefined;\n const queryRefId = ctx.query?.referenceId;\n const referenceId = referenceIdPart ?? queryRefId ?? (session.user as { id: string }).id;\n const res = await ctx.context.adapter.findMany<PaystackTransaction>({\n model: \"paystackTransaction\",\n where: [{ field: \"referenceId\", value: referenceId }],\n });\n // Sort by createdAt desc locally.\n const sorted = res.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());\n return ctx.json({ transactions: sorted });\n },\n );\n};\n\nconst enableDisableBodySchema = z.object({\n referenceId: z.string().optional(),\n subscriptionCode: z.string(),\n emailToken: z.string().optional(),\n atPeriodEnd: z.boolean().optional(),\n});\n\nfunction 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\nfunction 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\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 await ctx.context.adapter.update({\n model: \"subscription\",\n update: {\n status: atPeriodEnd === false ? \"canceled\" : \"active\",\n cancelAtPeriodEnd: atPeriodEnd !== false,\n updatedAt: new Date(),\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 await ctx.context.adapter.update({\n model: \"subscription\",\n update: {\n status: atPeriodEnd === false ? \"canceled\" : \"active\",\n cancelAtPeriodEnd: atPeriodEnd !== false,\n periodEnd,\n updatedAt: new Date(),\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 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 syncProducts = <P extends string = \"/sync-products\">(\n options: AnyPaystackOptions,\n path: P = \"/sync-products\" as P,\n): StrictEndpoint<\n P,\n {\n method: \"POST\";\n metadata: {\n scope: \"server\";\n };\n disableBody: true;\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 products: never[];\n }\n | {\n status: string;\n count: number;\n }\n> => {\n return createAuthEndpoint(\n path,\n {\n method: \"POST\",\n metadata: { ...HIDE_METADATA },\n disableBody: true,\n use: [sessionMiddleware],\n },\n async (ctx) => {\n const paystack = getPaystackOps(options.paystackClient);\n try {\n const raw = await paystack?.product?.list({});\n const productsData =\n unwrapSdkResult<components[\"schemas\"][\"ProductListsResponseArray\"][]>(raw);\n\n if (!Array.isArray(productsData)) {\n return ctx.json({ products: [] });\n }\n\n for (const product of productsData) {\n const paystackId = String(product.id);\n const existing = await ctx.context.adapter.findOne<PaystackProduct>({\n model: \"paystackProduct\",\n where: [{ field: \"paystackId\", value: paystackId }],\n });\n\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 unknown as { slug?: string }).slug ??\n product.name?.toLowerCase().replace(/\\s+/g, \"-\") ??\n \"\",\n metadata:\n (product as unknown as { metadata?: unknown }).metadata !== undefined &&\n (product as unknown as { metadata?: unknown }).metadata !== null\n ? JSON.stringify((product as unknown as { metadata?: unknown }).metadata)\n : undefined,\n updatedAt: new Date(),\n };\n\n if (existing !== undefined && existing !== null) {\n await ctx.context.adapter.update({\n model: \"paystackProduct\",\n update: productFields,\n where: [{ field: \"id\", value: String(existing.id) }],\n });\n } else {\n await ctx.context.adapter.create({\n model: \"paystackProduct\",\n data: { ...productFields, createdAt: new Date() },\n });\n }\n }\n\n return ctx.json({ 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 );\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 res = await ctx.context.adapter.findMany<PaystackProduct>({\n model: \"paystackProduct\",\n });\n const sorted = res.sort((a, b) => a.name.localeCompare(b.name));\n return ctx.json({ products: sorted });\n },\n );\n};\n\nexport const syncPlans = <P extends string = \"/sync-plans\">(\n options: AnyPaystackOptions,\n path: P = \"/sync-plans\" as P,\n): StrictEndpoint<\n P,\n {\n method: \"POST\";\n metadata: {\n scope: \"server\";\n };\n disableBody: true;\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 status: string;\n count: number;\n }\n> => {\n return createAuthEndpoint(\n path,\n {\n method: \"POST\",\n metadata: { ...HIDE_METADATA },\n disableBody: true,\n use: [sessionMiddleware],\n },\n async (ctx) => {\n const paystack = getPaystackOps(options.paystackClient);\n try {\n const raw = await paystack?.plan?.list();\n const plansData = unwrapSdkResult<components[\"schemas\"][\"PlanListResponseArray\"][]>(raw);\n\n if (!Array.isArray(plansData)) {\n return ctx.json({ status: \"success\", count: 0 });\n }\n\n for (const plan of plansData) {\n const paystackId = String(plan.id);\n const existing = await ctx.context.adapter.findOne<PaystackPlan>({\n model: \"paystackPlan\",\n where: [{ field: \"paystackId\", value: paystackId }],\n });\n\n const planData = {\n name: plan.name ?? \"\",\n description: plan.description ?? \"\",\n amount: plan.amount ?? 0,\n currency: plan.currency ?? \"\",\n interval: plan.interval ?? \"\",\n planCode: plan.plan_code ?? \"\",\n paystackId,\n metadata:\n (plan as unknown as { metadata?: unknown }).metadata !== undefined &&\n (plan as unknown as { metadata?: unknown }).metadata !== null\n ? JSON.stringify((plan as unknown as { metadata?: unknown }).metadata)\n : undefined,\n updatedAt: new Date(),\n };\n\n if (existing !== undefined && existing !== null) {\n await ctx.context.adapter.update({\n model: \"paystackPlan\",\n update: planData,\n where: [{ field: \"id\", value: existing.id! }],\n });\n } else {\n await ctx.context.adapter.create({\n model: \"paystackPlan\",\n data: { ...planData, createdAt: new Date() },\n });\n }\n }\n\n return ctx.json({ 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 );\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 ctx.context.adapter.findMany<PaystackPlan>({\n model: \"paystackPlan\",\n });\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 const plans =\n options.subscription?.enabled === true ? await getPlans(options.subscription) : [];\n const products = await getProducts(options.products);\n return ctx.json({ plans, products });\n },\n );\n};\n\nexport { PAYSTACK_ERROR_CODES };\n\nexport const chargeRecurringSubscription = <P extends string = \"/charge-recurring-subscription\">(\n options: AnyPaystackOptions,\n path: P = \"/charge-recurring-subscription\" as P,\n): StrictEndpoint<\n P,\n {\n method: \"POST\";\n body: z.ZodObject<\n {\n subscriptionId: z.ZodString;\n amount: z.ZodOptional<z.ZodNumber>;\n },\n z.core.$strip\n >;\n },\n {\n status: 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 return createAuthEndpoint(\n path,\n {\n method: \"POST\",\n body: z.object({\n subscriptionId: z.string(),\n amount: z.number().optional(),\n }),\n },\n async (ctx) => {\n const { subscriptionId, amount: bodyAmount } = ctx.body;\n const subscription = await ctx.context.adapter.findOne<Subscription>({\n model: \"subscription\",\n where: [{ field: \"id\", value: subscriptionId }],\n });\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((p) => p.name.toLowerCase() === subscription.plan.toLowerCase());\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 const referenceId = subscription.referenceId;\n if (referenceId !== undefined && referenceId !== null && referenceId !== \"\") {\n const user = await ctx.context.adapter.findOne<User>({\n model: \"user\",\n where: [{ field: \"id\", value: referenceId }],\n });\n if (user !== undefined && user !== null) {\n email = user.email;\n } else if (options.organization?.enabled === true) {\n const ownerMember = await ctx.context.adapter.findOne<Member>({\n model: \"member\",\n where: [\n { field: \"organizationId\", value: referenceId },\n { field: \"role\", value: \"owner\" },\n ],\n });\n if (ownerMember !== undefined && ownerMember !== null) {\n const ownerUser = await ctx.context.adapter.findOne<User>({\n model: \"user\",\n where: [{ field: \"id\", value: ownerMember.userId }],\n });\n email = ownerUser?.email;\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 = getPaystackOps(options.paystackClient);\n const chargeResRaw = await paystack?.transaction?.chargeAuthorization({\n body: {\n email,\n amount,\n authorization_code: subscription.paystackAuthorizationCode,\n reference: `rec_${subscription.id}_${Date.now()}`,\n metadata: JSON.stringify({\n subscriptionId,\n referenceId,\n }),\n },\n });\n\n const chargeData = unwrapSdkResult<PaystackTransactionResponse>(chargeResRaw);\n\n if (chargeData?.status === \"success\" && chargeData.reference !== undefined) {\n const now = new Date();\n const nextPeriodEnd = getNextPeriodEnd(now, plan.interval ?? \"monthly\");\n\n await ctx.context.adapter.update({\n model: \"subscription\",\n update: {\n periodStart: now,\n periodEnd: nextPeriodEnd,\n updatedAt: now,\n paystackTransactionReference: chargeData.reference,\n },\n where: [{ field: \"id\", value: subscription.id }],\n });\n\n return ctx.json({ status: \"success\", data: chargeData });\n }\n\n return ctx.json({ status: \"failed\", data: chargeData }, { status: 400 });\n },\n );\n};\n","import type { BetterAuthPluginDBSchema } from \"@better-auth/core/db\";\nimport { mergeSchema } from \"better-auth/db\";\n\nimport type { PaystackOptions } from \"./types\";\n\nexport const transactions: BetterAuthPluginDBSchema = {\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 subscriptions: BetterAuthPluginDBSchema = {\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 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 user: BetterAuthPluginDBSchema = {\n user: {\n fields: {\n paystackCustomerCode: {\n type: \"string\",\n required: false,\n index: true,\n },\n },\n },\n} satisfies BetterAuthPluginDBSchema;\n\nexport const organization: BetterAuthPluginDBSchema = {\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 products: BetterAuthPluginDBSchema = {\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 plans: BetterAuthPluginDBSchema = {\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 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 getSchema = (options: PaystackOptions): BetterAuthPluginDBSchema => {\n let baseSchema: BetterAuthPluginDBSchema;\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 } = options.schema;\n return mergeSchema(baseSchema, restSchema);\n }\n\n return mergeSchema(baseSchema, options.schema);\n};\n","import { APIError } from \"better-auth/api\";\nimport type { GenericEndpointContext } from \"better-auth\";\nimport type { components } from \"@alexasomba/paystack-node\";\n\nimport { getPaystackOps, unwrapSdkResult } from \"./paystack-sdk\";\nimport { getNextPeriodEnd, getPlans, validateMinAmount } from \"./utils\";\nimport type {\n AnyPaystackOptions,\n ChargeRecurringSubscriptionInput,\n ChargeRecurringSubscriptionResult,\n Member,\n PaystackPlan,\n PaystackProduct,\n PaystackSyncResult,\n PaystackTransactionResponse,\n Subscription,\n User,\n} from \"./types\";\n\nexport async function syncPaystackProducts(\n ctx: GenericEndpointContext,\n options: AnyPaystackOptions,\n): Promise<PaystackSyncResult> {\n const paystack = getPaystackOps(options.paystackClient);\n try {\n const raw = await paystack?.product?.list({});\n const productsData = unwrapSdkResult<components[\"schemas\"][\"ProductListsResponseArray\"][]>(raw);\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 existing = await ctx.context.adapter.findOne<PaystackProduct>({\n model: \"paystackProduct\",\n where: [{ field: \"paystackId\", value: paystackId }],\n });\n\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:\n (product as { metadata?: unknown }).metadata !== undefined &&\n (product as { metadata?: unknown }).metadata !== null\n ? JSON.stringify((product as { metadata?: unknown }).metadata)\n : undefined,\n updatedAt: new Date(),\n };\n\n if (existing !== undefined && existing !== null) {\n await ctx.context.adapter.update({\n model: \"paystackProduct\",\n update: productFields,\n where: [{ field: \"id\", value: String(existing.id) }],\n });\n } else {\n await ctx.context.adapter.create({\n model: \"paystackProduct\",\n data: { ...productFields, createdAt: new Date() },\n });\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 = getPaystackOps(options.paystackClient);\n try {\n const raw = await paystack?.plan?.list();\n const plansData = unwrapSdkResult<components[\"schemas\"][\"PlanListResponseArray\"][]>(raw);\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 existing = await ctx.context.adapter.findOne<PaystackPlan>({\n model: \"paystackPlan\",\n where: [{ field: \"paystackId\", value: paystackId }],\n });\n\n const planData = {\n name: plan.name ?? \"\",\n description: plan.description ?? \"\",\n amount: plan.amount ?? 0,\n currency: plan.currency ?? \"\",\n interval: plan.interval ?? \"\",\n planCode: plan.plan_code ?? \"\",\n paystackId,\n metadata:\n (plan as { metadata?: unknown }).metadata !== undefined &&\n (plan as { metadata?: unknown }).metadata !== null\n ? JSON.stringify((plan as { metadata?: unknown }).metadata)\n : undefined,\n updatedAt: new Date(),\n };\n\n if (existing !== undefined && existing !== null) {\n await ctx.context.adapter.update({\n model: \"paystackPlan\",\n update: planData,\n where: [{ field: \"id\", value: existing.id! }],\n });\n } else {\n await ctx.context.adapter.create({\n model: \"paystackPlan\",\n data: { ...planData, createdAt: new Date() },\n });\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 subscription = await ctx.context.adapter.findOne<Subscription>({\n model: \"subscription\",\n where: [{ field: \"id\", value: subscriptionId }],\n });\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 ctx.context.adapter.findOne<User>({\n model: \"user\",\n where: [{ field: \"id\", value: referenceId }],\n });\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 ctx.context.adapter.findOne<Member>({\n model: \"member\",\n where: [\n { field: \"organizationId\", value: referenceId },\n { field: \"role\", value: \"owner\" },\n ],\n });\n if (ownerMember !== undefined && ownerMember !== null) {\n const ownerUser = await ctx.context.adapter.findOne<User>({\n model: \"user\",\n where: [{ field: \"id\", value: ownerMember.userId }],\n });\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 = getPaystackOps(options.paystackClient);\n const chargeResRaw = await paystack?.transaction?.chargeAuthorization({\n body: {\n email,\n amount,\n authorization_code: subscription.paystackAuthorizationCode,\n reference: `rec_${subscription.id}_${Date.now()}`,\n metadata: JSON.stringify({\n subscriptionId,\n referenceId,\n }),\n },\n });\n\n const chargeData = unwrapSdkResult<PaystackTransactionResponse>(chargeResRaw);\n if (chargeData?.status === \"success\" && chargeData.reference !== undefined) {\n const now = new Date();\n const nextPeriodEnd = getNextPeriodEnd(now, plan.interval ?? \"monthly\");\n\n await ctx.context.adapter.create({\n model: \"paystackTransaction\",\n data: {\n reference: chargeData.reference,\n paystackId:\n chargeData.id !== undefined && chargeData.id !== null ? String(chargeData.id) : undefined,\n referenceId,\n userId: billingUserId,\n amount: chargeData.amount,\n currency: chargeData.currency,\n status: \"success\",\n plan: plan.name.toLowerCase(),\n metadata: JSON.stringify({\n type: \"renewal\",\n subscriptionId,\n referenceId,\n }),\n createdAt: now,\n updatedAt: now,\n },\n });\n\n await ctx.context.adapter.update({\n model: \"subscription\",\n update: {\n periodStart: now,\n periodEnd: nextPeriodEnd,\n updatedAt: now,\n paystackTransactionReference: chargeData.reference,\n },\n where: [{ field: \"id\", value: subscription.id }],\n });\n\n return { status: \"success\", data: chargeData };\n }\n\n return { status: \"failed\", data: chargeData };\n}\n","import { defineErrorCodes } from \"@better-auth/core/utils/error-codes\";\nimport type { CustomerCreatePayload } from \"@alexasomba/paystack-node\";\nimport type {\n AuthContext,\n BetterAuthPlugin,\n BetterAuthPluginDBSchema,\n GenericEndpointContext,\n MiddlewareInputContext,\n MiddlewareOptions,\n RawError,\n StrictEndpoint,\n ZodBoolean,\n ZodNumber,\n ZodObject,\n ZodOptional,\n ZodRecord,\n ZodString,\n ZodUnknown,\n} from \"better-auth\";\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, getOrganizationSubscription } from \"./limits\";\nimport { getPlanByName, syncSubscriptionSeats } from \"./utils\";\nimport type {\n PaystackClientLike,\n PaystackOptions,\n PaystackPlan,\n Subscription,\n SubscriptionOptions,\n PaystackProduct,\n PaystackCustomerResponse,\n Member,\n AnyPaystackOptions,\n User,\n PaystackTransaction,\n} from \"./types\";\nimport { getPaystackOps, unwrapSdkResult } from \"./paystack-sdk\";\nimport type { $strip } from \"zod/v4/core\";\n\ndeclare module \"@better-auth/core\" {\n interface BetterAuthPluginRegistry<AuthOptions, Options> {\n paystack: {\n creator: typeof paystack;\n };\n }\n}\n\nconst INTERNAL_ERROR_CODES = 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\nexport const paystack = <\n TPaystackClient extends PaystackClientLike = PaystackClientLike,\n O extends PaystackOptions<TPaystackClient> = PaystackOptions<TPaystackClient>,\n>(\n options: O,\n): {\n id: \"paystack\";\n endpoints: {\n initializeTransaction: StrictEndpoint<\n \"/paystack/initialize-transaction\",\n {\n method: \"POST\";\n body: ZodObject<\n {\n plan: ZodOptional<ZodString>;\n product: ZodOptional<ZodString>;\n amount: ZodOptional<ZodNumber>;\n currency: ZodOptional<ZodString>;\n email: ZodOptional<ZodString>;\n metadata: ZodOptional<ZodRecord<ZodString, ZodUnknown>>;\n referenceId: ZodOptional<ZodString>;\n callbackURL: ZodOptional<ZodString>;\n quantity: ZodOptional<ZodNumber>;\n scheduleAtPeriodEnd: ZodOptional<ZodBoolean>;\n cancelAtPeriodEnd: ZodOptional<ZodBoolean>;\n prorateAndCharge: ZodOptional<ZodBoolean>;\n },\n $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 message: string;\n scheduled: boolean;\n }\n | {\n status: string;\n message: string;\n prorated: boolean;\n }\n | {\n url: string;\n reference: string;\n accessCode: string;\n redirect: boolean;\n }\n | undefined\n >;\n verifyTransaction: StrictEndpoint<\n \"/paystack/verify-transaction\",\n {\n method: \"POST\";\n body: ZodObject<\n {\n reference: ZodString;\n },\n $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 listSubscriptions: StrictEndpoint<\n \"/paystack/list-subscriptions\",\n {\n method: \"GET\";\n query: ZodObject<\n {\n referenceId: ZodOptional<ZodString>;\n },\n $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 paystackWebhook: StrictEndpoint<\n \"/paystack/webhook\",\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 listTransactions: StrictEndpoint<\n \"/paystack/list-transactions\",\n {\n method: \"GET\";\n query: ZodObject<\n {\n referenceId: ZodOptional<ZodString>;\n },\n $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 getConfig: StrictEndpoint<\n \"/paystack/config\",\n {\n method: \"GET\";\n metadata: {\n openapi: {\n operationId: string;\n };\n };\n },\n {\n plans: PaystackPlan[];\n products: PaystackProduct[];\n }\n >;\n disableSubscription: StrictEndpoint<\n \"/paystack/disable-subscription\",\n {\n method: \"POST\";\n body: ZodObject<\n {\n referenceId: ZodOptional<ZodString>;\n subscriptionCode: ZodString;\n emailToken: ZodOptional<ZodString>;\n atPeriodEnd: ZodOptional<ZodBoolean>;\n },\n $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 enableSubscription: StrictEndpoint<\n \"/paystack/enable-subscription\",\n {\n method: \"POST\";\n body: ZodObject<\n {\n referenceId: ZodOptional<ZodString>;\n subscriptionCode: ZodString;\n emailToken: ZodOptional<ZodString>;\n atPeriodEnd: ZodOptional<ZodBoolean>;\n },\n $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 getSubscriptionManageLink: StrictEndpoint<\n \"/paystack/subscription-manage-link\",\n {\n method: \"GET\";\n query: ZodObject<\n {\n subscriptionCode: ZodString;\n },\n $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 subscriptionManageLink: StrictEndpoint<\n \"/paystack/subscription/manage-link\",\n {\n method: \"GET\";\n query: ZodObject<\n {\n subscriptionCode: ZodString;\n },\n $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 createSubscription: StrictEndpoint<\n \"/paystack/create-subscription\",\n {\n method: \"POST\";\n body: ZodObject<\n {\n plan: ZodOptional<ZodString>;\n product: ZodOptional<ZodString>;\n amount: ZodOptional<ZodNumber>;\n currency: ZodOptional<ZodString>;\n email: ZodOptional<ZodString>;\n metadata: ZodOptional<ZodRecord<ZodString, ZodUnknown>>;\n referenceId: ZodOptional<ZodString>;\n callbackURL: ZodOptional<ZodString>;\n quantity: ZodOptional<ZodNumber>;\n scheduleAtPeriodEnd: ZodOptional<ZodBoolean>;\n cancelAtPeriodEnd: ZodOptional<ZodBoolean>;\n prorateAndCharge: ZodOptional<ZodBoolean>;\n },\n $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 message: string;\n scheduled: boolean;\n }\n | {\n status: string;\n message: string;\n prorated: boolean;\n }\n | {\n url: string;\n reference: string;\n accessCode: string;\n redirect: boolean;\n }\n | undefined\n >;\n upgradeSubscription: StrictEndpoint<\n \"/paystack/upgrade-subscription\",\n {\n method: \"POST\";\n body: ZodObject<\n {\n plan: ZodOptional<ZodString>;\n product: ZodOptional<ZodString>;\n amount: ZodOptional<ZodNumber>;\n currency: ZodOptional<ZodString>;\n email: ZodOptional<ZodString>;\n metadata: ZodOptional<ZodRecord<ZodString, ZodUnknown>>;\n referenceId: ZodOptional<ZodString>;\n callbackURL: ZodOptional<ZodString>;\n quantity: ZodOptional<ZodNumber>;\n scheduleAtPeriodEnd: ZodOptional<ZodBoolean>;\n cancelAtPeriodEnd: ZodOptional<ZodBoolean>;\n prorateAndCharge: ZodOptional<ZodBoolean>;\n },\n $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 message: string;\n scheduled: boolean;\n }\n | {\n status: string;\n message: string;\n prorated: boolean;\n }\n | {\n url: string;\n reference: string;\n accessCode: string;\n redirect: boolean;\n }\n | undefined\n >;\n cancelSubscription: StrictEndpoint<\n \"/paystack/cancel-subscription\",\n {\n method: \"POST\";\n body: ZodObject<\n {\n referenceId: ZodOptional<ZodString>;\n subscriptionCode: ZodString;\n emailToken: ZodOptional<ZodString>;\n atPeriodEnd: ZodOptional<ZodBoolean>;\n },\n $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 restoreSubscription: StrictEndpoint<\n \"/paystack/restore-subscription\",\n {\n method: \"POST\";\n body: ZodObject<\n {\n referenceId: ZodOptional<ZodString>;\n subscriptionCode: ZodString;\n emailToken: ZodOptional<ZodString>;\n atPeriodEnd: ZodOptional<ZodBoolean>;\n },\n $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 listProducts: StrictEndpoint<\n \"/paystack/list-products\",\n {\n method: \"GET\";\n metadata: {\n openapi: {\n operationId: string;\n };\n };\n },\n {\n products: PaystackProduct[];\n }\n >;\n listPlans: StrictEndpoint<\n \"/paystack/list-plans\",\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 };\n schema: BetterAuthPluginDBSchema;\n init: (ctx: AuthContext) => {\n options: {\n databaseHooks: {\n user: {\n create: {\n after(\n user: { id: string; email?: string | null; name?: string | null },\n hookCtx?: GenericEndpointContext | null,\n ): Promise<void>;\n };\n };\n organization:\n | {\n create: {\n after(\n org: { id: string; name: string; email?: string | null },\n hookCtx: GenericEndpointContext | null,\n ): Promise<void>;\n };\n }\n | undefined;\n };\n member: {\n create: {\n before: (\n member: { organizationId: string },\n ctx: GenericEndpointContext | null | undefined,\n ) => Promise<void>;\n after: (\n member: { organizationId: string | undefined },\n ctx: GenericEndpointContext | null | undefined,\n ) => Promise<void>;\n };\n delete: {\n after: (\n member: { organizationId: string | undefined },\n ctx: GenericEndpointContext | null | undefined,\n ) => Promise<void>;\n };\n };\n invitation: {\n create: {\n before: (\n invitation: { organizationId: string },\n ctx: GenericEndpointContext | null | undefined,\n ) => Promise<void>;\n after: (\n invitation: { organizationId: string | undefined },\n ctx: GenericEndpointContext | null | undefined,\n ) => Promise<void>;\n };\n delete: {\n after: (\n invitation: { organizationId: string | undefined },\n ctx: GenericEndpointContext | null | undefined,\n ) => Promise<void>;\n };\n };\n team: {\n create: {\n before: (\n team: { organizationId: string },\n ctx: GenericEndpointContext | null | undefined,\n ) => Promise<void>;\n };\n };\n };\n };\n $ERROR_CODES: Record<string, RawError<string>>;\n options: NoInfer<O>;\n} => {\n const routeOptions = {\n ...(options as unknown as AnyPaystackOptions),\n webhook: {\n ...options.webhook,\n secret: options.webhook?.secret ?? options.paystackWebhookSecret,\n },\n } satisfies AnyPaystackOptions;\n return {\n id: \"paystack\",\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 return {\n options: {\n databaseHooks: {\n user: {\n create: {\n async after(\n user: { id: string; email?: string | null; name?: string | null },\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 paystackOps = getPaystackOps(\n options.paystackClient as PaystackClientLike,\n );\n if (!paystackOps) return;\n const raw =\n (await paystackOps.customer?.create({\n body: {\n email: user.email,\n first_name: user.name ?? undefined,\n metadata: JSON.stringify({\n userId: user.id,\n }),\n },\n })) ??\n (await Promise.reject(new Error(\"Paystack client missing customer ops\")));\n const sdkRes = unwrapSdkResult<PaystackCustomerResponse>(raw);\n const customerCode = sdkRes?.customer_code;\n\n if (\n customerCode !== undefined &&\n customerCode !== null &&\n customerCode !== \"\"\n ) {\n await ctx.adapter.update({\n model: \"user\",\n where: [{ field: \"id\", value: user.id }],\n update: {\n paystackCustomerCode: customerCode,\n },\n });\n\n if (typeof options.onCustomerCreate === \"function\") {\n await options.onCustomerCreate(\n {\n paystackCustomer: sdkRes,\n user: {\n ...(user as User),\n paystackCustomerCode: customerCode,\n },\n },\n hookCtx,\n );\n }\n }\n } catch (error: unknown) {\n ctx.logger.error(\"Failed to create Paystack customer for user\", error);\n }\n },\n },\n },\n organization:\n options.organization?.enabled === true\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 as Record<string, unknown>, hookCtx!)\n : {};\n\n let targetEmail = org.email;\n if (targetEmail === undefined || targetEmail === null) {\n const ownerMember = await ctx.adapter.findOne<Member>({\n model: \"member\",\n where: [\n { field: \"organizationId\", value: org.id },\n { field: \"role\", value: \"owner\" },\n ],\n });\n if (ownerMember !== null && ownerMember !== undefined) {\n const ownerUser = await ctx.adapter.findOne<User>({\n model: \"user\",\n where: [{ field: \"id\", value: ownerMember.userId }],\n });\n targetEmail = ownerUser?.email;\n }\n }\n\n if (targetEmail === undefined || targetEmail === null) return;\n\n const params = defu(\n {\n email: targetEmail,\n first_name: org.name,\n metadata: JSON.stringify({ organizationId: org.id }),\n },\n extraCreateParams,\n );\n const paystackOps = getPaystackOps(\n options.paystackClient as PaystackClientLike,\n );\n if (!paystackOps) return;\n const raw =\n (await paystackOps.customer?.create({\n body: params as CustomerCreatePayload,\n })) ??\n (await Promise.reject(\n new Error(\"Paystack client missing customer ops\"),\n ));\n const sdkRes = unwrapSdkResult<PaystackCustomerResponse>(raw);\n const customerCode = sdkRes?.customer_code as string | undefined;\n\n if (\n customerCode !== undefined &&\n customerCode !== null &&\n customerCode !== \"\" &&\n sdkRes !== undefined &&\n sdkRes !== null\n ) {\n await ctx.adapter.update({\n model: \"organization\",\n where: [{ field: \"id\", value: org.id }],\n update: {\n paystackCustomerCode: customerCode,\n },\n });\n\n if (typeof options.organization?.onCustomerCreate === \"function\") {\n await options.organization.onCustomerCreate(\n {\n paystackCustomer: sdkRes,\n organization: {\n ...org,\n paystackCustomerCode: customerCode,\n },\n },\n hookCtx!,\n );\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 }\n : undefined,\n },\n member: {\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 invitation: {\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 team: {\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 subscription = await getOrganizationSubscription(ctx, team.organizationId);\n if (subscription !== null && subscription !== undefined) {\n const plan = await getPlanByName(routeOptions, subscription.plan);\n const limits = plan?.limits;\n const maxTeams = limits?.teams as number | undefined;\n\n if (typeof maxTeams === \"number\") {\n await checkTeamLimit(ctx, team.organizationId, maxTeams);\n }\n }\n }\n },\n },\n },\n },\n };\n },\n $ERROR_CODES: INTERNAL_ERROR_CODES,\n options: options as NoInfer<O>,\n } satisfies BetterAuthPlugin;\n};\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 type {\n Subscription,\n SubscriptionOptions,\n PaystackPlan,\n PaystackOptions,\n PaystackProduct,\n PaystackClientLike,\n ChargeRecurringSubscriptionResult,\n PaystackSyncResult,\n} from \"./types\";\n"],"mappings":"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U;EACV,QAAQ;EACT;CACD,8BAA8B;EAC5B,MAAM;EACN,UAAU;EACV,OAAO;EACR;CACD,2BAA2B;EACzB,MAAM;EACN,UAAU;EACX;CACD,oBAAoB;EAClB,MAAM;EACN,UAAU;EACX;CACD,QAAQ;EACN,MAAM;EACN,cAAc;EACf;CACD,aAAa;EACX,MAAM;EACN,UAAU;EACX;CACD,WAAW;EACT,MAAM;EACN,UAAU;EACX;CACD,YAAY;EACV,MAAM;EACN,UAAU;EACX;CACD,UAAU;EACR,MAAM;EACN,UAAU;EACX;CACD,mBAAmB;EACjB,MAAM;EACN,UAAU;EACV,cAAc;EACf;CACD,SAAS;EACP,MAAM;EACN,UAAU;EACX;CACD,OAAO;EACL,MAAM;EACN,UAAU;EACX;CACD,aAAa;EACX,MAAM;EACN,UAAU;EACX;CACF,EACF,EACF;AAED,MAAa,OAAiC,EAC5C,MAAM,EACJ,QAAQ,EACN,sBAAsB;CACpB,MAAM;CACN,UAAU;CACV,OAAO;CACR,EACF,EACF,EACF;AAED,MAAa,eAAyC,EACpD,cAAc,EACZ,QAAQ;CACN,sBAAsB;EACpB,MAAM;EACN,UAAU;EACV,OAAO;EACR;CACD,OAAO;EACL,MAAM;EACN,UAAU;EACX;CACF,EACF,EACF;AAED,MAAa,WAAqC,EAChD,iBAAiB,EACf,QAAQ;CACN,MAAM;EACJ,MAAM;EACN,UAAU;EACX;CACD,aAAa;EACX,MAAM;EACN,UAAU;EACX;CACD,OAAO;EACL,MAAM;EACN,UAAU;EACX;CACD,UAAU;EACR,MAAM;EACN,UAAU;EACX;CACD,UAAU;EACR,MAAM;EACN,UAAU;EACV,cAAc;EACf;CACD,WAAW;EACT,MAAM;EACN,UAAU;EACV,cAAc;EACf;CACD,YAAY;EACV,MAAM;EACN,UAAU;EACV,QAAQ;EACT;CACD,MAAM;EACJ,MAAM;EACN,UAAU;EACV,QAAQ;EACT;CACD,UAAU;EACR,MAAM;EACN,UAAU;EACX;CACD,WAAW;EACT,MAAM;EACN,UAAU;EACX;CACD,WAAW;EACT,MAAM;EACN,UAAU;EACX;CACF,EACF,EACF;AA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"}