@alexasomba/better-auth-paystack 1.1.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { defineErrorCodes } from "@better-auth/core/utils";
1
+ import { defineErrorCodes } from "@better-auth/core/utils/error-codes";
2
2
  import { defu } from "defu";
3
3
  import { createAuthEndpoint, createAuthMiddleware } from "@better-auth/core/api";
4
4
  import { HIDE_METADATA, logger } from "better-auth";
@@ -73,6 +73,17 @@ function getPaystackOps(paystackClient) {
73
73
  if (paystackClient?.subscription_manageEmail !== void 0) return paystackClient.subscription_manageEmail({ params: { path: { code } } });
74
74
  return paystackClient?.subscription?.manage?.email?.(code, email);
75
75
  },
76
+ subscriptionUpdate: (params) => {
77
+ if (paystackClient?.subscription_update !== void 0) return paystackClient.subscription_update({
78
+ params: { path: { code: params.code } },
79
+ body: {
80
+ plan: params.plan,
81
+ authorization: params.authorization,
82
+ amount: params.amount
83
+ }
84
+ });
85
+ return paystackClient?.subscription?.update?.(params.code, params);
86
+ },
76
87
  transactionChargeAuthorization: (body) => {
77
88
  if (paystackClient?.transaction_chargeAuthorization !== void 0) return paystackClient.transaction_chargeAuthorization({ body });
78
89
  return paystackClient?.transaction?.chargeAuthorization?.(body);
@@ -220,6 +231,51 @@ async function syncProductQuantityFromPaystack(ctx, productName, paystackClient)
220
231
  });
221
232
  }
222
233
  }
234
+ async function syncSubscriptionSeats(ctx, organizationId, options) {
235
+ if (options.subscription?.enabled !== true) return;
236
+ const adapter = ctx.context?.adapter ?? ctx.adapter;
237
+ const subscription = await adapter.findOne({
238
+ model: "subscription",
239
+ where: [{
240
+ field: "referenceId",
241
+ value: organizationId
242
+ }]
243
+ });
244
+ if (subscription === null || subscription.paystackSubscriptionCode === void 0 || subscription.paystackSubscriptionCode === null) return;
245
+ const plan = await getPlanByName(options, subscription.plan);
246
+ if (plan === null) return;
247
+ if (plan.seatAmount === void 0 && plan.seatPlanCode === void 0) return;
248
+ const quantity = (await adapter.findMany({
249
+ model: "member",
250
+ where: [{
251
+ field: "organizationId",
252
+ value: organizationId
253
+ }]
254
+ })).length;
255
+ let totalAmount = plan.amount ?? 0;
256
+ if (plan.seatAmount !== void 0 && plan.seatAmount !== null) totalAmount += quantity * plan.seatAmount;
257
+ const ops = getPaystackOps(options.paystackClient);
258
+ try {
259
+ await ops.subscriptionUpdate({
260
+ code: subscription.paystackSubscriptionCode,
261
+ amount: totalAmount
262
+ });
263
+ await adapter.update({
264
+ model: "subscription",
265
+ where: [{
266
+ field: "id",
267
+ value: subscription.id
268
+ }],
269
+ update: {
270
+ seats: quantity,
271
+ updatedAt: /* @__PURE__ */ new Date()
272
+ }
273
+ });
274
+ } catch (e) {
275
+ const log = ctx.context?.logger ?? ctx.logger;
276
+ if (log !== void 0 && log !== null) log.error("Failed to sync subscription seats with Paystack", e);
277
+ }
278
+ }
223
279
 
224
280
  //#endregion
225
281
  //#region src/middleware.ts
@@ -260,6 +316,41 @@ const referenceMiddleware = (options, action) => createAuthMiddleware(async (ctx
260
316
  throw new APIError("BAD_REQUEST", { message: "Passing referenceId isn't allowed without subscription.authorizeReference or valid organization membership." });
261
317
  });
262
318
 
