@alexasomba/better-auth-paystack 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/operations.ts","../src/index.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -45,6 +45,30 @@ function getPaystackOps(client) {
45
45
  }
46
46
  //#endregion
47
47
  //#region src/utils.ts
48
+ function getPlanSeatAmount(plan) {
49
+ if (plan.seatAmount !== void 0) {
50
+ if (typeof plan.seatAmount === "number" && Number.isFinite(plan.seatAmount)) return plan.seatAmount;
51
+ throw new Error(`Invalid seatAmount for plan '${plan.name}'. Expected a finite number.`);
52
+ }
53
+ if (plan.seatPriceId === void 0 || plan.seatPriceId === null || plan.seatPriceId === "") return;
54
+ const parsed = typeof plan.seatPriceId === "string" ? Number(plan.seatPriceId) : plan.seatPriceId;
55
+ if (typeof parsed === "number" && Number.isFinite(parsed)) return parsed;
56
+ throw new Error(`Invalid seatPriceId for plan '${plan.name}'. Expected a numeric amount in the smallest currency unit.`);
57
+ }
58
+ function calculatePlanAmount(plan, quantity) {
59
+ return (plan.amount ?? 0) + quantity * (getPlanSeatAmount(plan) ?? 0);
60
+ }
61
+ function isLocalSubscriptionCode(subscriptionCode) {
62
+ return typeof subscriptionCode === "string" && (subscriptionCode.startsWith("LOC_") || subscriptionCode.startsWith("sub_local_"));
63
+ }
64
+ function isLocallyManagedSubscription(subscription) {
65
+ if (isLocalSubscriptionCode(subscription.paystackSubscriptionCode)) return true;
66
+ if (typeof subscription.paystackSubscriptionCode === "string" && subscription.paystackSubscriptionCode !== "") return false;
67
+ return subscription.paystackPlanCode === void 0 || subscription.paystackPlanCode === null || subscription.paystackPlanCode === "";
68
+ }
69
+ function assertLocallyManagedSubscription(subscription, action) {
70
+ if (!isLocallyManagedSubscription(subscription)) throw new Error(`Paystack-managed subscriptions do not support ${action}. Use local billing for seat-based or prorated subscription changes.`);
71
+ }
48
72
  async function getPlans(subscriptionOptions) {
49
73
  if (subscriptionOptions?.enabled === true) return typeof subscriptionOptions.plans === "function" ? subscriptionOptions.plans() : subscriptionOptions.plans;
50
74
  throw new Error("Subscriptions are not enabled in the Paystack options.");
@@ -135,7 +159,9 @@ async function syncProductQuantityFromPaystack(ctx, productName, paystackClient)
135
159
  return;
136
160
  }
