@alexasomba/better-auth-paystack 1.0.0-rc.3 → 1.0.4

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/utils.ts","../src/middleware.ts","../src/paystack-sdk.ts","../src/routes.ts","../src/schema.ts","../src/limits.ts","../src/index.ts"],"sourcesContent":["import type { PaystackOptions } from \"./types\";\n\nexport async function getPlans(subscriptionOptions: PaystackOptions[\"subscription\"]) {\n if (subscriptionOptions?.enabled) {\n return typeof subscriptionOptions.plans === \"function\"\n ? await subscriptionOptions.plans()\n : subscriptionOptions.plans;\n }\n throw new Error(\"Subscriptions are not enabled in the Paystack options.\");\n}\n\nexport async function getPlanByName(options: PaystackOptions<any>, name: string) {\n return await getPlans(options.subscription).then((plans) =>\n plans?.find((plan) => plan.name.toLowerCase() === name.toLowerCase()),\n );\n}\n\nexport async function getProducts(productOptions: PaystackOptions[\"products\"]) {\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(options: PaystackOptions<any>, name: string) {\n return await getProducts(options.products).then((products) =>\n products?.find((product) => product.name.toLowerCase() === name.toLowerCase()),\n );\n}\n","import { createAuthMiddleware } from \"@better-auth/core/api\";\nimport { logger } from \"better-auth\";\nimport { APIError } from \"better-auth/api\";\n\n\nimport type { PaystackOptions } 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) =>\n createAuthMiddleware(async (ctx) => {\n const session = ctx.context.session as any;\n\n if (!session) {\n throw new APIError(\"UNAUTHORIZED\");\n }\n const referenceId =\n ctx.body?.referenceId || ctx.query?.referenceId || session.user.id;\n \n const subscriptionOptions = options.subscription;\n\n\n\n if (referenceId === session.user.id) {\n return {\n referenceId,\n };\n }\n\n\n \n // 1. Try custom authorization first if provided\n if (subscriptionOptions?.enabled && 'authorizeReference' in subscriptionOptions && subscriptionOptions.authorizeReference) {\n const authorized = await subscriptionOptions.authorizeReference(\n {\n user: session.user,\n session,\n referenceId,\n action,\n },\n ctx,\n );\n if (authorized) {\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) {\n // Check if referenceId indicates an organization the user is a member of\n const member = await ctx.context.adapter.findOne<any>({\n model: \"member\",\n where: [\n { field: \"userId\", value: session.user.id },\n { field: \"organizationId\", value: referenceId }\n ]\n });\n \n if (member) {\n console.log(\"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 {\n PaystackClientLike,\n PaystackCustomerCreateInput,\n PaystackCustomerUpdateInput,\n PaystackNodeClient,\n PaystackOpenApiFetchResponse,\n PaystackSubscriptionFetchInit,\n PaystackSubscriptionCreateInput,\n PaystackSubscriptionToggleInput,\n PaystackTransactionInitializeInput,\n} from \"./types\";\n\nfunction isOpenApiFetchResponse(\n value: unknown,\n): value is PaystackOpenApiFetchResponse {\n return (\n !!value &&\n typeof value === \"object\" &&\n (\"data\" in value || \"error\" in value || \"response\" in value)\n );\n}\n\nexport function unwrapSdkResult<T = unknown>(result: unknown): T {\n if (isOpenApiFetchResponse(result)) {\n if (result.error) {\n throw result.error;\n }\n return result.data as T;\n }\n if (result && typeof result === \"object\" && \"data\" in result) {\n const data = (result as { data?: unknown }).data;\n return (data ?? result) as T;\n }\n return result as T;\n}\n\ntype MetadataValue = string | Record<string, unknown> | undefined;\n\nconst normalizeMetadata = (value: MetadataValue): string | undefined => {\n if (!value) return undefined;\n return typeof value === \"string\" ? value : JSON.stringify(value);\n};\n\nconst normalizeMetadataBody = <T extends { metadata?: MetadataValue }>(\n body: T,\n): Omit<T, \"metadata\"> & { metadata?: string } => {\n const { metadata, ...rest } = body;\n const normalized = normalizeMetadata(metadata);\n if (normalized === undefined) {\n return rest as Omit<T, \"metadata\"> & { metadata?: string };\n }\n return { ...rest, metadata: normalized } as Omit<T, \"metadata\"> & {\n metadata?: string;\n };\n};\n\ntype TransactionInitializeBody =\n Parameters<PaystackNodeClient[\"transaction_initialize\"]>[0] extends {\n body?: infer B;\n }\n ? B\n : never;\n\nexport function getPaystackOps(\n paystackClient: PaystackClientLike | null | undefined,\n) {\n return {\n customerCreate: async (params: PaystackCustomerCreateInput) => {\n if (paystackClient?.customer_create) {\n const body = normalizeMetadataBody(params);\n return paystackClient.customer_create({ body });\n }\n return paystackClient?.customer?.create?.(params);\n },\n customerUpdate: async (code: string, params: PaystackCustomerUpdateInput) => {\n if (paystackClient?.customer_update) {\n // Determine if it's the flat client (OpenAPI style)\n const body = normalizeMetadataBody(params);\n return paystackClient.customer_update({\n params: { path: { code } },\n body,\n });\n }\n return paystackClient?.customer?.update?.(code, params);\n },\n transactionInitialize: async (body: PaystackTransactionInitializeInput) => {\n if (paystackClient?.transaction_initialize) {\n return paystackClient.transaction_initialize({\n body: body as TransactionInitializeBody,\n });\n }\n return paystackClient?.transaction?.initialize?.(body);\n },\n transactionVerify: async (reference: string) => {\n if (paystackClient?.transaction_verify) {\n return paystackClient.transaction_verify({\n params: { path: { reference } },\n });\n }\n return paystackClient?.transaction?.verify?.(reference);\n },\n subscriptionCreate: async (body: PaystackSubscriptionCreateInput) => {\n if (paystackClient?.subscription_create) {\n return paystackClient.subscription_create({ body });\n }\n return paystackClient?.subscription?.create?.(body);\n },\n subscriptionDisable: async (body: PaystackSubscriptionToggleInput) => {\n if (paystackClient?.subscription_disable) {\n return paystackClient.subscription_disable({ body });\n }\n return paystackClient?.subscription?.disable?.(body);\n },\n subscriptionEnable: async (body: PaystackSubscriptionToggleInput) => {\n if (paystackClient?.subscription_enable) {\n return paystackClient.subscription_enable({ body });\n }\n return paystackClient?.subscription?.enable?.(body);\n },\n subscriptionFetch: async (idOrCode: string) => {\n if (paystackClient?.subscription_fetch) {\n try {\n return await paystackClient.subscription_fetch({\n params: { path: { code: idOrCode } },\n });\n } catch {\n const compatFetch = paystackClient.subscription_fetch as unknown as (\n init: PaystackSubscriptionFetchInit,\n ) => Promise<unknown>;\n return compatFetch({\n params: { path: { id_or_code: idOrCode } },\n });\n }\n }\n return paystackClient?.subscription?.fetch?.(idOrCode);\n },\n subscriptionManageLink: async (code: string) => {\n if (paystackClient?.subscription_manageLink) {\n return paystackClient.subscription_manageLink({\n params: { path: { code } },\n });\n }\n // Fallback for snake_case if older SDK version or different generator\n if (paystackClient?.subscription_manage_link) {\n return paystackClient.subscription_manage_link({\n params: { path: { code } },\n });\n }\n return paystackClient?.subscription?.manage?.link?.(code);\n },\n subscriptionManageEmail: async (code: string, email: string) => {\n if (paystackClient?.subscription_manageEmail) {\n return paystackClient.subscription_manageEmail({\n params: { path: { code } },\n });\n }\n return paystackClient?.subscription?.manage?.email?.(code, email);\n },\n };\n}\n","import { createAuthEndpoint } from \"@better-auth/core/api\";\nimport { defineErrorCodes } from \"@better-auth/core/utils\";\nimport { HIDE_METADATA } from \"better-auth\";\nimport {\n APIError,\n getSessionFromCtx,\n originCheck,\n sessionMiddleware,\n} from \"better-auth/api\";\nimport * as z from \"zod/v4\";\n\nimport type { InputPaystackTransaction, InputSubscription, PaystackOptions, PaystackTransaction, Subscription, Organization, Member, User } from \"./types\";\nimport { getPlanByName, getPlans, getProductByName, getProducts } from \"./utils\";\nimport { referenceMiddleware } from \"./middleware\";\nimport { getPaystackOps, unwrapSdkResult } from \"./paystack-sdk\";\n\ntype AnyPaystackOptions = PaystackOptions<any>;\n\nconst PAYSTACK_ERROR_CODES = 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:\n \"Email verification is required before you can subscribe to a plan\",\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 subtle = (globalThis.crypto as any)?.subtle;\n if (subtle) {\n const key = await subtle.importKey(\n \"raw\",\n keyData,\n { name: \"HMAC\", hash: \"SHA-512\" },\n 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 = (options: AnyPaystackOptions) => {\n return createAuthEndpoint(\n \"/paystack/webhook\",\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 = (ctx as any).requestClone ?? ctx.request;\n const payload = await request.text();\n const headers = (ctx as any).headers ?? (ctx.request as any)?.headers;\n const signature = headers?.get(\"x-paystack-signature\") as\n | string\n | null\n | undefined;\n\n if (!signature) {\n throw new APIError(\"UNAUTHORIZED\", {\n message: \"Missing x-paystack-signature header\",\n status: 401,\n });\n }\n\n const expected = await hmacSha512Hex(options.paystackWebhookSecret, 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 any;\n\n // Best-effort local state sync for subscription lifecycle.\n if (options.subscription?.enabled) {\n const eventName = String(event?.event ?? \"\");\n const data = event?.data as any;\n try {\n if (eventName === \"charge.success\") {\n const reference = data?.reference;\n const paystackId = data?.id ? String(data.id) : undefined;\n if (reference) {\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 }\n }\n\n if (eventName === \"charge.failure\") {\n const reference = data?.reference;\n if (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 // Transaction might not exist or other error, log and ignore\n ctx.context.logger.warn(\"Failed to update transaction status for charge.failure\", e);\n }\n }\n }\n\n if (eventName === \"subscription.create\") {\n const subscriptionCode =\n data?.subscription_code ??\n data?.subscription?.subscription_code ??\n data?.code;\n const customerCode =\n data?.customer?.customer_code ??\n data?.customer_code ??\n data?.customer?.code;\n const planCode =\n data?.plan?.plan_code ?? data?.plan_code ?? data?.plan;\n\n let metadata: any = data?.metadata;\n if (typeof metadata === \"string\") {\n try {\n metadata = JSON.parse(metadata);\n } catch {\n // ignore\n }\n }\n\n const referenceIdFromMetadata =\n typeof metadata === \"object\" && metadata\n ? (metadata.referenceId as string | undefined)\n : undefined;\n\n let planNameFromMetadata =\n typeof metadata === \"object\" && metadata\n ? (metadata.plan as string | undefined)\n : undefined;\n if (typeof planNameFromMetadata === \"string\") {\n planNameFromMetadata = planNameFromMetadata.toLowerCase();\n }\n\n const plans = await getPlans(options.subscription);\n const planFromCode = planCode\n ? plans.find((p) => p.planCode && p.planCode === planCode)\n : undefined;\n const planName = (planFromCode?.name ?? planNameFromMetadata)?.toLowerCase();\n\n if (subscriptionCode) {\n const where: Array<{ field: string; value: any }> = [];\n if (referenceIdFromMetadata) {\n where.push({ field: \"referenceId\", value: referenceIdFromMetadata });\n } else if (customerCode) {\n where.push({ field: \"paystackCustomerCode\", value: customerCode });\n }\n if (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,\n });\n const subscription = matches?.[0];\n if (subscription) {\n await ctx.context.adapter.update({\n model: \"subscription\",\n update: {\n paystackSubscriptionCode: subscriptionCode,\n status: \"active\",\n updatedAt: new Date(),\n },\n where: [{ field: \"id\", value: subscription.id }],\n });\n\n const plan = planFromCode ?? (planName ? await getPlanByName(options, planName) : undefined);\n if (plan) {\n await options.subscription.onSubscriptionComplete?.(\n { event, subscription: { ...subscription, paystackSubscriptionCode: subscriptionCode, status: \"active\" }, plan },\n ctx as any,\n );\n // Also call onSubscriptionCreated for subscriptions created outside of checkout\n await options.subscription.onSubscriptionCreated?.(\n { event, subscription: { ...subscription, paystackSubscriptionCode: subscriptionCode, status: \"active\" }, plan },\n ctx as any,\n );\n }\n }\n }\n }\n }\n\n if (eventName === \"subscription.disable\" || eventName === \"subscription.not_renew\") {\n const subscriptionCode =\n data?.subscription_code ??\n data?.subscription?.subscription_code ??\n data?.code;\n if (subscriptionCode) {\n // Find the subscription first to get full data for the hook\n const existing = await ctx.context.adapter.findOne<Subscription>({\n model: \"subscription\",\n where: [{ field: \"paystackSubscriptionCode\", value: subscriptionCode }],\n });\n\n await ctx.context.adapter.update({\n model: \"subscription\",\n update: {\n status: \"canceled\",\n updatedAt: new Date(),\n },\n where: [\n { field: \"paystackSubscriptionCode\", value: subscriptionCode },\n ],\n });\n\n if (existing) {\n await options.subscription.onSubscriptionCancel?.(\n { event, subscription: { ...existing, status: \"canceled\" } },\n ctx as any,\n );\n }\n }\n }\n } catch (e: any) {\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\n\nconst initializeTransactionBodySchema = z.object({\n plan: z.string().optional(),\n product: z.string().optional(),\n amount: z.number().int().positive().optional(), // Amount in smallest currency unit (e.g., kobo)\n currency: z.string().optional(),\n email: z.string().optional(),\n metadata: z.record(z.string(), z.any()).optional(),\n referenceId: z.string().optional(),\n callbackURL: z.string().optional(),\n quantity: z.number().int().positive().optional(),\n});\n\nexport const initializeTransaction = <P extends string = \"/paystack/initialize-transaction\">(options: AnyPaystackOptions, path: P = \"/paystack/initialize-transaction\" as P) => {\n const subscriptionOptions = options.subscription;\n // If subscriptions are enabled, use full middleware stack; otherwise just basics.\n // However, for one-time payments, we might not strictly need subscription middleware\n // checking for existing subs, but let's keep it consistent for now.\n const useMiddlewares = subscriptionOptions?.enabled\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 { plan: planName, product: productName, amount: bodyAmount, currency, email, metadata: extraMetadata, callbackURL, quantity } = ctx.body;\n\n // 1. Validate Callback URL validation (same as before)\n if (callbackURL) {\n const checkTrusted = () => {\n try {\n if (!callbackURL) return false;\n if (callbackURL.startsWith(\"/\")) return true;\n const baseUrl =\n (ctx.context as any)?.baseURL ??\n (ctx.request as any)?.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()) {\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) throw new APIError(\"UNAUTHORIZED\");\n const user = session.user;\n \n // 3. Email Verification Check (only if subscription options enforce it)\n if (subscriptionOptions?.enabled && subscriptionOptions.requireEmailVerification && !user.emailVerified) {\n throw new APIError(\"BAD_REQUEST\", {\n code: \"EMAIL_VERIFICATION_REQUIRED\",\n message: PAYSTACK_ERROR_CODES.EMAIL_VERIFICATION_REQUIRED,\n });\n }\n\n // 4. Determine Payment Mode: Subscription (Plan) vs Product vs One-Time (Amount)\n let plan: ReturnType<typeof getPlanByName> extends Promise<infer U> ? U : never;\n let product: ReturnType<typeof getProductByName> extends Promise<infer U> ? U : never;\n \n if (planName) {\n if (!subscriptionOptions?.enabled) {\n throw new APIError(\"BAD_REQUEST\", { message: \"Subscriptions are not enabled.\" });\n }\n plan = await getPlanByName(options, planName);\n if (!plan) {\n throw new APIError(\"BAD_REQUEST\", {\n code: \"SUBSCRIPTION_PLAN_NOT_FOUND\",\n message: PAYSTACK_ERROR_CODES.SUBSCRIPTION_PLAN_NOT_FOUND,\n status: 400\n });\n }\n } else if (productName) {\n product = await getProductByName(options, productName);\n if (!product) {\n throw new APIError(\"BAD_REQUEST\", {\n message: `Product '${productName}' not found.`,\n status: 400\n });\n }\n } else if (!bodyAmount) {\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 const amount = bodyAmount || product?.amount;\n const finalCurrency = currency || product?.currency || plan?.currency || \"NGN\";\n\n let url: string | undefined;\n let reference: string | undefined;\n let accessCode: string | undefined;\n\n // 5. Prepare Payload\n\n const referenceIdFromCtx = (ctx.context as any).referenceId as string | undefined;\n const referenceId = ctx.body.referenceId || referenceIdFromCtx || (session.user as any).id;\n\n console.log(\"DEBUG ROUTES REF:\", {\n referenceId,\n referenceIdFromCtx,\n bodyRef: ctx.body.referenceId,\n userId: (session.user as any).id,\n orgEnabled: options.organization?.enabled,\n contextKeys: Object.keys((ctx as any).context || {}),\n fullContext: (ctx as any).context\n });\n\n // Check trial eligibility - prevent trial abuse\n let trialStart: Date | undefined;\n let trialEnd: Date | undefined;\n if (plan && plan.freeTrial?.days && plan.freeTrial.days > 0) {\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) => sub.trialStart || sub.trialEnd || sub.status === \"trialing\"\n );\n \n if (!hadTrial) {\n trialStart = new Date();\n trialEnd = new Date();\n trialEnd.setDate(trialEnd.getDate() + plan.freeTrial.days);\n }\n }\n\n try {\n // Determine Customer Email & Code (Organization support)\n let targetEmail = email || user.email;\n let paystackCustomerCode = (user as any).paystackCustomerCode;\n\n if (options.organization?.enabled && referenceId && referenceId !== user.id) {\n const org = await ctx.context.adapter.findOne<Organization>({\n model: \"organization\",\n where: [{ field: \"id\", value: referenceId }],\n });\n if (org) {\n // Prefer organization's existing Paystack customer code\n if (org.paystackCustomerCode) {\n paystackCustomerCode = org.paystackCustomerCode;\n }\n if (org.email) {\n targetEmail = org.email;\n } else {\n // Fallback: Use Organization Owner Email\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\n if (ownerMember) {\n const ownerUser = await ctx.context.adapter.findOne<User>({\n model: \"user\",\n where: [{ field: \"id\", value: ownerMember.userId }]\n });\n\n if (ownerUser?.email) {\n targetEmail = ownerUser.email;\n }\n }\n }\n }\n }\n\n // Construct Metadata\n const metadata = JSON.stringify({\n referenceId,\n userId: user.id,\n plan: plan?.name.toLowerCase(), // Undefined for one-time\n product: product?.name.toLowerCase(),\n isTrial: !!trialStart,\n trialEnd: trialEnd?.toISOString(),\n ...extraMetadata,\n });\n\n const initBody: any = {\n email: targetEmail,\n callback_url: callbackURL,\n metadata,\n // If plan/product exists, use its currency; otherwise fallback to provided or default\n currency: finalCurrency,\n quantity,\n };\n\n // Sync/Update Customer: ensure email matches if code exists\n if (paystackCustomerCode) {\n try {\n const ops = getPaystackOps(options.paystackClient);\n // Only update if email is present\n if (initBody.email) {\n await ops.customerUpdate(paystackCustomerCode, { email: initBody.email });\n }\n } catch (e) {\n // Ignore sync errors\n }\n }\n\n\n if (plan) {\n // Subscription Flow\n if (trialStart) {\n // Trial Flow: Authorize card with minimum amount, don't start sub yet\n initBody.amount = 5000; // 50 NGN (minimum allowed)\n // Do NOT set initBody.plan\n } else {\n // Standard Flow\n initBody.plan = plan.planCode;\n initBody.invoice_limit = plan.invoiceLimit;\n // Paystack requires amount even with planCode (it uses plan's stored amount)\n // For local plans without planCode, use finalAmount; for planCode plans, use plan.amount or minimum\n const planAmount = amount ?? plan.amount ?? 50000; // 500 NGN minimum fallback\n initBody.amount = Math.max(Math.round(planAmount), 50000);\n if (quantity) {\n initBody.amount = initBody.amount * quantity;\n }\n }\n } else {\n // One-Time Payment Flow\n if (!amount) throw new Error(\"Amount is required for one-time payments\");\n initBody.amount = Math.round(amount);\n }\n\n const initRaw = await paystack.transactionInitialize(initBody);\n const initRes = unwrapSdkResult<any>(initRaw);\n let data =\n initRes && typeof initRes === \"object\" && \"status\" in initRes && \"data\" in initRes\n ? (initRes as any).data\n : initRes?.data ?? initRes;\n \n if (data && typeof data === \"object\" && \"status\" in data && \"data\" in data) {\n data = data.data;\n }\n url = data?.authorization_url;\n reference = data?.reference;\n accessCode = data?.access_code;\n } catch (error: any) {\n ctx.context.logger.error(\"Failed to initialize Paystack transaction\", error);\n throw new APIError(\"BAD_REQUEST\", {\n code: \"FAILED_TO_INITIALIZE_TRANSACTION\",\n message: error?.message || PAYSTACK_ERROR_CODES.FAILED_TO_INITIALIZE_TRANSACTION,\n });\n }\n\n // 6. Record Transaction & Subscription\n await ctx.context.adapter.create<InputPaystackTransaction, PaystackTransaction>({\n model: \"paystackTransaction\",\n data: {\n reference: reference!,\n referenceId,\n userId: user.id,\n amount: amount!,\n currency: plan?.currency || currency || \"NGN\",\n status: \"pending\",\n plan: plan?.name.toLowerCase(),\n metadata: extraMetadata ? JSON.stringify(extraMetadata) : undefined,\n createdAt: new Date(),\n updatedAt: new Date(),\n },\n });\n\n if (plan) {\n // Re-fetch customer code if it wasn't available before (though we didn't force-create it here)\n // For now, use what we have (user's or org's)\n let storedCustomerCode = (user as any).paystackCustomerCode;\n if (options.organization?.enabled && referenceId !== user.id) {\n const org = await ctx.context.adapter.findOne<Organization>({\n model: \"organization\",\n where: [{ field: \"id\", value: referenceId }],\n });\n if (org?.paystackCustomerCode) {\n storedCustomerCode = org.paystackCustomerCode;\n }\n }\n\n const newSubscription = await ctx.context.adapter.create<InputSubscription, Subscription>({\n model: \"subscription\",\n data: {\n plan: plan.name.toLowerCase(),\n referenceId,\n paystackCustomerCode: storedCustomerCode,\n paystackTransactionReference: reference,\n status: trialStart ? \"trialing\" : \"incomplete\",\n seats: quantity,\n trialStart,\n trialEnd,\n },\n });\n\n // Call trial start hook if trial was granted\n if (trialStart && newSubscription && plan.freeTrial?.onTrialStart) {\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 = (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 const verifyBodySchema = z.object({\n reference: z.string(),\n });\n\n const subscriptionOptions = options.subscription;\n const useMiddlewares = subscriptionOptions?.enabled\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 verifyRes: any;\n try {\n const verifyRaw = await paystack.transactionVerify(ctx.body.reference);\n verifyRes = unwrapSdkResult<any>(verifyRaw);\n } catch (error: any) {\n ctx.context.logger.error(\"Failed to verify Paystack transaction\", error);\n throw new APIError(\"BAD_REQUEST\", {\n code: \"FAILED_TO_VERIFY_TRANSACTION\",\n message:\n error?.message || PAYSTACK_ERROR_CODES.FAILED_TO_VERIFY_TRANSACTION,\n });\n }\n let data =\n verifyRes && typeof verifyRes === \"object\" && \"status\" in verifyRes && \"data\" in verifyRes\n ? (verifyRes as any).data\n : verifyRes?.data ?? verifyRes;\n \n if (data && typeof data === \"object\" && \"status\" in data && \"data\" in data) {\n data = data.data;\n }\n const status = data?.status;\n const reference = data?.reference ?? ctx.body.reference;\n const paystackId = data?.id ? String(data.id) : undefined;\n\n if (status === \"success\") {\n try {\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<any>({\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 = txRecord?.referenceId ?? (session?.user as any)?.id;\n\n // Authorization check: ensure the current user has access to this referenceId\n if (session && referenceId !== session.user.id) {\n const authRef = (subscriptionOptions as any)?.authorizeReference;\n let authorized = false;\n if (authRef) {\n authorized = await authRef({\n user: session.user,\n session,\n referenceId,\n action: \"verify-transaction\"\n }, ctx);\n } else if (options.organization?.enabled) {\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 if (member) authorized = true;\n }\n \n if (!authorized) {\n throw new APIError(\"UNAUTHORIZED\");\n }\n }\n\n await ctx.context.adapter.update({\n model: \"paystackTransaction\",\n update: {\n status: \"success\",\n paystackId,\n // Update with actual amount/currency from Paystack (for planCode subscriptions)\n ...(data?.amount && { amount: data.amount }),\n ...(data?.currency && { currency: data.currency }),\n updatedAt: new Date(),\n },\n where: [{ field: \"reference\", value: reference }],\n });\n\n // Sync Customer Code back to User or Org if missing\n const paystackCustomerCodeFromPaystack = data?.customer?.customer_code;\n if (paystackCustomerCodeFromPaystack && referenceId) {\n const isOrg = options.organization?.enabled && (referenceId.startsWith(\"org_\") || (await ctx.context.adapter.findOne({ model: \"organization\", where: [{ field: \"id\", value: referenceId }] })));\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 // Check for trial activation\n let isTrial = false;\n let trialEnd: string | undefined;\n let targetPlan: string | undefined;\n\n if (data?.metadata) {\n const meta = typeof data.metadata === 'string' ? JSON.parse(data.metadata) : data.metadata;\n isTrial = !!meta.isTrial;\n trialEnd = meta.trialEnd;\n targetPlan = meta.plan;\n }\n\n let paystackSubscriptionCode: string | undefined;\n\n if (isTrial && targetPlan && trialEnd) {\n // Trial Flow: Create subscription with future start date using auth code\n const authorizationCode = data?.authorization?.authorization_code;\n const email = data?.customer?.email;\n \n // We need the planCode. We have the plan NAME in metadata (lowercased).\n const plans = await getPlans(subscriptionOptions as any);\n const planConfig = plans.find(p => p.name.toLowerCase() === targetPlan?.toLowerCase());\n\n if (authorizationCode && email && planConfig?.planCode) {\n const subRes = await paystack.subscriptionCreate({\n customer: email,\n plan: planConfig.planCode,\n authorization: authorizationCode,\n start_date: trialEnd\n });\n const subData = unwrapSdkResult<any>(subRes);\n const cleanSubData = (subData as any).data || subData;\n console.log(\"Trial Subscription Created:\", JSON.stringify(cleanSubData, null, 2));\n paystackSubscriptionCode = cleanSubData?.subscription_code;\n }\n }\n\n const 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 ...(paystackSubscriptionCode && { paystackSubscriptionCode }),\n },\n where: [\n { field: \"paystackTransactionReference\", value: reference },\n ...(referenceId ? [{ field: \"referenceId\", value: referenceId }] : []),\n ],\n });\n\n if (updatedSubscription && subscriptionOptions?.enabled && (subscriptionOptions as any).onSubscriptionComplete) {\n const subOpts = subscriptionOptions as any;\n const plans = await getPlans(subOpts);\n const plan = plans.find(p => p.name.toLowerCase() === updatedSubscription.plan.toLowerCase());\n if (plan) {\n await subOpts.onSubscriptionComplete({\n event: data,\n subscription: updatedSubscription,\n plan\n }, ctx as any);\n }\n }\n } catch (e: any) {\n ctx.context.logger.error(\n \"Failed to update transaction/subscription after verification\",\n e,\n );\n }\n } else if (status === \"failed\" || status === \"abandoned\") {\n try {\n await ctx.context.adapter.update({\n model: \"paystackTransaction\",\n update: {\n status,\n updatedAt: new Date(),\n },\n where: [{ field: \"reference\", value: reference }],\n });\n } catch (e: any) {\n ctx.context.logger.error(\"Failed to update transaction status\", e);\n }\n }\n\n return ctx.json({\n status,\n reference,\n data,\n });\n },\n );\n};\n\nexport const listSubscriptions = (options: AnyPaystackOptions) => {\n const listQuerySchema = z.object({\n referenceId: z.string().optional(),\n });\n\n const subscriptionOptions = options.subscription;\n const useMiddlewares = subscriptionOptions?.enabled\n ? [sessionMiddleware, originCheck, referenceMiddleware(options, \"list-subscriptions\")]\n : [sessionMiddleware, originCheck];\n\n return createAuthEndpoint(\n \"/paystack/list-subscriptions\",\n {\n method: \"GET\",\n query: listQuerySchema,\n use: useMiddlewares,\n },\n async (ctx) => {\n if (!subscriptionOptions?.enabled) {\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) throw new APIError(\"UNAUTHORIZED\");\n const referenceId =\n ((ctx.context as any).referenceId as string | undefined) ??\n (ctx.query?.referenceId as string | undefined) ??\n ((session.user as any).id as string);\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 = \"/paystack/list-transactions\">(options: AnyPaystackOptions, path: P = \"/paystack/list-transactions\" as P) => {\n const listQuerySchema = z.object({\n referenceId: z.string().optional(),\n });\n\n const subscriptionOptions = options.subscription;\n const useMiddlewares = subscriptionOptions?.enabled\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) throw new APIError(\"UNAUTHORIZED\");\n const referenceId =\n ((ctx.context as any).referenceId as string | undefined) ??\n (ctx.query?.referenceId as string | undefined) ??\n ((session.user as any).id as string);\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 if adapter doesn't support it well, \n // but Better Auth adapters usually return in insertion order.\n // Let's sort to be sure.\n const sorted = res.sort((a, b) => new Date(b.createdAt).getTime() - new Date(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});\n\nfunction decodeBase64UrlToString(value: string): string {\n const normalized = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padded = normalized + \"===\".slice((normalized.length + 3) % 4);\n if (typeof (globalThis as any).atob === \"function\") {\n return (globalThis as any).atob(padded);\n }\n // Node fallback\n \n return Buffer.from(padded, \"base64\").toString(\"utf8\");\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) 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 any;\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 = \"/paystack/disable-subscription\">(options: AnyPaystackOptions, path: P = \"/paystack/disable-subscription\" as P) => {\n const subscriptionOptions = options.subscription;\n const useMiddlewares = subscriptionOptions?.enabled\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 } = ctx.body;\n const paystack = getPaystackOps(options.paystackClient);\n try {\n let emailToken = ctx.body.emailToken;\n if (!emailToken) {\n try {\n const raw = await paystack.subscriptionFetch(subscriptionCode);\n const fetchRes = unwrapSdkResult<any>(raw);\n const data =\n fetchRes && typeof fetchRes === \"object\" && \"status\" in fetchRes && \"data\" in fetchRes\n ? (fetchRes as any).data\n : fetchRes?.data ?? fetchRes;\n emailToken = data?.email_token;\n } catch {\n // ignore; try manage-link fallback below\n }\n }\n\n if (!emailToken) {\n try {\n const raw = await paystack.subscriptionManageLink(subscriptionCode);\n const linkRes = unwrapSdkResult<any>(raw);\n const data =\n linkRes && typeof linkRes === \"object\" && \"status\" in linkRes && \"data\" in linkRes\n ? (linkRes as any).data\n : linkRes?.data ?? linkRes;\n // data might be string (link) or object with link?\n // SDK says it returns string usually? \n // Actually the SDK wrapper returns the response object.\n const link = typeof data === \"string\" ? data : data?.link;\n \n if (link) {\n emailToken = tryGetEmailTokenFromSubscriptionManageLink(link);\n }\n } catch {\n // ignore\n }\n }\n \n if (!emailToken) {\n // One last try: send email to owner? No, that's async.\n // If we still don't have emailToken, we can't disable.\n throw new Error(\"Could not retrieve email_token for subscription disable.\");\n }\n\n await paystack.subscriptionDisable({ code: subscriptionCode, token: emailToken });\n \n // Update local status immediately\n await ctx.context.adapter.update({\n model: \"subscription\",\n update: {\n status: \"canceled\",\n updatedAt: new Date(),\n },\n where: [{ field: \"paystackSubscriptionCode\", value: subscriptionCode }],\n });\n\n return ctx.json({ status: \"success\" });\n } catch (error: any) {\n ctx.context.logger.error(\"Failed to disable subscription\", error);\n throw new APIError(\"BAD_REQUEST\", {\n code: \"FAILED_TO_DISABLE_SUBSCRIPTION\",\n message:\n error?.message || PAYSTACK_ERROR_CODES.FAILED_TO_DISABLE_SUBSCRIPTION,\n });\n }\n },\n );\n};\n\nexport const enablePaystackSubscription = <P extends string = \"/paystack/enable-subscription\">(options: AnyPaystackOptions, path: P = \"/paystack/enable-subscription\" as P) => {\n const subscriptionOptions = options.subscription;\n const useMiddlewares = subscriptionOptions?.enabled\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) {\n try {\n const raw = await paystack.subscriptionFetch(subscriptionCode);\n const fetchRes = unwrapSdkResult<any>(raw);\n const data =\n fetchRes && typeof fetchRes === \"object\" && \"status\" in fetchRes && \"data\" in fetchRes\n ? (fetchRes as any).data\n : fetchRes?.data ?? fetchRes;\n emailToken = data?.email_token;\n } catch {\n }\n }\n\n if (!emailToken) {\n try {\n const raw = await paystack.subscriptionManageLink(subscriptionCode);\n const linkRes = unwrapSdkResult<any>(raw);\n const data =\n linkRes && typeof linkRes === \"object\" && \"status\" in linkRes && \"data\" in linkRes\n ? (linkRes as any).data\n : linkRes?.data ?? linkRes;\n const link = typeof data === \"string\" ? data : data?.link;\n \n if (link) {\n emailToken = tryGetEmailTokenFromSubscriptionManageLink(link);\n }\n } catch {\n }\n }\n \n if (!emailToken) {\n throw new Error(\"Could not retrieve email_token for subscription enable.\");\n }\n\n await paystack.subscriptionEnable({ code: subscriptionCode, token: emailToken });\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: any) {\n ctx.context.logger.error(\"Failed to enable subscription\", error);\n throw new APIError(\"BAD_REQUEST\", {\n code: \"FAILED_TO_ENABLE_SUBSCRIPTION\",\n message:\n error?.message || PAYSTACK_ERROR_CODES.FAILED_TO_ENABLE_SUBSCRIPTION,\n });\n }\n },\n );\n};\n\nexport const getSubscriptionManageLink = (options: AnyPaystackOptions) => {\n const manageLinkQuerySchema = z.object({\n subscriptionCode: z.string(),\n });\n const subscriptionOptions = options.subscription;\n const useMiddlewares = subscriptionOptions?.enabled\n ? [sessionMiddleware, originCheck, referenceMiddleware(options, \"get-subscription-manage-link\")]\n : [sessionMiddleware, originCheck];\n\n return createAuthEndpoint(\n \"/paystack/get-subscription-manage-link\",\n {\n method: \"GET\",\n query: manageLinkQuerySchema,\n use: useMiddlewares,\n },\n async (ctx) => {\n const { subscriptionCode } = ctx.query;\n const paystack = getPaystackOps(options.paystackClient);\n try {\n const raw = await paystack.subscriptionManageLink(subscriptionCode);\n const res = unwrapSdkResult<any>(raw);\n const data =\n res && typeof res === \"object\" && \"status\" in res && \"data\" in res\n ? (res as any).data\n : res?.data ?? res;\n // data might be string or object with link\n const link = typeof data === \"string\" ? data : data?.link;\n \n return ctx.json({ link });\n } catch (error: any) {\n ctx.context.logger.error(\"Failed to get subscription manage link\", error);\n throw new APIError(\"BAD_REQUEST\", {\n message: error?.message || \"Failed to get subscription manage link\",\n });\n }\n },\n );\n};\n\nexport const getConfig = (options: AnyPaystackOptions) => {\n return createAuthEndpoint(\n \"/paystack/get-config\",\n {\n method: \"GET\",\n metadata: {\n openapi: {\n operationId: \"getPaystackConfig\",\n },\n },\n },\n async (ctx) => {\n const plans = options.subscription?.enabled\n ? await getPlans(options.subscription)\n : [];\n const products = await getProducts(options.products);\n return ctx.json({\n plans,\n products,\n });\n }\n );\n};\n\nexport { PAYSTACK_ERROR_CODES };\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 = {\n paystackTransaction: {\n fields: {\n reference: {\n type: \"string\",\n required: true,\n },\n paystackId: {\n type: \"string\",\n required: false,\n },\n referenceId: {\n type: \"string\",\n required: true,\n },\n userId: {\n type: \"string\",\n required: 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 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 = {\n subscription: {\n fields: {\n plan: {\n type: \"string\",\n required: true,\n },\n referenceId: {\n type: \"string\",\n required: true,\n },\n paystackCustomerCode: {\n type: \"string\",\n required: false,\n },\n paystackSubscriptionCode: {\n type: \"string\",\n required: false,\n },\n paystackTransactionReference: {\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 },\n },\n} satisfies BetterAuthPluginDBSchema;\n\nexport const user = {\n user: {\n fields: {\n paystackCustomerCode: {\n type: \"string\",\n required: false,\n },\n },\n },\n} satisfies BetterAuthPluginDBSchema;\n\nexport const organization = {\n organization: {\n fields: {\n paystackCustomerCode: {\n type: \"string\",\n required: false,\n },\n email: {\n type: \"string\",\n required: false,\n },\n },\n },\n} satisfies BetterAuthPluginDBSchema;\n\nexport const getSchema = (options: PaystackOptions<any>) => {\n let baseSchema: BetterAuthPluginDBSchema;\n\n if (options.subscription?.enabled) {\n baseSchema = {\n ...subscriptions,\n ...transactions,\n ...user,\n };\n } else {\n baseSchema = {\n ...user,\n ...transactions,\n };\n }\n\n // Add organization schema if organization support is enabled\n if (options.organization?.enabled) {\n baseSchema = {\n ...baseSchema,\n ...organization,\n };\n }\n\n if (\n options.schema &&\n !options.subscription?.enabled &&\n \"subscription\" in options.schema\n ) {\n const { subscription: _subscription, ...restSchema } = options.schema as any;\n return mergeSchema(baseSchema, restSchema);\n }\n\n return mergeSchema(baseSchema, options.schema);\n};\n","\nimport type { GenericEndpointContext } from \"better-auth\";\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: number = 1\n) => {\n const subscription = await getOrganizationSubscription(ctx, organizationId);\n \n // If no subscription or no seats defined, we assume no limit or fallback to default\n // For this implementation, let's say if no seats defined, it is unlimited or strictly limited \n // depending on requirement. Usually unlimited if not specified, OR 1.\n // Let's assume if 'seats' is present, it's the limit.\n \n if (!subscription || !subscription.seats) {\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 (members.length + seatsToAdd > subscription.seats) {\n throw new Error(`Organization member limit reached. Used: ${members.length}, Max: ${subscription.seats}`);\n }\n\n return true;\n};\n\nexport const checkTeamLimit = async (\n ctx: GenericEndpointContext,\n organizationId: string,\n maxTeams: number\n) => {\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 Error(`Organization team limit reached. Max teams: ${maxTeams}`);\n }\n\n return true;\n};\n","import { defineErrorCodes } from \"@better-auth/core/utils\";\nimport type { GenericEndpointContext } 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} from \"./routes\";\nimport { getSchema } from \"./schema\";\nimport { checkSeatLimit, checkTeamLimit, getOrganizationSubscription } from \"./limits\";\nimport { getPlanByName } from \"./utils\";\nimport type {\n PaystackNodeClient,\n PaystackClientLike,\n PaystackOptions,\n PaystackPlan,\n Subscription,\n SubscriptionOptions,\n PaystackProduct,\n\n} from \"./types\";\nimport { getPaystackOps, unwrapSdkResult } from \"./paystack-sdk\";\n\nconst INTERNAL_ERROR_CODES = defineErrorCodes({\n ...PAYSTACK_ERROR_CODES,\n});\n\nexport const paystack = <\n TPaystackClient extends PaystackClientLike = PaystackNodeClient,\n O extends PaystackOptions<TPaystackClient> = PaystackOptions<TPaystackClient>,\n>(\n options: O,\n) => {\n const res = {\n id: \"paystack\",\n endpoints: {\n \"initialize-transaction\": initializeTransaction(options),\n \"verify-transaction\": verifyTransaction(options),\n \"list-subscriptions\": listSubscriptions(options),\n \"paystack-webhook\": paystackWebhook(options),\n \"list-transactions\": listTransactions(options),\n \"get-config\": getConfig(options),\n \"disable-subscription\": disablePaystackSubscription(options),\n \"enable-subscription\": enablePaystackSubscription(options),\n \"get-subscription-manage-link\": getSubscriptionManageLink(options),\n \"create-subscription\": createSubscription(options),\n \"upgrade-subscription\": upgradeSubscription(options),\n \"cancel-subscription\": cancelSubscription(options),\n \"restore-subscription\": restoreSubscription(options),\n },\n schema: getSchema(options),\n init: async (ctx: any) => {\n return {\n options: {\n databaseHooks: {\n user: {\n create: {\n async after(user: any, hookCtx?: GenericEndpointContext | null) {\n if (!hookCtx || !options.createCustomerOnSignUp) return;\n\n const paystackOps = getPaystackOps(options.paystackClient as any);\n const raw = await paystackOps.customerCreate({\n email: user.email,\n first_name: user.name || undefined,\n metadata: {\n userId: user.id,\n },\n });\n const data = unwrapSdkResult<any>(raw);\n const customerCode = data?.customer_code || data?.data?.customer_code;\n\n if (!customerCode) {\n return;\n }\n await (hookCtx as any).context.adapter.update({\n model: \"user\",\n where: [{ field: \"id\", value: user.id }],\n update: {\n paystackCustomerCode: customerCode,\n },\n });\n },\n },\n },\n organization: options.organization?.enabled\n ? {\n create: {\n async after(org: any, hookCtx: GenericEndpointContext | null) {\n try {\n const extraCreateParams = options.organization?.getCustomerCreateParams\n ? await options.organization.getCustomerCreateParams(org, hookCtx as any)\n : {};\n\n let targetEmail = org.email;\n if (!targetEmail) {\n const ownerMember = await (hookCtx as any).context.adapter.findOne({\n model: \"member\",\n where: [\n { field: \"organizationId\", value: org.id },\n { field: \"role\", value: \"owner\" }\n ]\n });\n if (ownerMember) {\n const ownerUser = await (hookCtx as any).context.adapter.findOne({\n model: \"user\",\n where: [{ field: \"id\", value: ownerMember.userId }]\n });\n targetEmail = ownerUser?.email;\n }\n }\n\n if (!targetEmail) return;\n\n const params = defu(\n {\n email: targetEmail,\n first_name: org.name,\n metadata: { organizationId: org.id },\n },\n extraCreateParams,\n );\n const paystack = getPaystackOps(options.paystackClient as any);\n const raw = await paystack.customerCreate(params as any);\n const sdkRes = unwrapSdkResult<any>(raw);\n const paystackCustomer =\n sdkRes && typeof sdkRes === \"object\" && \"status\" in sdkRes && \"data\" in sdkRes\n ? (sdkRes as any).data\n : sdkRes?.data ?? sdkRes;\n const customerCode = paystackCustomer?.customer_code;\n\n if (!customerCode) return;\n\n await (hookCtx as any).context.internalAdapter.updateOrganization(org.id, {\n paystackCustomerCode: customerCode,\n });\n\n await options.organization?.onCustomerCreate?.(\n {\n paystackCustomer,\n organization: {\n ...(org as any),\n paystackCustomerCode: customerCode,\n },\n },\n hookCtx as any,\n );\n } catch (error: any) {\n ctx.context.logger.error(\"Failed to create Paystack customer for organization\", error);\n }\n },\n },\n }\n : undefined,\n },\n member: {\n create: {\n before: async (member: any, ctx: GenericEndpointContext | null | undefined) => {\n if (options.subscription?.enabled && member.organizationId && ctx) {\n await checkSeatLimit(ctx, member.organizationId);\n }\n },\n },\n },\n invitation: {\n create: {\n before: async (invitation: any, ctx: GenericEndpointContext | null | undefined) => {\n if (options.subscription?.enabled && invitation.organizationId && ctx) {\n await checkSeatLimit(ctx, invitation.organizationId);\n }\n },\n },\n },\n team: {\n create: {\n before: async (team: any, ctx: GenericEndpointContext | null | undefined) => {\n if (options.subscription?.enabled && team.organizationId && ctx) {\n const subscription = await getOrganizationSubscription(ctx, team.organizationId);\n if (subscription) {\n const plan = await getPlanByName(options, subscription.plan);\n const limits = plan?.limits as Record<string, unknown> | undefined;\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 } as const;\n\n\n\n return res;\n};\n\nexport type PaystackPlugin<O extends PaystackOptions<any> = PaystackOptions> = ReturnType<\n typeof paystack<any, O>\n>;\n\nexport type { Subscription, SubscriptionOptions, PaystackPlan, PaystackOptions, PaystackProduct };\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/utils.ts","../src/middleware.ts","../src/paystack-sdk.ts","../src/routes.ts","../src/schema.ts","../src/limits.ts","../src/index.ts"],"sourcesContent":["import type { PaystackClientLike, PaystackOptions } from \"./types\";\n\n \nexport async function getPlans(subscriptionOptions: PaystackOptions[\"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: PaystackOptions<PaystackClientLike>, 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: PaystackOptions<PaystackClientLike>, 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: PaystackOptions<PaystackClientLike>, 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: PaystackOptions[\"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: PaystackOptions<PaystackClientLike>, name: string) {\n\treturn await getProducts(options.products).then((products) =>\n\t\tproducts?.find((product) => product.name.toLowerCase() === name.toLowerCase()),\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","import { createAuthMiddleware } from \"@better-auth/core/api\";\nimport { logger } from \"better-auth\";\nimport { APIError } from \"better-auth/api\";\n\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<{ id: string }>({\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 {\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 typeof value === \"object\" &&\n (\"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;\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\treturn (data ?? result) as T;\n\t}\n\treturn result as T;\n}\n\ntype MetadataValue = string | Record<string, unknown> | undefined;\n\nconst normalizeMetadata = (value: MetadataValue): string | undefined => {\n\tif (value === undefined || value === null || value === \"\") return undefined;\n\treturn typeof value === \"string\" ? value : JSON.stringify(value);\n};\n\nconst normalizeMetadataBody = <T extends { metadata?: MetadataValue }>(\n\tbody: T,\n): Omit<T, \"metadata\"> & { metadata?: string } => {\n\tconst { metadata, ...rest } = body;\n\tconst normalized = normalizeMetadata(metadata);\n\tif (normalized === undefined) {\n\t\treturn rest as Omit<T, \"metadata\"> & { metadata?: string };\n\t}\n\treturn { ...rest, metadata: normalized } as Omit<T, \"metadata\"> & {\n metadata?: string;\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\tconst body = normalizeMetadataBody(params);\n\t\t\t\treturn paystackClient.customer_create({ 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\t// Determine if it's the flat client (OpenAPI style)\n\t\t\t\tconst body = normalizeMetadataBody(params);\n\t\t\t\treturn paystackClient.customer_update({\n\t\t\t\t\tparams: { path: { code } },\n\t\t\t\t\tbody,\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 init: PaystackSubscriptionFetchInit,\n ) => 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\ttransactionChargeAuthorization: (body: PaystackTransactionChargeAuthorizationInput) => {\n\t\t\tif (paystackClient?.transaction_chargeAuthorization !== undefined) {\n\t\t\t\treturn paystackClient.transaction_chargeAuthorization({\n\t\t\t\t\t \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};\n}\n","import { createAuthEndpoint } from \"@better-auth/core/api\";\nimport { defineErrorCodes } from \"@better-auth/core/utils\";\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 { InputPaystackTransaction, InputSubscription, PaystackOptions, PaystackTransaction, Subscription, Organization, Member, User, PaystackClientLike } from \"./types\";\nimport { getNextPeriodEnd, getPlanByName, getPlans, getProductByName, getProducts, validateMinAmount } from \"./utils\";\nimport type { PaystackPlan, PaystackProduct } from \"./types\";\nimport { referenceMiddleware } from \"./middleware\";\nimport { getPaystackOps, unwrapSdkResult } from \"./paystack-sdk\";\n\ntype AnyPaystackOptions = PaystackOptions<PaystackClientLike>;\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 \"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 GenericEndpointContext & { requestClone?: Request }).requestClone ?? ctx.request;\n\t\t\tif (!request) {\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 | string\n | null\n | 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);\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\tconst eventName = String(event?.event ?? \"\");\n\t\t\t\tconst data = event?.data;\n\t\t\t\ttry {\n\t\t\t\t\tif (eventName === \"charge.success\") {\n\t\t\t\t\t\tconst reference = (data as Record<string, unknown> | undefined)?.reference as string | undefined;\n\t\t\t\t\t\tconst paystackId = (data as Record<string, unknown> | undefined)?.id !== undefined && (data as Record<string, unknown> | undefined)?.id !== null ? String((data as Record<string, unknown>).id) : undefined;\n\t\t\t\t\t\tif (reference !== undefined && reference !== null && reference !== \"\") {\n\t\t\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\t\t\tmodel: \"paystackTransaction\",\n\t\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\t\t\t\t\tpaystackId,\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: [{ field: \"reference\", value: reference }],\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 === \"charge.failure\") {\n\t\t\t\t\t\tconst reference = (data as Record<string, unknown> | undefined)?.reference as string | undefined;\n\t\t\t\t\t\tif (reference !== undefined && reference !== null && reference !== \"\") {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\t\t\t\tmodel: \"paystackTransaction\",\n\t\t\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\t\t\tstatus: \"failed\",\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: \"reference\", value: reference }],\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\t\t// Transaction might not exist or other error, log and ignore\n\t\t\t\t\t\t\t\t(ctx as unknown as { context: { logger: { warn: (msg: string, err: unknown) => void } } }).context.logger.warn(\"Failed to update transaction status for charge.failure\", e);\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.create\") {\n\t\t\t\t\t\tconst subscriptionCode =\n data?.subscription_code ??\n data?.subscription?.subscription_code ??\n data?.code;\n\t\t\t\t\t\tconst customerCode =\n data?.customer?.customer_code ??\n data?.customer_code ??\n data?.customer?.code;\n\t\t\t\t\t\tconst planCode =\n data?.plan?.plan_code ?? data?.plan_code ?? data?.plan;\n\n\t\t\t\t\t\tlet metadata: unknown = data?.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 typeof metadata === \"object\" && metadata !== null\n \t? ((metadata as Record<string, unknown>).referenceId as string | undefined)\n \t: undefined;\n\n\t\t\t\t\t\tlet planNameFromMetadata =\n typeof metadata === \"object\" && metadata !== null\n \t? ((metadata as Record<string, unknown>).plan as string | undefined)\n \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 !== undefined && matches !== null) ? matches[0] : undefined;\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: (data?.next_payment_date !== undefined && data?.next_payment_date !== null && data?.next_payment_date !== \"\") ? new Date(data.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 ctx 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 ctx 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 subscriptionCode =\n data?.subscription_code ??\n data?.subscription?.subscription_code ??\n data?.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\tif (existing?.cancelAtPeriodEnd === true && existing.periodEnd !== undefined && existing.periodEnd !== null && new Date(existing.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\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) {\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 ctx 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\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\n\nconst initializeTransactionBodySchema = z.object({\n\tplan: z.string().optional(),\n\tproduct: z.string().optional(),\n\tamount: z.number().int().positive().optional(), // Amount in smallest currency unit (e.g., kobo)\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});\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 } = 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) return false;\n\t\t\t\t\t\tif (callbackURL.startsWith(\"/\")) return true;\n\t\t\t\t\t\tconst baseUrl =\n ((ctx.context as Record<string, unknown>)?.baseURL as string | undefined) ??\n ((ctx.request as unknown as { url?: string })?.url) ??\n \"\";\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()) {\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) {\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,\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 | 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);\n\t\t\t\tif (!plan) {\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,\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);\n\t\t\t\t}\n\t\t\t\tif (!product) {\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\tconst amount = bodyAmount ?? product?.amount;\n\t\t\tconst finalCurrency = currency ?? product?.currency ?? plan?.currency ?? \"NGN\";\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// 5. Prepare Payload\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// 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) => (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) {\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<Organization>({\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) {\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,\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\n\t\t\t\tif (plan) {\n\t\t\t\t\t// Subscription Flow\n\t\t\t\t\tif (trialStart) {\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 minimum\n\t\t\t\t\t\tconst planAmount = amount ?? plan.amount ?? 50000; // 500 NGN minimum fallback\n\t\t\t\t\t\tinitBody.amount = Math.max(Math.round(planAmount), 50000);\n\t\t\t\t\t\tif (quantity !== undefined && quantity !== null && quantity > 0) {\n\t\t\t\t\t\t\tinitBody.amount = initBody.amount * quantity;\n\t\t\t\t\t\t}\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 initRes = unwrapSdkResult<Record<string, unknown>>(initRaw);\n\t\t\t\tlet data =\n (initRes !== undefined && initRes !== null && typeof initRes === \"object\" && \"status\" in initRes && \"data\" in initRes)\n \t? (initRes).data\n \t: (initRes as Record<string, unknown> | undefined)?.data ?? initRes;\n \n\t\t\t\tif (data !== undefined && data !== null && typeof data === \"object\" && \"status\" in data && \"data\" in data) {\n\t\t\t\t\tdata = (data as Record<string, unknown>).data;\n\t\t\t\t}\n\t\t\t\turl = (data as Record<string, unknown>)?.authorization_url as string | undefined;\n\t\t\t\treference = (data as Record<string, unknown>)?.reference as string | undefined;\n\t\t\t\taccessCode = (data as Record<string, unknown>)?.access_code as string | undefined;\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,\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<InputPaystackTransaction, PaystackTransaction>({\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\tmetadata: (extraMetadata !== undefined && extraMetadata !== null) ? 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<Organization>({\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<InputSubscription, 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 (error as Error)?.message ?? PAYSTACK_ERROR_CODES.FAILED_TO_VERIFY_TRANSACTION,\n\t\t\t\t});\n\t\t\t}\n\t\t\tlet data =\n verifyRes !== null && verifyRes !== undefined && typeof verifyRes === \"object\" && \"status\" in verifyRes && \"data\" in verifyRes\n \t? (verifyRes as Record<string, unknown>).data\n \t: (verifyRes as Record<string, unknown>)?.data !== undefined ? (verifyRes as Record<string, unknown>).data : verifyRes;\n \n\t\t\tif (data !== null && data !== undefined && typeof data === \"object\" && \"status\" in data && \"data\" in data) {\n\t\t\t\tdata = (data as Record<string, unknown>).data;\n\t\t\t}\n\t\t\tconst status = (data as Record<string, unknown>)?.status as string | undefined;\n\t\t\tconst reference = ((data as Record<string, unknown>)?.reference as string | undefined) ?? ctx.body.reference;\n\t\t\tconst paystackId = (data as Record<string, unknown>)?.id !== undefined && (data as Record<string, unknown>)?.id !== null ? String((data as Record<string, unknown>).id) : undefined;\n\t\t\tconst authorizationCode = ((data as Record<string, unknown>)?.authorization as Record<string, unknown>)?.authorization_code as string | undefined;\n\n\t\t\tif (status === \"success\") {\n\t\t\t\ttry {\n\t\t\t\t\tconst session = await getSessionFromCtx(ctx);\n \n\t\t\t\t\t// Get the local transaction record to know the intended referenceId (Org or User)\n\t\t\t\t\tconst txRecord = await ctx.context.adapter.findOne<Record<string, unknown> & { referenceId?: string }>({\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 \n\t\t\t\t\t// Trust the referenceId from the record, fallback to session user if missing\n\t\t\t\t\tconst referenceId = txRecord?.referenceId ?? (session?.user as unknown as { id: string })?.id;\n\n\t\t\t\t\t// Authorization check: ensure the current user has access to this referenceId\n\t\t\t\t\tif (session !== null && session !== undefined && referenceId !== session.user.id) {\n\t\t\t\t\t\tconst authRef = (subscriptionOptions as unknown as { authorizeReference: (data: unknown, ctx: unknown) => Promise<boolean> })?.authorizeReference;\n\t\t\t\t\t\tlet authorized = false;\n\t\t\t\t\t\tif (authRef !== undefined && authRef !== null) {\n\t\t\t\t\t\t\tauthorized = await authRef({\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}, ctx);\n\t\t\t\t\t\t} else if (options.organization?.enabled === true) {\n\t\t\t\t\t\t\tconst member = await ctx.context.adapter.findOne({\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 !== null && member !== undefined) authorized = true;\n\t\t\t\t\t\t}\n \n\t\t\t\t\t\tif (!authorized) {\n\t\t\t\t\t\t\tthrow new APIError(\"UNAUTHORIZED\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\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 Record<string, unknown>)?.amount !== undefined && (data as Record<string, unknown>)?.amount !== null ? { amount: (data as Record<string, unknown>).amount } : {}),\n\t\t\t\t\t\t\t...((data as Record<string, unknown>)?.currency !== undefined && (data as Record<string, unknown>)?.currency !== null ? { currency: (data as Record<string, unknown>).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\t\t\t\t\t// Sync Customer Code back to User or Org if missing\n\t\t\t\t\tconst customer = (data as Record<string, unknown>)?.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\tconst isOrg = options.organization?.enabled === true && ((referenceId.startsWith(\"org_\")) || (await ctx.context.adapter.findOne({ model: \"organization\", where: [{ field: \"id\", value: referenceId }] }) !== null));\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// 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 Record<string, unknown>)?.metadata !== undefined && (data as Record<string, unknown>)?.metadata !== null) {\n\t\t\t\t\t\tconst metaRaw = (data as Record<string, 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\t\t\t\t\t\t \n\t\t\t\t\t\ttrialEnd = meta.trialEnd as string | undefined;\n\t\t\t\t\t\t \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 Record<string, unknown>)?.customer as Record<string, unknown>)?.email as string | undefined;\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.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 subRes = 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 subData = unwrapSdkResult<Record<string, unknown>>(subRes);\n\t\t\t\t\t\t\tconst cleanSubData = (subData as { data?: Record<string, unknown> })?.data ?? subData;\n\n\t\t\t\t\t\t\tpaystackSubscriptionCode = (cleanSubData)?.subscription_code as string | undefined;\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 Record<string, unknown>)?.plan as Record<string, unknown> | undefined;\n\t\t\t\t\t\tconst planCodeFromPaystack = planFromPaystack?.plan_code as string | undefined;\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 Record<string, unknown>)?.subscription as Record<string, unknown> | undefined)?.subscription_code as string | undefined;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\n\t\t\t\t\tconst updatedSubscription = await ctx.context.adapter.update<Subscription>({\n\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\tstatus: isTrial === true ? \"trialing\" : \"active\",\n\t\t\t\t\t\t\tperiodStart: new Date(),\n\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t\t...(isTrial === true && (trialEnd !== undefined && trialEnd !== null && trialEnd !== \"\") ? {\n\t\t\t\t\t\t\t\ttrialStart: new Date(),\n\t\t\t\t\t\t\t\ttrialEnd: new Date(trialEnd),\n\t\t\t\t\t\t\t\tperiodEnd: new Date(trialEnd),\n\t\t\t\t\t\t\t} : {}),\n\t\t\t\t\t\t\t...(paystackSubscriptionCode !== undefined && paystackSubscriptionCode !== null && paystackSubscriptionCode !== \"\" ? { paystackSubscriptionCode } : {}),\n\t\t\t\t\t\t\t...(authorizationCode !== undefined && authorizationCode !== null && authorizationCode !== \"\" ? { paystackAuthorizationCode: authorizationCode } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{ field: \"paystackTransactionReference\", value: reference },\n\t\t\t\t\t\t\t...(referenceId !== undefined && referenceId !== null && referenceId !== \"\" ? [{ field: \"referenceId\", value: referenceId }] : []),\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} else if (status === \"failed\" || status === \"abandoned\") {\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,\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\t\t\t\t} catch (e: unknown) {\n\t\t\t\t\tctx.context.logger.error(\"Failed to update transaction status\", e);\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 !== undefined && referenceIdPart !== null && referenceIdPart !== \"\")\n\t\t\t\t? referenceIdPart\n\t\t\t\t: (queryRefId !== undefined && queryRefId !== null && queryRefId !== \"\")\n\t\t\t\t\t? queryRefId\n\t\t\t\t\t: (session.user as unknown 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 ((ctx.context as Record<string, unknown>).referenceId as string | undefined) ??\n (ctx.query?.referenceId) ??\n ((session.user as unknown 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, b) => 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});\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 } = ctx.body;\n\t\t\tconst paystack = getPaystackOps(options.paystackClient);\n\t\t\ttry {\n\t\t\t\tif (subscriptionCode.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) {\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: \"active\",\n\t\t\t\t\t\t\t\tcancelAtPeriodEnd: true,\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<Record<string, unknown>>(raw);\n\t\t\t\t\tconst data =\n fetchRes !== null && fetchRes !== undefined && typeof fetchRes === \"object\" && \"status\" in fetchRes && \"data\" in fetchRes\n \t? (fetchRes).data\n \t: fetchRes?.data !== undefined ? fetchRes.data : fetchRes;\n\t\t\t\t\t\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 =\n linkRes !== null && linkRes !== undefined && typeof linkRes === \"object\" && \"status\" in linkRes && \"data\" in linkRes\n \t? (linkRes).data\n \t: linkRes?.data !== undefined ? linkRes.data : linkRes;\n\t\t\t\t\t\tconst link = typeof data === \"string\" ? data : (data as Record<string, unknown>)?.link as string | undefined;\n \n\t\t\t\t\t\tif (link !== undefined && link !== null && 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\t\t\t\t\n\t\t\t\t// Duplicate removed\n\n\t\t\t\tconst periodEnd = (nextPaymentDate !== undefined && nextPaymentDate !== null && nextPaymentDate !== \"\") ? new Date(nextPaymentDate) : undefined;\n\t\t\t\t\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) {\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: \"active\", // Keep active until period end\n\t\t\t\t\t\t\tcancelAtPeriodEnd: true,\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\t(ctx as unknown as { context: { logger: { error: (msg: string, err: unknown) => void } } }).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 (error as Error)?.message ?? PAYSTACK_ERROR_CODES.FAILED_TO_DISABLE_SUBSCRIPTION,\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<Record<string, unknown>>(raw);\n\t\t\t\t\t\tconst data =\n fetchRes !== null && fetchRes !== undefined && typeof fetchRes === \"object\" && \"status\" in fetchRes && \"data\" in fetchRes\n \t? (fetchRes).data\n \t: fetchRes?.data !== undefined ? fetchRes.data : fetchRes;\n\t\t\t\t\t\temailToken = (data as Record<string, unknown>)?.email_token as string | undefined;\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 =\n linkRes !== null && linkRes !== undefined && \"status\" in linkRes && \"data\" in linkRes\n \t? (linkRes).data\n \t: linkRes?.data !== undefined ? linkRes.data : linkRes;\n\t\t\t\t\t\tconst link = typeof data === \"string\" ? data : (data as Record<string, unknown>)?.link as string | undefined;\n \n\t\t\t\t\t\tif (link !== undefined && link !== null && 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 (error as Error)?.message ?? PAYSTACK_ERROR_CODES.FAILED_TO_ENABLE_SUBSCRIPTION,\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t);\n};\n\nexport const getSubscriptionManageLink = (options: AnyPaystackOptions) => {\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\treturn createAuthEndpoint(\n\t\t\"/paystack/get-subscription-manage-link\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tquery: manageLinkQuerySchema,\n\t\t\tuse: useMiddlewares,\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst { subscriptionCode } = ctx.query;\n\t\t\tconst paystack = getPaystackOps(options.paystackClient);\n\t\t\ttry {\n\t\t\t\tconst raw = await paystack.subscriptionManageLink(subscriptionCode);\n\t\t\t\tconst res = unwrapSdkResult<Record<string, unknown>>(raw);\n\t\t\t\tconst data =\n res !== null && res !== undefined && \"status\" in res && \"data\" in res\n \t? (res).data\n \t: res?.data !== undefined ? res.data : res;\n\t\t\t\t// data might be string or object with link\n\t\t\t\tconst link = typeof data === \"string\" ? data : (data as Record<string, unknown>)?.link;\n \n\t\t\t\treturn ctx.json({ link });\n\t\t\t} catch (error: unknown) {\n\t\t\t\tctx.context.logger.error(\"Failed to get subscription manage link\", error);\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: (error as Error)?.message ?? \"Failed to get subscription manage link\",\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) => {\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 === null || subscription === undefined) {\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 === undefined || plan === null) {\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\tif (!validateMinAmount(amount, plan.currency ?? \"NGN\")) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", { message: `Amount ${amount} is below minimum for ${plan.currency ?? \"NGN\"}` });\n\t\t\t}\n\n\t\t\tconst paystack = getPaystackOps(options.paystackClient);\n\t\t\tconst chargeRes = 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\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t\tcurrency: plan.currency as any,\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 data = unwrapSdkResult<Record<string, unknown>>(chargeRes);\n\t\t\tconst chargeData = (data as { data?: Record<string, unknown> })?.data ?? data;\n\n\t\t\tif (chargeData?.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.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},\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},\n\t\t\tuserId: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: 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\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},\n\t\t\treferenceId: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: 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},\n\t\t\tpaystackSubscriptionCode: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tpaystackTransactionReference: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\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},\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},\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},\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 getSchema = (options: PaystackOptions<PaystackClientLike>) => {\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};\n\t} else {\n\t\tbaseSchema = {\n\t\t\t...user,\n\t\t\t...transactions,\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 options.subscription?.enabled !== true &&\n \"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 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 { defineErrorCodes } from \"@better-auth/core/utils\";\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} from \"./routes\";\nimport { getSchema } from \"./schema\";\nimport { checkSeatLimit, checkTeamLimit, getOrganizationSubscription } from \"./limits\";\nimport { getPlanByName } from \"./utils\";\nimport type {\n\tPaystackNodeClient,\n\tPaystackClientLike,\n\tPaystackOptions,\n\tPaystackPlan,\n\tSubscription,\n\tSubscriptionOptions,\n\tPaystackProduct,\n\tMember,\n\tUser,\n\n} from \"./types\";\nimport { getPaystackOps, unwrapSdkResult } from \"./paystack-sdk\";\n\nconst INTERNAL_ERROR_CODES = defineErrorCodes({\n\t...PAYSTACK_ERROR_CODES,\n});\n\nexport const paystack = <\n TPaystackClient extends PaystackClientLike = PaystackNodeClient,\n O extends PaystackOptions<TPaystackClient> = PaystackOptions<TPaystackClient>,\n>(\n\t\toptions: O,\n\t) => {\n\tconst res = {\n\t\tid: \"paystack\",\n\t\tendpoints: {\n\t\t\tinitializeTransaction: initializeTransaction(options),\n\t\t\tverifyTransaction: verifyTransaction(options),\n\t\t\tlistSubscriptions: listSubscriptions(options),\n\t\t\tpaystackWebhook: paystackWebhook(options),\n\t\t\tlistTransactions: listTransactions(options),\n\t\t\tgetConfig: getConfig(options),\n\t\t\tdisableSubscription: disablePaystackSubscription(options),\n\t\t\tenableSubscription: enablePaystackSubscription(options),\n\t\t\tgetSubscriptionManageLink: getSubscriptionManageLink(options),\n\t\t\tcreateSubscription: createSubscription(options),\n\t\t\tupgradeSubscription: upgradeSubscription(options),\n\t\t\tcancelSubscription: cancelSubscription(options),\n\t\t\trestoreSubscription: restoreSubscription(options),\n\t\t\tchargeRecurringSubscription: chargeRecurringSubscription(options),\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; name?: string | null }, hookCtx?: GenericEndpointContext | null) {\n\t\t\t\t\t\t\t\t\tif (hookCtx === undefined || hookCtx === null || options.createCustomerOnSignUp !== true) 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},\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\tconst data = unwrapSdkResult<Record<string, unknown>>(raw);\n\t\t\t\t\t\t\t\t\tconst customerCode = (data?.customer_code as string | undefined) ?? (data?.data as Record<string, unknown>)?.customer_code as string | undefined;\n\n\t\t\t\t\t\t\t\t\tif (customerCode === undefined || customerCode === null) {\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 !== null && ownerMember !== undefined) {\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);\n\t\t\t\t\t\t\t\t\t\t\tconst sdkRes = unwrapSdkResult<Record<string, unknown>>(raw);\n\t\t\t\t\t\t\t\t\t\t\tconst paystackCustomer =\n sdkRes !== null && typeof sdkRes === \"object\" && \"status\" in sdkRes && \"data\" in sdkRes\n \t? (sdkRes as { data: Record<string, unknown> }).data\n \t: sdkRes?.data ?? sdkRes;\n\t\t\t\t\t\t\t\t\t\t\tconst customerCode = (paystackCustomer as Record<string, unknown>)?.customer_code as string | undefined;\n\n\t\t\t\t\t\t\t\t\t\t\tif (customerCode === undefined || customerCode === null) return;\n\n\t\t\t\t\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t\t\t\t\t\t\t\t\tawait (ctx.internalAdapter as any).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: paystackCustomer as Record<string, unknown>,\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 hookCtx!,\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},\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},\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 !== null && ctx !== undefined) {\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 !== null && subscription !== undefined) {\n\t\t\t\t\t\t\t\t\t\tconst plan = await getPlanByName(options, 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} as const;\n\n\n\n\treturn res;\n};\n\nexport type PaystackPlugin<O extends PaystackOptions<PaystackClientLike> = PaystackOptions> = ReturnType<\n typeof paystack<PaystackClientLike, O>\n>;\n\nexport type { Subscription, SubscriptionOptions, PaystackPlan, PaystackOptions, PaystackProduct };\n"],"mappings":"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"}