319
+ //#endregion
320
+ //#region src/limits.ts
321
+ const getOrganizationSubscription = async (ctx, organizationId) => {
322
+ return await ctx.context.adapter.findOne({
323
+ model: "subscription",
324
+ where: [{
325
+ field: "referenceId",
326
+ value: organizationId
327
+ }]
328
+ });
329
+ };
330
+ const checkSeatLimit = async (ctx, organizationId, seatsToAdd = 1) => {
331
+ const subscription = await getOrganizationSubscription(ctx, organizationId);
332
+ if (subscription?.seats === void 0 || subscription.seats === null) return true;
333
+ const members = await ctx.context.adapter.findMany({
334
+ model: "member",
335
+ where: [{
336
+ field: "organizationId",
337
+ value: organizationId
338
+ }]
339
+ });
340
+ if (members.length + seatsToAdd > subscription.seats) throw new APIError("FORBIDDEN", { message: `Organization member limit reached. Used: ${members.length}, Max: ${subscription.seats}` });
341
+ return true;
342
+ };
343
+ const checkTeamLimit = async (ctx, organizationId, maxTeams) => {
344
+ if ((await ctx.context.adapter.findMany({
345
+ model: "team",
346
+ where: [{
347
+ field: "organizationId",
348
+ value: organizationId
349
+ }]
350
+ })).length >= maxTeams) throw new APIError("FORBIDDEN", { message: `Organization team limit reached. Max teams: ${maxTeams}` });
351
+ return true;
352
+ };
353
+
263
354
  //#endregion
264
355
  //#region src/routes.ts
265
356
  const PAYSTACK_ERROR_CODES = defineErrorCodes({
@@ -479,6 +570,31 @@ const paystackWebhook = (options) => {
479
570
  }, ctx);
480
571
  }
481
572
  }
573
+ if (eventName === "charge.success" || eventName === "invoice.update") {
574
+ const payloadData = data;
575
+ const subscriptionCode = payloadData?.subscription?.subscription_code ?? payloadData?.subscription_code;
576
+ if (subscriptionCode) {
577
+ const existingSub = await ctx.context.adapter.findOne({
578
+ model: "subscription",
579
+ where: [{
580
+ field: "paystackSubscriptionCode",
581
+ value: subscriptionCode
582
+ }]
583
+ });
584
+ if (existingSub?.pendingPlan) await ctx.context.adapter.update({
585
+ model: "subscription",
586
+ update: {
587
+ plan: existingSub.pendingPlan,
588
+ pendingPlan: null,
589
+ updatedAt: /* @__PURE__ */ new Date()
590
+ },
591
+ where: [{
592
+ field: "id",
593
+ value: existingSub.id
594
+ }]
595
+ });
596
+ }
597
+ }
482
598
  } catch (_e) {
483
599
  ctx.context.logger.error("Failed to sync Paystack webhook event", _e);
484
600
  }
@@ -495,7 +611,10 @@ const initializeTransactionBodySchema = z.object({
495
611
  metadata: z.record(z.string(), z.unknown()).optional(),
496
612
  referenceId: z.string().optional(),
497
613
  callbackURL: z.string().optional(),
498
- quantity: z.number().int().positive().optional()
614
+ quantity: z.number().int().positive().optional(),
615
+ scheduleAtPeriodEnd: z.boolean().optional(),
616
+ cancelAtPeriodEnd: z.boolean().optional(),
617
+ prorateAndCharge: z.boolean().optional()
499
618
  });