137
161
  try {
138
- const remoteQuantity = unwrapSdkResult(await paystackClient.product?.fetch(localProduct.paystackId))?.quantity;
162
+ const paystackProductId = Number(localProduct.paystackId);
163
+ if (!Number.isFinite(paystackProductId)) return;
164
+ const remoteQuantity = unwrapSdkResult(await paystackClient.product?.fetch(paystackProductId))?.quantity;
139
165
  if (remoteQuantity !== void 0 && localProduct.id !== void 0) await ctx.context.adapter.update({
140
166
  model: "paystackProduct",
141
167
  update: {
@@ -175,7 +201,7 @@ async function syncSubscriptionSeats(ctx, organizationId, options) {
175
201
  if (subscription === null || subscription === void 0) return;
176
202
  const plan = await getPlanByName(options, subscription.plan);
177
203
  if (plan === null || plan === void 0) return;
178
- if (plan.seatAmount === void 0) return;
204
+ if (getPlanSeatAmount(plan) === void 0) return;
179
205
  const quantity = (await adapter.findMany({
180
206
  model: "member",
181
207
  where: [{
@@ -183,12 +209,8 @@ async function syncSubscriptionSeats(ctx, organizationId, options) {
183
209
  value: organizationId
184
210
  }]
185
211
  })).length;
186
- let totalAmount = plan.amount ?? 0;
187
- if (plan.seatAmount !== void 0 && plan.seatAmount !== null && typeof plan.seatAmount === "number") totalAmount += quantity * plan.seatAmount;
188
212
  try {
189
- const client = options.paystackClient;
190
- if (client === void 0 || client === null) return;
191
- unwrapSdkResult(await client.subscription?.update(subscription.paystackSubscriptionCode, { body: { amount: totalAmount } }));
213
+ assertLocallyManagedSubscription(subscription, "automatic seat sync");
192
214
  await adapter.update({
193
215
  model: "subscription",
194
216
  where: [{
@@ -202,7 +224,7 @@ async function syncSubscriptionSeats(ctx, organizationId, options) {
202
224
  });
203
225
  } catch (e) {
204
226
  const log = ctx.context.logger;
205
- if (log !== void 0 && log !== null) log.error("Failed to sync subscription seats with Paystack", e);
227
+ if (log !== void 0 && log !== null) log.error("Failed to sync subscription seats", e);
206
228
  }
207
229
  }
208
230
  //#endregion
@@ -288,8 +310,17 @@ const PAYSTACK_ERROR_CODES = defineErrorCodes({
288
310
  FAILED_TO_VERIFY_TRANSACTION: "Failed to verify transaction",
289
311
  FAILED_TO_DISABLE_SUBSCRIPTION: "Failed to disable subscription",
290
312
  FAILED_TO_ENABLE_SUBSCRIPTION: "Failed to enable subscription",
291
- EMAIL_VERIFICATION_REQUIRED: "Email verification is required before you can subscribe to a plan"
313
+ EMAIL_VERIFICATION_REQUIRED: "Email verification is required before you can subscribe to a plan",
314
+ SUBSCRIPTION_PAYMENT_CHANNEL_NOT_ALLOWED: "This subscription only supports specific payment channels"
292
315
  });
316
+ function getAllowedSubscriptionChannels(options) {
317
+ const channels = options.subscription?.allowedPaymentChannels;
318
+ return Array.isArray(channels) && channels.length > 0 ? channels : void 0;
319
+ }
320
+ function isAllowedSubscriptionChannel(channel, allowedChannels) {
321
+ if (allowedChannels === void 0) return true;
322
+ return channel !== void 0 && channel !== null && allowedChannels.includes(channel);
323
+ }
293
324
  async function hmacSha512Hex(secret, message) {
294
325
  const encoder = new TextEncoder();
295
326
  const keyData = encoder.encode(secret);
@@ -338,7 +369,7 @@ const paystackWebhook = (options, path = "/webhook") => {
338
369
  message: "Missing x-paystack-signature header",
339
370
  status: 401
340
371
  });
341
- if (await hmacSha512Hex(options.webhook?.secret ?? options.secretKey, payload) !== signature) throw new APIError("UNAUTHORIZED", {
372
+ if (await hmacSha512Hex(options.webhook?.secret ?? options.paystackWebhookSecret ?? options.secretKey, payload) !== signature) throw new APIError("UNAUTHORIZED", {
342
373
  message: "Invalid Paystack webhook signature",
343
374
  status: 401
344
375
  });
@@ -504,7 +535,7 @@ const paystackWebhook = (options, path = "/webhook") => {
504
535
  value: subscriptionCode
505
536
  }]
506
537
  });
507
- if (existing) await options.subscription.onSubscriptionCancel?.({
538
+ if (existing !== null && existing !== void 0) await options.subscription.onSubscriptionCancel?.({
508
539
  event,
509
540
  subscription: {
510
541
  ...existing,
@@ -575,7 +606,7 @@ const initializeTransaction = (options, path = "/initialize-transaction") => {
575
606
  if (callbackURL !== void 0 && callbackURL !== null && callbackURL !== "") {
576
607
  const checkTrusted = () => {
577
608
  try {
578
- if (callbackURL.startsWith("/")) return true;
609
+ if (callbackURL?.startsWith("/") === true) return true;
579
610
  const baseUrl = ctx.context?.baseURL ?? ctx.request?.url ?? "";
580
611
  if (baseUrl === "") return false;
581
612
  const baseOrigin = new URL(baseUrl).origin;
@@ -690,39 +721,44 @@ const initializeTransaction = (options, path = "/initialize-transaction") => {
690
721
  });
691
722
  }
692
723
  }
693
- if (plan !== void 0 && (plan.seatAmount !== void 0 || plan.seatPriceId !== void 0)) {
694
- const members = await ctx.context.adapter.findMany({
695
- model: "member",
696
- where: [{
697
- field: "organizationId",
698
- value: referenceId
699
- }]
700
- });
701
- const seatCount = members.length > 0 ? members.length : 1;
702
- const quantityToUse = quantity ?? seatCount;
703
- amount = (plan.amount ?? 0) + quantityToUse * (plan.seatAmount ?? plan.seatPriceId ?? 0);
724
+ if (plan !== void 0) try {
725
+ if (getPlanSeatAmount(plan) !== void 0) {
726
+ const members = await ctx.context.adapter.findMany({
727
+ model: "member",
728
+ where: [{
729
+ field: "organizationId",
730
+ value: referenceId
731
+ }]
732
+ });
733
+ const seatCount = members.length > 0 ? members.length : 1;
734
+ amount = calculatePlanAmount(plan, quantity ?? seatCount);
735
+ }
736
+ } catch (error) {
737
+ throw new APIError("BAD_REQUEST", { message: error instanceof Error ? error.message : "Invalid seat configuration for plan." });
704
738
  }
705
739
  let url;
706
740
  let reference;
707
741
  let accessCode;
708
742
  let trialStart;
709
743
  let trialEnd;
710
- if (plan?.freeTrial?.days !== void 0 && plan.freeTrial.days > 0) {
711
- if ((await ctx.context.adapter.findMany({
712
- model: "subscription",
713
- where: [{
714
- field: "referenceId",
715
- value: referenceId
716
- }]
717
- }))?.some((sub) => sub.trialStart !== void 0 && sub.trialStart !== null || sub.trialEnd !== void 0 && sub.trialEnd !== null || sub.status === "trialing") === false) {
718
- trialStart = /* @__PURE__ */ new Date();
719
- trialEnd = /* @__PURE__ */ new Date();
720
- trialEnd.setDate(trialEnd.getDate() + plan.freeTrial.days);
721
- }
722
- }
744
+ const requestedTrialDays = plan?.freeTrial?.days !== void 0 && plan.freeTrial.days > 0 ? plan.freeTrial.days : 0;
745
+ const trialRequested = requestedTrialDays > 0;
746
+ let trialGranted = false;
747
+ let trialDeniedReason;
748
+ if (trialRequested) if ((await ctx.context.adapter.findMany({
749
+ model: "subscription",
750
+ where: [{
751
+ field: "referenceId",
752
+ value: referenceId
753
+ }]
754
+ }))?.some((sub) => sub.trialStart !== void 0 && sub.trialStart !== null || sub.trialEnd !== void 0 && sub.trialEnd !== null || sub.status === "trialing") === false) {
755
+ trialStart = /* @__PURE__ */ new Date();
756
+ trialEnd = /* @__PURE__ */ new Date();
757
+ trialEnd.setDate(trialEnd.getDate() + requestedTrialDays);
758
+ trialGranted = true;
759
+ } else trialDeniedReason = "already_used";
723
760
  try {
724
761
  let targetEmail = email ?? user.email;
725
- let paystackCustomerCode = user.paystackCustomerCode;
726
762
  if (options.organization?.enabled === true && referenceId !== void 0 && referenceId !== null && referenceId !== user.id) {
727
763
  const org = await ctx.context.adapter.findOne({
728
764
  model: "organization",
@@ -732,8 +768,6 @@ const initializeTransaction = (options, path = "/initialize-transaction") => {
732
768
  }]
733
769
  });
734
770
  if (org !== void 0 && org !== null) {
735
- const paystackOrg = org;
736
- if (paystackOrg.paystackCustomerCode !== void 0 && paystackOrg.paystackCustomerCode !== null && paystackOrg.paystackCustomerCode !== "") paystackCustomerCode = paystackOrg.paystackCustomerCode;
737
771
  const orgWithEmail = org;
738
772
  if (orgWithEmail.email !== void 0 && orgWithEmail.email !== null && orgWithEmail.email !== "") targetEmail = orgWithEmail.email;
739
773
  else {
@@ -760,14 +794,18 @@ const initializeTransaction = (options, path = "/initialize-transaction") => {
760
794
  }
761
795
  }
762
796
  }
797
+ const allowedSubscriptionChannels = plan ? getAllowedSubscriptionChannels(options) : void 0;
763
798
  const metadata = JSON.stringify({
764
799
  referenceId,
765
800
  userId: user.id,
766
801
  plan: plan !== void 0 ? plan.name.toLowerCase() : void 0,
767
802
  product: product !== void 0 ? product.name.toLowerCase() : void 0,
803
+ ...extraMetadata,
768
804
  isTrial: trialStart !== void 0,
769
- trialEnd: trialEnd !== void 0 ? trialEnd.toISOString() : void 0,
770
- ...extraMetadata
805
+ trialRequested,
806
+ trialGranted,
807
+ trialDeniedReason,
808
+ trialEnd: trialEnd !== void 0 ? trialEnd.toISOString() : void 0
771
809
  });
772
810
  const initBody = {
773
811
  email: targetEmail,
@@ -776,13 +814,10 @@ const initializeTransaction = (options, path = "/initialize-transaction") => {
776
814
  currency: finalCurrency,
777
815
  quantity
778
816
  };
779
- if (paystackCustomerCode !== void 0 && paystackCustomerCode !== null && paystackCustomerCode !== "") try {
780
- const ops = getPaystackOps(options.paystackClient);
781
- if (ops !== void 0 && ops !== null && initBody.email !== "") await ops.customer?.update(paystackCustomerCode, { body: { email: initBody.email } });
782
- } catch (_e) {}
817
+ if (allowedSubscriptionChannels !== void 0) initBody.channels = allowedSubscriptionChannels;
783
818
  if (plan !== void 0 && prorateAndCharge === true) {
784
819
  const existingSub = await getOrganizationSubscription(ctx, referenceId);
785
- if (existingSub?.status === "active" && existingSub.paystackAuthorizationCode !== void 0 && existingSub.paystackAuthorizationCode !== null && existingSub.paystackAuthorizationCode !== "" && existingSub.paystackSubscriptionCode !== void 0 && existingSub.paystackSubscriptionCode !== null && existingSub.paystackSubscriptionCode !== "") {
820
+ if (existingSub?.status === "active" && existingSub.paystackSubscriptionCode !== void 0 && existingSub.paystackSubscriptionCode !== null && existingSub.paystackSubscriptionCode !== "") {
786
821
  if (existingSub.periodEnd !== void 0 && existingSub.periodEnd !== null && existingSub.periodStart !== void 0 && existingSub.periodStart !== null) {
787
822
  const now = /* @__PURE__ */ new Date();
788
823
  const periodEndLocal = new Date(existingSub.periodEnd);
@@ -800,51 +835,109 @@ const initializeTransaction = (options, path = "/initialize-transaction") => {
800
835
  }) ?? void 0;
801
836
  if (oldPlan !== void 0 && oldPlan !== null) {
802
837
  const oldSeatCount = existingSub.seats;
803
- oldAmount = (oldPlan.amount ?? 0) + oldSeatCount * (oldPlan.seatAmount ?? oldPlan.seatPriceId ?? 0);
838
+ oldAmount = calculatePlanAmount(oldPlan, oldSeatCount);
804
839
  }
805
840
  }
806
841
  let membersCount = 1;
807
- if (plan.seatAmount !== void 0 || plan.seatPriceId !== void 0) {
808
- const members = await ctx.context.adapter.findMany({
809
- model: "member",
810
- where: [{
811
- field: "organizationId",
812
- value: referenceId
813
- }]
814
- });
815
- membersCount = members.length > 0 ? members.length : 1;
842
+ let newSeatCount = quantity ?? existingSub.seats ?? membersCount;
843
+ let newAmount;
844
+ try {
845
+ assertLocallyManagedSubscription(existingSub, "plan or seat changes");
846
+ if (getPlanSeatAmount(plan) !== void 0) {
847
+ const members = await ctx.context.adapter.findMany({
848
+ model: "member",
849
+ where: [{
850
+ field: "organizationId",
851
+ value: referenceId
852
+ }]
853
+ });
854
+ membersCount = members.length > 0 ? members.length : 1;
855
+ }
856
+ newSeatCount = quantity ?? existingSub.seats ?? membersCount;
857
+ newAmount = calculatePlanAmount(plan, newSeatCount);
858
+ } catch (error) {
859
+ throw new APIError("BAD_REQUEST", { message: error instanceof Error ? error.message : "Invalid seat configuration for plan." });
816
860
  }
817
- const newSeatCount = quantity ?? existingSub.seats ?? membersCount;
818
- const newAmount = (plan.amount ?? 0) + newSeatCount * (plan.seatAmount ?? plan.seatPriceId ?? 0);
819
861
  const costDifference = newAmount - oldAmount;
862
+ const prorationMetadata = {
863
+ type: "proration",
864
+ subscriptionId: existingSub.id,
865
+ referenceId,
866
+ newPlan: plan.name.toLowerCase(),
867
+ oldPlan: existingSub.plan,
868
+ newSeatCount,
869
+ remainingDays
870
+ };
871
+ let completedProrationReference;
820
872
  if (costDifference > 0 && remainingDays > 0) {
821
873
  const proratedAmount = Math.round(costDifference / totalDays * remainingDays);
822
- if (proratedAmount >= 5e3) {
823
- const ops = getPaystackOps(options.paystackClient);
824
- if (ops === void 0 || ops === null) {
825
- ctx.context.logger.error("Paystack client not configured for proration charge");
826
- return;
827
- }
828
- if (unwrapSdkResult(await ops.transaction?.chargeAuthorization({ body: {
874
+ if (proratedAmount < 5e3) throw new APIError("BAD_REQUEST", {
875
+ message: "Prorated upgrade amount is below Paystack's minimum charge. Schedule the change for period end instead.",
876
+ status: 400
877
+ });
878
+ const ops = getPaystackOps(options.paystackClient);
879
+ if (ops === void 0 || ops === null) {
880
+ ctx.context.logger.error("Paystack client not configured for proration charge");
881
+ return;
882
+ }
883
+ if (existingSub.paystackAuthorizationCode !== void 0 && existingSub.paystackAuthorizationCode !== null && existingSub.paystackAuthorizationCode !== "") {
884
+ const sdkRes = unwrapSdkResult(await ops.transaction?.chargeAuthorization({ body: {
829
885
  email: targetEmail,
830
886
  amount: proratedAmount,
831
887
  authorization_code: existingSub.paystackAuthorizationCode,
832
888
  reference: `upg_${existingSub.id}_${Date.now()}_${Math.random().toString(36).substring(7)}`,
833
- metadata: {
834
- type: "proration",
889
+ metadata: JSON.stringify(prorationMetadata)
890
+ } }));
891
+ if (sdkRes?.status !== "success") throw new APIError("BAD_REQUEST", { message: "Failed to process prorated charge via saved authorization." });
892
+ await ctx.context.adapter.create({
893
+ model: "paystackTransaction",
894
+ data: {
895
+ reference: sdkRes.reference ?? "",
896
+ paystackId: sdkRes.id !== void 0 && sdkRes.id !== null ? String(sdkRes.id) : void 0,
835
897
  referenceId,
836
- newPlan: plan.name,
837
- oldPlan: existingSub.plan,
838
- remainingDays
898
+ userId: user.id,
899
+ amount: sdkRes.amount ?? proratedAmount,
900
+ currency: sdkRes.currency ?? finalCurrency,
901
+ status: "success",
902
+ plan: plan.name.toLowerCase(),
903
+ metadata: JSON.stringify(prorationMetadata),
904
+ createdAt: /* @__PURE__ */ new Date(),
905
+ updatedAt: /* @__PURE__ */ new Date()
839
906
  }
840
- } }))?.status !== "success") throw new APIError("BAD_REQUEST", { message: "Failed to process prorated charge via saved authorization." });
907
+ });
908
+ completedProrationReference = sdkRes.reference ?? void 0;
909
+ } else {
910
+ const initRes = unwrapSdkResult(await ops.transaction?.initialize({ body: {
911
+ email: targetEmail,
912
+ amount: proratedAmount,
913
+ currency: finalCurrency,
914
+ callback_url: callbackURL ?? void 0,
915
+ metadata: JSON.stringify(prorationMetadata),
916
+ ...allowedSubscriptionChannels !== void 0 ? { channels: allowedSubscriptionChannels } : {}
917
+ } }));
918
+ await ctx.context.adapter.create({
919
+ model: "paystackTransaction",
920
+ data: {
921
+ reference: initRes?.reference ?? "",
922
+ referenceId,
923
+ userId: user.id,
924
+ amount: proratedAmount,
925
+ currency: finalCurrency,
926
+ status: "pending",
927
+ plan: plan.name.toLowerCase(),
928
+ metadata: JSON.stringify(prorationMetadata),
929
+ createdAt: /* @__PURE__ */ new Date(),
930
+ updatedAt: /* @__PURE__ */ new Date()
931
+ }
932
+ });
933
+ return ctx.json({
934
+ url: initRes?.authorization_url,
935
+ reference: initRes?.reference,
936
+ accessCode: initRes?.access_code,
937
+ redirect: true
938
+ });
841
939
  }
842
940
  }
843
- const ops = getPaystackOps(options.paystackClient);
844
- if (ops !== void 0 && ops !== null) await ops.subscription?.update(existingSub.paystackSubscriptionCode, { body: {
845
- amount: newAmount,
846
- plan: plan.planCode
847
- } });
848
941
  await ctx.context.adapter.update({
849
942
  model: "subscription",
850
943
  where: [{
@@ -854,6 +947,7 @@ const initializeTransaction = (options, path = "/initialize-transaction") => {
854
947
  update: {
855
948
  plan: plan.name,
856
949
  seats: newSeatCount,
950
+ ...completedProrationReference !== void 0 ? { paystackTransactionReference: completedProrationReference } : {},
857
951
  updatedAt: /* @__PURE__ */ new Date()
858
952
  }
859
953
  });
@@ -987,6 +1081,7 @@ const verifyTransaction = (options, path = "/verify-transaction") => {
987
1081
  const paystackIdRaw = data.id;
988
1082
  const paystackId = paystackIdRaw !== void 0 && paystackIdRaw !== null ? String(paystackIdRaw) : void 0;
989
1083
  const authorizationCode = data.authorization?.authorization_code;
1084
+ const allowedSubscriptionChannels = getAllowedSubscriptionChannels(options);
990
1085
  if (status === "success") {
991
1086
  const session = await getSessionFromCtx(ctx);
992
1087
  const txRecord = await ctx.context.adapter.findOne({
@@ -997,6 +1092,26 @@ const verifyTransaction = (options, path = "/verify-transaction") => {
997
1092
  }]
998
1093
  });
999
1094
  const referenceId = txRecord !== void 0 && txRecord !== null && txRecord.referenceId !== void 0 && txRecord.referenceId !== null && txRecord.referenceId !== "" ? txRecord.referenceId : session !== void 0 && session !== null ? session.user.id : void 0;
1095
+ if ((txRecord?.plan !== void 0 && txRecord.plan !== null && txRecord.plan !== "" || Boolean(data.plan)) && isAllowedSubscriptionChannel(data.channel ?? void 0, allowedSubscriptionChannels) === false) {
1096
+ await ctx.context.adapter.update({
1097
+ model: "paystackTransaction",
1098
+ update: {
1099
+ status: "failed",
1100
+ paystackId,
1101
+ amount: data.amount,
1102
+ currency: data.currency,
1103
+ updatedAt: /* @__PURE__ */ new Date()
1104
+ },
1105
+ where: [{
1106
+ field: "reference",
1107
+ value: reference
1108
+ }]
1109
+ });
1110
+ throw new APIError("BAD_REQUEST", {
1111
+ code: "SUBSCRIPTION_PAYMENT_CHANNEL_NOT_ALLOWED",
1112
+ message: `This subscription requires one of: ${allowedSubscriptionChannels?.join(", ") ?? "allowed channels"}.`
1113
+ });
1114
+ }
1000
1115
  if (session !== void 0 && session !== null && referenceId !== void 0 && referenceId !== null && referenceId !== "" && referenceId !== session.user.id) {
1001
1116
  const authRef = subscriptionOptions?.authorizeReference;
1002
1117
  let authorized = false;
@@ -1077,11 +1192,36 @@ const verifyTransaction = (options, path = "/verify-transaction") => {
1077
1192
  let isTrial = false;
1078
1193
  let trialEnd;
1079
1194
  let targetPlan;
1195
+ let metadataObj = {};
1080
1196
  if (data.metadata !== void 0 && data.metadata !== null && data.metadata !== "") {
1081
- const meta = typeof data.metadata === "string" ? JSON.parse(data.metadata) : data.metadata;
1082
- isTrial = meta.isTrial === true || meta.isTrial === "true";
1083
- trialEnd = meta.trialEnd;
1084
- targetPlan = meta.plan;
1197
+ metadataObj = typeof data.metadata === "string" ? JSON.parse(data.metadata) : data.metadata;
1198
+ isTrial = metadataObj.isTrial === true || metadataObj.isTrial === "true";
1199
+ trialEnd = metadataObj.trialEnd;
1200
+ targetPlan = metadataObj.plan;
1201
+ }
1202
+ if (metadataObj.type === "proration") {
1203
+ const subscriptionId = metadataObj.subscriptionId;
1204
+ const newPlan = metadataObj.newPlan;
1205
+ const newSeatCount = metadataObj.newSeatCount;
1206
+ if (subscriptionId !== void 0 && subscriptionId !== "" && newPlan !== void 0 && newPlan !== "") await ctx.context.adapter.update({
1207
+ model: "subscription",
1208
+ update: {
1209
+ plan: newPlan,
1210
+ ...typeof newSeatCount === "number" ? { seats: newSeatCount } : {},
1211
+ paystackTransactionReference: reference,
1212
+ ...authorizationCode !== void 0 && authorizationCode !== null ? { paystackAuthorizationCode: authorizationCode } : {},
1213
+ updatedAt: /* @__PURE__ */ new Date()
1214
+ },
1215
+ where: [{
1216
+ field: "id",
1217
+ value: subscriptionId
1218
+ }]
1219
+ });
1220
+ return ctx.json({
1221
+ status,
1222
+ reference,
1223
+ data
1224
+ });
1085
1225
  }
1086
1226
  let paystackSubscriptionCode;
1087
1227
  if (isTrial && targetPlan !== void 0 && trialEnd !== void 0) {
@@ -1238,7 +1378,7 @@ const disablePaystackSubscription = (options, path = "/disable-subscription") =>
1238
1378
  const { subscriptionCode, atPeriodEnd } = ctx.body;
1239
1379
  const paystack = getPaystackOps(options.paystackClient);
1240
1380
  try {
1241
- if (subscriptionCode.startsWith("LOC_") || subscriptionCode.startsWith("sub_local_")) {
1381
+ if (isLocalSubscriptionCode(subscriptionCode)) {
1242
1382
  const sub = await ctx.context.adapter.findOne({
1243
1383
  model: "subscription",
1244
1384
  where: [{
@@ -1246,7 +1386,7 @@ const disablePaystackSubscription = (options, path = "/disable-subscription") =>
1246
1386
  value: subscriptionCode
1247
1387
  }]
1248
1388
  });
1249
- if (sub) {
1389
+ if (sub !== null && sub !== void 0) {
1250
1390
  await ctx.context.adapter.update({
1251
1391
  model: "subscription",
1252
1392
  update: {
@@ -1370,7 +1510,7 @@ const getSubscriptionManageLink = (options, path = "/subscription-manage-link")
1370
1510
  ] : [sessionMiddleware, originCheck];
1371
1511
  const handler = async (ctx) => {
1372
1512
  const { subscriptionCode } = ctx.query;
1373
- if (subscriptionCode.startsWith("LOC_") || subscriptionCode.startsWith("sub_local_")) return ctx.json({
1513
+ if (isLocalSubscriptionCode(subscriptionCode)) return ctx.json({
1374
1514
  link: null,
1375
1515
  message: "Local subscriptions cannot be managed on Paystack"
1376
1516
  });
@@ -1813,6 +1953,7 @@ async function chargeSubscriptionRenewal(ctx, options, input) {
1813
1953
  const amount = bodyAmount ?? plan.amount;
1814
1954
  if (amount === void 0 || amount === null) throw new APIError("BAD_REQUEST", { message: "Plan amount is not defined" });
1815
1955
  let email;
1956
+ let billingUserId = subscription.userId;
1816
1957
  const referenceId = subscription.referenceId;
1817
1958
  if (referenceId !== void 0 && referenceId !== null && referenceId !== "") {
1818
1959
  const user = await ctx.context.adapter.findOne({
@@ -1822,8 +1963,10 @@ async function chargeSubscriptionRenewal(ctx, options, input) {
1822
1963
  value: referenceId
1823
1964
  }]
1824
1965
  });
1825
- if (user !== void 0 && user !== null) email = user.email;
1826
- else if (options.organization?.enabled === true) {
1966
+ if (user !== void 0 && user !== null) {
1967
+ email = user.email;
1968
+ billingUserId = user.id;
1969
+ } else if (options.organization?.enabled === true) {
1827
1970
  const ownerMember = await ctx.context.adapter.findOne({
1828
1971
  model: "member",
1829
1972
  where: [{
@@ -1834,13 +1977,17 @@ async function chargeSubscriptionRenewal(ctx, options, input) {
1834
1977
  value: "owner"
1835
1978
  }]
1836
1979
  });
1837
- if (ownerMember !== void 0 && ownerMember !== null) email = (await ctx.context.adapter.findOne({
1838
- model: "user",
1839
- where: [{
1840
- field: "id",
1841
- value: ownerMember.userId
1842
- }]
1843
- }))?.email;
1980
+ if (ownerMember !== void 0 && ownerMember !== null) {
1981
+ const ownerUser = await ctx.context.adapter.findOne({
1982
+ model: "user",
1983
+ where: [{
1984
+ field: "id",
1985
+ value: ownerMember.userId
1986
+ }]
1987
+ });
1988
+ email = ownerUser?.email;
1989
+ billingUserId = ownerUser?.id ?? ownerMember.userId;
1990
+ }
1844
1991
  }
1845
1992
  }
1846
1993
  if (email === void 0 || email === null || email === "") throw new APIError("NOT_FOUND", { message: "User email not found" });
@@ -1854,14 +2001,34 @@ async function chargeSubscriptionRenewal(ctx, options, input) {
1854
2001
  amount,
1855
2002
  authorization_code: subscription.paystackAuthorizationCode,
1856
2003
  reference: `rec_${subscription.id}_${Date.now()}`,
1857
- metadata: {
2004
+ metadata: JSON.stringify({
1858
2005
  subscriptionId,
1859
2006
  referenceId
1860
- }
2007
+ })
1861
2008
  } }));
1862
2009
  if (chargeData?.status === "success" && chargeData.reference !== void 0) {
1863
2010
  const now = /* @__PURE__ */ new Date();
1864
2011
  const nextPeriodEnd = getNextPeriodEnd(now, plan.interval ?? "monthly");
2012
+ await ctx.context.adapter.create({
2013
+ model: "paystackTransaction",
2014
+ data: {
2015
+ reference: chargeData.reference,
2016
+ paystackId: chargeData.id !== void 0 && chargeData.id !== null ? String(chargeData.id) : void 0,
2017
+ referenceId,
2018
+ userId: billingUserId,
2019
+ amount: chargeData.amount,
2020
+ currency: chargeData.currency,
2021
+ status: "success",
2022
+ plan: plan.name.toLowerCase(),
2023
+ metadata: JSON.stringify({
2024
+ type: "renewal",
2025
+ subscriptionId,
2026
+ referenceId
2027
+ }),
2028
+ createdAt: now,
2029
+ updatedAt: now
2030
+ }
2031
+ });
1865
2032
  await ctx.context.adapter.update({
1866
2033
  model: "subscription",
1867
2034
  update: {
@@ -1889,7 +2056,13 @@ async function chargeSubscriptionRenewal(ctx, options, input) {
1889
2056
  //#region src/index.ts
1890
2057
  const INTERNAL_ERROR_CODES = defineErrorCodes(Object.fromEntries(Object.entries(PAYSTACK_ERROR_CODES).map(([key, value]) => [key, typeof value === "string" ? value : value.message])));
1891
2058
  const paystack = (options) => {
1892
- const routeOptions = options;
2059
+ const routeOptions = {
2060
+ ...options,
2061
+ webhook: {
2062
+ ...options.webhook,
2063
+ secret: options.webhook?.secret ?? options.paystackWebhookSecret
2064
+ }
2065
+ };
1893
2066
  return {
1894
2067
  id: "paystack",
1895
2068
  endpoints: {
@@ -1922,7 +2095,7 @@ const paystack = (options) => {
1922
2095
  const sdkRes = unwrapSdkResult(await paystackOps.customer?.create({ body: {
1923
2096
  email: user.email,
1924
2097
  first_name: user.name ?? void 0,
1925
- metadata: { userId: user.id }
2098
+ metadata: JSON.stringify({ userId: user.id })
1926
2099
  } }) ?? await Promise.reject(/* @__PURE__ */ new Error("Paystack client missing customer ops")));
1927
2100
  const customerCode = sdkRes?.customer_code;
1928
2101
  if (customerCode !== void 0 && customerCode !== null && customerCode !== "") {
@@ -1973,14 +2146,21 @@ const paystack = (options) => {
1973
2146
  const params = defu({
1974
2147
  email: targetEmail,
1975
2148
  first_name: org.name,
1976
- metadata: { organizationId: org.id }
2149
+ metadata: JSON.stringify({ organizationId: org.id })
1977
2150
  }, extraCreateParams);
1978
2151
  const paystackOps = getPaystackOps(options.paystackClient);
1979
2152
  if (!paystackOps) return;
1980
2153
  const sdkRes = unwrapSdkResult(await paystackOps.customer?.create({ body: params }) ?? await Promise.reject(/* @__PURE__ */ new Error("Paystack client missing customer ops")));
1981
2154
  const customerCode = sdkRes?.customer_code;
1982
2155
  if (customerCode !== void 0 && customerCode !== null && customerCode !== "" && sdkRes !== void 0 && sdkRes !== null) {
1983
- await ctx.internalAdapter.updateOrganization(org.id, { paystackCustomerCode: customerCode });
2156
+ await ctx.adapter.update({
2157
+ model: "organization",
2158
+ where: [{
2159
+ field: "id",
2160
+ value: org.id
2161
+ }],
2162
+ update: { paystackCustomerCode: customerCode }
2163
+ });
1984
2164
  if (typeof options.organization?.onCustomerCreate === "function") await options.organization.onCustomerCreate({
1985
2165
  paystackCustomer: sdkRes,
1986
2166
  organization: {