@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 +57 -38
- package/dist/client.d.mts +1 -1
- package/dist/index.d.mts +11 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +210 -11
- package/dist/index.mjs.map +1 -1
- package/dist/{types-Du5udJ7X.d.mts → types-Dlv_nSLg.d.mts} +18 -4
- package/dist/types-Dlv_nSLg.d.mts.map +1 -0
- package/package.json +4 -3
- package/dist/types-Du5udJ7X.d.mts.map +0 -1
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
|
-
| `
|
|
382
|
-
| `
|
|
383
|
-
| `
|
|
384
|
-
| `
|
|
385
|
-
| `
|
|
386
|
-
| `
|
|
387
|
-
| `
|
|
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
|
-
- [
|
|
446
|
-
- [
|
|
447
|
-
- [ ] **
|
|
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
|
|
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-
|
|
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-
|
|
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) => {
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;
|
|
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:
|
|
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
|
-
...
|
|
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
|
-
|
|
929
|
+
let nextPaymentDate;
|
|
930
|
+
try {
|
|
847
931
|
const fetchRes = unwrapSdkResult(await paystack.subscriptionFetch(subscriptionCode));
|
|
848
|
-
|
|
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
|
-
|
|
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: "
|
|
958
|
+
status: "active",
|
|
959
|
+
cancelAtPeriodEnd: true,
|
|
960
|
+
periodEnd,
|
|
865
961
|
updatedAt: /* @__PURE__ */ new Date()
|
|
866
962
|
},
|
|
867
963
|
where: [{
|
|
868
|
-
field: "
|
|
869
|
-
value:
|
|
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) => {
|
package/dist/index.mjs.map
CHANGED
|
@@ -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-
|
|
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.
|
|
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.
|
|
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": "^
|
|
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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"}
|