@alexasomba/better-auth-paystack 1.0.0 → 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.
package/README.md CHANGED
@@ -167,6 +167,21 @@ The plugin natively checks the `teams` limit if using the Better Auth Organizati
167
167
 
168
168
  ---
169
169
 
170
+ ## Currency Support
171
+
172
+ The plugin supports the following currencies with automatic minimum transaction amount validation:
173
+
174
+ | Currency | Name | Minimum Amount |
175
+ | -------- | ---------------------- | -------------- |
176
+ | **NGN** | Nigerian Naira | ₦50.00 |
177
+ | **GHS** | Ghanaian Cedi | ₵0.10 |
178
+ | **ZAR** | South African Rand | R1.00 |
179
+ | **KES** | Kenyan Shilling | KSh 3.00 |
180
+ | **USD** | United States Dollar | $2.00 |
181
+ | **XOF** | West African CFA Franc | CFA 100 |
182
+
183
+ Transactions below these thresholds will be rejected with a `BAD_REQUEST` error.
184
+
170
185
  ## Advanced Usage
171
186
 
172
187
  ### Organization Billing
@@ -338,6 +353,9 @@ type listSubscriptions = {
338
353
 
339
354
  Cancel or restore a subscription.
340
355
 
356
+ - **Cancel**: Sets `cancelAtPeriodEnd: true`. The subscription remains `active` until the end of the current billing period, after which it moves to `canceled`.
357
+ - **Restore**: Reactivates a subscription that is scheduled to cancel.
358
+
341
359
  ```ts
342
360
  type cancelSubscription = {
343
361
  /**
@@ -358,47 +376,48 @@ The plugin extends your database with the following fields and tables.
358
376
 
359
377
  ### `user`
360
378
 
361
- | Field | Type | Description |
362
- | :--------------------- | :------- | :-------------------------------------------- |
363
- | `paystackCustomerCode` | `string` | The unique customer identifier from Paystack. |
379
+ | Field | Type | Required | Description |
380
+ | :--------------------- | :------- | :------- | :-------------------------------------------- |
381
+ | `paystackCustomerCode` | `string` | No | The unique customer identifier from Paystack. |
364
382
 
365
383
  ### `organization`
366
384
 
367
- | Field | Type | Description |
368
- | :--------------------- | :------- | :----------------------------------------------------------------------------------------- |
369
- | `paystackCustomerCode` | `string` | The unique customer identifier for the organization. |
370
- | `email` | `string` | The billing email for the organization. fallsback to organization owner's email if absent. |
385
+ | Field | Type | Required | Description |
386
+ | :--------------------- | :------- | :------- | :----------------------------------------------------------------------------------------- |
387
+ | `paystackCustomerCode` | `string` | No | The unique customer identifier for the organization. |
388
+ | `email` | `string` | No | The billing email for the organization. fallsback to organization owner's email if absent. |
371
389
 
372
390
  ### `subscription`
373
391
 
374
- | Field | Type | Description |
375
- | :----------------------------- | :-------- | :-------------------------------------------------------------- |
376
- | `plan` | `string` | Lowercased name of the active plan. |
377
- | `referenceId` | `string` | Associated User ID or Organization ID. |
378
- | `paystackCustomerCode` | `string` | The Paystack customer code for this subscription. |
379
- | `paystackSubscriptionCode` | `string` | The unique code for the subscription (e.g., `SUB_...`). |
380
- | `paystackTransactionReference` | `string` | The reference of the transaction that started the subscription. |
381
- | `status` | `string` | `active`, `trialing`, `canceled`, `incomplete`. |
382
- | `periodStart` | `Date` | Start date of the current billing period. |
383
- | `periodEnd` | `Date` | End date of the current billing period. |
384
- | `trialStart` | `Date` | Start date of the trial period. |
385
- | `trialEnd` | `Date` | End date of the trial period. |
386
- | `cancelAtPeriodEnd` | `boolean` | Whether to cancel at the end of the current period. |
387
- | `seats` | `number` | Purchased seat count for team billing. |
392
+ | Field | Type | Required | Description |
393
+ | :----------------------------- | :-------- | :------- | :------------------------------------------------------------------- |
394
+ | `plan` | `string` | Yes | Lowercased name of the active plan. |
395
+ | `referenceId` | `string` | Yes | Associated User ID or Organization ID. |
396
+ | `paystackCustomerCode` | `string` | No | The Paystack customer code for this subscription. |
397
+ | `paystackSubscriptionCode` | `string` | No | The unique code for the subscription (e.g., `SUB_...` or `LOC_...`). |
398
+ | `paystackTransactionReference` | `string` | No | The reference of the transaction that started the subscription. |
399
+ | `paystackAuthorizationCode` | `string` | No | Stored card authorization code for recurring charges (local plans). |
400
+ | `status` | `string` | Yes | `active`, `trialing`, `canceled`, `incomplete`. |
401
+ | `periodStart` | `Date` | No | Start date of the current billing period. |
402
+ | `periodEnd` | `Date` | No | End date of the current billing period. |
403
+ | `trialStart` | `Date` | No | Start date of the trial period. |
404
+ | `trialEnd` | `Date` | No | End date of the trial period. |
405
+ | `cancelAtPeriodEnd` | `boolean` | No | Whether to cancel at the end of the current period. |
406
+ | `seats` | `number` | No | Purchased seat count for team billing. |
388
407
 
389
408
  ### `paystackTransaction`
390
409
 
391
- | Field | Type | Description |
392
- | :------------ | :------- | :------------------------------------------------ |
393
- | `reference` | `string` | Unique transaction reference. |
394
- | `referenceId` | `string` | Associated User ID or Organization ID. |
395
- | `userId` | `string` | The ID of the user who initiated the transaction. |
396
- | `amount` | `number` | Transaction amount in smallest currency unit. |
397
- | `currency` | `string` | Currency code (e.g., "NGN"). |
398
- | `status` | `string` | `success`, `pending`, `failed`, `abandoned`. |
399
- | `plan` | `string` | Name of the plan associated with the transaction. |
400
- | `metadata` | `string` | JSON string of extra transaction metadata. |
401
- | `paystackId` | `string` | The internal Paystack ID for the transaction. |
410
+ | Field | Type | Required | Description |
411
+ | :------------ | :------- | :------- | :------------------------------------------------ |
412
+ | `reference` | `string` | Yes | Unique transaction reference. |
413
+ | `referenceId` | `string` | Yes | Associated User ID or Organization ID. |
414
+ | `userId` | `string` | Yes | The ID of the user who initiated the transaction. |
415
+ | `amount` | `number` | Yes | Transaction amount in smallest currency unit. |
416
+ | `currency` | `string` | Yes | Currency code (e.g., "NGN"). |
417
+ | `status` | `string` | Yes | `success`, `pending`, `failed`, `abandoned`. |
418
+ | `plan` | `string` | No | Name of the plan associated with the transaction. |
419
+ | `metadata` | `string` | No | JSON string of extra transaction metadata. |
420
+ | `paystackId` | `string` | No | The internal Paystack ID for the transaction. |
402
421
 
403
422
  ---
404
423
 
@@ -440,14 +459,14 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
440
459
 
441
460
  Future features planned for upcoming versions:
442
461
 
443
- ### v1.1.0 - Manual Recurring Subscriptions
462
+ ### v1.1.0 - Manual Recurring Subscriptions (Available Now)
444
463
 
445
- - [ ] **Stored Authorization Codes**: Securely store Paystack authorization codes from verified transactions
446
- - [ ] **Card Management UI**: Let users view/delete saved payment methods (masked card data only)
447
- - [ ] **Charge Authorization Endpoint**: Server-side endpoint to charge stored cards for renewals
448
- - [ ] **Renewal Scheduler Integration**: Documentation for integrating with Cloudflare Workers Cron, Vercel Cron, etc.
464
+ - [x] **Stored Authorization Codes**: Securely store Paystack authorization codes from verified transactions.
465
+ - [x] **Charge Authorization Endpoint**: Server-side endpoint (`/charge-recurring`) to charge stored cards for renewals.
466
+ - [ ] **Card Management UI**: Let users view/delete saved payment methods (masked card data only) - _Upcoming_
467
+ - [ ] **Renewal Scheduler Integration**: Documentation for integrating with Cloudflare Workers Cron, Vercel Cron, etc. - _Upcoming_
449
468
 
450
- > **Note**: For automatic recurring subscriptions today, use Paystack-managed plans via `planCode`. Manual recurring (storing authorization codes) is planned for a future release.
469
+ > **Note**: For local-managed subscriptions (no `planCode`), the plugin now automatically captures and stores the `authorization_code`. You can trigger renewals using `authClient.paystack.chargeRecurringSubscription({ subscriptionId })`.
451
470
 
452
471
  ### Future Considerations
453
472
 
package/dist/client.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { o as PaystackTransaction, s as Subscription } from "./types-Du5udJ7X.mjs";
1
+ import { o as PaystackTransaction, s as Subscription } from "./types-Dlv_nSLg.mjs";
2
2
  import { paystack } from "./index.mjs";
3
3
  import { BetterFetch, BetterFetchOption, BetterFetchResponse } from "@better-fetch/fetch";
4
4
 
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as PaystackProduct, c as SubscriptionOptions, i as PaystackPlan, n as PaystackNodeClient, o as PaystackTransaction, r as PaystackOptions, s as Subscription, t as PaystackClientLike } from "./types-Du5udJ7X.mjs";
1
+ import { a as PaystackProduct, c as SubscriptionOptions, i as PaystackPlan, n as PaystackNodeClient, o as PaystackTransaction, r as PaystackOptions, s as Subscription, t as PaystackClientLike } from "./types-Dlv_nSLg.mjs";
2
2
  import * as better_auth0 from "better-auth";
3
3
  import { AuthContext, GenericEndpointContext } from "better-auth";
4
4
  import * as _better_auth_core_db0 from "@better-auth/core/db";
@@ -439,6 +439,16 @@ declare const paystack: <TPaystackClient extends PaystackClientLike = PaystackNo
439
439
  }, {
440
440
  status: string;
441
441
  }>;
442
+ readonly chargeRecurringSubscription: better_call0.StrictEndpoint<"/paystack/charge-recurring", {
443
+ method: "POST";
444
+ body: zod.ZodObject<{
445
+ subscriptionId: zod.ZodString;
446
+ amount: zod.ZodOptional<zod.ZodNumber>;
447
+ }, better_auth0.$strip>;
448
+ }, {
449
+ status: string;
450
+ data: Record<string, unknown>;
451
+ }>;
442
452
  };
443
453
  readonly schema: _better_auth_core_db0.BetterAuthPluginDBSchema;
444
454
  readonly init: (ctx: AuthContext) => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;cAyCa,QAAA,2BACe,kBAAA,GAAqB,kBAAA,YACnC,eAAA,CAAgB,eAAA,IAAmB,eAAA,CAAgB,eAAA,GAE/D,OAAA,EAAS,CAAA;EAAA;;;;;8BAAC,GAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBAoBE,WAAA;;;;;;cAMc,EAAA;cAAY,KAAA;cAAe,IAAA;YAAA,GAAsB,OAAA,GAAY,sBAAA,UAA6B,OAAA;UAAA;QAAA;;;;cA8B1F,EAAA;cAAY,IAAA;cAAc,KAAA;YAAA,GAAuB,OAAA,EAAW,sBAAA,UAA6B,OAAA;UAAA;QAAA;MAAA;;;;YAsErF,cAAA;UAAA,GAAwB,GAAA,EAAO,sBAAA,wBAAyC,OAAA;QAAA;MAAA;;;;YASpE,cAAA;UAAA,GAAwB,GAAA,EAAO,sBAAA,wBAAyC,OAAA;QAAA;MAAA;;;;YAS9E,cAAA;UAAA,GAAwB,GAAA,EAAO,sBAAA,wBAAyC,OAAA;QAAA;MAAA;IAAA;EAAA;EAAA;;;;;;;;;;;KA2B1F,cAAA,WAAyB,eAAA,CAAgB,kBAAA,IAAsB,eAAA,IAAmB,UAAA,QACnF,QAAA,CAAS,kBAAA,EAAoB,CAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;cA0Ca,QAAA,2BACe,kBAAA,GAAqB,kBAAA,YACnC,eAAA,CAAgB,eAAA,IAAmB,eAAA,CAAgB,eAAA,GAE/D,OAAA,EAAS,CAAA;EAAA;;;;;8BAAC,GAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBAqBE,WAAA;;;;;;cAMc,EAAA;cAAY,KAAA;cAAe,IAAA;YAAA,GAAsB,OAAA,GAAY,sBAAA,UAA6B,OAAA;UAAA;QAAA;;;;cA8B1F,EAAA;cAAY,IAAA;cAAc,KAAA;YAAA,GAAuB,OAAA,EAAW,sBAAA,UAA6B,OAAA;UAAA;QAAA;MAAA;;;;YAsErF,cAAA;UAAA,GAAwB,GAAA,EAAO,sBAAA,wBAAyC,OAAA;QAAA;MAAA;;;;YASpE,cAAA;UAAA,GAAwB,GAAA,EAAO,sBAAA,wBAAyC,OAAA;QAAA;MAAA;;;;YAS9E,cAAA;UAAA,GAAwB,GAAA,EAAO,sBAAA,wBAAyC,OAAA;QAAA;MAAA;IAAA;EAAA;EAAA;;;;;;;;;;;KA2B1F,cAAA,WAAyB,eAAA,CAAgB,kBAAA,IAAsB,eAAA,IAAmB,UAAA,QACnF,QAAA,CAAS,kBAAA,EAAoB,CAAA"}
package/dist/index.mjs CHANGED
@@ -22,6 +22,46 @@ async function getProducts(productOptions) {
22
22
  async function getProductByName(options, name) {
23
23
  return await getProducts(options.products).then((products) => products?.find((product) => product.name.toLowerCase() === name.toLowerCase()));
24
24
  }
25
+ function getNextPeriodEnd(startDate, interval) {
26
+ const date = new Date(startDate);
27
+ switch (interval) {
28
+ case "daily":
29
+ date.setDate(date.getDate() + 1);
30
+ break;
31
+ case "weekly":
32
+ date.setDate(date.getDate() + 7);
33
+ break;
34
+ case "monthly":
35
+ date.setMonth(date.getMonth() + 1);
36
+ break;
37
+ case "quarterly":
38
+ date.setMonth(date.getMonth() + 3);
39
+ break;
40
+ case "biannually":
41
+ date.setMonth(date.getMonth() + 6);
42
+ break;
43
+ case "annually":
44
+ date.setFullYear(date.getFullYear() + 1);
45
+ break;
46
+ default: date.setMonth(date.getMonth() + 1);
47
+ }
48
+ return date;
49
+ }
50
+ /**
51
+ * Validates if the amount meets Paystack's minimum transaction requirements.
52
+ * Amounts should be in the smallest currency unit (e.g., kobo, cents).
53
+ */
54
+ function validateMinAmount(amount, currency) {
55
+ const min = {
56
+ NGN: 5e3,
57
+ GHS: 10,
58
+ ZAR: 100,
59
+ KES: 300,
60
+ USD: 200,
61
+ XOF: 100
62
+ }[currency.toUpperCase()];
63
+ return min !== void 0 ? amount >= min : true;
64
+ }
25
65
 
26
66
  //#endregion
27
67
  //#region src/middleware.ts
@@ -144,6 +184,10 @@ function getPaystackOps(paystackClient) {
144
184
  subscriptionManageEmail: (code, email) => {
145
185
  if (paystackClient?.subscription_manageEmail !== void 0) return paystackClient.subscription_manageEmail({ params: { path: { code } } });
146
186
  return paystackClient?.subscription?.manage?.email?.(code, email);
187
+ },
188
+ transactionChargeAuthorization: (body) => {
189
+ if (paystackClient?.transaction_chargeAuthorization !== void 0) return paystackClient.transaction_chargeAuthorization({ body });
190
+ return paystackClient?.transaction?.chargeAuthorization?.(body);
147
191
  }
148
192
  };
149
193
  }
@@ -279,7 +323,8 @@ const paystackWebhook = (options) => {
279
323
  update: {
280
324
  paystackSubscriptionCode: subscriptionCode,
281
325
  status: "active",
282
- updatedAt: /* @__PURE__ */ new Date()
326
+ updatedAt: /* @__PURE__ */ new Date(),
327
+ periodEnd: data?.next_payment_date !== void 0 && data?.next_payment_date !== null && data?.next_payment_date !== "" ? new Date(data.next_payment_date) : void 0
283
328
  },
284
329
  where: [{
285
330
  field: "id",
@@ -321,10 +366,12 @@ const paystackWebhook = (options) => {
321
366
  value: subscriptionCode
322
367
  }]
323
368
  });
369
+ let newStatus = "canceled";
370
+ if (existing?.cancelAtPeriodEnd === true && existing.periodEnd !== void 0 && existing.periodEnd !== null && new Date(existing.periodEnd) > /* @__PURE__ */ new Date()) newStatus = "active";
324
371
  await ctx.context.adapter.update({
325
372
  model: "subscription",
326
373
  update: {
327
- status: "canceled",
374
+ status: newStatus,
328
375
  updatedAt: /* @__PURE__ */ new Date()
329
376
  },
330
377
  where: [{
@@ -609,6 +656,7 @@ const verifyTransaction = (options, path = "/paystack/verify-transaction") => {
609
656
  const status = data?.status;
610
657
  const reference = data?.reference ?? ctx.body.reference;
611
658
  const paystackId = data?.id !== void 0 && data?.id !== null ? String(data.id) : void 0;
659
+ const authorizationCode = (data?.authorization)?.authorization_code;
612
660
  if (status === "success") try {
613
661
  const session = await getSessionFromCtx(ctx);
614
662
  const referenceId = (await ctx.context.adapter.findOne({
@@ -692,9 +740,9 @@ const verifyTransaction = (options, path = "/paystack/verify-transaction") => {
692
740
  }
693
741
  let paystackSubscriptionCode;
694
742
  if (isTrial === true && targetPlan !== void 0 && targetPlan !== null && targetPlan !== "" && trialEnd !== void 0 && trialEnd !== null && trialEnd !== "") {
695
- const authorizationCode = (data?.authorization)?.authorization_code;
696
743
  const email = (data?.customer)?.email;
697
744
  const planConfig = (await getPlans(subscriptionOptions)).find((p) => p.name.toLowerCase() === targetPlan?.toLowerCase());
745
+ if (planConfig !== void 0 && (planConfig.planCode === void 0 || planConfig.planCode === null || planConfig.planCode === "")) paystackSubscriptionCode = `LOC_${reference}`;
698
746
  if (authorizationCode !== void 0 && authorizationCode !== null && authorizationCode !== "" && email !== void 0 && email !== null && email !== "" && planConfig?.planCode !== void 0 && planConfig?.planCode !== null && planConfig?.planCode !== "") {
699
747
  const subData = unwrapSdkResult(await paystack.subscriptionCreate({
700
748
  customer: email,
@@ -704,6 +752,10 @@ const verifyTransaction = (options, path = "/paystack/verify-transaction") => {
704
752
  }));
705
753
  paystackSubscriptionCode = (subData?.data ?? subData)?.subscription_code;
706
754
  }
755
+ } else if (isTrial !== true) {
756
+ const planCodeFromPaystack = (data?.plan)?.plan_code;
757
+ if (planCodeFromPaystack === void 0 || planCodeFromPaystack === null || planCodeFromPaystack === "") paystackSubscriptionCode = `LOC_${reference}`;
758
+ else paystackSubscriptionCode = (data?.subscription)?.subscription_code;
707
759
  }
708
760
  const updatedSubscription = await ctx.context.adapter.update({
709
761
  model: "subscription",
@@ -711,7 +763,13 @@ const verifyTransaction = (options, path = "/paystack/verify-transaction") => {
711
763
  status: isTrial === true ? "trialing" : "active",
712
764
  periodStart: /* @__PURE__ */ new Date(),
713
765
  updatedAt: /* @__PURE__ */ new Date(),
714
- ...paystackSubscriptionCode !== void 0 && paystackSubscriptionCode !== null && paystackSubscriptionCode !== "" ? { paystackSubscriptionCode } : {}
766
+ ...isTrial === true && trialEnd !== void 0 && trialEnd !== null && trialEnd !== "" ? {
767
+ trialStart: /* @__PURE__ */ new Date(),
768
+ trialEnd: new Date(trialEnd),
769
+ periodEnd: new Date(trialEnd)
770
+ } : {},
771
+ ...paystackSubscriptionCode !== void 0 && paystackSubscriptionCode !== null && paystackSubscriptionCode !== "" ? { paystackSubscriptionCode } : {},
772
+ ...authorizationCode !== void 0 && authorizationCode !== null && authorizationCode !== "" ? { paystackAuthorizationCode: authorizationCode } : {}
715
773
  },
716
774
  where: [{
717
775
  field: "paystackTransactionReference",
@@ -842,10 +900,38 @@ const disablePaystackSubscription = (options, path = "/paystack/disable-subscrip
842
900
  const { subscriptionCode } = ctx.body;
843
901
  const paystack = getPaystackOps(options.paystackClient);
844
902
  try {
903
+ if (subscriptionCode.startsWith("LOC_")) {
904
+ const sub = await ctx.context.adapter.findOne({
905
+ model: "subscription",
906
+ where: [{
907
+ field: "paystackSubscriptionCode",
908
+ value: subscriptionCode
909
+ }]
910
+ });
911
+ if (sub) {
912
+ await ctx.context.adapter.update({
913
+ model: "subscription",
914
+ update: {
915
+ status: "active",
916
+ cancelAtPeriodEnd: true,
917
+ updatedAt: /* @__PURE__ */ new Date()
918
+ },
919
+ where: [{
920
+ field: "id",
921
+ value: sub.id
922
+ }]
923
+ });
924
+ return ctx.json({ status: "success" });
925
+ }
926
+ throw new APIError("BAD_REQUEST", { message: "Subscription not found" });
927
+ }
845
928
  let emailToken = ctx.body.emailToken;
846
- if (emailToken === void 0 || emailToken === null || emailToken === "") try {
929
+ let nextPaymentDate;
930
+ try {
847
931
  const fetchRes = unwrapSdkResult(await paystack.subscriptionFetch(subscriptionCode));
848
- emailToken = (fetchRes !== null && fetchRes !== void 0 && typeof fetchRes === "object" && "status" in fetchRes && "data" in fetchRes ? fetchRes.data : fetchRes?.data !== void 0 ? fetchRes.data : fetchRes)?.email_token;
932
+ const data = fetchRes !== null && fetchRes !== void 0 && typeof fetchRes === "object" && "status" in fetchRes && "data" in fetchRes ? fetchRes.data : fetchRes?.data !== void 0 ? fetchRes.data : fetchRes;
933
+ if (emailToken === void 0 || emailToken === null || emailToken === "") emailToken = data?.email_token;
934
+ nextPaymentDate = data?.next_payment_date;
849
935
  } catch {}
850
936
  if (emailToken === void 0 || emailToken === null || emailToken === "") try {
851
937
  const linkRes = unwrapSdkResult(await paystack.subscriptionManageLink(subscriptionCode));
@@ -858,17 +944,28 @@ const disablePaystackSubscription = (options, path = "/paystack/disable-subscrip
858
944
  code: subscriptionCode,
859
945
  token: emailToken
860
946
  });
861
- await ctx.context.adapter.update({
947
+ const periodEnd = nextPaymentDate !== void 0 && nextPaymentDate !== null && nextPaymentDate !== "" ? new Date(nextPaymentDate) : void 0;
948
+ const sub = await ctx.context.adapter.findOne({
949
+ model: "subscription",
950
+ where: [{
951
+ field: "paystackSubscriptionCode",
952
+ value: subscriptionCode
953
+ }]
954
+ });
955
+ if (sub) await ctx.context.adapter.update({
862
956
  model: "subscription",
863
957
  update: {
864
- status: "canceled",
958
+ status: "active",
959
+ cancelAtPeriodEnd: true,
960
+ periodEnd,
865
961
  updatedAt: /* @__PURE__ */ new Date()
866
962
  },
867
963
  where: [{
868
- field: "paystackSubscriptionCode",
869
- value: subscriptionCode
964
+ field: "id",
965
+ value: sub.id
870
966
  }]
871
967
  });
968
+ else ctx.context.logger.warn(`Could not find subscription with code ${subscriptionCode} to disable`);
872
969
  return ctx.json({ status: "success" });
873
970
  } catch (error) {
874
971
  ctx.context.logger.error("Failed to disable subscription", error);
@@ -965,6 +1062,99 @@ const getConfig = (options) => {
965
1062
  });
966
1063
  });
967
1064
  };
1065
+ const chargeRecurringSubscription = (options) => {
1066
+ return createAuthEndpoint("/paystack/charge-recurring", {
1067
+ method: "POST",
1068
+ body: z.object({
1069
+ subscriptionId: z.string(),
1070
+ amount: z.number().optional()
1071
+ })
1072
+ }, async (ctx) => {
1073
+ const { subscriptionId, amount: bodyAmount } = ctx.body;
1074
+ const subscription = await ctx.context.adapter.findOne({
1075
+ model: "subscription",
1076
+ where: [{
1077
+ field: "id",
1078
+ value: subscriptionId
1079
+ }]
1080
+ });
1081
+ if (subscription === null || subscription === void 0) throw new APIError("NOT_FOUND", { message: "Subscription not found" });
1082
+ if (subscription.paystackAuthorizationCode === void 0 || subscription.paystackAuthorizationCode === null || subscription.paystackAuthorizationCode === "") throw new APIError("BAD_REQUEST", { message: "No authorization code found for this subscription" });
1083
+ const plan = (await getPlans(options.subscription)).find((p) => p.name.toLowerCase() === subscription.plan.toLowerCase());
1084
+ if (plan === void 0 || plan === null) throw new APIError("NOT_FOUND", { message: "Plan not found" });
1085
+ const amount = bodyAmount ?? plan.amount;
1086
+ if (amount === void 0 || amount === null) throw new APIError("BAD_REQUEST", { message: "Plan amount is not defined" });
1087
+ let email;
1088
+ if (subscription.referenceId !== void 0 && subscription.referenceId !== null && subscription.referenceId !== "") {
1089
+ const user = await ctx.context.adapter.findOne({
1090
+ model: "user",
1091
+ where: [{
1092
+ field: "id",
1093
+ value: subscription.referenceId
1094
+ }]
1095
+ });
1096
+ if (user !== void 0 && user !== null) email = user.email;
1097
+ else if (options.organization?.enabled === true) {
1098
+ const ownerMember = await ctx.context.adapter.findOne({
1099
+ model: "member",
1100
+ where: [{
1101
+ field: "organizationId",
1102
+ value: subscription.referenceId
1103
+ }, {
1104
+ field: "role",
1105
+ value: "owner"
1106
+ }]
1107
+ });
1108
+ if (ownerMember !== void 0 && ownerMember !== null) email = (await ctx.context.adapter.findOne({
1109
+ model: "user",
1110
+ where: [{
1111
+ field: "id",
1112
+ value: ownerMember.userId
1113
+ }]
1114
+ }))?.email;
1115
+ }
1116
+ }
1117
+ if (email === void 0 || email === null || email === "") throw new APIError("NOT_FOUND", { message: "User email not found" });
1118
+ if (!validateMinAmount(amount, plan.currency ?? "NGN")) throw new APIError("BAD_REQUEST", { message: `Amount ${amount} is below minimum for ${plan.currency ?? "NGN"}` });
1119
+ const data = unwrapSdkResult(await getPaystackOps(options.paystackClient).transactionChargeAuthorization({
1120
+ email,
1121
+ amount,
1122
+ authorization_code: subscription.paystackAuthorizationCode,
1123
+ currency: plan.currency,
1124
+ metadata: {
1125
+ subscriptionId,
1126
+ referenceId: subscription.referenceId,
1127
+ plan: plan.name
1128
+ }
1129
+ }));
1130
+ const chargeData = data?.data ?? data;
1131
+ if (chargeData?.status === "success") {
1132
+ const now = /* @__PURE__ */ new Date();
1133
+ const nextPeriodEnd = getNextPeriodEnd(now, plan.interval ?? "monthly");
1134
+ await ctx.context.adapter.update({
1135
+ model: "subscription",
1136
+ update: {
1137
+ periodStart: now,
1138
+ periodEnd: nextPeriodEnd,
1139
+ updatedAt: now,
1140
+ paystackTransactionReference: chargeData.reference
1141
+ },
1142
+ where: [{
1143
+ field: "id",
1144
+ value: subscription.id
1145
+ }]
1146
+ });
1147
+ return ctx.json({
1148
+ status: "success",
1149
+ data: chargeData
1150
+ });
1151
+ }
1152
+ return ctx.json({
1153
+ status: "failed",
1154
+ data: chargeData
1155
+ }, { status: 400 });
1156
+ });
1157
+ };
968
1158
 
969
1159
  //#endregion
970
1160
  //#region src/schema.ts
@@ -1035,6 +1225,14 @@ const subscriptions = { subscription: { fields: {
1035
1225
  type: "string",
1036
1226
  required: false
1037
1227
  },
1228
+ paystackAuthorizationCode: {
1229
+ type: "string",
1230
+ required: false
1231
+ },
1232
+ paystackEmailToken: {
1233
+ type: "string",
1234
+ required: false
1235
+ },
1038
1236
  status: {
1039
1237
  type: "string",
1040
1238
  defaultValue: "incomplete"
@@ -1159,7 +1357,8 @@ const paystack = (options) => {
1159
1357
  createSubscription: createSubscription(options),
1160
1358
  upgradeSubscription: upgradeSubscription(options),
1161
1359
  cancelSubscription: cancelSubscription(options),
1162
- restoreSubscription: restoreSubscription(options)
1360
+ restoreSubscription: restoreSubscription(options),
1361
+ chargeRecurringSubscription: chargeRecurringSubscription(options)
1163
1362
  },
1164
1363
  schema: getSchema(options),
1165
1364
  init: (ctx) => {
@@ -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 { 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","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} 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};\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 { getPlanByName, getPlans, getProductByName, getProducts } 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},\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\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: \"canceled\",\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\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 authorizationCode = ((data as Record<string, unknown>)?.authorization as Record<string, unknown>)?.authorization_code as string | undefined;\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\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}\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...(paystackSubscriptionCode !== undefined && paystackSubscriptionCode !== null && paystackSubscriptionCode !== \"\" ? { paystackSubscriptionCode } : {}),\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\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 && 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\t// data might be string (link) or object with link?\n\t\t\t\t\t\t// SDK says it returns string usually? \n\t\t\t\t\t\t// Actually the SDK wrapper returns the response object.\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\t// One last try: send email to owner? No, that's async.\n\t\t\t\t\t// If we still don't have emailToken, we can't disable.\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// 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: \"canceled\",\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\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 };\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\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} 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},\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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AAI,KAAK;GACf;GACA;GACA,CAAC;GAEH;;;;;ACpnCF,MAAa,eAAe,EAC3B,qBAAqB,EACpB,QAAQ;CACP,WAAW;EACV,MAAM;EACN,UAAU;EACV;CACD,YAAY;EACX,MAAM;EACN,UAAU;EACV;CACD,aAAa;EACZ,MAAM;EACN,UAAU;EACV;CACD,QAAQ;EACP,MAAM;EACN,UAAU;EACV;CACD,QAAQ;EACP,MAAM;EACN,UAAU;EACV;CACD,UAAU;EACT,MAAM;EACN,UAAU;EACV;CACD,QAAQ;EACP,MAAM;EACN,UAAU;EACV;CACD,MAAM;EACL,MAAM;EACN,UAAU;EACV;CACD,UAAU;EACT,MAAM;EACN,UAAU;EACV;CACD,WAAW;EACV,MAAM;EACN,UAAU;EACV;CACD,WAAW;EACV,MAAM;EACN,UAAU;EACV;CACD,EACD,EACD;AAED,MAAa,gBAAgB,EAC5B,cAAc,EACb,QAAQ;CACP,MAAM;EACL,MAAM;EACN,UAAU;EACV;CACD,aAAa;EACZ,MAAM;EACN,UAAU;EACV;CACD,sBAAsB;EACrB,MAAM;EACN,UAAU;EACV;CACD,0BAA0B;EACzB,MAAM;EACN,UAAU;EACV;CACD,8BAA8B;EAC7B,MAAM;EACN,UAAU;EACV;CACD,QAAQ;EACP,MAAM;EACN,cAAc;EACd;CACD,aAAa;EACZ,MAAM;EACN,UAAU;EACV;CACD,WAAW;EACV,MAAM;EACN,UAAU;EACV;CACD,YAAY;EACX,MAAM;EACN,UAAU;EACV;CACD,UAAU;EACT,MAAM;EACN,UAAU;EACV;CACD,mBAAmB;EAClB,MAAM;EACN,UAAU;EACV,cAAc;EACd;CACD,SAAS;EACR,MAAM;EACN,UAAU;EACV;CACD,OAAO;EACN,MAAM;EACN,UAAU;EACV;CACD,EACD,EACD;AAED,MAAa,OAAO,EACnB,MAAM,EACL,QAAQ,EACP,sBAAsB;CACrB,MAAM;CACN,UAAU;CACV,EACD,EACD,EACD;AAED,MAAa,eAAe,EAC3B,cAAc,EACb,QAAQ;CACP,sBAAsB;EACrB,MAAM;EACN,UAAU;EACV;CACD,OAAO;EACN,MAAM;EACN,UAA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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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"}
@@ -26,6 +26,14 @@ declare const subscriptions: {
26
26
  type: "string";
27
27
  required: false;
28
28
  };
29
+ paystackAuthorizationCode: {
30
+ type: "string";
31
+ required: false;
32
+ };
33
+ paystackEmailToken: {
34
+ type: "string";
35
+ required: false;
36
+ };
29
37
  status: {
30
38
  type: "string";
31
39
  defaultValue: string;
@@ -89,6 +97,7 @@ declare const organization: {
89
97
  //#endregion
90
98
  //#region src/types.d.ts
91
99
  type PaystackNodeClient = ReturnType<typeof createPaystack>;
100
+ type PaystackCurrency = "NGN" | "GHS" | "KES" | "ZAR" | "USD" | "XOF";
92
101
  type NonNullableInit<T> = Exclude<T, undefined>;
93
102
  type ExtractBody<T> = T extends {
94
103
  body?: infer B;
@@ -107,9 +116,11 @@ type CustomerUpdateInit = NonNullableInit<Parameters<PaystackNodeClient["custome
107
116
  type TransactionInitializeInit = NonNullableInit<Parameters<PaystackNodeClient["transaction_initialize"]>[0]>;
108
117
  type SubscriptionCreateInit = NonNullableInit<Parameters<PaystackNodeClient["subscription_create"]>[0]>;
109
118
  type SubscriptionToggleInit = NonNullableInit<Parameters<PaystackNodeClient["subscription_disable"]>[0]>;
119
+ type TransactionChargeAuthorizationInit = NonNullableInit<Parameters<PaystackNodeClient["transaction_chargeAuthorization"]>[0]>;
110
120
  type PaystackCustomerCreateInput = WithMetadataStringOrObject<ExtractBody<CustomerCreateInit>>;
111
121
  type PaystackCustomerUpdateInput = WithMetadataStringOrObject<WithEmail<ExtractBody<CustomerUpdateInit>>>;
112
122
  type PaystackTransactionInitializeInput = WithMetadataObject<ExtractBody<TransactionInitializeInit>>;
123
+ type PaystackTransactionChargeAuthorizationInput = WithMetadataObject<ExtractBody<TransactionChargeAuthorizationInit>>;
113
124
  type PaystackSubscriptionCreateInput = ExtractBody<SubscriptionCreateInit>;
114
125
  type PaystackSubscriptionToggleInput = ExtractBody<SubscriptionToggleInit>;
115
126
  type PaystackClientLike = Partial<PaystackNodeClient> & {
@@ -121,6 +132,7 @@ type PaystackClientLike = Partial<PaystackNodeClient> & {
121
132
  transaction?: {
122
133
  initialize?: (params: PaystackTransactionInitializeInput) => Promise<unknown>;
123
134
  verify?: (reference: string) => Promise<unknown>;
135
+ chargeAuthorization?: (params: PaystackTransactionChargeAuthorizationInput) => Promise<unknown>;
124
136
  };
125
137
  subscription?: {
126
138
  fetch?: (idOrCode: string) => Promise<unknown>;
@@ -142,7 +154,7 @@ interface PaystackPlan {
142
154
  /** Amount in the smallest currency unit (e.g. kobo). */
143
155
  amount?: number | undefined;
144
156
  /** Currency ISO code (e.g. NGN). */
145
- currency?: string | undefined;
157
+ currency?: PaystackCurrency | (string & {}) | undefined;
146
158
  /** Paystack interval keyword (when using Paystack plans). */
147
159
  interval?: "daily" | "weekly" | "monthly" | "quarterly" | "biannually" | "annually" | undefined;
148
160
  /** Optional description of the plan. */
@@ -169,7 +181,7 @@ interface PaystackProduct {
169
181
  /** Amount in the smallest currency unit (e.g., kobo). */
170
182
  amount: number;
171
183
  /** Currency ISO code (e.g., NGN). */
172
- currency: string;
184
+ currency: PaystackCurrency | (string & {});
173
185
  /** Optional metadata to include with the transaction. */
174
186
  metadata?: Record<string, unknown> | undefined;
175
187
  /** Optional description of the product. */
@@ -184,7 +196,7 @@ interface PaystackTransaction {
184
196
  referenceId: string;
185
197
  userId: string;
186
198
  amount: number;
187
- currency: string;
199
+ currency: PaystackCurrency | (string & {});
188
200
  status: string;
189
201
  plan?: string | undefined;
190
202
  metadata?: string | undefined;
@@ -198,6 +210,8 @@ interface Subscription {
198
210
  paystackCustomerCode?: string | undefined;
199
211
  paystackSubscriptionCode?: string | undefined;
200
212
  paystackTransactionReference?: string | undefined;
213
+ paystackAuthorizationCode?: string | undefined;
214
+ paystackEmailToken?: string | undefined;
201
215
  status: "active" | "canceled" | "incomplete" | "incomplete_expired" | "paused" | "trialing" | "unpaid";
202
216
  periodStart?: Date | undefined;
203
217
  periodEnd?: Date | undefined;
@@ -280,4 +294,4 @@ interface PaystackOptions<TPaystackClient extends PaystackClientLike = PaystackN
280
294
  }
281
295
  //#endregion
282
296
  export { PaystackProduct as a, SubscriptionOptions as c, PaystackPlan as i, PaystackNodeClient as n, PaystackTransaction as o, PaystackOptions as r, Subscription as s, PaystackClientLike as t };
283
- //# sourceMappingURL=types-Du5udJ7X.d.mts.map
297
+ //# sourceMappingURL=types-Dlv_nSLg.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-Dlv_nSLg.d.mts","names":["GenericEndpointContext","InferOptionSchema","Session","User","createPaystack","organization","subscriptions","user","PaystackNodeClient","ReturnType","PaystackCurrency","PaystackOpenApiFetchResponse","T","Response","data","error","response","PaystackApiResult","Promise","NonNullableInit","Exclude","ExtractBody","body","B","WithMetadataStringOrObject","Omit","Record","metadata","WithMetadataObject","WithEmail","email","CustomerCreateInit","Parameters","CustomerUpdateInit","TransactionInitializeInit","SubscriptionCreateInit","SubscriptionToggleInit","TransactionChargeAuthorizationInit","PaystackCustomerCreateInput","PaystackCustomerUpdateInput","PaystackTransactionInitializeInput","PaystackTransactionChargeAuthorizationInput","PaystackSubscriptionCreateInput","PaystackSubscriptionToggleInput","PaystackSubscriptionFetchInit","params","path","code","id_or_code","PaystackClientLike","Partial","subscription_manage_link","customer","create","update","transaction","initialize","verify","reference","chargeAuthorization","subscription","fetch","idOrCode","disable","enable","manage","link","NoInfer","AuthSession","session","PaystackPlan","Subscription","name","planCode","amount","currency","interval","description","features","invoiceLimit","limits","freeTrial","days","onTrialStart","onTrialEnd","ctx","onTrialExpired","PaystackProduct","PaystackTransaction","Date","id","paystackId","referenceId","userId","status","plan","createdAt","updatedAt","InputPaystackTransaction","paystackCustomerCode","paystackSubscriptionCode","paystackTransactionReference","paystackAuthorizationCode","paystackEmailToken","periodStart","periodEnd","trialStart","trialEnd","cancelAtPeriodEnd","groupId","seats","InputSubscription","SubscriptionOptions","plans","requireEmailVerification","authorizeReference","action","onSubscriptionComplete","event","onSubscriptionUpdate","onSubscriptionCreated","onSubscriptionCancel","onSubscriptionDelete","ProductOptions","products","OrganizationOptions","enabled","createCustomerOnOrganizationCreate","onCustomerCreate","paystackCustomer","getCustomerCreateParams","PaystackOptions","TPaystackClient","paystackClient","paystackWebhookSecret","createCustomerOnSignUp","onEvent","schema","Organization","slug","key","Member","organizationId","role"],"sources":["../src/schema.ts","../src/types.d.ts"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alexasomba/better-auth-paystack",
3
- "version": "1.0.0",
3
+ "version": "1.0.4",
4
4
  "description": "Production-ready Paystack billing plugin for Better Auth. Supports subscriptions, one-time payments, organization billing, secure webhooks and more",
5
5
  "license": "MIT",
6
6
  "author": "alexasomba",
@@ -86,14 +86,14 @@
86
86
  "@eslint/compat": "^2.0.2",
87
87
  "@eslint/js": "^10.0.1",
88
88
  "@rollup/rollup-linux-x64-gnu": "^4.57.1",
89
- "@types/node": "^22.19.10",
89
+ "@types/node": "^22.19.11",
90
90
  "@typescript-eslint/eslint-plugin": "^8.55.0",
91
91
  "@typescript-eslint/parser": "^8.55.0",
92
92
  "@vitest/coverage-v8": "^3.2.4",
93
93
  "better-auth": "^1.4.18",
94
94
  "eslint": "^10.0.0",
95
95
  "eslint-plugin-import-x": "^4.16.1",
96
- "eslint-plugin-unicorn": "^62.0.0",
96
+ "eslint-plugin-unicorn": "^63.0.0",
97
97
  "eslint-plugin-promise": "^7.2.1",
98
98
  "eslint-plugin-react-hooks": "^7.0.1",
99
99
  "husky": "^9.1.7",
@@ -107,6 +107,7 @@
107
107
  "lint-staged": {
108
108
  "*.{ts,tsx}": [
109
109
  "bash -c 'pnpm tsc --noEmit'",
110
+ "eslint --fix",
110
111
  "vitest related --run"
111
112
  ]
112
113
  },
@@ -1 +0,0 @@
1
- {"version":3,"file":"types-Du5udJ7X.d.mts","names":["GenericEndpointContext","InferOptionSchema","Session","User","createPaystack","organization","subscriptions","user","PaystackNodeClient","ReturnType","PaystackOpenApiFetchResponse","T","Response","data","error","response","PaystackApiResult","Promise","NonNullableInit","Exclude","ExtractBody","body","B","WithMetadataStringOrObject","Omit","Record","metadata","WithMetadataObject","WithEmail","email","CustomerCreateInit","Parameters","CustomerUpdateInit","TransactionInitializeInit","SubscriptionCreateInit","SubscriptionToggleInit","PaystackCustomerCreateInput","PaystackCustomerUpdateInput","PaystackTransactionInitializeInput","PaystackSubscriptionCreateInput","PaystackSubscriptionToggleInput","PaystackSubscriptionFetchInit","params","path","code","id_or_code","PaystackClientLike","Partial","subscription_manage_link","customer","create","update","transaction","initialize","verify","reference","subscription","fetch","idOrCode","disable","enable","manage","link","NoInfer","AuthSession","session","PaystackPlan","Subscription","name","planCode","amount","currency","interval","description","features","invoiceLimit","limits","freeTrial","days","onTrialStart","onTrialEnd","ctx","onTrialExpired","PaystackProduct","PaystackTransaction","Date","id","paystackId","referenceId","userId","status","plan","createdAt","updatedAt","InputPaystackTransaction","paystackCustomerCode","paystackSubscriptionCode","paystackTransactionReference","periodStart","periodEnd","trialStart","trialEnd","cancelAtPeriodEnd","groupId","seats","InputSubscription","SubscriptionOptions","plans","requireEmailVerification","authorizeReference","action","onSubscriptionComplete","event","onSubscriptionUpdate","onSubscriptionCreated","onSubscriptionCancel","onSubscriptionDelete","ProductOptions","products","OrganizationOptions","enabled","createCustomerOnOrganizationCreate","onCustomerCreate","paystackCustomer","getCustomerCreateParams","PaystackOptions","TPaystackClient","paystackClient","paystackWebhookSecret","createCustomerOnSignUp","onEvent","schema","Organization","slug","key","Member","organizationId","role"],"sources":["../src/schema.ts","../src/types.d.ts"],"mappings":"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"}