@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.
- package/README.md +76 -12
- package/dist/client.d.mts +130 -155
- package/dist/client.d.mts.map +1 -1
- package/dist/client.mjs +90 -74
- package/dist/client.mjs.map +1 -1
- package/dist/index.d.mts +423 -2
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +278 -98
- package/dist/index.mjs.map +1 -1
- package/dist/types-B5ZnlFrq.d.mts +258 -0
- package/dist/types-B5ZnlFrq.d.mts.map +1 -0
- package/package.json +4 -4
- package/dist/index-Dwbeddkr.d.mts +0 -711
- package/dist/index-Dwbeddkr.d.mts.map +0 -1
|
@@ -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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
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
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
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
|
-
|
|
770
|
-
|
|
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 (
|
|
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.
|
|
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
|
|
838
|
+
oldAmount = calculatePlanAmount(oldPlan, oldSeatCount);
|
|
804
839
|
}
|
|
805
840
|
}
|
|
806
841
|
let membersCount = 1;
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
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
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
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
|
-
|
|
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
|
-
|
|
837
|
-
|
|
838
|
-
|
|
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
|
-
}
|
|
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
|
-
|
|
1082
|
-
isTrial =
|
|
1083
|
-
trialEnd =
|
|
1084
|
-
targetPlan =
|
|
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 (
|
|
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 (
|
|
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)
|
|
1826
|
-
|
|
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)
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
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 =
|
|
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.
|
|
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: {
|