@cimplify/sdk 0.103.0 → 0.104.1
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/advanced.d.mts +3 -7
- package/dist/advanced.d.ts +3 -7
- package/dist/advanced.js +23 -23
- package/dist/advanced.mjs +4 -4
- package/dist/{client-DHBwvh7U.d.ts → catalogue-BlQ85Uma.d.mts} +492 -748
- package/dist/{client-BfpNjJ_a.d.mts → catalogue-C8TqOj9K.d.ts} +492 -748
- package/dist/{payment-H5LoIvXU.d.mts → checkout-BqK9XUz5.d.mts} +4338 -1495
- package/dist/{payment-H5LoIvXU.d.ts → checkout-BqK9XUz5.d.ts} +4338 -1495
- package/dist/{chunk-GOHSXBKW.mjs → chunk-33VCYWVL.mjs} +25 -1
- package/dist/{chunk-C2JSNJUC.mjs → chunk-6G3ANKQA.mjs} +1080 -369
- package/dist/{chunk-QOWPGS7Z.js → chunk-BWEIMKLF.js} +572 -17
- package/dist/{chunk-JSWJ4XDE.js → chunk-DQEXY542.js} +1630 -824
- package/dist/{chunk-CNN7Z2IP.js → chunk-EV2EVOYS.js} +27 -0
- package/dist/{chunk-VIL6IQCG.js → chunk-HYFA67A7.js} +1084 -373
- package/dist/{chunk-H7ACMHM3.mjs → chunk-L5SNEU2O.mjs} +553 -16
- package/dist/{chunk-JG5CQNCB.js → chunk-RBNBSQI7.mjs} +221 -19
- package/dist/{chunk-VNPEYLB2.mjs → chunk-SFUJMS5E.js} +265 -2
- package/dist/{chunk-M4URVKHE.mjs → chunk-U54CWUUT.mjs} +11 -2
- package/dist/{chunk-GERXZQSX.mjs → chunk-UFOWPN3D.mjs} +967 -582
- package/dist/{chunk-J6PNHDHL.mjs → chunk-V4457OKB.mjs} +1580 -785
- package/dist/{chunk-R6OLQ33I.js → chunk-WXREIBFW.js} +1041 -654
- package/dist/{chunk-NNG6IFFX.js → chunk-XAUSDMMZ.js} +13 -3
- package/dist/{client-DpqRobY9.d.mts → client-DhXeiUrf.d.ts} +2 -2
- package/dist/{client-Dqg2mc-7.d.ts → client-mXiUrV4X.d.mts} +2 -2
- package/dist/{index-C8uDqLwJ.d.ts → index-B0AdZvrM.d.mts} +9 -4
- package/dist/{index-e2y6AK70.d.mts → index-CK8Nk5uQ.d.ts} +9 -4
- package/dist/index-DPWI5XcU.d.ts +8 -0
- package/dist/index-DVfUh-ci.d.mts +8 -0
- package/dist/index.d.mts +34 -15
- package/dist/index.d.ts +34 -15
- package/dist/index.js +306 -133
- package/dist/index.mjs +7 -6
- package/dist/mock/cli.mjs +1494 -395
- package/dist/mock/library.js +1220 -361
- package/dist/mock/library.mjs +1220 -361
- package/dist/mock/msw.js +1220 -361
- package/dist/mock/msw.mjs +1220 -361
- package/dist/{price-C2RqscMY.d.ts → price-6hQIIac9.d.ts} +1 -1
- package/dist/{price-BvePgDXe.d.mts → price-BUDv1rI7.d.mts} +1 -1
- package/dist/react.d.mts +10 -5
- package/dist/react.d.ts +10 -5
- package/dist/react.js +279 -225
- package/dist/react.mjs +140 -86
- package/dist/{server-DoXIpSd7.d.ts → server-DJ0mSs9i.d.mts} +33 -57
- package/dist/{server-C7FyLdrz.d.mts → server-DSTX76Ki.d.ts} +33 -57
- package/dist/server.d.mts +3 -4
- package/dist/server.d.ts +3 -4
- package/dist/server.js +12 -11
- package/dist/server.mjs +6 -5
- package/dist/styles.css +2 -2
- package/dist/testing/msw.d.mts +2 -2
- package/dist/testing/msw.d.ts +2 -2
- package/dist/testing/msw.js +4 -4
- package/dist/testing/msw.mjs +3 -3
- package/dist/testing/suite.d.mts +5 -6
- package/dist/testing/suite.d.ts +5 -6
- package/dist/testing/suite.js +29 -28
- package/dist/testing/suite.mjs +10 -9
- package/dist/testing.d.mts +2217 -14
- package/dist/testing.d.ts +2217 -14
- package/dist/testing.js +173 -83
- package/dist/testing.mjs +28 -10
- package/dist/utils.d.mts +3 -4
- package/dist/utils.d.ts +3 -4
- package/dist/utils.js +35 -31
- package/dist/utils.mjs +2 -2
- package/package.json +9 -9
- package/registry/chat-widget.json +1 -1
- package/registry/order-history.json +1 -1
- package/registry/order-summary.json +1 -1
- package/dist/link-cuNVYc2s.d.mts +0 -297
- package/dist/link-cuNVYc2s.d.ts +0 -297
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
3
|
+
var chunkEV2EVOYS_js = require('./chunk-EV2EVOYS.js');
|
|
4
|
+
var chunkXAUSDMMZ_js = require('./chunk-XAUSDMMZ.js');
|
|
5
|
+
var chunkSFUJMS5E_js = require('./chunk-SFUJMS5E.js');
|
|
6
6
|
|
|
7
7
|
// src/types/result.ts
|
|
8
8
|
function ok(value) {
|
|
@@ -117,11 +117,11 @@ function clearIntentIdempotencyKey(scope, storage = sessionStorageOrNull()) {
|
|
|
117
117
|
|
|
118
118
|
// src/internal/safe.ts
|
|
119
119
|
function toCimplifyError(error) {
|
|
120
|
-
if (error instanceof
|
|
120
|
+
if (error instanceof chunkSFUJMS5E_js.CimplifyError) return chunkSFUJMS5E_js.enrichError(error);
|
|
121
121
|
if (error instanceof Error) {
|
|
122
|
-
return
|
|
122
|
+
return chunkSFUJMS5E_js.enrichError(new chunkSFUJMS5E_js.CimplifyError(chunkSFUJMS5E_js.ErrorCode.UNKNOWN_ERROR, error.message, false));
|
|
123
123
|
}
|
|
124
|
-
return
|
|
124
|
+
return chunkSFUJMS5E_js.enrichError(new chunkSFUJMS5E_js.CimplifyError(chunkSFUJMS5E_js.ErrorCode.UNKNOWN_ERROR, String(error), false));
|
|
125
125
|
}
|
|
126
126
|
async function safe(promise) {
|
|
127
127
|
try {
|
|
@@ -696,7 +696,7 @@ var CartOperations = class {
|
|
|
696
696
|
if (typeof updates.quantity !== "number") {
|
|
697
697
|
return {
|
|
698
698
|
ok: false,
|
|
699
|
-
error: new
|
|
699
|
+
error: new chunkSFUJMS5E_js.CimplifyError(
|
|
700
700
|
"VALIDATION_ERROR",
|
|
701
701
|
"updateItem requires a quantity; richer mid-cart edits are not supported"
|
|
702
702
|
)
|
|
@@ -787,703 +787,796 @@ var CartOperations = class {
|
|
|
787
787
|
}
|
|
788
788
|
};
|
|
789
789
|
|
|
790
|
-
// src/
|
|
791
|
-
var
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
var
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
790
|
+
// src/payment-authorization/types.ts
|
|
791
|
+
var PAYMENT_AUTHORIZATION_OUTCOME_STATUS = {
|
|
792
|
+
SUBMITTED: "submitted",
|
|
793
|
+
CANCELLED: "cancelled",
|
|
794
|
+
FAILED: "failed"
|
|
795
|
+
};
|
|
796
|
+
var PAYMENT_AUTHORIZATION_PROVIDER = {
|
|
797
|
+
PAYSTACK: "paystack",
|
|
798
|
+
STRIPE: "stripe"
|
|
799
|
+
};
|
|
800
|
+
|
|
801
|
+
// src/payment-authorization/providers/paystack.ts
|
|
802
|
+
var PAYSTACK_POPUP_ERROR = {
|
|
803
|
+
PROVIDER_UNAVAILABLE: chunkSFUJMS5E_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
804
|
+
SUBMISSION_UNKNOWN: "SUBMISSION_UNKNOWN",
|
|
805
|
+
CANCELLED: "CANCELLED",
|
|
806
|
+
PAYMENT_CANCELLED: chunkSFUJMS5E_js.ErrorCode.PAYMENT_CANCELLED,
|
|
807
|
+
PAYMENT_FAILED: chunkSFUJMS5E_js.ErrorCode.PAYMENT_FAILED,
|
|
808
|
+
POPUP_BLOCKED: chunkSFUJMS5E_js.ErrorCode.POPUP_BLOCKED
|
|
809
|
+
};
|
|
810
|
+
async function openPaystackPopup(options, signal) {
|
|
811
|
+
if (typeof window === "undefined") {
|
|
812
|
+
return { success: false, error: PAYSTACK_POPUP_ERROR.PROVIDER_UNAVAILABLE };
|
|
812
813
|
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
814
|
+
let PaystackPop;
|
|
815
|
+
try {
|
|
816
|
+
const imported = await import('@paystack/inline-js');
|
|
817
|
+
PaystackPop = imported.default;
|
|
818
|
+
} catch {
|
|
819
|
+
return { success: false, error: PAYSTACK_POPUP_ERROR.PROVIDER_UNAVAILABLE };
|
|
818
820
|
}
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
const
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
state,
|
|
832
|
-
zip_code: zipCode
|
|
821
|
+
return new Promise((resolve) => {
|
|
822
|
+
let settled = false;
|
|
823
|
+
let providerStarted = false;
|
|
824
|
+
const resolveOnce = (result) => {
|
|
825
|
+
if (settled) {
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
settled = true;
|
|
829
|
+
if (signal) {
|
|
830
|
+
signal.removeEventListener("abort", onAbort);
|
|
831
|
+
}
|
|
832
|
+
resolve(result);
|
|
833
833
|
};
|
|
834
|
-
}
|
|
835
|
-
const value = submission.value.trim();
|
|
836
|
-
if (!value) {
|
|
837
|
-
throw new Error("Authorization value is required.");
|
|
838
|
-
}
|
|
839
|
-
return { type: submission.type, value };
|
|
840
|
-
}
|
|
841
|
-
function formatMoney(value) {
|
|
842
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
843
|
-
return value.toFixed(2);
|
|
844
|
-
}
|
|
845
|
-
if (typeof value === "string" && value.trim().length > 0) {
|
|
846
|
-
return value;
|
|
847
|
-
}
|
|
848
|
-
return "0.00";
|
|
849
|
-
}
|
|
850
|
-
function createAbortError() {
|
|
851
|
-
const error = new Error("CANCELLED");
|
|
852
|
-
error.name = "AbortError";
|
|
853
|
-
return error;
|
|
854
|
-
}
|
|
855
|
-
function isAbortError(error) {
|
|
856
|
-
if (error instanceof DOMException && error.name === "AbortError") {
|
|
857
|
-
return true;
|
|
858
|
-
}
|
|
859
|
-
return error instanceof Error && (error.name === "AbortError" || error.message === "CANCELLED");
|
|
860
|
-
}
|
|
861
|
-
function waitForAbortable(promise, signal) {
|
|
862
|
-
if (!signal) return promise;
|
|
863
|
-
if (signal.aborted) return Promise.reject(createAbortError());
|
|
864
|
-
return new Promise((resolve, reject) => {
|
|
865
834
|
const onAbort = () => {
|
|
866
|
-
|
|
867
|
-
|
|
835
|
+
resolveOnce({
|
|
836
|
+
success: false,
|
|
837
|
+
// Once Paystack owns the transaction, cancellation is ambiguous. The
|
|
838
|
+
// adapter converts this into submitted so Cimplify polling decides.
|
|
839
|
+
error: providerStarted ? PAYSTACK_POPUP_ERROR.SUBMISSION_UNKNOWN : PAYSTACK_POPUP_ERROR.CANCELLED
|
|
840
|
+
});
|
|
868
841
|
};
|
|
869
|
-
signal
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
signal.removeEventListener("abort", onAbort);
|
|
877
|
-
reject(error);
|
|
878
|
-
}
|
|
879
|
-
);
|
|
880
|
-
});
|
|
881
|
-
}
|
|
882
|
-
var CheckoutResolver = class {
|
|
883
|
-
constructor(options) {
|
|
884
|
-
this.client = options.client;
|
|
885
|
-
this.checkoutData = options.checkoutData;
|
|
886
|
-
this.pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
887
|
-
this.maxPollAttempts = options.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS;
|
|
888
|
-
this.onStatusChange = options.onStatusChange;
|
|
889
|
-
this.onAuthorizationUiChange = options.onAuthorizationUiChange;
|
|
890
|
-
this.onAuthorizationRequired = options.onAuthorizationRequired;
|
|
891
|
-
this.signal = options.signal;
|
|
892
|
-
this.returnUrl = options.returnUrl;
|
|
893
|
-
this.enrollInLink = options.enrollInLink !== false;
|
|
894
|
-
this.businessId = options.businessId;
|
|
895
|
-
this.addressData = options.addressData;
|
|
896
|
-
this.paymentData = options.paymentData;
|
|
897
|
-
this.orderType = options.orderType;
|
|
898
|
-
this.cartTotal = options.cartTotal;
|
|
899
|
-
this.cartCurrency = options.cartCurrency;
|
|
900
|
-
this.allowPopups = options.allowPopups ?? typeof window !== "undefined";
|
|
901
|
-
}
|
|
902
|
-
async resolve(checkoutResult) {
|
|
842
|
+
if (signal?.aborted) {
|
|
843
|
+
resolveOnce({ success: false, error: PAYSTACK_POPUP_ERROR.CANCELLED });
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
if (signal) {
|
|
847
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
848
|
+
}
|
|
903
849
|
try {
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
false
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
|
|
850
|
+
const popup = new PaystackPop();
|
|
851
|
+
popup.newTransaction({
|
|
852
|
+
key: options.key,
|
|
853
|
+
email: options.email,
|
|
854
|
+
amount: options.amount,
|
|
855
|
+
currency: options.currency,
|
|
856
|
+
reference: options.reference,
|
|
857
|
+
accessCode: options.accessCode,
|
|
858
|
+
onSuccess: (transaction) => {
|
|
859
|
+
resolveOnce({
|
|
860
|
+
success: true,
|
|
861
|
+
reference: transaction.reference ?? options.reference
|
|
862
|
+
});
|
|
863
|
+
},
|
|
864
|
+
onCancel: () => {
|
|
865
|
+
resolveOnce({ success: false, error: PAYSTACK_POPUP_ERROR.PAYMENT_CANCELLED });
|
|
866
|
+
},
|
|
867
|
+
onError: (error) => {
|
|
868
|
+
resolveOnce({
|
|
869
|
+
success: false,
|
|
870
|
+
error: error?.message || PAYSTACK_POPUP_ERROR.PAYMENT_FAILED
|
|
871
|
+
});
|
|
872
|
+
}
|
|
873
|
+
});
|
|
874
|
+
providerStarted = true;
|
|
875
|
+
} catch {
|
|
876
|
+
resolveOnce({ success: false, error: PAYSTACK_POPUP_ERROR.POPUP_BLOCKED });
|
|
930
877
|
}
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
var PaystackAuthorizationAdapter = class {
|
|
881
|
+
constructor(openPopup = openPaystackPopup) {
|
|
882
|
+
this.openPopup = openPopup;
|
|
883
|
+
this.provider = PAYMENT_AUTHORIZATION_PROVIDER.PAYSTACK;
|
|
931
884
|
}
|
|
932
|
-
|
|
933
|
-
|
|
885
|
+
async authorize(context) {
|
|
886
|
+
const result = await this.openPopup(
|
|
887
|
+
{
|
|
888
|
+
key: context.action.public_key,
|
|
889
|
+
email: context.email,
|
|
890
|
+
accessCode: context.action.client_secret,
|
|
891
|
+
reference: context.reference || context.action.client_secret,
|
|
892
|
+
currency: context.currency
|
|
893
|
+
},
|
|
894
|
+
context.signal
|
|
895
|
+
);
|
|
896
|
+
if (result.success) {
|
|
934
897
|
return {
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
client_secret: checkoutResult.client_secret,
|
|
938
|
-
public_key: checkoutResult.public_key
|
|
898
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.SUBMITTED,
|
|
899
|
+
reference: result.reference || context.reference
|
|
939
900
|
};
|
|
940
901
|
}
|
|
941
|
-
if (
|
|
902
|
+
if (result.error === PAYSTACK_POPUP_ERROR.SUBMISSION_UNKNOWN) {
|
|
903
|
+
return {
|
|
904
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.SUBMITTED,
|
|
905
|
+
reference: context.reference
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
if (!result.error || result.error === PAYSTACK_POPUP_ERROR.CANCELLED || result.error === PAYSTACK_POPUP_ERROR.PAYMENT_CANCELLED) {
|
|
909
|
+
return { status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED };
|
|
910
|
+
}
|
|
911
|
+
if (result.error === PAYSTACK_POPUP_ERROR.POPUP_BLOCKED) {
|
|
942
912
|
return {
|
|
943
|
-
|
|
944
|
-
|
|
913
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
914
|
+
code: chunkSFUJMS5E_js.ErrorCode.POPUP_BLOCKED,
|
|
915
|
+
message: "Unable to open the Paystack payment popup. Please allow popups and try again.",
|
|
916
|
+
recoverable: true
|
|
945
917
|
};
|
|
946
918
|
}
|
|
947
|
-
if (
|
|
919
|
+
if (result.error === PAYSTACK_POPUP_ERROR.PROVIDER_UNAVAILABLE) {
|
|
948
920
|
return {
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
921
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
922
|
+
code: chunkSFUJMS5E_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
923
|
+
message: "Paystack is unavailable in this environment.",
|
|
924
|
+
recoverable: false
|
|
952
925
|
};
|
|
953
926
|
}
|
|
954
|
-
return {
|
|
927
|
+
return {
|
|
928
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
929
|
+
code: chunkSFUJMS5E_js.ErrorCode.PAYMENT_FAILED,
|
|
930
|
+
message: result.error || "Paystack payment could not be submitted.",
|
|
931
|
+
recoverable: true
|
|
932
|
+
};
|
|
955
933
|
}
|
|
956
|
-
|
|
957
|
-
|
|
934
|
+
};
|
|
935
|
+
|
|
936
|
+
// src/payment-authorization/providers/stripe.ts
|
|
937
|
+
var STRIPE_REDIRECT_MODE = "if_required";
|
|
938
|
+
var STRIPE_PAYMENT_ELEMENT_TYPE = "payment";
|
|
939
|
+
async function loadStripeFromPeer(publicKey, options) {
|
|
940
|
+
try {
|
|
941
|
+
const imported = await import('@stripe/stripe-js');
|
|
942
|
+
return imported.loadStripe ? imported.loadStripe(publicKey, options) : null;
|
|
943
|
+
} catch {
|
|
944
|
+
return null;
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
function createStripeModal() {
|
|
948
|
+
if (typeof document === "undefined" || !document.body) return null;
|
|
949
|
+
const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
950
|
+
const root = document.createElement("div");
|
|
951
|
+
root.setAttribute("role", "dialog");
|
|
952
|
+
root.setAttribute("aria-modal", "true");
|
|
953
|
+
root.setAttribute("aria-label", "Secure card payment");
|
|
954
|
+
Object.assign(root.style, {
|
|
955
|
+
position: "fixed",
|
|
956
|
+
inset: "0",
|
|
957
|
+
zIndex: "2147483647",
|
|
958
|
+
display: "grid",
|
|
959
|
+
placeItems: "center",
|
|
960
|
+
padding: "16px",
|
|
961
|
+
background: "rgba(15, 23, 42, 0.58)"
|
|
962
|
+
});
|
|
963
|
+
const form = document.createElement("form");
|
|
964
|
+
Object.assign(form.style, {
|
|
965
|
+
width: "min(100%, 480px)",
|
|
966
|
+
maxHeight: "calc(100vh - 32px)",
|
|
967
|
+
overflow: "auto",
|
|
968
|
+
borderRadius: "12px",
|
|
969
|
+
padding: "24px",
|
|
970
|
+
background: "#fff",
|
|
971
|
+
boxShadow: "0 24px 80px rgba(15, 23, 42, 0.32)"
|
|
972
|
+
});
|
|
973
|
+
const title = document.createElement("h2");
|
|
974
|
+
title.textContent = "Complete card payment";
|
|
975
|
+
Object.assign(title.style, { margin: "0 0 18px", font: "600 18px/1.4 system-ui" });
|
|
976
|
+
const paymentMount = document.createElement("div");
|
|
977
|
+
paymentMount.setAttribute("data-cimplify-stripe-payment-element", "");
|
|
978
|
+
const error = document.createElement("p");
|
|
979
|
+
error.setAttribute("role", "alert");
|
|
980
|
+
Object.assign(error.style, {
|
|
981
|
+
minHeight: "20px",
|
|
982
|
+
margin: "14px 0 0",
|
|
983
|
+
color: "#b91c1c",
|
|
984
|
+
font: "14px/1.4 system-ui"
|
|
985
|
+
});
|
|
986
|
+
const actions = document.createElement("div");
|
|
987
|
+
Object.assign(actions.style, {
|
|
988
|
+
display: "flex",
|
|
989
|
+
justifyContent: "flex-end",
|
|
990
|
+
gap: "10px",
|
|
991
|
+
marginTop: "18px"
|
|
992
|
+
});
|
|
993
|
+
const cancelButton = document.createElement("button");
|
|
994
|
+
cancelButton.type = "button";
|
|
995
|
+
cancelButton.textContent = "Cancel";
|
|
996
|
+
Object.assign(cancelButton.style, {
|
|
997
|
+
border: "1px solid #cbd5e1",
|
|
998
|
+
borderRadius: "8px",
|
|
999
|
+
padding: "10px 16px",
|
|
1000
|
+
background: "#fff",
|
|
1001
|
+
color: "#0f172a",
|
|
1002
|
+
cursor: "pointer"
|
|
1003
|
+
});
|
|
1004
|
+
const submitButton = document.createElement("button");
|
|
1005
|
+
submitButton.type = "submit";
|
|
1006
|
+
submitButton.textContent = "Pay securely";
|
|
1007
|
+
Object.assign(submitButton.style, {
|
|
1008
|
+
border: "0",
|
|
1009
|
+
borderRadius: "8px",
|
|
1010
|
+
padding: "10px 16px",
|
|
1011
|
+
background: "#0f172a",
|
|
1012
|
+
color: "#fff",
|
|
1013
|
+
cursor: "pointer"
|
|
1014
|
+
});
|
|
1015
|
+
actions.append(cancelButton, submitButton);
|
|
1016
|
+
form.append(title, paymentMount, error, actions);
|
|
1017
|
+
root.append(form);
|
|
1018
|
+
document.body.append(root);
|
|
1019
|
+
cancelButton.focus();
|
|
1020
|
+
return { root, form, paymentMount, submitButton, cancelButton, error, previousFocus };
|
|
1021
|
+
}
|
|
1022
|
+
function stripeFailure(error) {
|
|
1023
|
+
const message = error?.message || "Stripe could not authorize this payment.";
|
|
1024
|
+
if (error?.code === "payment_intent_authentication_failure" || error?.type === "invalid_request_error") {
|
|
1025
|
+
return {
|
|
1026
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
1027
|
+
code: chunkSFUJMS5E_js.ErrorCode.AUTHORIZATION_FAILED,
|
|
1028
|
+
message,
|
|
1029
|
+
recoverable: true
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
return {
|
|
1033
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
1034
|
+
code: chunkSFUJMS5E_js.ErrorCode.PAYMENT_FAILED,
|
|
1035
|
+
message,
|
|
1036
|
+
recoverable: true
|
|
1037
|
+
};
|
|
1038
|
+
}
|
|
1039
|
+
var StripeAuthorizationAdapter = class {
|
|
1040
|
+
constructor(loadStripe = loadStripeFromPeer) {
|
|
1041
|
+
this.loadStripe = loadStripe;
|
|
1042
|
+
this.provider = PAYMENT_AUTHORIZATION_PROVIDER.STRIPE;
|
|
1043
|
+
}
|
|
1044
|
+
async authorize(context) {
|
|
1045
|
+
if (typeof window === "undefined" || typeof document === "undefined" || context.signal?.aborted) {
|
|
1046
|
+
return context.signal?.aborted ? { status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED } : {
|
|
1047
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
1048
|
+
code: chunkSFUJMS5E_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
1049
|
+
message: "Stripe Payment Element is unavailable in this environment.",
|
|
1050
|
+
recoverable: false
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
let stripe;
|
|
1054
|
+
try {
|
|
1055
|
+
stripe = await this.loadStripe(
|
|
1056
|
+
context.action.public_key,
|
|
1057
|
+
context.action.provider_account_id ? { stripeAccount: context.action.provider_account_id } : void 0
|
|
1058
|
+
);
|
|
1059
|
+
} catch (error) {
|
|
958
1060
|
return {
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
false
|
|
964
|
-
)
|
|
1061
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
1062
|
+
code: chunkSFUJMS5E_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
1063
|
+
message: error instanceof Error ? error.message : "Stripe.js could not be loaded.",
|
|
1064
|
+
recoverable: true
|
|
965
1065
|
};
|
|
966
1066
|
}
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
provider: action.provider
|
|
972
|
-
});
|
|
973
|
-
if (!this.allowPopups) {
|
|
1067
|
+
if (context.signal?.aborted) {
|
|
1068
|
+
return { status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED };
|
|
1069
|
+
}
|
|
1070
|
+
if (!stripe) {
|
|
974
1071
|
return {
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
false
|
|
980
|
-
)
|
|
1072
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
1073
|
+
code: chunkSFUJMS5E_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
1074
|
+
message: "Stripe.js could not be loaded.",
|
|
1075
|
+
recoverable: false
|
|
981
1076
|
};
|
|
982
1077
|
}
|
|
983
|
-
const
|
|
984
|
-
if (!
|
|
1078
|
+
const modal = createStripeModal();
|
|
1079
|
+
if (!modal) {
|
|
985
1080
|
return {
|
|
986
|
-
|
|
987
|
-
|
|
1081
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
1082
|
+
code: chunkSFUJMS5E_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
1083
|
+
message: "Stripe Payment Element could not be mounted.",
|
|
1084
|
+
recoverable: false
|
|
988
1085
|
};
|
|
989
1086
|
}
|
|
990
|
-
let
|
|
1087
|
+
let paymentElement;
|
|
1088
|
+
let elements;
|
|
991
1089
|
try {
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
signal: this.signal
|
|
999
|
-
});
|
|
1000
|
-
} finally {
|
|
1001
|
-
this.notifyAuthorizationUiChange(false);
|
|
1002
|
-
}
|
|
1003
|
-
if (outcome.status === "submitted") {
|
|
1004
|
-
return { ok: true, reference: outcome.reference };
|
|
1005
|
-
}
|
|
1006
|
-
if (outcome.status === "cancelled") {
|
|
1090
|
+
elements = stripe.elements({ clientSecret: context.action.client_secret });
|
|
1091
|
+
paymentElement = elements.create(STRIPE_PAYMENT_ELEMENT_TYPE);
|
|
1092
|
+
paymentElement.mount(modal.paymentMount);
|
|
1093
|
+
} catch {
|
|
1094
|
+
modal.root.remove();
|
|
1095
|
+
modal.previousFocus?.focus();
|
|
1007
1096
|
return {
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
true
|
|
1013
|
-
)
|
|
1097
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
1098
|
+
code: chunkSFUJMS5E_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
1099
|
+
message: "Stripe Payment Element could not be initialized.",
|
|
1100
|
+
recoverable: false
|
|
1014
1101
|
};
|
|
1015
1102
|
}
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1103
|
+
if (context.signal?.aborted) {
|
|
1104
|
+
if (paymentElement.destroy) paymentElement.destroy();
|
|
1105
|
+
else paymentElement.unmount?.();
|
|
1106
|
+
modal.root.remove();
|
|
1107
|
+
modal.previousFocus?.focus();
|
|
1108
|
+
return { status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED };
|
|
1109
|
+
}
|
|
1110
|
+
return new Promise((resolve) => {
|
|
1111
|
+
let settled = false;
|
|
1112
|
+
let submitting = false;
|
|
1113
|
+
let confirmationStarted = false;
|
|
1114
|
+
const cleanup = () => {
|
|
1115
|
+
context.signal?.removeEventListener("abort", onAbort);
|
|
1116
|
+
modal.form.removeEventListener("submit", onSubmit);
|
|
1117
|
+
modal.cancelButton.removeEventListener("click", onCancel);
|
|
1118
|
+
if (paymentElement.destroy) paymentElement.destroy();
|
|
1119
|
+
else paymentElement.unmount?.();
|
|
1120
|
+
modal.root.remove();
|
|
1121
|
+
modal.previousFocus?.focus();
|
|
1122
|
+
};
|
|
1123
|
+
const settle = (outcome) => {
|
|
1124
|
+
if (settled) return;
|
|
1125
|
+
settled = true;
|
|
1126
|
+
cleanup();
|
|
1127
|
+
resolve(outcome);
|
|
1128
|
+
};
|
|
1129
|
+
const onAbort = () => {
|
|
1130
|
+
if (confirmationStarted) {
|
|
1131
|
+
settle({
|
|
1132
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.SUBMITTED,
|
|
1133
|
+
reference: context.reference
|
|
1134
|
+
});
|
|
1135
|
+
return;
|
|
1044
1136
|
}
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
return this.fail(
|
|
1051
|
-
"INVALID_REDIRECT_AUTHORIZATION",
|
|
1052
|
-
"The payment provider returned an invalid authorization URL.",
|
|
1053
|
-
false
|
|
1054
|
-
);
|
|
1055
|
-
}
|
|
1056
|
-
if (typeof window !== "undefined" && this.returnUrl) {
|
|
1057
|
-
window.location.assign(authorizationUrl);
|
|
1058
|
-
return this.fail(
|
|
1059
|
-
"REDIRECT_REQUIRED",
|
|
1060
|
-
"Redirecting to complete payment authorization.",
|
|
1061
|
-
true
|
|
1062
|
-
);
|
|
1063
|
-
}
|
|
1064
|
-
if (typeof window !== "undefined") {
|
|
1065
|
-
const popup = window.open(
|
|
1066
|
-
authorizationUrl,
|
|
1067
|
-
"cimplify-auth",
|
|
1068
|
-
"width=520,height=760,noopener,noreferrer"
|
|
1069
|
-
);
|
|
1070
|
-
if (!popup) {
|
|
1071
|
-
return this.fail(
|
|
1072
|
-
"POPUP_BLOCKED",
|
|
1073
|
-
"Authorization popup was blocked. Please allow popups and retry.",
|
|
1074
|
-
true
|
|
1075
|
-
);
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
break actionLoop;
|
|
1137
|
+
settle({ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED });
|
|
1138
|
+
};
|
|
1139
|
+
const onCancel = () => {
|
|
1140
|
+
if (!confirmationStarted) {
|
|
1141
|
+
settle({ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED });
|
|
1079
1142
|
}
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
return
|
|
1143
|
+
};
|
|
1144
|
+
const onSubmit = async (event) => {
|
|
1145
|
+
event.preventDefault();
|
|
1146
|
+
if (submitting || settled) return;
|
|
1147
|
+
submitting = true;
|
|
1148
|
+
modal.submitButton.disabled = true;
|
|
1149
|
+
modal.error.textContent = "";
|
|
1150
|
+
try {
|
|
1151
|
+
const validation = elements.submit ? await elements.submit() : {};
|
|
1152
|
+
if (validation.error) {
|
|
1153
|
+
modal.error.textContent = validation.error.message || "Check your payment details.";
|
|
1154
|
+
submitting = false;
|
|
1155
|
+
modal.submitButton.disabled = false;
|
|
1156
|
+
return;
|
|
1094
1157
|
}
|
|
1095
|
-
if (
|
|
1096
|
-
|
|
1158
|
+
if (settled || context.signal?.aborted) {
|
|
1159
|
+
settle({ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED });
|
|
1160
|
+
return;
|
|
1097
1161
|
}
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1162
|
+
confirmationStarted = true;
|
|
1163
|
+
modal.cancelButton.disabled = true;
|
|
1164
|
+
const confirmation = await stripe.confirmPayment({
|
|
1165
|
+
elements,
|
|
1166
|
+
confirmParams: { return_url: context.returnUrl || window.location.href },
|
|
1167
|
+
redirect: STRIPE_REDIRECT_MODE
|
|
1168
|
+
});
|
|
1169
|
+
if (settled) return;
|
|
1170
|
+
if (confirmation.error) {
|
|
1171
|
+
settle(stripeFailure(confirmation.error));
|
|
1172
|
+
return;
|
|
1102
1173
|
}
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1174
|
+
settle({
|
|
1175
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.SUBMITTED,
|
|
1176
|
+
reference: confirmation.paymentIntent?.id || context.reference
|
|
1177
|
+
});
|
|
1178
|
+
} catch (error) {
|
|
1179
|
+
if (confirmationStarted) {
|
|
1180
|
+
settle({
|
|
1181
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.SUBMITTED,
|
|
1182
|
+
reference: context.reference
|
|
1183
|
+
});
|
|
1184
|
+
return;
|
|
1109
1185
|
}
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
break actionLoop;
|
|
1115
|
-
default:
|
|
1116
|
-
return this.fail(
|
|
1117
|
-
"UNSUPPORTED_NEXT_ACTION",
|
|
1118
|
-
"The payment provider requested an unsupported authorization action.",
|
|
1119
|
-
false
|
|
1186
|
+
settle(
|
|
1187
|
+
stripeFailure({
|
|
1188
|
+
message: error instanceof Error ? error.message : "Stripe confirmation failed."
|
|
1189
|
+
})
|
|
1120
1190
|
);
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1191
|
+
}
|
|
1192
|
+
};
|
|
1193
|
+
modal.form.addEventListener("submit", onSubmit);
|
|
1194
|
+
modal.cancelButton.addEventListener("click", onCancel);
|
|
1195
|
+
context.signal?.addEventListener("abort", onAbort, { once: true });
|
|
1196
|
+
paymentElement.on?.("escape", onCancel);
|
|
1197
|
+
paymentElement.on?.("loaderror", (event) => {
|
|
1198
|
+
if (confirmationStarted) return;
|
|
1199
|
+
settle({
|
|
1200
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
1201
|
+
code: chunkSFUJMS5E_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
1202
|
+
message: event?.error?.message || "Stripe Payment Element failed to load.",
|
|
1203
|
+
recoverable: true
|
|
1204
|
+
});
|
|
1205
|
+
});
|
|
1128
1206
|
});
|
|
1129
1207
|
}
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1208
|
+
};
|
|
1209
|
+
|
|
1210
|
+
// src/payment-authorization/registry.ts
|
|
1211
|
+
function normalizeProvider(provider) {
|
|
1212
|
+
return typeof provider === "string" ? provider.trim().toLowerCase() : "";
|
|
1213
|
+
}
|
|
1214
|
+
var PaymentAuthorizationAdapterRegistry = class {
|
|
1215
|
+
constructor(adapters = []) {
|
|
1216
|
+
this.adapters = /* @__PURE__ */ new Map();
|
|
1217
|
+
for (const adapter of adapters) {
|
|
1218
|
+
this.register(adapter);
|
|
1137
1219
|
}
|
|
1138
|
-
resolutionState.authorizationSteps += 1;
|
|
1139
|
-
return void 0;
|
|
1140
1220
|
}
|
|
1141
|
-
|
|
1142
|
-
const
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
while (resolutionState.pollAttempts < this.maxPollAttempts) {
|
|
1146
|
-
this.ensureNotAborted();
|
|
1147
|
-
const attempt = resolutionState.pollAttempts;
|
|
1148
|
-
resolutionState.pollAttempts += 1;
|
|
1149
|
-
this.emit("polling", {
|
|
1150
|
-
poll_attempt: attempt,
|
|
1151
|
-
max_poll_attempts: this.maxPollAttempts,
|
|
1152
|
-
order_id: input.orderId,
|
|
1153
|
-
order_number: latestCheckoutResult.order_number
|
|
1154
|
-
});
|
|
1155
|
-
const statusResult = await this.client.checkout.pollPaymentStatus(input.orderId);
|
|
1156
|
-
if (!statusResult.ok) {
|
|
1157
|
-
resolutionState.consecutivePollErrors += 1;
|
|
1158
|
-
if (resolutionState.consecutivePollErrors >= MAX_CONSECUTIVE_NETWORK_ERRORS) {
|
|
1159
|
-
return this.fail(
|
|
1160
|
-
"NETWORK_ERROR",
|
|
1161
|
-
"Unable to confirm payment due to repeated network errors.",
|
|
1162
|
-
true
|
|
1163
|
-
);
|
|
1164
|
-
}
|
|
1165
|
-
await this.wait(this.pollIntervalMs);
|
|
1166
|
-
continue;
|
|
1167
|
-
}
|
|
1168
|
-
resolutionState.consecutivePollErrors = 0;
|
|
1169
|
-
if (statusResult.value.reference) {
|
|
1170
|
-
paymentReference = statusResult.value.reference;
|
|
1171
|
-
}
|
|
1172
|
-
const normalized = chunkNNG6IFFX_js.normalizeStatusResponse(statusResult.value);
|
|
1173
|
-
if (normalized.paid || chunkNNG6IFFX_js.isPaymentStatusSuccess(normalized.status)) {
|
|
1174
|
-
return this.finalizeSuccess({
|
|
1175
|
-
...latestCheckoutResult,
|
|
1176
|
-
payment_status: normalized.status,
|
|
1177
|
-
payment_reference: paymentReference || latestCheckoutResult.payment_reference
|
|
1178
|
-
});
|
|
1179
|
-
}
|
|
1180
|
-
if (chunkNNG6IFFX_js.isPaymentStatusFailure(normalized.status)) {
|
|
1181
|
-
return this.fail(
|
|
1182
|
-
normalized.status ? normalized.status.toUpperCase() : "PAYMENT_FAILED",
|
|
1183
|
-
normalized.message || "Payment failed during confirmation.",
|
|
1184
|
-
false
|
|
1185
|
-
);
|
|
1186
|
-
}
|
|
1187
|
-
if (chunkNNG6IFFX_js.isPaymentStatusRequiresAction(normalized.status)) {
|
|
1188
|
-
const authorizationType = latestCheckoutResult.authorization_type;
|
|
1189
|
-
const paymentId = latestCheckoutResult.payment_id;
|
|
1190
|
-
if (!authorizationType || !normalizeAuthorizationType(authorizationType) || !paymentId) {
|
|
1191
|
-
return this.fail(
|
|
1192
|
-
"INVALID_AUTHORIZATION_RESPONSE",
|
|
1193
|
-
"The payment provider returned an incomplete authorization response.",
|
|
1194
|
-
false
|
|
1195
|
-
);
|
|
1196
|
-
}
|
|
1197
|
-
return this.resolveNextAction(
|
|
1198
|
-
{
|
|
1199
|
-
...latestCheckoutResult,
|
|
1200
|
-
payment_status: normalized.status,
|
|
1201
|
-
payment_reference: paymentReference,
|
|
1202
|
-
display_text: normalized.message || latestCheckoutResult.display_text,
|
|
1203
|
-
next_action: {
|
|
1204
|
-
type: NEXT_ACTION_AUTHORIZATION,
|
|
1205
|
-
authorization_type: authorizationType,
|
|
1206
|
-
display_text: normalized.message || latestCheckoutResult.display_text
|
|
1207
|
-
}
|
|
1208
|
-
},
|
|
1209
|
-
resolutionState
|
|
1210
|
-
);
|
|
1211
|
-
}
|
|
1212
|
-
await this.wait(this.pollIntervalMs);
|
|
1221
|
+
register(adapter) {
|
|
1222
|
+
const provider = normalizeProvider(adapter.provider);
|
|
1223
|
+
if (!provider) {
|
|
1224
|
+
throw new TypeError("Payment authorization adapter provider cannot be empty.");
|
|
1213
1225
|
}
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
"Payment confirmation timed out. Please retry checkout.",
|
|
1217
|
-
true
|
|
1218
|
-
);
|
|
1226
|
+
this.adapters.set(provider, adapter);
|
|
1227
|
+
return this;
|
|
1219
1228
|
}
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
const paymentId = input.paymentId;
|
|
1223
|
-
if (!authorizationType || !paymentId) {
|
|
1224
|
-
return {
|
|
1225
|
-
ok: false,
|
|
1226
|
-
result: this.fail(
|
|
1227
|
-
"INVALID_AUTHORIZATION_RESPONSE",
|
|
1228
|
-
"The payment provider returned an incomplete authorization response.",
|
|
1229
|
-
false
|
|
1230
|
-
)
|
|
1231
|
-
};
|
|
1232
|
-
}
|
|
1233
|
-
this.emit("awaiting_authorization", {
|
|
1234
|
-
authorization_type: authorizationType,
|
|
1235
|
-
display_text: input.displayText,
|
|
1236
|
-
provider: input.provider,
|
|
1237
|
-
order_id: input.orderId,
|
|
1238
|
-
order_number: input.orderNumber
|
|
1239
|
-
});
|
|
1240
|
-
let authorizationRequest;
|
|
1241
|
-
const submit = (authorization) => {
|
|
1242
|
-
this.ensureNotAborted();
|
|
1243
|
-
let normalizedAuthorization;
|
|
1244
|
-
try {
|
|
1245
|
-
normalizedAuthorization = normalizeAuthorizationSubmission(
|
|
1246
|
-
authorizationType,
|
|
1247
|
-
authorization
|
|
1248
|
-
);
|
|
1249
|
-
} catch (error) {
|
|
1250
|
-
return Promise.reject(error);
|
|
1251
|
-
}
|
|
1252
|
-
if (!authorizationRequest) {
|
|
1253
|
-
const request = this.client.checkout.submitAuthorization({
|
|
1254
|
-
payment_id: paymentId,
|
|
1255
|
-
authorization: normalizedAuthorization
|
|
1256
|
-
}).then((submitResult) => {
|
|
1257
|
-
if (!submitResult.ok) {
|
|
1258
|
-
throw new Error(submitResult.error.message || "Authorization failed.");
|
|
1259
|
-
}
|
|
1260
|
-
return submitResult.value;
|
|
1261
|
-
});
|
|
1262
|
-
authorizationRequest = request;
|
|
1263
|
-
void request.catch(() => {
|
|
1264
|
-
if (authorizationRequest === request) {
|
|
1265
|
-
authorizationRequest = void 0;
|
|
1266
|
-
}
|
|
1267
|
-
});
|
|
1268
|
-
}
|
|
1269
|
-
return authorizationRequest.then(() => void 0);
|
|
1270
|
-
};
|
|
1271
|
-
try {
|
|
1272
|
-
if (this.onAuthorizationRequired) {
|
|
1273
|
-
await waitForAbortable(
|
|
1274
|
-
Promise.resolve(this.onAuthorizationRequired(authorizationType, submit)),
|
|
1275
|
-
this.signal
|
|
1276
|
-
);
|
|
1277
|
-
} else {
|
|
1278
|
-
return {
|
|
1279
|
-
ok: false,
|
|
1280
|
-
result: this.fail(
|
|
1281
|
-
"AUTHORIZATION_REQUIRED",
|
|
1282
|
-
"Authorization callback is required in headless checkout mode.",
|
|
1283
|
-
false
|
|
1284
|
-
)
|
|
1285
|
-
};
|
|
1286
|
-
}
|
|
1287
|
-
if (!authorizationRequest) {
|
|
1288
|
-
return {
|
|
1289
|
-
ok: false,
|
|
1290
|
-
result: this.fail(
|
|
1291
|
-
"AUTHORIZATION_NOT_SUBMITTED",
|
|
1292
|
-
"The authorization callback returned without submitting a value.",
|
|
1293
|
-
true
|
|
1294
|
-
)
|
|
1295
|
-
};
|
|
1296
|
-
}
|
|
1297
|
-
return {
|
|
1298
|
-
ok: true,
|
|
1299
|
-
value: await waitForAbortable(authorizationRequest, this.signal)
|
|
1300
|
-
};
|
|
1301
|
-
} catch (error) {
|
|
1302
|
-
if (isAbortError(error)) {
|
|
1303
|
-
return {
|
|
1304
|
-
ok: false,
|
|
1305
|
-
result: this.fail("CANCELLED", "Checkout was cancelled.", true)
|
|
1306
|
-
};
|
|
1307
|
-
}
|
|
1308
|
-
const message = error instanceof Error ? error.message : "Payment authorization failed.";
|
|
1309
|
-
return {
|
|
1310
|
-
ok: false,
|
|
1311
|
-
result: this.fail("AUTHORIZATION_FAILED", message, true)
|
|
1312
|
-
};
|
|
1313
|
-
}
|
|
1229
|
+
unregister(provider) {
|
|
1230
|
+
return this.adapters.delete(normalizeProvider(provider));
|
|
1314
1231
|
}
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
if (!currency) {
|
|
1318
|
-
return this.fail("INVALID_CURRENCY", "Payment currency is missing or unsupported.", false);
|
|
1319
|
-
}
|
|
1320
|
-
this.emit("finalizing", {
|
|
1321
|
-
order_id: checkoutResult.order_id,
|
|
1322
|
-
order_number: checkoutResult.order_number
|
|
1323
|
-
});
|
|
1324
|
-
const enrolledInLink = await this.maybeEnrollInLink(checkoutResult.order_id);
|
|
1325
|
-
this.emit("success", {
|
|
1326
|
-
order_id: checkoutResult.order_id,
|
|
1327
|
-
order_number: checkoutResult.order_number
|
|
1328
|
-
});
|
|
1329
|
-
return {
|
|
1330
|
-
success: true,
|
|
1331
|
-
order: {
|
|
1332
|
-
id: checkoutResult.order_id,
|
|
1333
|
-
order_number: checkoutResult.order_number || checkoutResult.order_id,
|
|
1334
|
-
status: checkoutResult.payment_status || "paid",
|
|
1335
|
-
total: this.getOrderTotal(checkoutResult),
|
|
1336
|
-
currency
|
|
1337
|
-
},
|
|
1338
|
-
enrolled_in_link: enrolledInLink
|
|
1339
|
-
};
|
|
1232
|
+
get(provider) {
|
|
1233
|
+
return this.adapters.get(normalizeProvider(provider));
|
|
1340
1234
|
}
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
return false;
|
|
1344
|
-
}
|
|
1345
|
-
let businessId = this.businessId;
|
|
1346
|
-
if (!businessId) {
|
|
1347
|
-
const businessResult = await this.client.business.getInfo();
|
|
1348
|
-
if (!businessResult.ok || !businessResult.value?.id) {
|
|
1349
|
-
return false;
|
|
1350
|
-
}
|
|
1351
|
-
businessId = businessResult.value.id;
|
|
1352
|
-
}
|
|
1353
|
-
const address = this.getEnrollmentAddress();
|
|
1354
|
-
const mobileMoney = this.getEnrollmentMobileMoney();
|
|
1355
|
-
try {
|
|
1356
|
-
const enrollment = await this.client.link.enrollAndLinkOrder({
|
|
1357
|
-
order_id: orderId,
|
|
1358
|
-
business_id: businessId,
|
|
1359
|
-
order_type: this.orderType || this.checkoutData.order_type,
|
|
1360
|
-
address,
|
|
1361
|
-
mobile_money: mobileMoney
|
|
1362
|
-
});
|
|
1363
|
-
return enrollment.ok && enrollment.value.success;
|
|
1364
|
-
} catch {
|
|
1365
|
-
return false;
|
|
1366
|
-
}
|
|
1235
|
+
supports(provider) {
|
|
1236
|
+
return this.adapters.has(normalizeProvider(provider));
|
|
1367
1237
|
}
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
if (!source?.street_address) {
|
|
1371
|
-
return void 0;
|
|
1372
|
-
}
|
|
1373
|
-
return {
|
|
1374
|
-
label: "Default",
|
|
1375
|
-
street_address: source.street_address,
|
|
1376
|
-
apartment: source.apartment || void 0,
|
|
1377
|
-
city: source.city || "",
|
|
1378
|
-
region: source.region || "",
|
|
1379
|
-
postal_code: source.postal_code || void 0,
|
|
1380
|
-
country: source.country || void 0,
|
|
1381
|
-
delivery_instructions: source.delivery_instructions || void 0,
|
|
1382
|
-
phone_for_delivery: source.phone_for_delivery || void 0,
|
|
1383
|
-
latitude: source.latitude,
|
|
1384
|
-
longitude: source.longitude
|
|
1385
|
-
};
|
|
1238
|
+
providers() {
|
|
1239
|
+
return [...this.adapters.keys()];
|
|
1386
1240
|
}
|
|
1387
|
-
|
|
1388
|
-
|
|
1241
|
+
async authorize(action, options) {
|
|
1242
|
+
const provider = normalizeProvider(action.provider);
|
|
1243
|
+
if (!provider) {
|
|
1389
1244
|
return {
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1245
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
1246
|
+
code: chunkSFUJMS5E_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
1247
|
+
message: "Card authorization response did not identify a payment provider.",
|
|
1248
|
+
recoverable: false
|
|
1393
1249
|
};
|
|
1394
1250
|
}
|
|
1395
|
-
|
|
1251
|
+
const adapter = this.adapters.get(provider);
|
|
1252
|
+
if (!adapter) {
|
|
1396
1253
|
return {
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1254
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
1255
|
+
code: chunkSFUJMS5E_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
1256
|
+
message: `Card authorization provider '${provider}' is not supported by this SDK client.`,
|
|
1257
|
+
recoverable: false
|
|
1400
1258
|
};
|
|
1401
1259
|
}
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
return
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1260
|
+
try {
|
|
1261
|
+
const normalizedAction = action.provider === provider ? action : { ...action, provider };
|
|
1262
|
+
return await adapter.authorize({ ...options, action: normalizedAction });
|
|
1263
|
+
} catch (error) {
|
|
1264
|
+
return {
|
|
1265
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
1266
|
+
code: chunkSFUJMS5E_js.ErrorCode.PAYMENT_FAILED,
|
|
1267
|
+
message: error instanceof Error ? error.message : `Card authorization provider '${provider}' failed unexpectedly.`,
|
|
1268
|
+
recoverable: true
|
|
1269
|
+
};
|
|
1410
1270
|
}
|
|
1411
|
-
return "0.00";
|
|
1412
1271
|
}
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1272
|
+
};
|
|
1273
|
+
function createDefaultPaymentAuthorizationAdapterRegistry() {
|
|
1274
|
+
return new PaymentAuthorizationAdapterRegistry([
|
|
1275
|
+
new PaystackAuthorizationAdapter(),
|
|
1276
|
+
new StripeAuthorizationAdapter()
|
|
1277
|
+
]);
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
// src/utils/purchase-intent-confirmation.ts
|
|
1281
|
+
var EXACT_ZERO_MONEY = /^[+-]?0+(?:\.0+)?(?:[eE][+-]?\d+)?$/;
|
|
1282
|
+
function isExactlyZeroMoney(value) {
|
|
1283
|
+
if (typeof value === "number") return Object.is(value, 0) || Object.is(value, -0);
|
|
1284
|
+
return EXACT_ZERO_MONEY.test(value.trim());
|
|
1285
|
+
}
|
|
1286
|
+
function selectPurchaseIntentPaymentOption(terms, selection) {
|
|
1287
|
+
return terms.payment_options.filter((option) => option.status === chunkSFUJMS5E_js.PAYMENT_OPTION_STATUS.ELIGIBLE).sort((left, right) => left.rank - right.rank).find(
|
|
1288
|
+
(option) => option.method_kind === selection.method_kind && (selection.payment_option_id === void 0 || option.id === selection.payment_option_id)
|
|
1289
|
+
);
|
|
1290
|
+
}
|
|
1291
|
+
function createPurchaseIntentConfirmation(terms, paymentOption, idempotencyKey) {
|
|
1292
|
+
const normalizedKey = idempotencyKey.trim();
|
|
1293
|
+
if (!normalizedKey) throw new TypeError("idempotencyKey must not be empty");
|
|
1294
|
+
const requiresOption = purchaseIntentRequiresPaymentOption(terms);
|
|
1295
|
+
if (!paymentOption && requiresOption) {
|
|
1296
|
+
throw new TypeError("Nonzero rail terms require an eligible payment option");
|
|
1297
|
+
}
|
|
1298
|
+
if (paymentOption && !requiresOption) {
|
|
1299
|
+
throw new TypeError("Zero-rail terms must not name a payment option");
|
|
1300
|
+
}
|
|
1301
|
+
const authoritativeOption = paymentOption ? terms.payment_options.find(
|
|
1302
|
+
(candidate) => candidate.id === paymentOption.id && candidate.status === chunkSFUJMS5E_js.PAYMENT_OPTION_STATUS.ELIGIBLE
|
|
1303
|
+
) : void 0;
|
|
1304
|
+
if (paymentOption && !authoritativeOption) {
|
|
1305
|
+
throw new TypeError("Payment option is not eligible for these checkout terms");
|
|
1424
1306
|
}
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1307
|
+
return {
|
|
1308
|
+
accepted_intent_revision: terms.intent_revision,
|
|
1309
|
+
accepted_terms_version: terms.terms_version,
|
|
1310
|
+
accepted_due_now: terms.money.due_now,
|
|
1311
|
+
// Rail fees and routes may differ by option. Consent is to the exact
|
|
1312
|
+
// server-issued buyer debit, never an ambiguous principal/fee aggregate.
|
|
1313
|
+
accepted_customer_debit_amount: authoritativeOption?.customer_debit_amount ?? terms.money.rail_amount,
|
|
1314
|
+
currency: terms.money.currency,
|
|
1315
|
+
payment_option_id: authoritativeOption?.id ?? null,
|
|
1316
|
+
idempotency_key: normalizedKey
|
|
1317
|
+
};
|
|
1318
|
+
}
|
|
1319
|
+
function purchaseIntentRequiresPaymentOption(terms) {
|
|
1320
|
+
return terms.payment_options.length > 0 || !isExactlyZeroMoney(terms.money.rail_amount);
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
// src/utils/purchase-intent-adapter.ts
|
|
1324
|
+
function tenderPreference(form) {
|
|
1325
|
+
if (form.payment_method === chunkSFUJMS5E_js.PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY) {
|
|
1326
|
+
if (form.link_payment_method_id) {
|
|
1327
|
+
return {
|
|
1328
|
+
method_kind: chunkSFUJMS5E_js.PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY,
|
|
1329
|
+
authority: {
|
|
1330
|
+
authority_kind: chunkSFUJMS5E_js.MOBILE_MONEY_TENDER_AUTHORITY_KIND.SAVED_REFERENCE,
|
|
1331
|
+
stored_instrument_id: form.link_payment_method_id
|
|
1332
|
+
}
|
|
1333
|
+
};
|
|
1428
1334
|
}
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1335
|
+
const details = form.mobile_money_details;
|
|
1336
|
+
if (!details?.phone_number || !details.provider) {
|
|
1337
|
+
throw new chunkSFUJMS5E_js.CimplifyError(
|
|
1338
|
+
chunkSFUJMS5E_js.ErrorCode.INVALID_PAYMENT_METHOD,
|
|
1339
|
+
"Mobile money requires a phone number and network.",
|
|
1340
|
+
false
|
|
1341
|
+
);
|
|
1432
1342
|
}
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1343
|
+
const network = chunkXAUSDMMZ_js.purchaseIntentMobileMoneyNetwork(details.provider);
|
|
1344
|
+
if (!network) {
|
|
1345
|
+
throw new chunkSFUJMS5E_js.CimplifyError(
|
|
1346
|
+
chunkSFUJMS5E_js.ErrorCode.INVALID_PAYMENT_METHOD,
|
|
1347
|
+
"That mobile money network is not available for PurchaseIntent checkout.",
|
|
1348
|
+
false
|
|
1349
|
+
);
|
|
1438
1350
|
}
|
|
1439
|
-
}
|
|
1440
|
-
fail(code, message, recoverable) {
|
|
1441
|
-
this.emit("failed", {
|
|
1442
|
-
display_text: message
|
|
1443
|
-
});
|
|
1444
1351
|
return {
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1352
|
+
method_kind: chunkSFUJMS5E_js.PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY,
|
|
1353
|
+
authority: {
|
|
1354
|
+
authority_kind: chunkSFUJMS5E_js.MOBILE_MONEY_TENDER_AUTHORITY_KIND.TRANSIENT,
|
|
1355
|
+
phone_number: details.phone_number,
|
|
1356
|
+
network
|
|
1450
1357
|
}
|
|
1451
1358
|
};
|
|
1452
1359
|
}
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1360
|
+
if (form.payment_method === chunkSFUJMS5E_js.LEGACY_CHECKOUT_PAYMENT_METHOD_ALIAS.CASH || form.payment_method === chunkSFUJMS5E_js.PURCHASE_INTENT_PAYMENT_METHOD.OFFLINE) {
|
|
1361
|
+
throw new chunkSFUJMS5E_js.CimplifyError(
|
|
1362
|
+
chunkSFUJMS5E_js.ErrorCode.INVALID_PAYMENT_METHOD,
|
|
1363
|
+
"Offline tender requires an authenticated staff checkout.",
|
|
1364
|
+
false
|
|
1365
|
+
);
|
|
1456
1366
|
}
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1367
|
+
if (form.payment_method === chunkSFUJMS5E_js.PURCHASE_INTENT_PAYMENT_METHOD.CARD) {
|
|
1368
|
+
return {
|
|
1369
|
+
method_kind: chunkSFUJMS5E_js.PURCHASE_INTENT_PAYMENT_METHOD.CARD,
|
|
1370
|
+
stored_instrument_id: form.link_payment_method_id
|
|
1371
|
+
};
|
|
1460
1372
|
}
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
throw createAbortError();
|
|
1464
|
-
}
|
|
1373
|
+
if (form.payment_method === chunkSFUJMS5E_js.LEGACY_CHECKOUT_PAYMENT_METHOD_ALIAS.STORE_CREDIT) {
|
|
1374
|
+
return void 0;
|
|
1465
1375
|
}
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1376
|
+
throw new chunkSFUJMS5E_js.CimplifyError(
|
|
1377
|
+
chunkSFUJMS5E_js.ErrorCode.INVALID_PAYMENT_METHOD,
|
|
1378
|
+
"Checkout payment method is not supported.",
|
|
1379
|
+
false
|
|
1380
|
+
);
|
|
1381
|
+
}
|
|
1382
|
+
function checkoutFormToIntentRequest(form, clientIntentKey) {
|
|
1383
|
+
return {
|
|
1384
|
+
client_intent_key: clientIntentKey,
|
|
1385
|
+
source: { kind: chunkSFUJMS5E_js.PURCHASE_INTENT_SOURCE_KIND.CART, cart_id: form.cart_id },
|
|
1386
|
+
checkout: {
|
|
1387
|
+
customer: form.customer,
|
|
1388
|
+
order_type: form.order_type,
|
|
1389
|
+
address_info: form.address_info,
|
|
1390
|
+
location_id: form.location_id,
|
|
1391
|
+
delivery_rate_id: form.delivery_rate_id,
|
|
1392
|
+
special_instructions: form.special_instructions,
|
|
1393
|
+
link_address_id: form.link_address_id,
|
|
1394
|
+
metadata: form.metadata,
|
|
1395
|
+
pay_currency: form.pay_currency,
|
|
1396
|
+
fx_quote_id: form.fx_quote_id,
|
|
1397
|
+
use_store_credit: form.use_store_credit || form.payment_method === chunkSFUJMS5E_js.LEGACY_CHECKOUT_PAYMENT_METHOD_ALIAS.STORE_CREDIT,
|
|
1398
|
+
voucher_code: form.voucher_code,
|
|
1399
|
+
pay_deposit: form.pay_deposit,
|
|
1400
|
+
tender_preference: tenderPreference(form)
|
|
1401
|
+
}
|
|
1402
|
+
};
|
|
1403
|
+
}
|
|
1404
|
+
function selectCheckoutPaymentOption(terms, form) {
|
|
1405
|
+
const preference = tenderPreference(form);
|
|
1406
|
+
if (!preference) return void 0;
|
|
1407
|
+
return terms.payment_options.filter((option) => option.status === chunkSFUJMS5E_js.PAYMENT_OPTION_STATUS.ELIGIBLE).sort((left, right) => left.rank - right.rank).find((option) => option.method_kind === preference.method_kind);
|
|
1408
|
+
}
|
|
1409
|
+
function checkoutFormToConfirmation(_form, terms, paymentOption, idempotencyKey) {
|
|
1410
|
+
return createPurchaseIntentConfirmation(terms, paymentOption, idempotencyKey);
|
|
1411
|
+
}
|
|
1412
|
+
function committedBase(response) {
|
|
1413
|
+
return {
|
|
1414
|
+
intent_id: response.intent_id,
|
|
1415
|
+
attempt_id: response.attempt_id,
|
|
1416
|
+
order_id: response.order_id,
|
|
1417
|
+
order_number: response.order_number || response.order_id,
|
|
1418
|
+
payment_id: response.payment_id
|
|
1419
|
+
};
|
|
1420
|
+
}
|
|
1421
|
+
function confirmationToCheckoutResult(response) {
|
|
1422
|
+
switch (response.status) {
|
|
1423
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.ORDER_CREATED:
|
|
1424
|
+
return ok({
|
|
1425
|
+
...committedBase(response),
|
|
1426
|
+
payment_status: chunkSFUJMS5E_js.LEGACY_CHECKOUT_PAYMENT_STATUS.SUCCEEDED,
|
|
1427
|
+
requires_authorization: false,
|
|
1428
|
+
next_action: { type: chunkEV2EVOYS_js.CHECKOUT_NEXT_ACTION.NONE }
|
|
1429
|
+
});
|
|
1430
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.COLLECTION_PROCESSING:
|
|
1431
|
+
return ok({
|
|
1432
|
+
...committedBase(response),
|
|
1433
|
+
payment_status: chunkSFUJMS5E_js.LEGACY_CHECKOUT_PAYMENT_STATUS.PROCESSING,
|
|
1434
|
+
requires_authorization: false,
|
|
1435
|
+
next_action: { type: chunkEV2EVOYS_js.CHECKOUT_NEXT_ACTION.POLL }
|
|
1436
|
+
});
|
|
1437
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.PAYMENT_OUTCOME_UNKNOWN:
|
|
1438
|
+
return ok({
|
|
1439
|
+
...committedBase(response),
|
|
1440
|
+
payment_status: chunkSFUJMS5E_js.LEGACY_CHECKOUT_PAYMENT_STATUS.UNKNOWN,
|
|
1441
|
+
requires_authorization: false,
|
|
1442
|
+
next_action: { type: chunkEV2EVOYS_js.CHECKOUT_NEXT_ACTION.POLL }
|
|
1443
|
+
});
|
|
1444
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.PAYMENT_FAILED:
|
|
1445
|
+
return err(
|
|
1446
|
+
new chunkSFUJMS5E_js.CimplifyError(
|
|
1447
|
+
chunkSFUJMS5E_js.PURCHASE_INTENT_ERROR_CODE.PAYMENT_FAILED,
|
|
1448
|
+
"Payment failed. The order remains recorded, but collection did not succeed.",
|
|
1449
|
+
true
|
|
1450
|
+
)
|
|
1451
|
+
);
|
|
1452
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.REDIRECT_REQUIRED:
|
|
1453
|
+
return ok({
|
|
1454
|
+
...committedBase(response),
|
|
1455
|
+
payment_status: chunkSFUJMS5E_js.LEGACY_CHECKOUT_PAYMENT_STATUS.REQUIRES_ACTION,
|
|
1456
|
+
requires_authorization: false,
|
|
1457
|
+
authorization_url: response.authorization_url,
|
|
1458
|
+
next_action: {
|
|
1459
|
+
type: chunkEV2EVOYS_js.CHECKOUT_NEXT_ACTION.REDIRECT,
|
|
1460
|
+
authorization_url: response.authorization_url
|
|
1472
1461
|
}
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1462
|
+
});
|
|
1463
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.CARD_POPUP_REQUIRED:
|
|
1464
|
+
return ok({
|
|
1465
|
+
...committedBase(response),
|
|
1466
|
+
payment_status: chunkSFUJMS5E_js.LEGACY_CHECKOUT_PAYMENT_STATUS.REQUIRES_ACTION,
|
|
1467
|
+
requires_authorization: false,
|
|
1468
|
+
provider: response.provider,
|
|
1469
|
+
client_secret: response.client_secret,
|
|
1470
|
+
public_key: response.public_key,
|
|
1471
|
+
next_action: {
|
|
1472
|
+
type: chunkEV2EVOYS_js.CHECKOUT_NEXT_ACTION.CARD_POPUP,
|
|
1473
|
+
provider: response.provider,
|
|
1474
|
+
client_secret: response.client_secret,
|
|
1475
|
+
public_key: response.public_key,
|
|
1476
|
+
provider_account_id: response.provider_account_id ?? void 0
|
|
1477
|
+
}
|
|
1478
|
+
});
|
|
1479
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.AUTHORIZATION_REQUIRED:
|
|
1480
|
+
return ok({
|
|
1481
|
+
...committedBase(response),
|
|
1482
|
+
payment_status: chunkSFUJMS5E_js.LEGACY_CHECKOUT_PAYMENT_STATUS.REQUIRES_ACTION,
|
|
1483
|
+
requires_authorization: true,
|
|
1484
|
+
authorization_type: response.authorization_type,
|
|
1485
|
+
display_text: response.display_text,
|
|
1486
|
+
next_action: {
|
|
1487
|
+
type: chunkEV2EVOYS_js.CHECKOUT_NEXT_ACTION.AUTHORIZATION,
|
|
1488
|
+
authorization_type: response.authorization_type,
|
|
1489
|
+
display_text: response.display_text
|
|
1490
|
+
}
|
|
1491
|
+
});
|
|
1492
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.TERMS_CHANGED:
|
|
1493
|
+
return err(
|
|
1494
|
+
new chunkSFUJMS5E_js.CimplifyError(
|
|
1495
|
+
chunkSFUJMS5E_js.PURCHASE_INTENT_ERROR_CODE.TERMS_CHANGED,
|
|
1496
|
+
"Checkout terms changed. Review the replacement terms before confirming again.",
|
|
1497
|
+
true
|
|
1498
|
+
)
|
|
1499
|
+
);
|
|
1500
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.SELECTION_UNAVAILABLE:
|
|
1501
|
+
return err(
|
|
1502
|
+
new chunkSFUJMS5E_js.CimplifyError(
|
|
1503
|
+
chunkSFUJMS5E_js.PURCHASE_INTENT_ERROR_CODE.SELECTION_UNAVAILABLE,
|
|
1504
|
+
"One or more checkout selections are no longer available.",
|
|
1505
|
+
true
|
|
1506
|
+
)
|
|
1507
|
+
);
|
|
1508
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.OFFER_ENDED:
|
|
1509
|
+
return err(
|
|
1510
|
+
new chunkSFUJMS5E_js.CimplifyError(
|
|
1511
|
+
chunkSFUJMS5E_js.PURCHASE_INTENT_ERROR_CODE.OFFER_ENDED,
|
|
1512
|
+
"This offer has ended.",
|
|
1513
|
+
false
|
|
1514
|
+
)
|
|
1515
|
+
);
|
|
1516
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.SOURCE_UNAVAILABLE:
|
|
1517
|
+
return err(
|
|
1518
|
+
new chunkSFUJMS5E_js.CimplifyError(
|
|
1519
|
+
chunkSFUJMS5E_js.PURCHASE_INTENT_ERROR_CODE.SOURCE_UNAVAILABLE,
|
|
1520
|
+
"This purchase source is unavailable.",
|
|
1521
|
+
false
|
|
1522
|
+
)
|
|
1523
|
+
);
|
|
1483
1524
|
}
|
|
1484
|
-
}
|
|
1525
|
+
}
|
|
1485
1526
|
|
|
1486
1527
|
// src/checkout.ts
|
|
1528
|
+
function checkoutActionAuthority(response) {
|
|
1529
|
+
if (response.status !== chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.CARD_POPUP_REQUIRED && response.status !== chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.AUTHORIZATION_REQUIRED) {
|
|
1530
|
+
return null;
|
|
1531
|
+
}
|
|
1532
|
+
const paymentId = response.payment_id?.trim();
|
|
1533
|
+
return paymentId ? {
|
|
1534
|
+
intentId: response.intent_id,
|
|
1535
|
+
attemptId: response.attempt_id,
|
|
1536
|
+
paymentId
|
|
1537
|
+
} : null;
|
|
1538
|
+
}
|
|
1539
|
+
function isAmbiguousCheckoutError(error) {
|
|
1540
|
+
return error.code === chunkSFUJMS5E_js.ErrorCode.NETWORK_ERROR || error.code === chunkSFUJMS5E_js.ErrorCode.TIMEOUT;
|
|
1541
|
+
}
|
|
1542
|
+
function authorizationKind(value) {
|
|
1543
|
+
if (value && typeof value === "object" && chunkEV2EVOYS_js.AUTHORIZATION_TYPE.ADDRESS in value) {
|
|
1544
|
+
return chunkEV2EVOYS_js.AUTHORIZATION_TYPE.ADDRESS;
|
|
1545
|
+
}
|
|
1546
|
+
if (value === chunkEV2EVOYS_js.AUTHORIZATION_TYPE.OTP || value === chunkEV2EVOYS_js.AUTHORIZATION_TYPE.PIN || value === chunkEV2EVOYS_js.AUTHORIZATION_TYPE.PHONE || value === chunkEV2EVOYS_js.AUTHORIZATION_TYPE.BIRTHDAY) {
|
|
1547
|
+
return value;
|
|
1548
|
+
}
|
|
1549
|
+
return void 0;
|
|
1550
|
+
}
|
|
1551
|
+
function normalizeAuthorizationSubmission(expected, submission) {
|
|
1552
|
+
if (submission.type !== expected) throw new Error(`Expected ${expected} authorization details.`);
|
|
1553
|
+
if (submission.type === chunkEV2EVOYS_js.AUTHORIZATION_TYPE.ADDRESS) {
|
|
1554
|
+
const address = submission.address.trim();
|
|
1555
|
+
const city = submission.city.trim();
|
|
1556
|
+
const state = submission.state.trim();
|
|
1557
|
+
const zipCode = submission.zip_code.trim();
|
|
1558
|
+
if (!address || !city || !state || !zipCode) {
|
|
1559
|
+
throw new Error("Complete all authorization address fields.");
|
|
1560
|
+
}
|
|
1561
|
+
return { type: chunkEV2EVOYS_js.AUTHORIZATION_TYPE.ADDRESS, address, city, state, zip_code: zipCode };
|
|
1562
|
+
}
|
|
1563
|
+
const value = submission.value.trim();
|
|
1564
|
+
if (!value) throw new Error("Authorization value is required.");
|
|
1565
|
+
return { type: submission.type, value };
|
|
1566
|
+
}
|
|
1567
|
+
var DECIMAL_WIRE_VALUE = /^([+-]?)(\d+)(?:\.(\d+))?(?:[eE][+-]?\d+)?$/;
|
|
1568
|
+
function decimalSign(value) {
|
|
1569
|
+
if (typeof value === "number") {
|
|
1570
|
+
if (!Number.isFinite(value)) return null;
|
|
1571
|
+
if (Object.is(value, 0) || Object.is(value, -0)) return 0;
|
|
1572
|
+
return value > 0 ? 1 : -1;
|
|
1573
|
+
}
|
|
1574
|
+
const match = DECIMAL_WIRE_VALUE.exec(value.trim());
|
|
1575
|
+
if (!match) return null;
|
|
1576
|
+
const nonzero = [...match[2], ...match[3] ?? ""].some((digit) => digit !== "0");
|
|
1577
|
+
if (!nonzero) return 0;
|
|
1578
|
+
return match[1] === "-" ? -1 : 1;
|
|
1579
|
+
}
|
|
1487
1580
|
function toTerminalFailure(code, message, recoverable) {
|
|
1488
1581
|
return {
|
|
1489
1582
|
success: false,
|
|
@@ -1499,7 +1592,7 @@ function isValidCustomerName(name) {
|
|
|
1499
1592
|
return trimmed.length >= 2 && /\p{L}/u.test(trimmed);
|
|
1500
1593
|
}
|
|
1501
1594
|
function isOfflinePaymentMethod(method) {
|
|
1502
|
-
return method ===
|
|
1595
|
+
return method === chunkSFUJMS5E_js.LEGACY_CHECKOUT_PAYMENT_METHOD_ALIAS.CASH || method === chunkSFUJMS5E_js.PURCHASE_INTENT_PAYMENT_METHOD.OFFLINE;
|
|
1503
1596
|
}
|
|
1504
1597
|
function notifyCheckoutStatus(observer, status, context = {}) {
|
|
1505
1598
|
try {
|
|
@@ -1507,7 +1600,35 @@ function notifyCheckoutStatus(observer, status, context = {}) {
|
|
|
1507
1600
|
} catch {
|
|
1508
1601
|
}
|
|
1509
1602
|
}
|
|
1603
|
+
function notifyAuthorizationUi(observer, open) {
|
|
1604
|
+
try {
|
|
1605
|
+
observer?.(open);
|
|
1606
|
+
} catch {
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1510
1609
|
var MAX_STOREFRONT_COLLECTION_OPTIONS = 32;
|
|
1610
|
+
var CHECKOUT_INTENT_SCOPE_PREFIX = "checkout:";
|
|
1611
|
+
var CHECKOUT_CONFIRMATION_SCOPE_PREFIX = "checkout-confirm:";
|
|
1612
|
+
var CHECKOUT_INTENT_RECOVERY_FINGERPRINT = "cart-intent-v1";
|
|
1613
|
+
var ABORT_ERROR_NAME = "AbortError";
|
|
1614
|
+
var AUTHORIZATION_POPUP_NAME = "cimplify-auth";
|
|
1615
|
+
var AUTHORIZATION_POPUP_FEATURES = "width=520,height=760,noopener,noreferrer";
|
|
1616
|
+
var ORDER_TOKEN_QUERY_PARAMETER = "token";
|
|
1617
|
+
var CHECKOUT_API_ROUTE = {
|
|
1618
|
+
COLLECTION_OPTIONS: "/api/v1/payments/collection-options",
|
|
1619
|
+
paymentStatus: (orderId) => `/api/v1/orders/${orderId}/payment-status`,
|
|
1620
|
+
updateCustomer: (orderId) => `/api/v1/orders/${orderId}/customer`,
|
|
1621
|
+
verifyPayment: (orderId) => `/api/v1/orders/${orderId}/verify-payment`
|
|
1622
|
+
};
|
|
1623
|
+
var CHECKOUT_STATUS_BY_PURCHASE_INTENT_RESOLVE_STATUS = {
|
|
1624
|
+
[chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLVE_STATUS.CONFIRMING]: chunkEV2EVOYS_js.CHECKOUT_STATUS.PROCESSING,
|
|
1625
|
+
[chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLVE_STATUS.POLLING]: chunkEV2EVOYS_js.CHECKOUT_STATUS.POLLING,
|
|
1626
|
+
[chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLVE_STATUS.AWAITING_ACTION]: chunkEV2EVOYS_js.CHECKOUT_STATUS.AWAITING_AUTHORIZATION,
|
|
1627
|
+
[chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLVE_STATUS.REVIEWING_TERMS]: chunkEV2EVOYS_js.CHECKOUT_STATUS.REVIEWING_TERMS,
|
|
1628
|
+
[chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLVE_STATUS.COMPLETED]: chunkEV2EVOYS_js.CHECKOUT_STATUS.FINALIZING,
|
|
1629
|
+
[chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLVE_STATUS.FAILED]: chunkEV2EVOYS_js.CHECKOUT_STATUS.FAILED,
|
|
1630
|
+
[chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLVE_STATUS.OUTCOME_UNKNOWN]: chunkEV2EVOYS_js.CHECKOUT_STATUS.RECOVERING
|
|
1631
|
+
};
|
|
1511
1632
|
function normalizeCollectionOptions(value, expectedCurrency) {
|
|
1512
1633
|
if (!value || typeof value !== "object") return null;
|
|
1513
1634
|
const response = value;
|
|
@@ -1520,39 +1641,44 @@ function normalizeCollectionOptions(value, expectedCurrency) {
|
|
|
1520
1641
|
for (const candidate of response.options) {
|
|
1521
1642
|
if (!candidate || typeof candidate !== "object") continue;
|
|
1522
1643
|
const option = candidate;
|
|
1523
|
-
if (option.method ===
|
|
1524
|
-
if (!seen.has(
|
|
1525
|
-
seen.add(
|
|
1526
|
-
options.push({ method:
|
|
1644
|
+
if (option.method === chunkEV2EVOYS_js.PAYMENT_METHOD.CARD && option.network == null) {
|
|
1645
|
+
if (!seen.has(chunkEV2EVOYS_js.PAYMENT_METHOD.CARD)) {
|
|
1646
|
+
seen.add(chunkEV2EVOYS_js.PAYMENT_METHOD.CARD);
|
|
1647
|
+
options.push({ method: chunkEV2EVOYS_js.PAYMENT_METHOD.CARD, network: null });
|
|
1527
1648
|
}
|
|
1528
1649
|
continue;
|
|
1529
1650
|
}
|
|
1530
|
-
if (option.method !==
|
|
1651
|
+
if (option.method !== chunkEV2EVOYS_js.PAYMENT_METHOD.MOBILE_MONEY || typeof option.network !== "string" || !option.network.trim()) {
|
|
1531
1652
|
continue;
|
|
1532
1653
|
}
|
|
1533
|
-
const network = option.network
|
|
1534
|
-
|
|
1654
|
+
const network = chunkXAUSDMMZ_js.purchaseIntentMobileMoneyNetwork(option.network);
|
|
1655
|
+
if (!network) continue;
|
|
1656
|
+
const key = `${chunkEV2EVOYS_js.PAYMENT_METHOD.MOBILE_MONEY}:${network}`;
|
|
1535
1657
|
if (seen.has(key)) continue;
|
|
1536
1658
|
seen.add(key);
|
|
1537
|
-
options.push({ method:
|
|
1659
|
+
options.push({ method: chunkEV2EVOYS_js.PAYMENT_METHOD.MOBILE_MONEY, network });
|
|
1538
1660
|
}
|
|
1539
1661
|
return { presentment_currency: expectedCurrency, options };
|
|
1540
1662
|
}
|
|
1541
1663
|
var CheckoutService = class {
|
|
1542
1664
|
constructor(client) {
|
|
1543
1665
|
this.client = client;
|
|
1666
|
+
/** Raw checkout material is component-lifetime only, never browser storage. */
|
|
1667
|
+
this.intentCommands = /* @__PURE__ */ new Map();
|
|
1668
|
+
/** Opaque owner/attempt authority for deprecated action submission. */
|
|
1669
|
+
this.actionAuthorities = /* @__PURE__ */ new Map();
|
|
1544
1670
|
}
|
|
1545
1671
|
validateCheckoutData(data) {
|
|
1546
1672
|
if (isOfflinePaymentMethod(data.payment_method)) {
|
|
1547
|
-
return new
|
|
1548
|
-
|
|
1673
|
+
return new chunkSFUJMS5E_js.CimplifyError(
|
|
1674
|
+
chunkSFUJMS5E_js.ErrorCode.INVALID_PAYMENT_METHOD,
|
|
1549
1675
|
"Offline payment isn't available for online checkout. Please pay by card or mobile money.",
|
|
1550
1676
|
false
|
|
1551
1677
|
);
|
|
1552
1678
|
}
|
|
1553
1679
|
if (!isValidCustomerName(data.customer?.name)) {
|
|
1554
|
-
return new
|
|
1555
|
-
|
|
1680
|
+
return new chunkSFUJMS5E_js.CimplifyError(
|
|
1681
|
+
chunkSFUJMS5E_js.ErrorCode.INVALID_CUSTOMER_NAME,
|
|
1556
1682
|
"Enter your name, not a phone number.",
|
|
1557
1683
|
false
|
|
1558
1684
|
);
|
|
@@ -1561,15 +1687,15 @@ var CheckoutService = class {
|
|
|
1561
1687
|
}
|
|
1562
1688
|
orderTokenParam(orderId) {
|
|
1563
1689
|
const token = this.client.getOrderToken(orderId);
|
|
1564
|
-
return token ?
|
|
1690
|
+
return token ? `?${ORDER_TOKEN_QUERY_PARAMETER}=${encodeURIComponent(token)}` : "";
|
|
1565
1691
|
}
|
|
1566
1692
|
/** Available storefront collection methods for one presentment currency. */
|
|
1567
1693
|
async collectionOptions(currency) {
|
|
1568
1694
|
const normalized = currency.trim().toUpperCase();
|
|
1569
|
-
if (!
|
|
1695
|
+
if (!chunkSFUJMS5E_js.isSupportedCurrency(normalized)) {
|
|
1570
1696
|
return err(
|
|
1571
|
-
new
|
|
1572
|
-
|
|
1697
|
+
new chunkSFUJMS5E_js.CimplifyError(
|
|
1698
|
+
chunkSFUJMS5E_js.ErrorCode.UNSUPPORTED_CURRENCY,
|
|
1573
1699
|
"No online payment method is available for this currency.",
|
|
1574
1700
|
false
|
|
1575
1701
|
)
|
|
@@ -1577,72 +1703,201 @@ var CheckoutService = class {
|
|
|
1577
1703
|
}
|
|
1578
1704
|
const response = await safe(
|
|
1579
1705
|
this.client.get(
|
|
1580
|
-
|
|
1706
|
+
`${CHECKOUT_API_ROUTE.COLLECTION_OPTIONS}?currency=${encodeURIComponent(normalized)}`
|
|
1581
1707
|
)
|
|
1582
1708
|
);
|
|
1583
|
-
if (!response.ok) return response;
|
|
1584
|
-
const options = normalizeCollectionOptions(response.value, normalized);
|
|
1585
|
-
return options ? ok(options) : err(
|
|
1586
|
-
new
|
|
1587
|
-
|
|
1588
|
-
"Payment methods could not be verified for this currency.",
|
|
1589
|
-
false
|
|
1590
|
-
)
|
|
1709
|
+
if (!response.ok) return response;
|
|
1710
|
+
const options = normalizeCollectionOptions(response.value, normalized);
|
|
1711
|
+
return options ? ok(options) : err(
|
|
1712
|
+
new chunkSFUJMS5E_js.CimplifyError(
|
|
1713
|
+
chunkSFUJMS5E_js.ErrorCode.PAYMENT_CAPABILITY_MISMATCH,
|
|
1714
|
+
"Payment methods could not be verified for this currency.",
|
|
1715
|
+
false
|
|
1716
|
+
)
|
|
1717
|
+
);
|
|
1718
|
+
}
|
|
1719
|
+
/**
|
|
1720
|
+
* Run provider-owned UI for a backend `card_popup` action. A submitted
|
|
1721
|
+
* outcome is not proof of payment; callers must poll/verify with Cimplify.
|
|
1722
|
+
*/
|
|
1723
|
+
authorizeCardPopup(action, options) {
|
|
1724
|
+
return this.client.authorizationAdapters.authorize(action, options);
|
|
1725
|
+
}
|
|
1726
|
+
async startIntentCheckout(data, options) {
|
|
1727
|
+
const invalid = this.validateCheckoutData(data);
|
|
1728
|
+
if (invalid) return err(invalid);
|
|
1729
|
+
const intentScope = `${CHECKOUT_INTENT_SCOPE_PREFIX}${data.cart_id}`;
|
|
1730
|
+
const inMemoryCommand = JSON.stringify(data);
|
|
1731
|
+
const previousCommand = this.intentCommands.get(intentScope);
|
|
1732
|
+
if (previousCommand !== void 0 && previousCommand !== inMemoryCommand) {
|
|
1733
|
+
clearIntentIdempotencyKey(intentScope);
|
|
1734
|
+
}
|
|
1735
|
+
this.intentCommands.set(intentScope, inMemoryCommand);
|
|
1736
|
+
const clientIntentKey = data.idempotency_key || intentIdempotencyKey(intentScope, CHECKOUT_INTENT_RECOVERY_FINGERPRINT);
|
|
1737
|
+
const checkoutData = { ...data, idempotency_key: clientIntentKey };
|
|
1738
|
+
let mintRequest;
|
|
1739
|
+
try {
|
|
1740
|
+
mintRequest = checkoutFormToIntentRequest(checkoutData, clientIntentKey);
|
|
1741
|
+
} catch (error) {
|
|
1742
|
+
clearIntentIdempotencyKey(intentScope);
|
|
1743
|
+
this.intentCommands.delete(intentScope);
|
|
1744
|
+
return err(
|
|
1745
|
+
error instanceof chunkSFUJMS5E_js.CimplifyError ? error : new chunkSFUJMS5E_js.CimplifyError(
|
|
1746
|
+
chunkSFUJMS5E_js.ErrorCode.CHECKOUT_VALIDATION_FAILED,
|
|
1747
|
+
"Checkout details are invalid.",
|
|
1748
|
+
false
|
|
1749
|
+
)
|
|
1750
|
+
);
|
|
1751
|
+
}
|
|
1752
|
+
const minted = await this.client.purchaseIntents.mint(mintRequest, options);
|
|
1753
|
+
if (!minted.ok) {
|
|
1754
|
+
if (!isAmbiguousCheckoutError(minted.error)) {
|
|
1755
|
+
clearIntentIdempotencyKey(intentScope);
|
|
1756
|
+
this.intentCommands.delete(intentScope);
|
|
1757
|
+
}
|
|
1758
|
+
return minted;
|
|
1759
|
+
}
|
|
1760
|
+
const terms = minted.value.current_terms;
|
|
1761
|
+
if (!terms) {
|
|
1762
|
+
clearIntentIdempotencyKey(intentScope);
|
|
1763
|
+
this.intentCommands.delete(intentScope);
|
|
1764
|
+
return err(
|
|
1765
|
+
new chunkSFUJMS5E_js.CimplifyError(
|
|
1766
|
+
chunkSFUJMS5E_js.ErrorCode.CHECKOUT_TERMS_UNAVAILABLE,
|
|
1767
|
+
"Checkout terms are not available for this purchase intent.",
|
|
1768
|
+
true
|
|
1769
|
+
)
|
|
1770
|
+
);
|
|
1771
|
+
}
|
|
1772
|
+
let paymentOption;
|
|
1773
|
+
try {
|
|
1774
|
+
paymentOption = selectCheckoutPaymentOption(terms, checkoutData);
|
|
1775
|
+
} catch (error) {
|
|
1776
|
+
return err(
|
|
1777
|
+
error instanceof chunkSFUJMS5E_js.CimplifyError ? error : new chunkSFUJMS5E_js.CimplifyError(
|
|
1778
|
+
chunkSFUJMS5E_js.ErrorCode.INVALID_PAYMENT_METHOD,
|
|
1779
|
+
"Payment details are invalid.",
|
|
1780
|
+
false
|
|
1781
|
+
)
|
|
1782
|
+
);
|
|
1783
|
+
}
|
|
1784
|
+
if (!paymentOption && purchaseIntentRequiresPaymentOption(terms)) {
|
|
1785
|
+
return err(
|
|
1786
|
+
new chunkSFUJMS5E_js.CimplifyError(
|
|
1787
|
+
chunkSFUJMS5E_js.ErrorCode.PAYMENT_CAPABILITY_MISMATCH,
|
|
1788
|
+
"The selected payment method is not eligible for these checkout terms.",
|
|
1789
|
+
true
|
|
1790
|
+
)
|
|
1791
|
+
);
|
|
1792
|
+
}
|
|
1793
|
+
const confirmationScope = `${CHECKOUT_CONFIRMATION_SCOPE_PREFIX}${minted.value.id}`;
|
|
1794
|
+
const confirmationFingerprint = JSON.stringify([
|
|
1795
|
+
terms.intent_revision,
|
|
1796
|
+
terms.terms_version,
|
|
1797
|
+
terms.terms_digest,
|
|
1798
|
+
paymentOption?.id ?? null,
|
|
1799
|
+
terms.money.due_now,
|
|
1800
|
+
paymentOption?.customer_debit_amount ?? terms.money.rail_amount,
|
|
1801
|
+
terms.money.currency
|
|
1802
|
+
]);
|
|
1803
|
+
const confirmationKey = intentIdempotencyKey(
|
|
1804
|
+
confirmationScope,
|
|
1805
|
+
confirmationFingerprint
|
|
1806
|
+
);
|
|
1807
|
+
const confirmation = checkoutFormToConfirmation(
|
|
1808
|
+
checkoutData,
|
|
1809
|
+
terms,
|
|
1810
|
+
paymentOption,
|
|
1811
|
+
confirmationKey
|
|
1812
|
+
);
|
|
1813
|
+
const confirmed = await this.client.purchaseIntents.confirm(
|
|
1814
|
+
minted.value.id,
|
|
1815
|
+
confirmation,
|
|
1816
|
+
options
|
|
1591
1817
|
);
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
* outcome is not proof of payment; callers must poll/verify with Cimplify.
|
|
1596
|
-
*/
|
|
1597
|
-
authorizeCardPopup(action, options) {
|
|
1598
|
-
return this.client.authorizationAdapters.authorize(action, options);
|
|
1599
|
-
}
|
|
1600
|
-
async process(data) {
|
|
1601
|
-
const invalid = this.validateCheckoutData(data);
|
|
1602
|
-
if (invalid) {
|
|
1603
|
-
return err(invalid);
|
|
1604
|
-
}
|
|
1605
|
-
const intentScope = `checkout:${data.cart_id}`;
|
|
1606
|
-
const intentFingerprint = JSON.stringify([
|
|
1607
|
-
data.payment_method,
|
|
1608
|
-
data.mobile_money_details,
|
|
1609
|
-
data.pay_currency,
|
|
1610
|
-
data.voucher_code,
|
|
1611
|
-
data.pay_deposit
|
|
1612
|
-
]);
|
|
1613
|
-
const checkoutData = {
|
|
1614
|
-
...data,
|
|
1615
|
-
idempotency_key: data.idempotency_key || intentIdempotencyKey(intentScope, intentFingerprint)
|
|
1616
|
-
};
|
|
1617
|
-
const result = await safe(this.client.post("/api/v1/checkout", checkoutData));
|
|
1618
|
-
if (result.ok) {
|
|
1619
|
-
clearIntentIdempotencyKey(intentScope);
|
|
1620
|
-
if (result.value.bill_token) {
|
|
1621
|
-
this.client.setOrderToken(result.value.order_id, result.value.bill_token);
|
|
1818
|
+
if (!confirmed.ok) {
|
|
1819
|
+
if (!isAmbiguousCheckoutError(confirmed.error)) {
|
|
1820
|
+
clearIntentIdempotencyKey(confirmationScope);
|
|
1622
1821
|
}
|
|
1623
|
-
|
|
1624
|
-
|
|
1822
|
+
return confirmed;
|
|
1823
|
+
}
|
|
1824
|
+
return ok({
|
|
1825
|
+
intentId: minted.value.id,
|
|
1826
|
+
intentScope,
|
|
1827
|
+
confirmationScope,
|
|
1828
|
+
confirmation,
|
|
1829
|
+
initialResponse: confirmed.value,
|
|
1830
|
+
terms
|
|
1831
|
+
});
|
|
1832
|
+
}
|
|
1833
|
+
/** @deprecated Use `client.purchaseIntents.mint()` then `confirm()`. */
|
|
1834
|
+
async process(data, options) {
|
|
1835
|
+
const started = await this.startIntentCheckout(data, options);
|
|
1836
|
+
if (!started.ok) return started;
|
|
1837
|
+
this.reconcileActionAuthority(started.value.initialResponse);
|
|
1838
|
+
const result = confirmationToCheckoutResult(started.value.initialResponse);
|
|
1839
|
+
if (started.value.initialResponse.status === chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.ORDER_CREATED || started.value.initialResponse.status === chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.PAYMENT_FAILED) {
|
|
1840
|
+
clearIntentIdempotencyKey(started.value.intentScope);
|
|
1841
|
+
clearIntentIdempotencyKey(started.value.confirmationScope);
|
|
1842
|
+
this.intentCommands.delete(started.value.intentScope);
|
|
1625
1843
|
}
|
|
1626
1844
|
return result;
|
|
1627
1845
|
}
|
|
1628
1846
|
async initializePayment(_orderId, _method) {
|
|
1629
1847
|
return err(
|
|
1630
|
-
new
|
|
1631
|
-
|
|
1848
|
+
new chunkSFUJMS5E_js.CimplifyError(
|
|
1849
|
+
chunkSFUJMS5E_js.ErrorCode.NOT_IMPLEMENTED,
|
|
1632
1850
|
"initializePayment is not available in REST mode.",
|
|
1633
1851
|
false
|
|
1634
1852
|
)
|
|
1635
1853
|
);
|
|
1636
1854
|
}
|
|
1637
|
-
|
|
1638
|
-
|
|
1855
|
+
/**
|
|
1856
|
+
* @deprecated Use `client.purchaseIntents.submitAction()`. This adapter works
|
|
1857
|
+
* only while this CheckoutService instance retains the opaque authority
|
|
1858
|
+
* returned by its own `process()` call; it never falls back to a payment-id
|
|
1859
|
+
* mutation.
|
|
1860
|
+
*/
|
|
1861
|
+
async submitAuthorization(input, options) {
|
|
1862
|
+
const paymentId = input.payment_id.trim();
|
|
1863
|
+
const authority = this.actionAuthorities.get(paymentId);
|
|
1864
|
+
if (!authority) {
|
|
1865
|
+
return err(
|
|
1866
|
+
new chunkSFUJMS5E_js.CimplifyError(
|
|
1867
|
+
chunkSFUJMS5E_js.ErrorCode.CHECKOUT_AUTHORITY_REQUIRED,
|
|
1868
|
+
"The purchase-intent action authority is unavailable. Restart checkout before submitting authorization.",
|
|
1869
|
+
false
|
|
1870
|
+
)
|
|
1871
|
+
);
|
|
1872
|
+
}
|
|
1873
|
+
const submitted = await this.client.purchaseIntents.submitAction(
|
|
1874
|
+
authority.intentId,
|
|
1875
|
+
authority.attemptId,
|
|
1876
|
+
{ authorization: input.authorization },
|
|
1877
|
+
{
|
|
1878
|
+
signal: options?.signal,
|
|
1879
|
+
timeoutMs: options?.timeoutMs
|
|
1880
|
+
}
|
|
1881
|
+
);
|
|
1882
|
+
if (!submitted.ok) return submitted;
|
|
1883
|
+
this.reconcileActionAuthority(submitted.value, paymentId);
|
|
1884
|
+
return confirmationToCheckoutResult(submitted.value);
|
|
1885
|
+
}
|
|
1886
|
+
reconcileActionAuthority(response, previousPaymentId) {
|
|
1887
|
+
if (previousPaymentId) this.actionAuthorities.delete(previousPaymentId);
|
|
1888
|
+
if ("payment_id" in response && typeof response.payment_id === "string" && response.payment_id.trim()) {
|
|
1889
|
+
this.actionAuthorities.delete(response.payment_id.trim());
|
|
1890
|
+
}
|
|
1891
|
+
const authority = checkoutActionAuthority(response);
|
|
1892
|
+
if (authority) this.actionAuthorities.set(authority.paymentId, authority);
|
|
1639
1893
|
}
|
|
1640
|
-
async pollPaymentStatus(orderId) {
|
|
1894
|
+
async pollPaymentStatus(orderId, options) {
|
|
1641
1895
|
const encodedId = encodeURIComponent(orderId);
|
|
1642
1896
|
const tokenParam = this.orderTokenParam(orderId);
|
|
1643
1897
|
return safe(
|
|
1644
1898
|
this.client.get(
|
|
1645
|
-
|
|
1899
|
+
`${CHECKOUT_API_ROUTE.paymentStatus(encodedId)}${tokenParam}`,
|
|
1900
|
+
options
|
|
1646
1901
|
)
|
|
1647
1902
|
);
|
|
1648
1903
|
}
|
|
@@ -1650,20 +1905,58 @@ var CheckoutService = class {
|
|
|
1650
1905
|
const encodedId = encodeURIComponent(orderId);
|
|
1651
1906
|
const tokenParam = this.orderTokenParam(orderId);
|
|
1652
1907
|
return safe(
|
|
1653
|
-
this.client.post(
|
|
1908
|
+
this.client.post(`${CHECKOUT_API_ROUTE.updateCustomer(encodedId)}${tokenParam}`, customer)
|
|
1654
1909
|
);
|
|
1655
1910
|
}
|
|
1656
1911
|
async verifyPayment(orderId) {
|
|
1657
1912
|
const encodedId = encodeURIComponent(orderId);
|
|
1658
1913
|
const tokenParam = this.orderTokenParam(orderId);
|
|
1659
|
-
return safe(
|
|
1914
|
+
return safe(
|
|
1915
|
+
this.client.post(`${CHECKOUT_API_ROUTE.verifyPayment(encodedId)}${tokenParam}`)
|
|
1916
|
+
);
|
|
1917
|
+
}
|
|
1918
|
+
async maybeEnrollResolvedOrder(orderId, data) {
|
|
1919
|
+
if (data.enroll_in_link === false) return false;
|
|
1920
|
+
const business = await safe(this.client.resolveBusinessId());
|
|
1921
|
+
if (!business.ok) return false;
|
|
1922
|
+
const address = data.address_info.street_address ? {
|
|
1923
|
+
label: "Default",
|
|
1924
|
+
street_address: data.address_info.street_address,
|
|
1925
|
+
apartment: data.address_info.apartment,
|
|
1926
|
+
city: data.address_info.city ?? "",
|
|
1927
|
+
region: data.address_info.region ?? "",
|
|
1928
|
+
postal_code: data.address_info.postal_code,
|
|
1929
|
+
country: data.address_info.country,
|
|
1930
|
+
delivery_instructions: data.address_info.delivery_instructions,
|
|
1931
|
+
phone_for_delivery: data.address_info.phone_for_delivery,
|
|
1932
|
+
latitude: data.address_info.latitude,
|
|
1933
|
+
longitude: data.address_info.longitude
|
|
1934
|
+
} : void 0;
|
|
1935
|
+
const mobileMoney = data.payment_method === chunkEV2EVOYS_js.PAYMENT_METHOD.MOBILE_MONEY && data.mobile_money_details ? {
|
|
1936
|
+
phone_number: data.mobile_money_details.phone_number,
|
|
1937
|
+
provider: data.mobile_money_details.provider,
|
|
1938
|
+
label: "Mobile Money"
|
|
1939
|
+
} : void 0;
|
|
1940
|
+
try {
|
|
1941
|
+
const enrollment = await this.client.link.enrollAndLinkOrder({
|
|
1942
|
+
order_id: orderId,
|
|
1943
|
+
business_id: business.value,
|
|
1944
|
+
order_type: data.order_type,
|
|
1945
|
+
address,
|
|
1946
|
+
mobile_money: mobileMoney
|
|
1947
|
+
});
|
|
1948
|
+
return enrollment.ok && enrollment.value.success;
|
|
1949
|
+
} catch {
|
|
1950
|
+
return false;
|
|
1951
|
+
}
|
|
1660
1952
|
}
|
|
1953
|
+
/** @deprecated Use `client.purchaseIntents.resolve()`. */
|
|
1661
1954
|
async processAndResolve(data) {
|
|
1662
|
-
notifyCheckoutStatus(data.on_status_change,
|
|
1955
|
+
notifyCheckoutStatus(data.on_status_change, chunkEV2EVOYS_js.CHECKOUT_STATUS.PREPARING);
|
|
1663
1956
|
if (!data.cart_id) {
|
|
1664
1957
|
return ok(
|
|
1665
1958
|
toTerminalFailure(
|
|
1666
|
-
|
|
1959
|
+
chunkSFUJMS5E_js.ErrorCode.INVALID_CART,
|
|
1667
1960
|
"A valid cart is required before checkout can start.",
|
|
1668
1961
|
false
|
|
1669
1962
|
)
|
|
@@ -1671,13 +1964,19 @@ var CheckoutService = class {
|
|
|
1671
1964
|
}
|
|
1672
1965
|
const cartResult = await this.client.cart.get();
|
|
1673
1966
|
if (!cartResult.ok || !cartResult.value?.id) {
|
|
1674
|
-
return ok(
|
|
1967
|
+
return ok(
|
|
1968
|
+
toTerminalFailure(
|
|
1969
|
+
chunkSFUJMS5E_js.ErrorCode.INVALID_CART,
|
|
1970
|
+
"Unable to load cart for checkout.",
|
|
1971
|
+
false
|
|
1972
|
+
)
|
|
1973
|
+
);
|
|
1675
1974
|
}
|
|
1676
1975
|
const cart = cartResult.value;
|
|
1677
1976
|
if (cart.id !== data.cart_id || cart.items.length === 0) {
|
|
1678
1977
|
return ok(
|
|
1679
1978
|
toTerminalFailure(
|
|
1680
|
-
|
|
1979
|
+
chunkSFUJMS5E_js.ErrorCode.INVALID_CART,
|
|
1681
1980
|
"Cart is empty or no longer valid. Please refresh and try again.",
|
|
1682
1981
|
false
|
|
1683
1982
|
)
|
|
@@ -1704,10 +2003,10 @@ var CheckoutService = class {
|
|
|
1704
2003
|
pay_deposit: data.pay_deposit
|
|
1705
2004
|
};
|
|
1706
2005
|
const rawBaseCurrency = typeof cart.pricing.currency === "string" ? cart.pricing.currency.trim().toUpperCase() : "";
|
|
1707
|
-
if (!
|
|
2006
|
+
if (!chunkSFUJMS5E_js.isSupportedCurrency(rawBaseCurrency)) {
|
|
1708
2007
|
return ok(
|
|
1709
2008
|
toTerminalFailure(
|
|
1710
|
-
|
|
2009
|
+
chunkSFUJMS5E_js.ErrorCode.UNSUPPORTED_CURRENCY,
|
|
1711
2010
|
"Cart currency is missing or unsupported. Refresh the cart before checkout.",
|
|
1712
2011
|
false
|
|
1713
2012
|
)
|
|
@@ -1715,18 +2014,27 @@ var CheckoutService = class {
|
|
|
1715
2014
|
}
|
|
1716
2015
|
const baseCurrency = rawBaseCurrency;
|
|
1717
2016
|
const payCurrency = data.pay_currency?.trim().toUpperCase();
|
|
1718
|
-
if (payCurrency && !
|
|
2017
|
+
if (payCurrency && !chunkSFUJMS5E_js.isSupportedCurrency(payCurrency)) {
|
|
1719
2018
|
return ok(
|
|
1720
2019
|
toTerminalFailure(
|
|
1721
|
-
|
|
2020
|
+
chunkSFUJMS5E_js.ErrorCode.UNSUPPORTED_CURRENCY,
|
|
1722
2021
|
"Payment currency is unsupported for checkout.",
|
|
1723
2022
|
false
|
|
1724
2023
|
)
|
|
1725
2024
|
);
|
|
1726
2025
|
}
|
|
1727
|
-
const payCurrencyCode = payCurrency &&
|
|
1728
|
-
const
|
|
1729
|
-
if (
|
|
2026
|
+
const payCurrencyCode = payCurrency && chunkSFUJMS5E_js.isSupportedCurrency(payCurrency) ? payCurrency : void 0;
|
|
2027
|
+
const cartTotalSign = decimalSign(cart.pricing.total_price);
|
|
2028
|
+
if (cartTotalSign === null || cartTotalSign < 0) {
|
|
2029
|
+
return ok(
|
|
2030
|
+
toTerminalFailure(
|
|
2031
|
+
chunkSFUJMS5E_js.ErrorCode.CHECKOUT_VALIDATION_FAILED,
|
|
2032
|
+
"Cart total is not a valid non-negative decimal amount.",
|
|
2033
|
+
false
|
|
2034
|
+
)
|
|
2035
|
+
);
|
|
2036
|
+
}
|
|
2037
|
+
if (payCurrencyCode && payCurrencyCode !== baseCurrency && !checkoutData.fx_quote_id && cartTotalSign > 0) {
|
|
1730
2038
|
const fxQuoteResult = await this.client.fx.lockQuote({
|
|
1731
2039
|
from: baseCurrency,
|
|
1732
2040
|
to: payCurrencyCode,
|
|
@@ -1735,7 +2043,7 @@ var CheckoutService = class {
|
|
|
1735
2043
|
if (!fxQuoteResult.ok) {
|
|
1736
2044
|
return ok(
|
|
1737
2045
|
toTerminalFailure(
|
|
1738
|
-
|
|
2046
|
+
chunkSFUJMS5E_js.ErrorCode.FX_QUOTE_FAILED,
|
|
1739
2047
|
fxQuoteResult.error.message || "Unable to lock FX quote for checkout.",
|
|
1740
2048
|
true
|
|
1741
2049
|
)
|
|
@@ -1744,35 +2052,266 @@ var CheckoutService = class {
|
|
|
1744
2052
|
checkoutData.pay_currency = payCurrencyCode;
|
|
1745
2053
|
checkoutData.fx_quote_id = fxQuoteResult.value.id;
|
|
1746
2054
|
}
|
|
1747
|
-
notifyCheckoutStatus(data.on_status_change,
|
|
1748
|
-
const
|
|
1749
|
-
if (!
|
|
2055
|
+
notifyCheckoutStatus(data.on_status_change, chunkEV2EVOYS_js.CHECKOUT_STATUS.PROCESSING);
|
|
2056
|
+
const started = await this.startIntentCheckout(checkoutData, { signal: data.signal });
|
|
2057
|
+
if (!started.ok) {
|
|
1750
2058
|
return ok(
|
|
1751
2059
|
toTerminalFailure(
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
2060
|
+
started.error.code || chunkSFUJMS5E_js.ErrorCode.CHECKOUT_FAILED,
|
|
2061
|
+
started.error.message || "Unable to process checkout.",
|
|
2062
|
+
started.error.retryable ?? true
|
|
2063
|
+
)
|
|
2064
|
+
);
|
|
2065
|
+
}
|
|
2066
|
+
let actionFailure;
|
|
2067
|
+
try {
|
|
2068
|
+
const resolved = await this.client.purchaseIntents.resolve(started.value.intentId, {
|
|
2069
|
+
confirmation: started.value.confirmation,
|
|
2070
|
+
initialResponse: started.value.initialResponse,
|
|
2071
|
+
pollIntervalMs: data.poll_interval_ms,
|
|
2072
|
+
maxPollAttempts: data.max_poll_attempts,
|
|
2073
|
+
signal: data.signal,
|
|
2074
|
+
onStatusChange: (status, response) => {
|
|
2075
|
+
const context = {};
|
|
2076
|
+
if (response && "order_id" in response) context.order_id = response.order_id;
|
|
2077
|
+
if (response?.status === chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.TERMS_CHANGED) {
|
|
2078
|
+
context.replacement_terms = response.replacement;
|
|
2079
|
+
context.terms_deltas = response.deltas;
|
|
2080
|
+
}
|
|
2081
|
+
if (response?.status === chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.SELECTION_UNAVAILABLE) {
|
|
2082
|
+
context.unavailable_lines = response.lines;
|
|
2083
|
+
}
|
|
2084
|
+
const checkoutStatus = CHECKOUT_STATUS_BY_PURCHASE_INTENT_RESOLVE_STATUS[status];
|
|
2085
|
+
notifyCheckoutStatus(data.on_status_change, checkoutStatus, context);
|
|
2086
|
+
},
|
|
2087
|
+
onActionRequired: async (action) => {
|
|
2088
|
+
switch (action.status) {
|
|
2089
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.CARD_POPUP_REQUIRED: {
|
|
2090
|
+
const allowPopups = data.allow_popups ?? typeof window !== "undefined";
|
|
2091
|
+
if (!allowPopups) {
|
|
2092
|
+
actionFailure = {
|
|
2093
|
+
code: chunkSFUJMS5E_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
2094
|
+
message: "Card authorization UI is unavailable in this environment.",
|
|
2095
|
+
recoverable: false
|
|
2096
|
+
};
|
|
2097
|
+
return chunkSFUJMS5E_js.PURCHASE_INTENT_ACTION_DECISION.STOP;
|
|
2098
|
+
}
|
|
2099
|
+
let outcome;
|
|
2100
|
+
try {
|
|
2101
|
+
notifyAuthorizationUi(data.on_authorization_ui_change, true);
|
|
2102
|
+
outcome = await this.authorizeCardPopup(
|
|
2103
|
+
{
|
|
2104
|
+
type: chunkEV2EVOYS_js.CHECKOUT_NEXT_ACTION.CARD_POPUP,
|
|
2105
|
+
provider: action.provider,
|
|
2106
|
+
client_secret: action.client_secret,
|
|
2107
|
+
public_key: action.public_key,
|
|
2108
|
+
provider_account_id: action.provider_account_id ?? void 0
|
|
2109
|
+
},
|
|
2110
|
+
{
|
|
2111
|
+
email: checkoutData.customer.email,
|
|
2112
|
+
currency: started.value.terms.money.currency,
|
|
2113
|
+
returnUrl: data.return_url,
|
|
2114
|
+
signal: data.signal
|
|
2115
|
+
}
|
|
2116
|
+
);
|
|
2117
|
+
} finally {
|
|
2118
|
+
notifyAuthorizationUi(data.on_authorization_ui_change, false);
|
|
2119
|
+
}
|
|
2120
|
+
if (outcome.status === PAYMENT_AUTHORIZATION_OUTCOME_STATUS.SUBMITTED) {
|
|
2121
|
+
return chunkSFUJMS5E_js.PURCHASE_INTENT_ACTION_DECISION.CONTINUE;
|
|
2122
|
+
}
|
|
2123
|
+
actionFailure = outcome.status === PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED ? {
|
|
2124
|
+
code: chunkSFUJMS5E_js.ErrorCode.PAYMENT_CANCELLED,
|
|
2125
|
+
message: "Card payment was cancelled before submission.",
|
|
2126
|
+
recoverable: true
|
|
2127
|
+
} : {
|
|
2128
|
+
code: outcome.code,
|
|
2129
|
+
message: outcome.message,
|
|
2130
|
+
recoverable: outcome.recoverable
|
|
2131
|
+
};
|
|
2132
|
+
return chunkSFUJMS5E_js.PURCHASE_INTENT_ACTION_DECISION.STOP;
|
|
2133
|
+
}
|
|
2134
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.REDIRECT_REQUIRED: {
|
|
2135
|
+
const authorizationUrl = chunkXAUSDMMZ_js.paymentAuthorizationUrl(action.authorization_url);
|
|
2136
|
+
if (!authorizationUrl) {
|
|
2137
|
+
actionFailure = {
|
|
2138
|
+
code: chunkSFUJMS5E_js.ErrorCode.AUTHORIZATION_FAILED,
|
|
2139
|
+
message: "The provider returned an invalid authorization URL.",
|
|
2140
|
+
recoverable: false
|
|
2141
|
+
};
|
|
2142
|
+
return chunkSFUJMS5E_js.PURCHASE_INTENT_ACTION_DECISION.STOP;
|
|
2143
|
+
}
|
|
2144
|
+
if (typeof window !== "undefined") {
|
|
2145
|
+
if (data.allow_popups === false) {
|
|
2146
|
+
window.location.assign(authorizationUrl);
|
|
2147
|
+
} else {
|
|
2148
|
+
const popup = window.open(
|
|
2149
|
+
authorizationUrl,
|
|
2150
|
+
AUTHORIZATION_POPUP_NAME,
|
|
2151
|
+
AUTHORIZATION_POPUP_FEATURES
|
|
2152
|
+
);
|
|
2153
|
+
if (!popup) {
|
|
2154
|
+
actionFailure = {
|
|
2155
|
+
code: chunkSFUJMS5E_js.ErrorCode.POPUP_BLOCKED,
|
|
2156
|
+
message: "Authorization popup was blocked.",
|
|
2157
|
+
recoverable: true
|
|
2158
|
+
};
|
|
2159
|
+
return chunkSFUJMS5E_js.PURCHASE_INTENT_ACTION_DECISION.STOP;
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
actionFailure = {
|
|
2164
|
+
code: chunkSFUJMS5E_js.ErrorCode.REDIRECT_REQUIRED,
|
|
2165
|
+
message: "Complete authorization at the payment provider, then resume checkout.",
|
|
2166
|
+
recoverable: true
|
|
2167
|
+
};
|
|
2168
|
+
return chunkSFUJMS5E_js.PURCHASE_INTENT_ACTION_DECISION.STOP;
|
|
2169
|
+
}
|
|
2170
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.AUTHORIZATION_REQUIRED: {
|
|
2171
|
+
const expected = authorizationKind(action.authorization_type);
|
|
2172
|
+
if (!expected || !data.on_authorization_required) {
|
|
2173
|
+
actionFailure = {
|
|
2174
|
+
code: chunkSFUJMS5E_js.ErrorCode.AUTHORIZATION_REQUIRED,
|
|
2175
|
+
message: "Additional payment authorization is required.",
|
|
2176
|
+
recoverable: true
|
|
2177
|
+
};
|
|
2178
|
+
return chunkSFUJMS5E_js.PURCHASE_INTENT_ACTION_DECISION.STOP;
|
|
2179
|
+
}
|
|
2180
|
+
let submission;
|
|
2181
|
+
await data.on_authorization_required(expected, async (candidate) => {
|
|
2182
|
+
if (submission) throw new Error("Authorization was already submitted.");
|
|
2183
|
+
submission = normalizeAuthorizationSubmission(expected, candidate);
|
|
2184
|
+
});
|
|
2185
|
+
if (!submission) {
|
|
2186
|
+
actionFailure = {
|
|
2187
|
+
code: chunkSFUJMS5E_js.ErrorCode.AUTHORIZATION_REQUIRED,
|
|
2188
|
+
message: "Payment authorization was not submitted.",
|
|
2189
|
+
recoverable: true
|
|
2190
|
+
};
|
|
2191
|
+
return chunkSFUJMS5E_js.PURCHASE_INTENT_ACTION_DECISION.STOP;
|
|
2192
|
+
}
|
|
2193
|
+
return {
|
|
2194
|
+
kind: chunkSFUJMS5E_js.PURCHASE_INTENT_ACTION_DECISION.SUBMIT,
|
|
2195
|
+
request: { authorization: submission }
|
|
2196
|
+
};
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
}
|
|
2200
|
+
});
|
|
2201
|
+
if (!resolved.ok) {
|
|
2202
|
+
return ok(
|
|
2203
|
+
toTerminalFailure(
|
|
2204
|
+
resolved.error.code || chunkSFUJMS5E_js.ErrorCode.CHECKOUT_FAILED,
|
|
2205
|
+
resolved.error.message || "Unable to resolve checkout.",
|
|
2206
|
+
resolved.error.retryable ?? true
|
|
2207
|
+
)
|
|
2208
|
+
);
|
|
2209
|
+
}
|
|
2210
|
+
switch (resolved.value.kind) {
|
|
2211
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLUTION_KIND.COMPLETED: {
|
|
2212
|
+
clearIntentIdempotencyKey(started.value.intentScope);
|
|
2213
|
+
clearIntentIdempotencyKey(started.value.confirmationScope);
|
|
2214
|
+
const response = resolved.value.response;
|
|
2215
|
+
notifyCheckoutStatus(data.on_status_change, chunkEV2EVOYS_js.CHECKOUT_STATUS.FINALIZING, {
|
|
2216
|
+
order_id: response.order_id
|
|
2217
|
+
});
|
|
2218
|
+
const enrolledInLink = await this.maybeEnrollResolvedOrder(response.order_id, data);
|
|
2219
|
+
notifyCheckoutStatus(data.on_status_change, chunkEV2EVOYS_js.CHECKOUT_STATUS.SUCCESS, {
|
|
2220
|
+
order_id: response.order_id
|
|
2221
|
+
});
|
|
2222
|
+
return ok({
|
|
2223
|
+
success: true,
|
|
2224
|
+
order: {
|
|
2225
|
+
id: response.order_id,
|
|
2226
|
+
order_number: response.order_number ?? response.order_id,
|
|
2227
|
+
status: chunkEV2EVOYS_js.CHECKOUT_ORDER_RESULT_STATUS.CONFIRMED,
|
|
2228
|
+
total: String(cart.pricing.total_price),
|
|
2229
|
+
currency: started.value.terms.money.currency
|
|
2230
|
+
},
|
|
2231
|
+
enrolled_in_link: enrolledInLink
|
|
2232
|
+
});
|
|
2233
|
+
}
|
|
2234
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLUTION_KIND.FAILED:
|
|
2235
|
+
clearIntentIdempotencyKey(started.value.confirmationScope);
|
|
2236
|
+
return ok(
|
|
2237
|
+
toTerminalFailure(
|
|
2238
|
+
chunkSFUJMS5E_js.PURCHASE_INTENT_ERROR_CODE.PAYMENT_FAILED,
|
|
2239
|
+
"Payment failed. Choose another method or retry collection.",
|
|
2240
|
+
true
|
|
2241
|
+
)
|
|
2242
|
+
);
|
|
2243
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLUTION_KIND.OUTCOME_UNKNOWN:
|
|
2244
|
+
return ok(
|
|
2245
|
+
toTerminalFailure(
|
|
2246
|
+
chunkSFUJMS5E_js.ErrorCode.PAYMENT_OUTCOME_UNKNOWN,
|
|
2247
|
+
"Payment outcome is still unknown. Resume this intent before retrying.",
|
|
2248
|
+
true
|
|
2249
|
+
)
|
|
2250
|
+
);
|
|
2251
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLUTION_KIND.TIMED_OUT:
|
|
2252
|
+
return ok(
|
|
2253
|
+
toTerminalFailure(
|
|
2254
|
+
chunkSFUJMS5E_js.ErrorCode.TIMEOUT,
|
|
2255
|
+
"Payment is still processing. Resume this intent to continue polling.",
|
|
2256
|
+
true
|
|
2257
|
+
)
|
|
2258
|
+
);
|
|
2259
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLUTION_KIND.ACTION_REQUIRED:
|
|
2260
|
+
return ok(
|
|
2261
|
+
toTerminalFailure(
|
|
2262
|
+
actionFailure?.code ?? chunkSFUJMS5E_js.ErrorCode.AUTHORIZATION_REQUIRED,
|
|
2263
|
+
actionFailure?.message ?? "Checkout requires additional authorization.",
|
|
2264
|
+
actionFailure?.recoverable ?? true
|
|
2265
|
+
)
|
|
2266
|
+
);
|
|
2267
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_RESOLUTION_KIND.REVIEW_REQUIRED: {
|
|
2268
|
+
const response = resolved.value.response;
|
|
2269
|
+
switch (response.status) {
|
|
2270
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.TERMS_CHANGED:
|
|
2271
|
+
return ok(
|
|
2272
|
+
toTerminalFailure(
|
|
2273
|
+
chunkSFUJMS5E_js.PURCHASE_INTENT_ERROR_CODE.TERMS_CHANGED,
|
|
2274
|
+
"Checkout terms changed and require explicit review.",
|
|
2275
|
+
true
|
|
2276
|
+
)
|
|
2277
|
+
);
|
|
2278
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.SELECTION_UNAVAILABLE:
|
|
2279
|
+
return ok(
|
|
2280
|
+
toTerminalFailure(
|
|
2281
|
+
chunkSFUJMS5E_js.PURCHASE_INTENT_ERROR_CODE.SELECTION_UNAVAILABLE,
|
|
2282
|
+
"One or more checkout selections are unavailable.",
|
|
2283
|
+
true
|
|
2284
|
+
)
|
|
2285
|
+
);
|
|
2286
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.OFFER_ENDED:
|
|
2287
|
+
return ok(
|
|
2288
|
+
toTerminalFailure(
|
|
2289
|
+
chunkSFUJMS5E_js.PURCHASE_INTENT_ERROR_CODE.OFFER_ENDED,
|
|
2290
|
+
"This offer has ended.",
|
|
2291
|
+
false
|
|
2292
|
+
)
|
|
2293
|
+
);
|
|
2294
|
+
case chunkSFUJMS5E_js.PURCHASE_INTENT_CONFIRM_STATUS.SOURCE_UNAVAILABLE:
|
|
2295
|
+
return ok(
|
|
2296
|
+
toTerminalFailure(
|
|
2297
|
+
chunkSFUJMS5E_js.PURCHASE_INTENT_ERROR_CODE.SOURCE_UNAVAILABLE,
|
|
2298
|
+
"This purchase source is unavailable.",
|
|
2299
|
+
false
|
|
2300
|
+
)
|
|
2301
|
+
);
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
} catch (error) {
|
|
2306
|
+
const cancelled = data.signal?.aborted || error instanceof Error && error.name === ABORT_ERROR_NAME;
|
|
2307
|
+
return ok(
|
|
2308
|
+
toTerminalFailure(
|
|
2309
|
+
cancelled ? chunkSFUJMS5E_js.ErrorCode.CANCELLED : chunkSFUJMS5E_js.ErrorCode.AUTHORIZATION_FAILED,
|
|
2310
|
+
cancelled ? "Checkout was cancelled." : error instanceof Error ? error.message : "Checkout authorization failed.",
|
|
2311
|
+
true
|
|
1755
2312
|
)
|
|
1756
2313
|
);
|
|
1757
2314
|
}
|
|
1758
|
-
const resolver = new CheckoutResolver({
|
|
1759
|
-
client: this.client,
|
|
1760
|
-
checkoutData,
|
|
1761
|
-
pollIntervalMs: data.poll_interval_ms,
|
|
1762
|
-
maxPollAttempts: data.max_poll_attempts,
|
|
1763
|
-
onStatusChange: data.on_status_change,
|
|
1764
|
-
onAuthorizationUiChange: data.on_authorization_ui_change,
|
|
1765
|
-
onAuthorizationRequired: data.on_authorization_required,
|
|
1766
|
-
signal: data.signal,
|
|
1767
|
-
returnUrl: data.return_url,
|
|
1768
|
-
enrollInLink: data.enroll_in_link,
|
|
1769
|
-
cartTotal: cart.pricing.total_price,
|
|
1770
|
-
cartCurrency: checkoutData.pay_currency || baseCurrency,
|
|
1771
|
-
orderType: checkoutData.order_type,
|
|
1772
|
-
allowPopups: data.allow_popups
|
|
1773
|
-
});
|
|
1774
|
-
const resolved = await resolver.resolve(processResult.value);
|
|
1775
|
-
return ok(resolved);
|
|
1776
2315
|
}
|
|
1777
2316
|
};
|
|
1778
2317
|
|
|
@@ -1835,43 +2374,86 @@ function encodePathSegment(value) {
|
|
|
1835
2374
|
var LinkService = class {
|
|
1836
2375
|
constructor(client) {
|
|
1837
2376
|
this.client = client;
|
|
2377
|
+
this.activationGeneration = 0;
|
|
2378
|
+
}
|
|
2379
|
+
beginActivation() {
|
|
2380
|
+
return {
|
|
2381
|
+
generation: ++this.activationGeneration,
|
|
2382
|
+
sessionEpoch: this.client.getSessionEpoch(),
|
|
2383
|
+
publicKeyEpoch: this.client.getPublicKeyEpoch()
|
|
2384
|
+
};
|
|
2385
|
+
}
|
|
2386
|
+
isActivationFenceCurrent(fence) {
|
|
2387
|
+
return fence.generation === this.activationGeneration && fence.sessionEpoch === this.client.getSessionEpoch() && fence.publicKeyEpoch === this.client.getPublicKeyEpoch();
|
|
2388
|
+
}
|
|
2389
|
+
supersededActivation() {
|
|
2390
|
+
return {
|
|
2391
|
+
ok: false,
|
|
2392
|
+
error: new chunkSFUJMS5E_js.CimplifyError(
|
|
2393
|
+
"session_superseded",
|
|
2394
|
+
"A newer authentication session replaced this one"
|
|
2395
|
+
)
|
|
2396
|
+
};
|
|
2397
|
+
}
|
|
2398
|
+
async activateAuthenticatedSession(result, fence) {
|
|
2399
|
+
if (!result.ok || !result.value.session_token) return result;
|
|
2400
|
+
if (!this.isActivationFenceCurrent(fence)) return this.supersededActivation();
|
|
2401
|
+
const accessToken = result.value.session_token;
|
|
2402
|
+
this.client.setAccessToken(accessToken);
|
|
2403
|
+
const installedSessionEpoch = this.client.getSessionEpoch();
|
|
2404
|
+
if (!this.client.getPublicKey().trim()) {
|
|
2405
|
+
this.client.activity.refreshIdentity();
|
|
2406
|
+
return result;
|
|
2407
|
+
}
|
|
2408
|
+
const claim = await this.client.support.claimConversation();
|
|
2409
|
+
if (fence.generation !== this.activationGeneration || fence.publicKeyEpoch !== this.client.getPublicKeyEpoch() || this.client.getAccessToken() !== accessToken) {
|
|
2410
|
+
return this.supersededActivation();
|
|
2411
|
+
}
|
|
2412
|
+
if (!claim.ok && claim.error.code !== "already_claimed") {
|
|
2413
|
+
if (this.client.getSessionEpoch() !== installedSessionEpoch) {
|
|
2414
|
+
return this.supersededActivation();
|
|
2415
|
+
}
|
|
2416
|
+
if (this.client.hasClaimedSessionAuthority()) {
|
|
2417
|
+
this.client.clearSession();
|
|
2418
|
+
} else {
|
|
2419
|
+
this.client.setAccessToken(null);
|
|
2420
|
+
}
|
|
2421
|
+
return claim;
|
|
2422
|
+
}
|
|
2423
|
+
this.client.activity.refreshIdentity();
|
|
2424
|
+
return result;
|
|
1838
2425
|
}
|
|
1839
2426
|
async requestOtp(input, opts) {
|
|
1840
2427
|
const idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
1841
2428
|
return safe(
|
|
1842
|
-
this.client.linkPost("/v1/link/auth/request-otp", input, {
|
|
2429
|
+
this.client.linkPost("/v1/link/auth/request-otp", input, {
|
|
2430
|
+
idempotencyKey
|
|
2431
|
+
})
|
|
1843
2432
|
);
|
|
1844
2433
|
}
|
|
1845
2434
|
async verifyOtp(input, opts) {
|
|
1846
2435
|
const idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
2436
|
+
const activationFence = opts?.activateSession === false ? null : this.beginActivation();
|
|
1847
2437
|
const { business_id: _ignoredBusinessId, ...body } = input;
|
|
1848
2438
|
const result = await safe(
|
|
1849
2439
|
this.client.linkPost("/v1/link/auth/verify-otp", body, { idempotencyKey })
|
|
1850
2440
|
);
|
|
1851
|
-
|
|
1852
|
-
this.client.setAccessToken(result.value.session_token);
|
|
1853
|
-
this.client.activity.refreshIdentity();
|
|
1854
|
-
this.client.autoClaimChatIdentity();
|
|
1855
|
-
}
|
|
1856
|
-
return result;
|
|
2441
|
+
return activationFence ? this.activateAuthenticatedSession(result, activationFence) : result;
|
|
1857
2442
|
}
|
|
1858
2443
|
async refreshSession(sessionToken, opts) {
|
|
1859
2444
|
const idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
2445
|
+
const activationFence = opts?.activateSession === false ? null : this.beginActivation();
|
|
1860
2446
|
const body = sessionToken ? { session_token: sessionToken } : {};
|
|
1861
2447
|
const result = await safe(
|
|
1862
2448
|
this.client.linkPost("/v1/link/auth/refresh", body, { idempotencyKey })
|
|
1863
2449
|
);
|
|
1864
|
-
|
|
1865
|
-
this.client.setAccessToken(result.value.session_token);
|
|
1866
|
-
this.client.activity.refreshIdentity();
|
|
1867
|
-
this.client.autoClaimChatIdentity();
|
|
1868
|
-
}
|
|
1869
|
-
return result;
|
|
2450
|
+
return activationFence ? this.activateAuthenticatedSession(result, activationFence) : result;
|
|
1870
2451
|
}
|
|
1871
2452
|
async logout() {
|
|
1872
|
-
|
|
2453
|
+
this.activationGeneration += 1;
|
|
2454
|
+
const request = safe(this.client.linkPost("/v1/link/auth/logout"));
|
|
1873
2455
|
this.client.clearSession();
|
|
1874
|
-
return
|
|
2456
|
+
return request;
|
|
1875
2457
|
}
|
|
1876
2458
|
async checkStatus(contact) {
|
|
1877
2459
|
return safe(this.client.linkPost("/v1/link/check-status", { contact }));
|
|
@@ -1917,11 +2499,9 @@ var LinkService = class {
|
|
|
1917
2499
|
async enrollAndLinkOrder(data, opts) {
|
|
1918
2500
|
const idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
1919
2501
|
return safe(
|
|
1920
|
-
this.client.linkPost(
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
{ idempotencyKey }
|
|
1924
|
-
)
|
|
2502
|
+
this.client.linkPost("/v1/link/enroll-and-link-order", data, {
|
|
2503
|
+
idempotencyKey
|
|
2504
|
+
})
|
|
1925
2505
|
);
|
|
1926
2506
|
}
|
|
1927
2507
|
async updatePreferences(preferences) {
|
|
@@ -2090,7 +2670,7 @@ var BusinessService = class {
|
|
|
2090
2670
|
if (!result.ok) return err(result.error);
|
|
2091
2671
|
const location = result.value.find((item) => item.id === locationId);
|
|
2092
2672
|
if (!location) {
|
|
2093
|
-
return err(new
|
|
2673
|
+
return err(new chunkSFUJMS5E_js.CimplifyError(chunkSFUJMS5E_js.ErrorCode.NOT_FOUND, `Location not found: ${locationId}`, false));
|
|
2094
2674
|
}
|
|
2095
2675
|
return ok(location);
|
|
2096
2676
|
}
|
|
@@ -2344,6 +2924,7 @@ var MESSAGE_TYPES = {
|
|
|
2344
2924
|
INIT: "init",
|
|
2345
2925
|
SET_TOKEN: "set_token",
|
|
2346
2926
|
SET_SESSION: "set_session",
|
|
2927
|
+
SESSION_CLEARED: "session_cleared",
|
|
2347
2928
|
SET_CART: "set_cart",
|
|
2348
2929
|
GET_DATA: "get_data",
|
|
2349
2930
|
NAVIGATE: "navigate",
|
|
@@ -2360,9 +2941,13 @@ var MESSAGE_TYPES = {
|
|
|
2360
2941
|
LOGOUT_COMPLETE: "logout_complete",
|
|
2361
2942
|
AUTH_REQUESTED: "auth_requested",
|
|
2362
2943
|
SESSION_ESTABLISHED: "session_established",
|
|
2944
|
+
SESSION_ESTABLISHMENT_FAILED: "session_establishment_failed",
|
|
2945
|
+
CONTINUE_WITHOUT_SAVED_DETAILS: "continue_without_saved_details",
|
|
2363
2946
|
CONTACT_PROVIDED: "contact_provided",
|
|
2364
2947
|
CHECKOUT_STATUS: "checkout_status",
|
|
2365
2948
|
CHECKOUT_COMPLETE: "checkout_complete",
|
|
2949
|
+
TERMS_CHANGED: "terms_changed",
|
|
2950
|
+
SELECTION_UNAVAILABLE: "selection_unavailable",
|
|
2366
2951
|
ORDER_TYPE_CHANGED: "order_type_changed",
|
|
2367
2952
|
REQUEST_SUBMIT: "request_submit"
|
|
2368
2953
|
};
|
|
@@ -2710,7 +3295,7 @@ function startRedirectSignIn(opts, authorizeEndpoint, pkce, state) {
|
|
|
2710
3295
|
|
|
2711
3296
|
// src/elements.ts
|
|
2712
3297
|
function toCheckoutError(code, message, recoverable) {
|
|
2713
|
-
const hint =
|
|
3298
|
+
const hint = chunkSFUJMS5E_js.getErrorHint(code);
|
|
2714
3299
|
return {
|
|
2715
3300
|
success: false,
|
|
2716
3301
|
error: {
|
|
@@ -2723,6 +3308,7 @@ function toCheckoutError(code, message, recoverable) {
|
|
|
2723
3308
|
};
|
|
2724
3309
|
}
|
|
2725
3310
|
var DEFAULT_LINK_URL = "https://link.cimplify.io";
|
|
3311
|
+
var AUTH_ESTABLISHMENT_WAIT_MS = 8e3;
|
|
2726
3312
|
var AUTH_CONTACT_TYPES = new Set(Object.values(ELEMENTS_AUTH_CONTACT_TYPES));
|
|
2727
3313
|
var AUTH_MODES = new Set(Object.values(ELEMENTS_AUTH_MODES));
|
|
2728
3314
|
var AUTH_PROMPTS = new Set(Object.values(ELEMENTS_AUTH_PROMPTS));
|
|
@@ -2773,6 +3359,7 @@ var KNOWN_IFRAME_TYPES = /* @__PURE__ */ new Set([
|
|
|
2773
3359
|
MESSAGE_TYPES.HEIGHT_CHANGE,
|
|
2774
3360
|
MESSAGE_TYPES.AUTH_REQUESTED,
|
|
2775
3361
|
MESSAGE_TYPES.SESSION_ESTABLISHED,
|
|
3362
|
+
MESSAGE_TYPES.CONTINUE_WITHOUT_SAVED_DETAILS,
|
|
2776
3363
|
MESSAGE_TYPES.ERROR,
|
|
2777
3364
|
MESSAGE_TYPES.ADDRESS_CHANGED,
|
|
2778
3365
|
MESSAGE_TYPES.ADDRESS_SELECTED,
|
|
@@ -2781,6 +3368,8 @@ var KNOWN_IFRAME_TYPES = /* @__PURE__ */ new Set([
|
|
|
2781
3368
|
MESSAGE_TYPES.LOGOUT_COMPLETE,
|
|
2782
3369
|
MESSAGE_TYPES.CHECKOUT_STATUS,
|
|
2783
3370
|
MESSAGE_TYPES.CHECKOUT_COMPLETE,
|
|
3371
|
+
MESSAGE_TYPES.TERMS_CHANGED,
|
|
3372
|
+
MESSAGE_TYPES.SELECTION_UNAVAILABLE,
|
|
2784
3373
|
MESSAGE_TYPES.ORDER_TYPE_CHANGED,
|
|
2785
3374
|
MESSAGE_TYPES.REQUEST_SUBMIT
|
|
2786
3375
|
]);
|
|
@@ -2817,6 +3406,7 @@ function parseIframeMessage(data) {
|
|
|
2817
3406
|
if (!record.method || typeof record.method !== "object") return null;
|
|
2818
3407
|
break;
|
|
2819
3408
|
case MESSAGE_TYPES.CONTACT_PROVIDED:
|
|
3409
|
+
case MESSAGE_TYPES.CONTINUE_WITHOUT_SAVED_DETAILS:
|
|
2820
3410
|
if (typeof record.contact !== "string" || typeof record.contactType !== "string") return null;
|
|
2821
3411
|
break;
|
|
2822
3412
|
case MESSAGE_TYPES.ERROR:
|
|
@@ -2826,7 +3416,15 @@ function parseIframeMessage(data) {
|
|
|
2826
3416
|
if (typeof record.success !== "boolean") return null;
|
|
2827
3417
|
break;
|
|
2828
3418
|
case MESSAGE_TYPES.CHECKOUT_STATUS:
|
|
2829
|
-
if (typeof record.status !== "string" || !record.context || typeof record.context !== "object")
|
|
3419
|
+
if (typeof record.status !== "string" || !record.context || typeof record.context !== "object")
|
|
3420
|
+
return null;
|
|
3421
|
+
break;
|
|
3422
|
+
case MESSAGE_TYPES.TERMS_CHANGED:
|
|
3423
|
+
if (typeof record.intent_id !== "string" || !record.replacement || typeof record.replacement !== "object" || !Array.isArray(record.deltas))
|
|
3424
|
+
return null;
|
|
3425
|
+
break;
|
|
3426
|
+
case MESSAGE_TYPES.SELECTION_UNAVAILABLE:
|
|
3427
|
+
if (typeof record.intent_id !== "string" || !Array.isArray(record.lines)) return null;
|
|
2830
3428
|
break;
|
|
2831
3429
|
case MESSAGE_TYPES.READY:
|
|
2832
3430
|
case MESSAGE_TYPES.HEIGHT_CHANGE:
|
|
@@ -2849,6 +3447,8 @@ var CimplifyElements = class {
|
|
|
2849
3447
|
this.paymentData = null;
|
|
2850
3448
|
this.checkoutInProgress = false;
|
|
2851
3449
|
this.authInProgress = false;
|
|
3450
|
+
this.authEstablishmentInProgress = false;
|
|
3451
|
+
this.authGeneration = 0;
|
|
2852
3452
|
this.activeCheckoutAbort = null;
|
|
2853
3453
|
this.businessIdResolvePromise = null;
|
|
2854
3454
|
this.client = client;
|
|
@@ -2883,6 +3483,12 @@ var CimplifyElements = class {
|
|
|
2883
3483
|
}
|
|
2884
3484
|
}
|
|
2885
3485
|
destroy() {
|
|
3486
|
+
this.authGeneration += 1;
|
|
3487
|
+
if (this.authEstablishmentInProgress) {
|
|
3488
|
+
this.client.setAccessToken(null);
|
|
3489
|
+
}
|
|
3490
|
+
this.authInProgress = false;
|
|
3491
|
+
this.authEstablishmentInProgress = false;
|
|
2886
3492
|
this.elements.forEach((element) => element.destroy());
|
|
2887
3493
|
this.elements.clear();
|
|
2888
3494
|
if (typeof window !== "undefined") {
|
|
@@ -2892,7 +3498,10 @@ var CimplifyElements = class {
|
|
|
2892
3498
|
async submitCheckout(data) {
|
|
2893
3499
|
const result = await this.processCheckout({
|
|
2894
3500
|
cart_id: data.cart_id,
|
|
2895
|
-
|
|
3501
|
+
intent_id: data.intent_id,
|
|
3502
|
+
hosted_session_id: data.hosted_session_id,
|
|
3503
|
+
initial_terms: data.initial_terms,
|
|
3504
|
+
order_type: data.order_type ?? chunkEV2EVOYS_js.ORDER_TYPE.DELIVERY,
|
|
2896
3505
|
location_id: data.location_id,
|
|
2897
3506
|
notes: data.notes,
|
|
2898
3507
|
scheduled_time: data.scheduled_time,
|
|
@@ -2904,7 +3513,7 @@ var CimplifyElements = class {
|
|
|
2904
3513
|
success: true,
|
|
2905
3514
|
order: {
|
|
2906
3515
|
id: result.order?.id || "",
|
|
2907
|
-
status: result.order?.status ||
|
|
3516
|
+
status: result.order?.status || chunkEV2EVOYS_js.CHECKOUT_ORDER_RESULT_STATUS.UNKNOWN,
|
|
2908
3517
|
total: result.order?.total || ""
|
|
2909
3518
|
}
|
|
2910
3519
|
};
|
|
@@ -2912,7 +3521,7 @@ var CimplifyElements = class {
|
|
|
2912
3521
|
return {
|
|
2913
3522
|
success: false,
|
|
2914
3523
|
error: {
|
|
2915
|
-
code: result.error?.code ||
|
|
3524
|
+
code: result.error?.code || chunkSFUJMS5E_js.ErrorCode.CHECKOUT_FAILED,
|
|
2916
3525
|
message: result.error?.message || "Checkout failed"
|
|
2917
3526
|
}
|
|
2918
3527
|
};
|
|
@@ -2920,22 +3529,39 @@ var CimplifyElements = class {
|
|
|
2920
3529
|
processCheckout(options) {
|
|
2921
3530
|
let abortFn = null;
|
|
2922
3531
|
const task = (async () => {
|
|
2923
|
-
this.debug("[cimplify:checkout] processCheckout called", {
|
|
3532
|
+
this.debug("[cimplify:checkout] processCheckout called", {
|
|
3533
|
+
cart_id: options.cart_id,
|
|
3534
|
+
intent_id: options.intent_id,
|
|
3535
|
+
hosted_session_id: options.hosted_session_id,
|
|
3536
|
+
order_type: options.order_type,
|
|
3537
|
+
location_id: options.location_id
|
|
3538
|
+
});
|
|
2924
3539
|
if (this.checkoutInProgress) {
|
|
2925
3540
|
this.debug("[cimplify:checkout] BLOCKED: already processing");
|
|
2926
3541
|
return toCheckoutError(
|
|
2927
|
-
|
|
3542
|
+
chunkSFUJMS5E_js.ErrorCode.ALREADY_PROCESSING,
|
|
2928
3543
|
"Checkout is already in progress.",
|
|
2929
3544
|
false
|
|
2930
3545
|
);
|
|
2931
3546
|
}
|
|
2932
3547
|
this.checkoutInProgress = true;
|
|
2933
|
-
if (
|
|
2934
|
-
this.
|
|
3548
|
+
if (this.authEstablishmentInProgress) {
|
|
3549
|
+
await this.waitForAuthEstablishment(AUTH_ESTABLISHMENT_WAIT_MS);
|
|
3550
|
+
if (this.authEstablishmentInProgress) {
|
|
3551
|
+
this.checkoutInProgress = false;
|
|
3552
|
+
return toCheckoutError(
|
|
3553
|
+
chunkSFUJMS5E_js.ErrorCode.AUTH_INCOMPLETE,
|
|
3554
|
+
"Authentication must finish establishing the checkout session.",
|
|
3555
|
+
true
|
|
3556
|
+
);
|
|
3557
|
+
}
|
|
3558
|
+
}
|
|
3559
|
+
if (!options.cart_id && !options.intent_id) {
|
|
3560
|
+
this.debug("[cimplify:checkout] BLOCKED: no cart_id or intent_id");
|
|
2935
3561
|
this.checkoutInProgress = false;
|
|
2936
3562
|
return toCheckoutError(
|
|
2937
|
-
|
|
2938
|
-
"A
|
|
3563
|
+
chunkSFUJMS5E_js.ErrorCode.CHECKOUT_AUTHORITY_REQUIRED,
|
|
3564
|
+
"A cart or existing purchase intent is required before checkout can start.",
|
|
2939
3565
|
false
|
|
2940
3566
|
);
|
|
2941
3567
|
}
|
|
@@ -2943,7 +3569,7 @@ var CimplifyElements = class {
|
|
|
2943
3569
|
this.debug("[cimplify:checkout] BLOCKED: no order_type");
|
|
2944
3570
|
this.checkoutInProgress = false;
|
|
2945
3571
|
return toCheckoutError(
|
|
2946
|
-
|
|
3572
|
+
chunkSFUJMS5E_js.ErrorCode.ORDER_TYPE_REQUIRED,
|
|
2947
3573
|
"Order type is required before checkout can start.",
|
|
2948
3574
|
false
|
|
2949
3575
|
);
|
|
@@ -2953,7 +3579,7 @@ var CimplifyElements = class {
|
|
|
2953
3579
|
this.debug("[cimplify:checkout] BLOCKED: no checkout element");
|
|
2954
3580
|
this.checkoutInProgress = false;
|
|
2955
3581
|
return toCheckoutError(
|
|
2956
|
-
|
|
3582
|
+
chunkSFUJMS5E_js.ErrorCode.NO_PAYMENT_ELEMENT,
|
|
2957
3583
|
"Checkout element must be mounted before checkout.",
|
|
2958
3584
|
false
|
|
2959
3585
|
);
|
|
@@ -2962,7 +3588,7 @@ var CimplifyElements = class {
|
|
|
2962
3588
|
this.debug("[cimplify:checkout] BLOCKED: checkout element not mounted");
|
|
2963
3589
|
this.checkoutInProgress = false;
|
|
2964
3590
|
return toCheckoutError(
|
|
2965
|
-
|
|
3591
|
+
chunkSFUJMS5E_js.ErrorCode.PAYMENT_NOT_MOUNTED,
|
|
2966
3592
|
"Checkout element must be mounted before checkout.",
|
|
2967
3593
|
false
|
|
2968
3594
|
);
|
|
@@ -2974,7 +3600,7 @@ var CimplifyElements = class {
|
|
|
2974
3600
|
this.debug("[cimplify:checkout] BLOCKED: auth incomplete");
|
|
2975
3601
|
this.checkoutInProgress = false;
|
|
2976
3602
|
return toCheckoutError(
|
|
2977
|
-
|
|
3603
|
+
chunkSFUJMS5E_js.ErrorCode.AUTH_INCOMPLETE,
|
|
2978
3604
|
"Authentication must complete before checkout can start.",
|
|
2979
3605
|
true
|
|
2980
3606
|
);
|
|
@@ -2987,10 +3613,19 @@ var CimplifyElements = class {
|
|
|
2987
3613
|
}
|
|
2988
3614
|
await this.hydrateCustomerData();
|
|
2989
3615
|
}
|
|
2990
|
-
this.debug("[cimplify:checkout] customer data hydrated", {
|
|
3616
|
+
this.debug("[cimplify:checkout] customer data hydrated", {
|
|
3617
|
+
customerData: this.customerData,
|
|
3618
|
+
accountId: this.accountId,
|
|
3619
|
+
isUnifiedCheckout
|
|
3620
|
+
});
|
|
2991
3621
|
const processMessage = {
|
|
2992
3622
|
type: MESSAGE_TYPES.PROCESS_CHECKOUT,
|
|
2993
|
-
|
|
3623
|
+
// Existing intent authority wins if a compatibility caller supplied
|
|
3624
|
+
// both values; the iframe must never mint a replacement.
|
|
3625
|
+
cart_id: options.intent_id ? void 0 : options.cart_id,
|
|
3626
|
+
intent_id: options.intent_id,
|
|
3627
|
+
hosted_session_id: options.hosted_session_id,
|
|
3628
|
+
initial_terms: options.intent_id ? options.initial_terms : void 0,
|
|
2994
3629
|
order_type: options.order_type,
|
|
2995
3630
|
location_id: options.location_id,
|
|
2996
3631
|
notes: options.notes,
|
|
@@ -3029,7 +3664,7 @@ var CimplifyElements = class {
|
|
|
3029
3664
|
const timeout = setTimeout(() => {
|
|
3030
3665
|
settle(
|
|
3031
3666
|
toCheckoutError(
|
|
3032
|
-
|
|
3667
|
+
chunkSFUJMS5E_js.ErrorCode.TIMEOUT,
|
|
3033
3668
|
"Checkout timed out before receiving a terminal response.",
|
|
3034
3669
|
true
|
|
3035
3670
|
)
|
|
@@ -3050,8 +3685,26 @@ var CimplifyElements = class {
|
|
|
3050
3685
|
options.on_status_change?.(message.status, message.context);
|
|
3051
3686
|
return;
|
|
3052
3687
|
}
|
|
3688
|
+
if (message.type === MESSAGE_TYPES.TERMS_CHANGED) {
|
|
3689
|
+
options.on_status_change?.(chunkEV2EVOYS_js.CHECKOUT_STATUS.REVIEWING_TERMS, {
|
|
3690
|
+
intent_id: message.intent_id,
|
|
3691
|
+
replacement_terms: message.replacement,
|
|
3692
|
+
terms_deltas: message.deltas
|
|
3693
|
+
});
|
|
3694
|
+
return;
|
|
3695
|
+
}
|
|
3696
|
+
if (message.type === MESSAGE_TYPES.SELECTION_UNAVAILABLE) {
|
|
3697
|
+
options.on_status_change?.(chunkEV2EVOYS_js.CHECKOUT_STATUS.REVIEWING_TERMS, {
|
|
3698
|
+
intent_id: message.intent_id,
|
|
3699
|
+
unavailable_lines: message.lines
|
|
3700
|
+
});
|
|
3701
|
+
return;
|
|
3702
|
+
}
|
|
3053
3703
|
if (message.type === MESSAGE_TYPES.CHECKOUT_COMPLETE) {
|
|
3054
|
-
this.debug("[cimplify:checkout] received checkout_complete", {
|
|
3704
|
+
this.debug("[cimplify:checkout] received checkout_complete", {
|
|
3705
|
+
success: message.success,
|
|
3706
|
+
error: message.error
|
|
3707
|
+
});
|
|
3055
3708
|
settle({
|
|
3056
3709
|
success: message.success,
|
|
3057
3710
|
order: message.order,
|
|
@@ -3063,7 +3716,7 @@ var CimplifyElements = class {
|
|
|
3063
3716
|
checkoutElement.sendMessage({ type: MESSAGE_TYPES.ABORT_CHECKOUT });
|
|
3064
3717
|
settle(
|
|
3065
3718
|
toCheckoutError(
|
|
3066
|
-
|
|
3719
|
+
chunkSFUJMS5E_js.ErrorCode.AUTH_LOST,
|
|
3067
3720
|
"Authentication was cleared during checkout.",
|
|
3068
3721
|
true
|
|
3069
3722
|
)
|
|
@@ -3075,16 +3728,18 @@ var CimplifyElements = class {
|
|
|
3075
3728
|
}
|
|
3076
3729
|
abortFn = () => {
|
|
3077
3730
|
checkoutElement.sendMessage({ type: MESSAGE_TYPES.ABORT_CHECKOUT });
|
|
3078
|
-
settle(
|
|
3079
|
-
toCheckoutError(
|
|
3080
|
-
"CANCELLED",
|
|
3081
|
-
"Checkout was cancelled.",
|
|
3082
|
-
true
|
|
3083
|
-
)
|
|
3084
|
-
);
|
|
3731
|
+
settle(toCheckoutError(chunkSFUJMS5E_js.ErrorCode.CANCELLED, "Checkout was cancelled.", true));
|
|
3085
3732
|
};
|
|
3086
3733
|
this.activeCheckoutAbort = abortFn;
|
|
3087
|
-
this.debug("[cimplify:checkout] sending process_checkout to checkout iframe", {
|
|
3734
|
+
this.debug("[cimplify:checkout] sending process_checkout to checkout iframe", {
|
|
3735
|
+
cart_id: processMessage.cart_id,
|
|
3736
|
+
intent_id: processMessage.intent_id,
|
|
3737
|
+
hosted_session_id: processMessage.hosted_session_id,
|
|
3738
|
+
order_type: processMessage.order_type,
|
|
3739
|
+
hasCustomer: !!processMessage.customer,
|
|
3740
|
+
hasAddress: !!processMessage.address,
|
|
3741
|
+
isUnifiedCheckout
|
|
3742
|
+
});
|
|
3088
3743
|
checkoutElement.sendMessage(processMessage);
|
|
3089
3744
|
this.debug("[cimplify:checkout] postMessage sent, waiting for checkout_complete...");
|
|
3090
3745
|
});
|
|
@@ -3130,11 +3785,16 @@ var CimplifyElements = class {
|
|
|
3130
3785
|
getAppearance() {
|
|
3131
3786
|
return this.options.appearance;
|
|
3132
3787
|
}
|
|
3133
|
-
|
|
3134
|
-
|
|
3788
|
+
isAuthGenerationCurrent(generation, token) {
|
|
3789
|
+
return this.authGeneration === generation && this.client.getAccessToken() === token;
|
|
3790
|
+
}
|
|
3791
|
+
async hydrateCustomerData(generation = this.authGeneration, token = this.accessToken, force = false) {
|
|
3792
|
+
if (!token || !this.isAuthGenerationCurrent(generation, token)) return false;
|
|
3793
|
+
if (this.customerData && !force) return true;
|
|
3135
3794
|
const linkDataResult = await this.client.link.getLinkData();
|
|
3795
|
+
if (!this.isAuthGenerationCurrent(generation, token)) return false;
|
|
3136
3796
|
if (!linkDataResult.ok || !linkDataResult.value?.customer) {
|
|
3137
|
-
return;
|
|
3797
|
+
return true;
|
|
3138
3798
|
}
|
|
3139
3799
|
const customer = linkDataResult.value.customer;
|
|
3140
3800
|
this.customerData = {
|
|
@@ -3143,6 +3803,7 @@ var CimplifyElements = class {
|
|
|
3143
3803
|
phone: customer.phone || null
|
|
3144
3804
|
};
|
|
3145
3805
|
this.customerId = customer.id;
|
|
3806
|
+
return true;
|
|
3146
3807
|
}
|
|
3147
3808
|
sourceElementFor(event, message) {
|
|
3148
3809
|
for (const element of this.elements.values()) {
|
|
@@ -3181,48 +3842,123 @@ var CimplifyElements = class {
|
|
|
3181
3842
|
} catch {
|
|
3182
3843
|
}
|
|
3183
3844
|
}
|
|
3845
|
+
clearClaimedAuthorityAfterRestoreFailure() {
|
|
3846
|
+
if (!this.client.getAccessToken() && !this.client.hasClaimedSessionAuthority()) return;
|
|
3847
|
+
this.accessToken = null;
|
|
3848
|
+
this.accountId = null;
|
|
3849
|
+
this.customerId = null;
|
|
3850
|
+
this.customerData = null;
|
|
3851
|
+
this.addressData = null;
|
|
3852
|
+
this.paymentData = null;
|
|
3853
|
+
this.authEstablishmentInProgress = false;
|
|
3854
|
+
this.client.clearSession();
|
|
3855
|
+
this.broadcastClearedSession();
|
|
3856
|
+
}
|
|
3184
3857
|
async restoreSession() {
|
|
3185
3858
|
if (typeof window === "undefined" || this.accessToken) return;
|
|
3859
|
+
const generation = ++this.authGeneration;
|
|
3186
3860
|
const storageKey = this.sessionStorageKey();
|
|
3187
3861
|
if (!storageKey) return;
|
|
3188
3862
|
let refreshToken = null;
|
|
3189
3863
|
try {
|
|
3190
3864
|
refreshToken = window.localStorage.getItem(storageKey);
|
|
3191
3865
|
} catch {
|
|
3866
|
+
this.clearClaimedAuthorityAfterRestoreFailure();
|
|
3192
3867
|
return;
|
|
3193
3868
|
}
|
|
3194
|
-
if (!refreshToken)
|
|
3195
|
-
|
|
3869
|
+
if (!refreshToken) {
|
|
3870
|
+
this.clearClaimedAuthorityAfterRestoreFailure();
|
|
3871
|
+
return;
|
|
3872
|
+
}
|
|
3873
|
+
const result = await this.client.link.refreshSession(refreshToken, {
|
|
3874
|
+
activateSession: false
|
|
3875
|
+
});
|
|
3876
|
+
if (this.authGeneration !== generation) return;
|
|
3196
3877
|
if (!result.ok || !result.value.session_token) {
|
|
3197
3878
|
this.clearPersistedSession();
|
|
3879
|
+
this.clearClaimedAuthorityAfterRestoreFailure();
|
|
3198
3880
|
return;
|
|
3199
3881
|
}
|
|
3200
3882
|
this.persistRefreshToken(result.value.refresh_token ?? void 0);
|
|
3201
|
-
const
|
|
3202
|
-
|
|
3203
|
-
|
|
3883
|
+
const application = await this.applyAccessToken(result.value.session_token, generation);
|
|
3884
|
+
if (application.kind === "claim_failed") {
|
|
3885
|
+
this.clearPersistedSession();
|
|
3886
|
+
this.broadcastClearedSession();
|
|
3887
|
+
return;
|
|
3888
|
+
}
|
|
3889
|
+
if (application.kind !== "authenticated" || !this.broadcastAccessToken(result.value.session_token, generation)) {
|
|
3890
|
+
return;
|
|
3891
|
+
}
|
|
3892
|
+
this.elements.forEach((element) => element._emitAuthenticated(application.data));
|
|
3204
3893
|
}
|
|
3205
|
-
async applyAccessToken(token) {
|
|
3894
|
+
async applyAccessToken(token, generation) {
|
|
3895
|
+
if (this.authGeneration !== generation) return { kind: "incomplete" };
|
|
3896
|
+
this.authEstablishmentInProgress = true;
|
|
3897
|
+
this.accessToken = null;
|
|
3898
|
+
this.accountId = null;
|
|
3899
|
+
this.customerId = null;
|
|
3900
|
+
this.customerData = null;
|
|
3901
|
+
this.addressData = null;
|
|
3902
|
+
this.paymentData = null;
|
|
3903
|
+
this.client.setAccessToken(token);
|
|
3904
|
+
const claim = await this.client.support.claimConversation();
|
|
3905
|
+
if (!this.isAuthGenerationCurrent(generation, token)) return { kind: "incomplete" };
|
|
3906
|
+
if (!claim.ok && claim.error.code !== "already_claimed") {
|
|
3907
|
+
if (this.client.hasClaimedSessionAuthority()) {
|
|
3908
|
+
this.client.clearSession();
|
|
3909
|
+
} else {
|
|
3910
|
+
this.client.setAccessToken(null);
|
|
3911
|
+
}
|
|
3912
|
+
this.authEstablishmentInProgress = false;
|
|
3913
|
+
return {
|
|
3914
|
+
kind: "claim_failed",
|
|
3915
|
+
code: claim.error.code,
|
|
3916
|
+
message: claim.error.userMessage
|
|
3917
|
+
};
|
|
3918
|
+
}
|
|
3206
3919
|
this.accessToken = token;
|
|
3207
3920
|
this.accountId = decodeJwtSub(token);
|
|
3208
|
-
this.
|
|
3209
|
-
|
|
3210
|
-
|
|
3921
|
+
if (!await this.hydrateCustomerData(generation, token, true)) {
|
|
3922
|
+
return { kind: "incomplete" };
|
|
3923
|
+
}
|
|
3924
|
+
if (!this.isAuthGenerationCurrent(generation, token)) return { kind: "incomplete" };
|
|
3925
|
+
this.authEstablishmentInProgress = false;
|
|
3211
3926
|
return {
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3927
|
+
kind: "authenticated",
|
|
3928
|
+
data: {
|
|
3929
|
+
accountId: this.accountId ?? "",
|
|
3930
|
+
customerId: this.customerId ?? "",
|
|
3931
|
+
token,
|
|
3932
|
+
customer: this.customerData ?? { name: "", email: null, phone: null }
|
|
3933
|
+
}
|
|
3216
3934
|
};
|
|
3217
3935
|
}
|
|
3218
|
-
|
|
3936
|
+
async waitForAuthEstablishment(timeoutMs) {
|
|
3937
|
+
const deadline = Date.now() + timeoutMs;
|
|
3938
|
+
while (this.authEstablishmentInProgress && Date.now() < deadline) {
|
|
3939
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
3940
|
+
}
|
|
3941
|
+
}
|
|
3942
|
+
broadcastAccessToken(token, generation) {
|
|
3943
|
+
if (!this.isAuthGenerationCurrent(generation, token) || this.accessToken !== token || this.authEstablishmentInProgress) {
|
|
3944
|
+
return false;
|
|
3945
|
+
}
|
|
3219
3946
|
const sessionToken = this.client.getSessionToken();
|
|
3220
3947
|
this.elements.forEach((element) => {
|
|
3221
|
-
element.sendMessage({ type: MESSAGE_TYPES.SET_TOKEN, token });
|
|
3222
3948
|
if (sessionToken) {
|
|
3223
3949
|
element.sendMessage({ type: MESSAGE_TYPES.SET_SESSION, sessionToken });
|
|
3224
3950
|
}
|
|
3951
|
+
element.sendMessage({ type: MESSAGE_TYPES.SET_TOKEN, token });
|
|
3952
|
+
});
|
|
3953
|
+
return true;
|
|
3954
|
+
}
|
|
3955
|
+
broadcastClearedSession() {
|
|
3956
|
+
const sessionToken = this.client.getSessionToken();
|
|
3957
|
+
if (!sessionToken) return null;
|
|
3958
|
+
this.elements.forEach((element) => {
|
|
3959
|
+
element.sendMessage({ type: MESSAGE_TYPES.SESSION_CLEARED, sessionToken });
|
|
3225
3960
|
});
|
|
3961
|
+
return sessionToken;
|
|
3226
3962
|
}
|
|
3227
3963
|
startEmbeddedAuth(sourceElement, request) {
|
|
3228
3964
|
if (this.authInProgress) return;
|
|
@@ -3231,11 +3967,12 @@ var CimplifyElements = class {
|
|
|
3231
3967
|
const redirectUri = auth.redirectUri ?? readPublicEnv("NEXT_PUBLIC_CIMPLIFY_REDIRECT_URI");
|
|
3232
3968
|
if (!clientId || !redirectUri) {
|
|
3233
3969
|
sourceElement._emitError({
|
|
3234
|
-
code:
|
|
3970
|
+
code: chunkSFUJMS5E_js.ErrorCode.AUTH_CONFIG_REQUIRED,
|
|
3235
3971
|
message: "Cimplify OAuth clientId and redirectUri are required."
|
|
3236
3972
|
});
|
|
3237
3973
|
return;
|
|
3238
3974
|
}
|
|
3975
|
+
const generation = ++this.authGeneration;
|
|
3239
3976
|
this.authInProgress = true;
|
|
3240
3977
|
void startSignIn({
|
|
3241
3978
|
clientId,
|
|
@@ -3250,19 +3987,27 @@ var CimplifyElements = class {
|
|
|
3250
3987
|
mode: "modal",
|
|
3251
3988
|
silentFirst: request.mode === ELEMENTS_AUTH_MODES.CHECKOUT && request.prompt !== ELEMENTS_AUTH_PROMPTS.LOGIN,
|
|
3252
3989
|
onSuccess: async ({ accessToken }) => {
|
|
3990
|
+
if (this.authGeneration !== generation) return;
|
|
3253
3991
|
this.authInProgress = false;
|
|
3254
3992
|
if (!accessToken) {
|
|
3255
3993
|
sourceElement._emitError({
|
|
3256
|
-
code:
|
|
3994
|
+
code: chunkSFUJMS5E_js.ErrorCode.AUTH_CALLBACK_MISSING_TOKEN,
|
|
3257
3995
|
message: "Sign-in callback did not return an access token."
|
|
3258
3996
|
});
|
|
3259
3997
|
return;
|
|
3260
3998
|
}
|
|
3261
|
-
const
|
|
3262
|
-
this.broadcastAccessToken(accessToken)
|
|
3263
|
-
|
|
3999
|
+
const application = await this.applyAccessToken(accessToken, generation);
|
|
4000
|
+
if (application.kind === "authenticated" && this.broadcastAccessToken(accessToken, generation)) {
|
|
4001
|
+
sourceElement._emitAuthenticated(application.data);
|
|
4002
|
+
} else if (application.kind === "claim_failed") {
|
|
4003
|
+
sourceElement._emitError({
|
|
4004
|
+
code: application.code,
|
|
4005
|
+
message: application.message
|
|
4006
|
+
});
|
|
4007
|
+
}
|
|
3264
4008
|
},
|
|
3265
4009
|
onError: (err2) => {
|
|
4010
|
+
if (this.authGeneration !== generation) return;
|
|
3266
4011
|
this.authInProgress = false;
|
|
3267
4012
|
sourceElement._emitError({
|
|
3268
4013
|
code: err2.error,
|
|
@@ -3270,9 +4015,10 @@ var CimplifyElements = class {
|
|
|
3270
4015
|
});
|
|
3271
4016
|
}
|
|
3272
4017
|
}).catch((error) => {
|
|
4018
|
+
if (this.authGeneration !== generation) return;
|
|
3273
4019
|
this.authInProgress = false;
|
|
3274
4020
|
sourceElement._emitError({
|
|
3275
|
-
code:
|
|
4021
|
+
code: chunkSFUJMS5E_js.ErrorCode.AUTH_START_FAILED,
|
|
3276
4022
|
message: error instanceof Error ? error.message : "Unable to start sign-in."
|
|
3277
4023
|
});
|
|
3278
4024
|
});
|
|
@@ -3290,11 +4036,29 @@ var CimplifyElements = class {
|
|
|
3290
4036
|
this.startEmbeddedAuth(sourceElement, message);
|
|
3291
4037
|
break;
|
|
3292
4038
|
case MESSAGE_TYPES.SESSION_ESTABLISHED:
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
this.
|
|
3296
|
-
|
|
3297
|
-
|
|
4039
|
+
{
|
|
4040
|
+
this.authInProgress = false;
|
|
4041
|
+
const generation = ++this.authGeneration;
|
|
4042
|
+
void this.applyAccessToken(message.accessToken, generation).then((application) => {
|
|
4043
|
+
if (this.authGeneration !== generation) return;
|
|
4044
|
+
if (application.kind === "claim_failed") {
|
|
4045
|
+
this.clearPersistedSession();
|
|
4046
|
+
sourceElement.sendMessage({
|
|
4047
|
+
type: MESSAGE_TYPES.SESSION_ESTABLISHMENT_FAILED,
|
|
4048
|
+
accessToken: message.accessToken,
|
|
4049
|
+
code: application.code,
|
|
4050
|
+
message: application.message
|
|
4051
|
+
});
|
|
4052
|
+
this.broadcastClearedSession();
|
|
4053
|
+
return;
|
|
4054
|
+
}
|
|
4055
|
+
if (application.kind !== "authenticated" || !this.broadcastAccessToken(message.accessToken, generation)) {
|
|
4056
|
+
return;
|
|
4057
|
+
}
|
|
4058
|
+
this.persistRefreshToken(message.refreshToken);
|
|
4059
|
+
sourceElement._emitAuthenticated(application.data);
|
|
4060
|
+
});
|
|
4061
|
+
}
|
|
3298
4062
|
break;
|
|
3299
4063
|
case MESSAGE_TYPES.ADDRESS_CHANGED:
|
|
3300
4064
|
case MESSAGE_TYPES.ADDRESS_SELECTED:
|
|
@@ -3307,13 +4071,41 @@ var CimplifyElements = class {
|
|
|
3307
4071
|
if (!this.customerData) {
|
|
3308
4072
|
this.customerData = { name: "", email: null, phone: null };
|
|
3309
4073
|
}
|
|
3310
|
-
if (message.contactType ===
|
|
4074
|
+
if (message.contactType === ELEMENTS_AUTH_CONTACT_TYPES.EMAIL) {
|
|
4075
|
+
this.customerData.email = message.contact;
|
|
4076
|
+
} else {
|
|
4077
|
+
this.customerData.phone = message.contact;
|
|
4078
|
+
}
|
|
4079
|
+
break;
|
|
4080
|
+
case MESSAGE_TYPES.CONTINUE_WITHOUT_SAVED_DETAILS: {
|
|
4081
|
+
this.authGeneration += 1;
|
|
4082
|
+
this.authInProgress = false;
|
|
4083
|
+
this.authEstablishmentInProgress = false;
|
|
4084
|
+
const carriedIdentityAuthority = Boolean(this.client.getAccessToken()) || this.client.hasClaimedSessionAuthority();
|
|
4085
|
+
this.accessToken = null;
|
|
4086
|
+
this.accountId = null;
|
|
4087
|
+
this.customerId = null;
|
|
4088
|
+
this.customerData = { name: "", email: null, phone: null };
|
|
4089
|
+
this.addressData = null;
|
|
4090
|
+
this.paymentData = null;
|
|
4091
|
+
this.clearPersistedSession();
|
|
4092
|
+
if (carriedIdentityAuthority) {
|
|
4093
|
+
this.client.clearSession();
|
|
4094
|
+
} else {
|
|
4095
|
+
this.client.setAccessToken(null);
|
|
4096
|
+
}
|
|
4097
|
+
this.broadcastClearedSession();
|
|
4098
|
+
if (message.contactType === ELEMENTS_AUTH_CONTACT_TYPES.EMAIL) {
|
|
3311
4099
|
this.customerData.email = message.contact;
|
|
3312
4100
|
} else {
|
|
3313
4101
|
this.customerData.phone = message.contact;
|
|
3314
4102
|
}
|
|
3315
4103
|
break;
|
|
4104
|
+
}
|
|
3316
4105
|
case MESSAGE_TYPES.LOGOUT_COMPLETE:
|
|
4106
|
+
this.authGeneration += 1;
|
|
4107
|
+
this.authInProgress = false;
|
|
4108
|
+
this.authEstablishmentInProgress = false;
|
|
3317
4109
|
if (this.checkoutInProgress && this.activeCheckoutAbort) {
|
|
3318
4110
|
this.activeCheckoutAbort();
|
|
3319
4111
|
}
|
|
@@ -3325,6 +4117,7 @@ var CimplifyElements = class {
|
|
|
3325
4117
|
this.paymentData = null;
|
|
3326
4118
|
this.clearPersistedSession();
|
|
3327
4119
|
this.client.clearSession();
|
|
4120
|
+
this.broadcastClearedSession();
|
|
3328
4121
|
break;
|
|
3329
4122
|
}
|
|
3330
4123
|
}
|
|
@@ -3338,7 +4131,7 @@ var CimplifyElements = class {
|
|
|
3338
4131
|
if (!this.customerData) {
|
|
3339
4132
|
this.customerData = { name: "", email: null, phone: null };
|
|
3340
4133
|
}
|
|
3341
|
-
if (contactType ===
|
|
4134
|
+
if (contactType === ELEMENTS_AUTH_CONTACT_TYPES.EMAIL) {
|
|
3342
4135
|
this.customerData.email = contact;
|
|
3343
4136
|
} else {
|
|
3344
4137
|
this.customerData.phone = contact;
|
|
@@ -3458,10 +4251,9 @@ var CimplifyElement = class {
|
|
|
3458
4251
|
const iframe = this.iframe;
|
|
3459
4252
|
if (!iframe || !iframe.isConnected) {
|
|
3460
4253
|
if (iframe && !iframe.isConnected) {
|
|
3461
|
-
console.warn(
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
);
|
|
4254
|
+
console.warn("[cimplify:checkout] sendMessage DROPPED \u2014 iframe detached", {
|
|
4255
|
+
type: message.type
|
|
4256
|
+
});
|
|
3465
4257
|
}
|
|
3466
4258
|
return;
|
|
3467
4259
|
}
|
|
@@ -3502,7 +4294,7 @@ var CimplifyElement = class {
|
|
|
3502
4294
|
if (!resolvedBusinessId || !this.container || !this.mounted) {
|
|
3503
4295
|
console.error("Unable to mount element without a resolved business ID");
|
|
3504
4296
|
this.emit(EVENT_TYPES.ERROR, {
|
|
3505
|
-
code:
|
|
4297
|
+
code: chunkSFUJMS5E_js.ErrorCode.BUSINESS_ID_REQUIRED,
|
|
3506
4298
|
message: "Unable to initialize checkout without a business ID."
|
|
3507
4299
|
});
|
|
3508
4300
|
return;
|
|
@@ -3557,16 +4349,19 @@ var CimplifyElement = class {
|
|
|
3557
4349
|
orderTypes: this.options.orderTypes,
|
|
3558
4350
|
defaultOrderType: this.options.defaultOrderType,
|
|
3559
4351
|
renderSubmitButton: true,
|
|
3560
|
-
submitLabel: this.options.submitLabel
|
|
4352
|
+
submitLabel: this.options.submitLabel,
|
|
4353
|
+
intentId: this.options.intentId,
|
|
4354
|
+
hostedSessionId: this.options.hostedSessionId,
|
|
4355
|
+
initialTerms: this.options.initialTerms
|
|
3561
4356
|
});
|
|
3562
4357
|
const token = this.parent.getAccessToken();
|
|
3563
|
-
if (token) {
|
|
3564
|
-
this.sendMessage({ type: MESSAGE_TYPES.SET_TOKEN, token });
|
|
3565
|
-
}
|
|
3566
4358
|
const sessionToken = this.parent.getSessionToken();
|
|
3567
4359
|
if (sessionToken) {
|
|
3568
4360
|
this.sendMessage({ type: MESSAGE_TYPES.SET_SESSION, sessionToken });
|
|
3569
4361
|
}
|
|
4362
|
+
if (token) {
|
|
4363
|
+
this.sendMessage({ type: MESSAGE_TYPES.SET_TOKEN, token });
|
|
4364
|
+
}
|
|
3570
4365
|
this.pendingInit = null;
|
|
3571
4366
|
}
|
|
3572
4367
|
this.flushPending();
|
|
@@ -3634,12 +4429,20 @@ exports.LinkService = LinkService;
|
|
|
3634
4429
|
exports.LiteService = LiteService;
|
|
3635
4430
|
exports.MESSAGE_TYPES = MESSAGE_TYPES;
|
|
3636
4431
|
exports.OrderQueries = OrderQueries;
|
|
4432
|
+
exports.PAYMENT_AUTHORIZATION_OUTCOME_STATUS = PAYMENT_AUTHORIZATION_OUTCOME_STATUS;
|
|
4433
|
+
exports.PAYMENT_AUTHORIZATION_PROVIDER = PAYMENT_AUTHORIZATION_PROVIDER;
|
|
3637
4434
|
exports.PKCE_COOKIE = PKCE_COOKIE;
|
|
3638
4435
|
exports.PKCE_COOKIE_PATH = PKCE_COOKIE_PATH;
|
|
4436
|
+
exports.PaymentAuthorizationAdapterRegistry = PaymentAuthorizationAdapterRegistry;
|
|
4437
|
+
exports.PaystackAuthorizationAdapter = PaystackAuthorizationAdapter;
|
|
3639
4438
|
exports.SchedulingService = SchedulingService;
|
|
4439
|
+
exports.StripeAuthorizationAdapter = StripeAuthorizationAdapter;
|
|
4440
|
+
exports.clearIntentIdempotencyKey = clearIntentIdempotencyKey;
|
|
3640
4441
|
exports.combine = combine;
|
|
3641
4442
|
exports.combineObject = combineObject;
|
|
4443
|
+
exports.createDefaultPaymentAuthorizationAdapterRegistry = createDefaultPaymentAuthorizationAdapterRegistry;
|
|
3642
4444
|
exports.createElements = createElements;
|
|
4445
|
+
exports.createPurchaseIntentConfirmation = createPurchaseIntentConfirmation;
|
|
3643
4446
|
exports.decodePkceState = decodePkceState;
|
|
3644
4447
|
exports.err = err;
|
|
3645
4448
|
exports.flatMap = flatMap;
|
|
@@ -3649,12 +4452,15 @@ exports.generatePkce = generatePkce;
|
|
|
3649
4452
|
exports.generateState = generateState;
|
|
3650
4453
|
exports.getAuthorizationEndpoint = getAuthorizationEndpoint;
|
|
3651
4454
|
exports.getOrElse = getOrElse;
|
|
4455
|
+
exports.intentIdempotencyKey = intentIdempotencyKey;
|
|
3652
4456
|
exports.isErr = isErr;
|
|
3653
4457
|
exports.isOk = isOk;
|
|
3654
4458
|
exports.mapError = mapError;
|
|
3655
4459
|
exports.mapResult = mapResult;
|
|
3656
4460
|
exports.ok = ok;
|
|
4461
|
+
exports.purchaseIntentRequiresPaymentOption = purchaseIntentRequiresPaymentOption;
|
|
3657
4462
|
exports.safe = safe;
|
|
4463
|
+
exports.selectPurchaseIntentPaymentOption = selectPurchaseIntentPaymentOption;
|
|
3658
4464
|
exports.startSignIn = startSignIn;
|
|
3659
4465
|
exports.toNullable = toNullable;
|
|
3660
4466
|
exports.tryCatch = tryCatch;
|