500
619
  const initializeTransaction = (options, path = "/paystack/initialize-transaction") => {
501
620
  const subscriptionOptions = options.subscription;
@@ -509,7 +628,7 @@ const initializeTransaction = (options, path = "/paystack/initialize-transaction
509
628
  ] : [sessionMiddleware, originCheck]
510
629
  }, async (ctx) => {
511
630
  const paystack = getPaystackOps(options.paystackClient);
512
- const { plan: planName, product: productName, amount: bodyAmount, currency, email, metadata: extraMetadata, callbackURL, quantity } = ctx.body;
631
+ const { plan: planName, product: productName, amount: bodyAmount, currency, email, metadata: extraMetadata, callbackURL, quantity, scheduleAtPeriodEnd, cancelAtPeriodEnd, prorateAndCharge } = ctx.body;
513
632
  if (callbackURL !== void 0 && callbackURL !== null && callbackURL !== "") {
514
633
  const checkTrusted = () => {
515
634
  try {
@@ -533,7 +652,7 @@ const initializeTransaction = (options, path = "/paystack/initialize-transaction
533
652
  const user = session.user;
534
653
  if (subscriptionOptions?.enabled === true && subscriptionOptions.requireEmailVerification === true && !user.emailVerified) throw new APIError("BAD_REQUEST", {
535
654
  code: "EMAIL_VERIFICATION_REQUIRED",
536
- message: PAYSTACK_ERROR_CODES.EMAIL_VERIFICATION_REQUIRED
655
+ message: PAYSTACK_ERROR_CODES.EMAIL_VERIFICATION_REQUIRED.message
537
656
  });
538
657
  let plan;
539
658
  let product;
@@ -559,7 +678,7 @@ const initializeTransaction = (options, path = "/paystack/initialize-transaction
559
678
  }
560
679
  if (!plan) throw new APIError("BAD_REQUEST", {
561
680
  code: "SUBSCRIPTION_PLAN_NOT_FOUND",
562
- message: PAYSTACK_ERROR_CODES.SUBSCRIPTION_PLAN_NOT_FOUND,
681
+ message: PAYSTACK_ERROR_CODES.SUBSCRIPTION_PLAN_NOT_FOUND.message,
563
682
  status: 400
564
683
  });
565
684
  } else if (productName !== void 0 && productName !== null && productName !== "") {
@@ -581,13 +700,67 @@ const initializeTransaction = (options, path = "/paystack/initialize-transaction
581
700
  message: "Either 'plan', 'product', or 'amount' is required to initialize a transaction.",
582
701
  status: 400
583
702
  });
584
- const amount = bodyAmount ?? product?.price;
703
+ let amount = bodyAmount ?? product?.price;
585
704
  const finalCurrency = currency ?? product?.currency ?? plan?.currency ?? "NGN";
705
+ const referenceIdFromCtx = ctx.context.referenceId;
706
+ const referenceId = ctx.body.referenceId !== void 0 && ctx.body.referenceId !== null && ctx.body.referenceId !== "" ? ctx.body.referenceId : referenceIdFromCtx !== void 0 && referenceIdFromCtx !== null && referenceIdFromCtx !== "" ? referenceIdFromCtx : session.user.id;
707
+ if (plan && scheduleAtPeriodEnd === true) {
708
+ const existingSub = await getOrganizationSubscription(ctx, referenceId);
709
+ if (existingSub?.status === "active") {
710
+ await ctx.context.adapter.update({
711
+ model: "subscription",
712
+ where: [{
713
+ field: "id",
714
+ value: existingSub.id
715
+ }],
716
+ update: {
717
+ pendingPlan: plan.name,
718
+ updatedAt: /* @__PURE__ */ new Date()
719
+ }
720
+ });
721
+ return ctx.json({
722
+ status: "success",
723
+ message: "Plan change scheduled at period end.",
724
+ scheduled: true
725
+ });
726
+ }
727
+ }
728
+ if (cancelAtPeriodEnd === true) {
729
+ const existingSub = await getOrganizationSubscription(ctx, referenceId);
730
+ if (existingSub?.status === "active") {
731
+ await ctx.context.adapter.update({
732
+ model: "subscription",
733
+ where: [{
734
+ field: "id",
735
+ value: existingSub.id
736
+ }],
737
+ update: {
738
+ cancelAtPeriodEnd: true,
739
+ updatedAt: /* @__PURE__ */ new Date()
740
+ }
741
+ });
742
+ return ctx.json({
743
+ status: "success",
744
+ message: "Subscription cancellation scheduled at period end.",
745
+ scheduled: true
746
+ });
747
+ }
748
+ }
749
+ if (plan && (plan.seatAmount !== void 0 || plan.seatPriceId !== void 0)) {
750
+ const members = await ctx.context.adapter.findMany({
751
+ model: "member",
752
+ where: [{
753
+ field: "organizationId",
754
+ value: referenceId
755
+ }]
756
+ });
757
+ const seatCount = members.length > 0 ? members.length : 1;
758
+ const quantityToUse = quantity ?? seatCount;
759
+ amount = (plan.amount ?? 0) + quantityToUse * (plan.seatAmount ?? plan.seatPriceId ?? 0);
760
+ }
586
761
  let url;
587
762
  let reference;
588
763
  let accessCode;
589
- const referenceIdFromCtx = ctx.context.referenceId;
590
- const referenceId = ctx.body.referenceId !== void 0 && ctx.body.referenceId !== null && ctx.body.referenceId !== "" ? ctx.body.referenceId : referenceIdFromCtx !== void 0 && referenceIdFromCtx !== null && referenceIdFromCtx !== "" ? referenceIdFromCtx : session.user.id;
591
764
  let trialStart;
592
765
  let trialEnd;
593
766
  if (plan?.freeTrial?.days !== void 0 && plan.freeTrial.days !== null && plan.freeTrial.days > 0) {
@@ -661,13 +834,95 @@ const initializeTransaction = (options, path = "/paystack/initialize-transaction
661
834
  const ops = getPaystackOps(options.paystackClient);
662
835
  if (initBody.email !== void 0 && initBody.email !== null && initBody.email !== "") await ops.customerUpdate(paystackCustomerCode, { email: initBody.email });
663
836
  } catch (_e) {}
837
+ if (plan && prorateAndCharge === true) {
838
+ const existingSub = await getOrganizationSubscription(ctx, referenceId);
839
+ if (existingSub?.status === "active" && existingSub.paystackAuthorizationCode !== null && existingSub.paystackAuthorizationCode !== void 0 && existingSub.paystackSubscriptionCode !== null && existingSub.paystackSubscriptionCode !== void 0) {
840
+ const now = /* @__PURE__ */ new Date();
841
+ const periodEndLocal = existingSub.periodEnd ? new Date(existingSub.periodEnd) : new Date(now.getTime() + 720 * 60 * 60 * 1e3);
842
+ const periodStartLocal = existingSub.periodStart ? new Date(existingSub.periodStart) : now;
843
+ const totalDays = Math.max(1, Math.ceil((periodEndLocal.getTime() - periodStartLocal.getTime()) / (1e3 * 60 * 60 * 24)));
844
+ const remainingDays = Math.max(0, Math.ceil((periodEndLocal.getTime() - now.getTime()) / (1e3 * 60 * 60 * 24)));
845
+ let oldAmount = 0;
846
+ if (existingSub.plan) {
847
+ const oldPlan = await getPlanByName(options, existingSub.plan) ?? await ctx.context.adapter.findOne({
848
+ model: "paystackPlan",
849
+ where: [{
850
+ field: "name",
851
+ value: existingSub.plan
852
+ }]
853
+ });
854
+ if (oldPlan) {
855
+ const oldSeatCount = existingSub.seats ?? 1;
856
+ oldAmount = (oldPlan.amount ?? 0) + oldSeatCount * (oldPlan.seatAmount ?? oldPlan.seatPriceId ?? 0);
857
+ }
858
+ }
859
+ let membersCount = 1;
860
+ if (plan.seatAmount !== void 0 || plan.seatPriceId !== void 0) {
861
+ const members = await ctx.context.adapter.findMany({
862
+ model: "member",
863
+ where: [{
864
+ field: "organizationId",
865
+ value: referenceId
866
+ }]
867
+ });
868
+ membersCount = members.length > 0 ? members.length : 1;
869
+ }
870
+ const newSeatCount = quantity ?? existingSub.seats ?? membersCount;
871
+ const newAmount = (plan.amount ?? 0) + newSeatCount * (plan.seatAmount ?? plan.seatPriceId ?? 0);
872
+ const costDifference = newAmount - oldAmount;
873
+ if (costDifference > 0 && remainingDays > 0) {
874
+ const proratedAmount = Math.round(costDifference / totalDays * remainingDays);
875
+ if (proratedAmount >= 5e3) {
876
+ const chargeData = unwrapSdkResult(await getPaystackOps(options.paystackClient).transactionChargeAuthorization({
877
+ email: targetEmail,
878
+ amount: proratedAmount,
879
+ authorization_code: existingSub.paystackAuthorizationCode,
880
+ reference: `prorate_${Date.now()}_${Math.random().toString(36).substring(7)}`,
881
+ metadata: {
882
+ type: "proration",
883
+ referenceId,
884
+ newPlan: plan.name,
885
+ oldPlan: existingSub.plan,
886
+ remainingDays
887
+ }
888
+ }));
889
+ if ((chargeData?.data?.status ?? chargeData?.status) !== "success") throw new APIError("BAD_REQUEST", { message: "Failed to process prorated charge via saved authorization." });
890
+ }
891
+ }
892
+ await getPaystackOps(options.paystackClient).subscriptionUpdate({
893
+ code: existingSub.paystackSubscriptionCode,
894
+ amount: newAmount,
895
+ plan: plan.planCode
896
+ });
897
+ await ctx.context.adapter.update({
898
+ model: "subscription",
899
+ where: [{
900
+ field: "id",
901
+ value: existingSub.id
902
+ }],
903
+ update: {
904
+ plan: plan.name,
905
+ seats: newSeatCount,
906
+ updatedAt: /* @__PURE__ */ new Date()
907
+ }
908
+ });
909
+ return ctx.json({
910
+ status: "success",
911
+ message: "Subscription successfully upgraded with prorated charge.",
912
+ prorated: true
913
+ });
914
+ }
915
+ }
664
916
  if (plan) if (trialStart) initBody.amount = 5e3;
665
917
  else {
666
918
  initBody.plan = plan.planCode;
667
919
  initBody.invoice_limit = plan.invoiceLimit;
668
- const planAmount = amount ?? plan.amount ?? 5e4;
669
- initBody.amount = Math.max(Math.round(planAmount), 5e4);
670
- if (quantity !== void 0 && quantity !== null && quantity > 0) initBody.amount = initBody.amount * quantity;
920
+ let finalAmount;
921
+ if (amount !== void 0 && amount !== null) {
922
+ finalAmount = amount;
923
+ initBody.quantity = 1;
924
+ } else finalAmount = (plan.amount ?? 5e4) * (quantity ?? 1);
925
+ initBody.amount = Math.max(Math.round(finalAmount), 5e4);
671
926
  }
672
927
  else {
673
928
  if (amount === void 0 || amount === null || amount === 0) throw new APIError("BAD_REQUEST", { message: "Amount is required for one-time payments" });
@@ -683,7 +938,7 @@ const initializeTransaction = (options, path = "/paystack/initialize-transaction
683
938
  ctx.context.logger.error("Failed to initialize Paystack transaction", error);
684
939
  throw new APIError("BAD_REQUEST", {
685
940
  code: "FAILED_TO_INITIALIZE_TRANSACTION",
686
- message: error?.message ?? PAYSTACK_ERROR_CODES.FAILED_TO_INITIALIZE_TRANSACTION
941
+ message: error?.message ?? PAYSTACK_ERROR_CODES.FAILED_TO_INITIALIZE_TRANSACTION.message
687
942
  });
688
943
  }
689
944
  await ctx.context.adapter.create({
@@ -765,7 +1020,7 @@ const verifyTransaction = (options, path = "/paystack/verify-transaction") => {
765
1020
  ctx.context.logger.error("Failed to verify Paystack transaction", error);
766
1021
  throw new APIError("BAD_REQUEST", {
767
1022
  code: "FAILED_TO_VERIFY_TRANSACTION",
768
- message: error?.message ?? PAYSTACK_ERROR_CODES.FAILED_TO_VERIFY_TRANSACTION
1023
+ message: error?.message ?? PAYSTACK_ERROR_CODES.FAILED_TO_VERIFY_TRANSACTION.message
769
1024
  });
770
1025
  }
771
1026
  const data = unwrapSdkResult(verifyRes);
@@ -998,7 +1253,8 @@ const listTransactions = (options, path = "/paystack/list-transactions") => {
998
1253
  const enableDisableBodySchema = z.object({
999
1254
  referenceId: z.string().optional(),
1000
1255
  subscriptionCode: z.string(),
1001
- emailToken: z.string().optional()
1256
+ emailToken: z.string().optional(),
1257
+ atPeriodEnd: z.boolean().optional()
1002
1258
  });
1003
1259
  function decodeBase64UrlToString(value) {
1004
1260
  const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
@@ -1029,7 +1285,7 @@ const disablePaystackSubscription = (options, path = "/paystack/disable-subscrip
1029
1285
  referenceMiddleware(options, "disable-subscription")
1030
1286
  ] : [sessionMiddleware, originCheck]
1031
1287
  }, async (ctx) => {
1032
- const { subscriptionCode } = ctx.body;
1288
+ const { subscriptionCode, atPeriodEnd } = ctx.body;
1033
1289
  const paystack = getPaystackOps(options.paystackClient);
1034
1290
  try {
1035
1291
  if (subscriptionCode.startsWith("LOC_")) {
@@ -1044,8 +1300,8 @@ const disablePaystackSubscription = (options, path = "/paystack/disable-subscrip
1044
1300
  await ctx.context.adapter.update({
1045
1301
  model: "subscription",
1046
1302
  update: {
1047
- status: "active",
1048
- cancelAtPeriodEnd: true,
1303
+ status: atPeriodEnd === false ? "canceled" : "active",
1304
+ cancelAtPeriodEnd: atPeriodEnd !== false,
1049
1305
  updatedAt: /* @__PURE__ */ new Date()
1050
1306
  },
1051
1307
  where: [{
@@ -1087,8 +1343,8 @@ const disablePaystackSubscription = (options, path = "/paystack/disable-subscrip
1087
1343
  if (sub) await ctx.context.adapter.update({
1088
1344
  model: "subscription",
1089
1345
  update: {
1090
- status: "active",
1091
- cancelAtPeriodEnd: true,
1346
+ status: atPeriodEnd === false ? "canceled" : "active",
1347
+ cancelAtPeriodEnd: atPeriodEnd !== false,
1092
1348
  periodEnd,
1093
1349
  updatedAt: /* @__PURE__ */ new Date()
1094
1350
  },
@@ -1103,7 +1359,7 @@ const disablePaystackSubscription = (options, path = "/paystack/disable-subscrip
1103
1359
  ctx.context.logger.error("Failed to disable subscription", error);
1104
1360
  throw new APIError("BAD_REQUEST", {
1105
1361
  code: "FAILED_TO_DISABLE_SUBSCRIPTION",
1106
- message: error?.message ?? PAYSTACK_ERROR_CODES.FAILED_TO_DISABLE_SUBSCRIPTION
1362
+ message: error?.message ?? PAYSTACK_ERROR_CODES.FAILED_TO_DISABLE_SUBSCRIPTION.message
1107
1363
  });
1108
1364
  }
1109
1365
  });
@@ -1153,7 +1409,7 @@ const enablePaystackSubscription = (options, path = "/paystack/enable-subscripti
1153
1409
  ctx.context.logger.error("Failed to enable subscription", error);
1154
1410
  throw new APIError("BAD_REQUEST", {
1155
1411
  code: "FAILED_TO_ENABLE_SUBSCRIPTION",
1156
- message: error?.message ?? PAYSTACK_ERROR_CODES.FAILED_TO_ENABLE_SUBSCRIPTION
1412
+ message: error?.message ?? PAYSTACK_ERROR_CODES.FAILED_TO_ENABLE_SUBSCRIPTION.message
1157
1413
  });
1158
1414
  }
1159
1415
  });
@@ -1568,6 +1824,10 @@ const subscriptions = { subscription: { fields: {
1568
1824
  seats: {
1569
1825
  type: "number",
1570
1826
  required: false
1827
+ },
1828
+ pendingPlan: {
1829
+ type: "string",
1830
+ required: false
1571
1831
  }
1572
1832
  } } };
1573
1833
  const user = { user: { fields: { paystackCustomerCode: {
@@ -1706,44 +1966,9 @@ const getSchema = (options) => {
1706
1966
  return mergeSchema(baseSchema, options.schema);
1707
1967
  };
1708
1968
 
1709
- //#endregion
1710
- //#region src/limits.ts
1711
- const getOrganizationSubscription = async (ctx, organizationId) => {
1712
- return await ctx.context.adapter.findOne({
1713
- model: "subscription",
1714
- where: [{
1715
- field: "referenceId",
1716
- value: organizationId
1717
- }]
1718
- });
1719
- };
1720
- const checkSeatLimit = async (ctx, organizationId, seatsToAdd = 1) => {
1721
- const subscription = await getOrganizationSubscription(ctx, organizationId);
1722
- if (subscription?.seats === void 0 || subscription.seats === null) return true;
1723
- const members = await ctx.context.adapter.findMany({
1724
- model: "member",
1725
- where: [{
1726
- field: "organizationId",
1727
- value: organizationId
1728
- }]
1729
- });
1730
- if (members.length + seatsToAdd > subscription.seats) throw new APIError("FORBIDDEN", { message: `Organization member limit reached. Used: ${members.length}, Max: ${subscription.seats}` });
1731
- return true;
1732
- };
1733
- const checkTeamLimit = async (ctx, organizationId, maxTeams) => {
1734
- if ((await ctx.context.adapter.findMany({
1735
- model: "team",
1736
- where: [{
1737
- field: "organizationId",
1738
- value: organizationId
1739
- }]
1740
- })).length >= maxTeams) throw new APIError("FORBIDDEN", { message: `Organization team limit reached. Max teams: ${maxTeams}` });
1741
- return true;
1742
- };
1743
-
1744
1969
  //#endregion
1745
1970
  //#region src/index.ts
1746
- const INTERNAL_ERROR_CODES = defineErrorCodes({ ...PAYSTACK_ERROR_CODES });
1971
+ const INTERNAL_ERROR_CODES = defineErrorCodes({ ...Object.fromEntries(Object.entries(PAYSTACK_ERROR_CODES).map(([key, value]) => [key, typeof value === "string" ? value : value.message])) });
1747
1972
  const paystack = (options) => {
1748
1973
  const routeOptions = options;
1749
1974
  return {
@@ -1836,12 +2061,32 @@ const paystack = (options) => {
1836
2061
  }
1837
2062
  } } } : void 0
1838
2063
  },
1839
- member: { create: { before: async (member, ctx) => {
1840
- if (options.subscription?.enabled === true && member.organizationId && ctx !== null && ctx !== void 0) await checkSeatLimit(ctx, member.organizationId);
1841
- } } },
1842
- invitation: { create: { before: async (invitation, ctx) => {
1843
- if (options.subscription?.enabled === true && invitation.organizationId && ctx !== null && ctx !== void 0) await checkSeatLimit(ctx, invitation.organizationId);
1844
- } } },
2064
+ member: {
2065
+ create: {
2066
+ before: async (member, ctx) => {
2067
+ if (options.subscription?.enabled === true && member.organizationId && ctx !== null && ctx !== void 0) await checkSeatLimit(ctx, member.organizationId);
2068
+ },
2069
+ after: async (member, ctx) => {
2070
+ if (options.subscription?.enabled === true && member?.organizationId !== void 0 && member?.organizationId !== null && ctx !== void 0 && ctx !== null) await syncSubscriptionSeats(ctx, member.organizationId, options);
2071
+ }
2072
+ },
2073
+ delete: { after: async (member, ctx) => {
2074
+ if (options.subscription?.enabled === true && member?.organizationId !== void 0 && member?.organizationId !== null && ctx !== void 0 && ctx !== null) await syncSubscriptionSeats(ctx, member.organizationId, options);
2075
+ } }
2076
+ },
2077
+ invitation: {
2078
+ create: {
2079
+ before: async (invitation, ctx) => {
2080
+ if (options.subscription?.enabled === true && invitation.organizationId && ctx !== null && ctx !== void 0) await checkSeatLimit(ctx, invitation.organizationId);
2081
+ },
2082
+ after: async (invitation, ctx) => {
2083
+ if (options.subscription?.enabled === true && invitation?.organizationId !== void 0 && invitation?.organizationId !== null && ctx !== void 0 && ctx !== null) await syncSubscriptionSeats(ctx, invitation.organizationId, options);
2084
+ }
2085
+ },
2086
+ delete: { after: async (invitation, ctx) => {
2087
+ if (options.subscription?.enabled === true && invitation?.organizationId !== void 0 && invitation?.organizationId !== null && ctx !== void 0 && ctx !== null) await syncSubscriptionSeats(ctx, invitation.organizationId, options);
2088
+ } }
2089
+ },
1845
2090
  team: { create: { before: async (team, ctx) => {
1846
2091
  if (options.subscription?.enabled === true && team.organizationId && ctx !== null && ctx !== void 0) {
1847
2092
  const subscription = await getOrganizationSubscription(ctx, team.organizationId);