@cimplify/sdk 0.102.0 → 0.104.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/advanced.d.mts +3 -3
- package/dist/advanced.d.ts +3 -3
- package/dist/advanced.js +23 -22
- package/dist/advanced.mjs +4 -3
- package/dist/{chunk-DCMXUKDQ.mjs → chunk-2WPVUIHX.mjs} +455 -105
- package/dist/{chunk-NIOUSKQQ.js → chunk-4BKOKHE3.js} +9 -0
- package/dist/{chunk-YDA46OZ6.js → chunk-5BDYDZ4U.js} +722 -90
- package/dist/{chunk-4KNFBPV2.mjs → chunk-5RT4HYMP.mjs} +61 -15
- package/dist/{chunk-WMEC5JWN.js → chunk-7PDEX54K.js} +50 -13
- package/dist/chunk-CNN7Z2IP.js +125 -0
- package/dist/{chunk-DLW3RWRK.mjs → chunk-DYIAX3WI.mjs} +46 -12
- package/dist/{chunk-LOWSMGRT.js → chunk-E4K2VQDD.js} +64 -16
- package/dist/chunk-GOHSXBKW.mjs +105 -0
- package/dist/{chunk-O3YUHLZL.mjs → chunk-H3RATH4B.mjs} +9 -0
- package/dist/{chunk-YER7DIOM.js → chunk-IQFFSKE2.js} +753 -594
- package/dist/{chunk-Z3K2D3TE.mjs → chunk-OCCNG6MO.mjs} +735 -558
- package/dist/{chunk-DKLHCZ5M.mjs → chunk-OKADBZAI.mjs} +652 -25
- package/dist/{chunk-EAZGA7LD.js → chunk-YVAEY3VC.js} +457 -107
- package/dist/{client-nsiMwuC1.d.ts → client-BVNWjk6W.d.ts} +2 -2
- package/dist/{client-B40KFazg.d.ts → client-BuLcOWLv.d.ts} +202 -319
- package/dist/{client-BizGfqB7.d.mts → client-D5AoobFc.d.mts} +202 -319
- package/dist/{client-BdErclfU.d.mts → client-fM716k7G.d.mts} +2 -2
- package/dist/{index-DpmnI__D.d.mts → index-BtcoqrY1.d.ts} +14 -4
- package/dist/{index-nEyXWIyR.d.ts → index-D7Tf3v7c.d.mts} +14 -4
- package/dist/index.d.mts +83 -8
- package/dist/index.d.ts +83 -8
- package/dist/index.js +203 -169
- package/dist/index.mjs +7 -5
- package/dist/link-D9iSVxt5.d.mts +308 -0
- package/dist/link-D9iSVxt5.d.ts +308 -0
- package/dist/mock/cli.mjs +463 -104
- package/dist/mock/library.js +463 -104
- package/dist/mock/library.mjs +463 -104
- package/dist/mock/msw.js +463 -104
- package/dist/mock/msw.mjs +463 -104
- package/dist/{product-Byf0unSy.d.mts → payment-g0HFkEDU.d.mts} +708 -61
- package/dist/{product-Byf0unSy.d.ts → payment-g0HFkEDU.d.ts} +708 -61
- package/dist/{price-BstChV9a.d.ts → price-BLIeAb8K.d.ts} +1 -1
- package/dist/{price-CS4E5zLS.d.mts → price-Czq_cTC_.d.mts} +1 -1
- package/dist/react.d.mts +4 -4
- package/dist/react.d.ts +4 -4
- package/dist/react.js +194 -169
- package/dist/react.mjs +55 -30
- package/dist/{server-DqbZh8Bk.d.mts → server-BkVhOIwn.d.mts} +14 -10
- package/dist/{server-Cj40R2ZD.d.ts → server-DKK_D-PP.d.ts} +14 -10
- package/dist/server.d.mts +4 -4
- package/dist/server.d.ts +4 -4
- package/dist/server.js +12 -10
- package/dist/server.mjs +6 -4
- package/dist/testing/msw.d.mts +2 -2
- package/dist/testing/msw.d.ts +2 -2
- package/dist/testing/msw.js +4 -3
- package/dist/testing/msw.mjs +3 -2
- package/dist/testing/suite.d.mts +6 -6
- package/dist/testing/suite.d.ts +6 -6
- package/dist/testing/suite.js +26 -25
- package/dist/testing/suite.mjs +7 -6
- package/dist/testing.d.mts +195 -56
- package/dist/testing.d.ts +195 -56
- package/dist/testing.js +95 -82
- package/dist/testing.mjs +14 -9
- package/dist/utils.d.mts +4 -4
- package/dist/utils.d.ts +4 -4
- package/dist/utils.js +37 -29
- package/dist/utils.mjs +2 -2
- package/package.json +7 -1
- package/registry/chat-widget.json +1 -1
- package/dist/payment-l0rkieEQ.d.mts +0 -113
- package/dist/payment-vzNnIi1n.d.ts +0 -113
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { MOBILE_MONEY_PROVIDER, PAYMENT_METHOD, MAX_PAYMENT_AUTHORIZATION_STEPS } from './chunk-GOHSXBKW.mjs';
|
|
2
|
+
import { normalizeStatusResponse, paymentAuthorizationUrl, isPaymentStatusSuccess, isPaymentStatusFailure, isPaymentStatusRequiresAction } from './chunk-DYIAX3WI.mjs';
|
|
3
|
+
import { CimplifyError, isSupportedCurrency, ErrorCode, enrichError, getErrorHint } from './chunk-H3RATH4B.mjs';
|
|
3
4
|
|
|
4
5
|
// src/types/result.ts
|
|
5
6
|
function ok(value) {
|
|
@@ -784,222 +785,15 @@ var CartOperations = class {
|
|
|
784
785
|
}
|
|
785
786
|
};
|
|
786
787
|
|
|
787
|
-
// src/constants.ts
|
|
788
|
-
var CHECKOUT_MODE = {
|
|
789
|
-
LINK: "link",
|
|
790
|
-
GUEST: "guest"
|
|
791
|
-
};
|
|
792
|
-
var ORDER_TYPE = {
|
|
793
|
-
DELIVERY: "delivery",
|
|
794
|
-
PICKUP: "pickup",
|
|
795
|
-
DINE_IN: "dine-in",
|
|
796
|
-
WALK_IN: "walk-in"
|
|
797
|
-
};
|
|
798
|
-
var PAYMENT_METHOD = {
|
|
799
|
-
MOBILE_MONEY: "mobile_money",
|
|
800
|
-
CARD: "card"
|
|
801
|
-
};
|
|
802
|
-
var CHECKOUT_STEP = {
|
|
803
|
-
AUTHENTICATION: "authentication",
|
|
804
|
-
ORDER_DETAILS: "order_details",
|
|
805
|
-
PAYMENT_METHOD: "payment_method",
|
|
806
|
-
PAYMENT: "payment",
|
|
807
|
-
CONFIRMATION: "confirmation"
|
|
808
|
-
};
|
|
809
|
-
var PAYMENT_STATE = {
|
|
810
|
-
INITIAL: "initial",
|
|
811
|
-
PREPARING: "preparing",
|
|
812
|
-
PROCESSING: "processing",
|
|
813
|
-
VERIFYING: "verifying",
|
|
814
|
-
AWAITING_AUTHORIZATION: "awaiting_authorization",
|
|
815
|
-
SUCCESS: "success",
|
|
816
|
-
ERROR: "error",
|
|
817
|
-
TIMEOUT: "timeout"
|
|
818
|
-
};
|
|
819
|
-
var PICKUP_TIME_TYPE = {
|
|
820
|
-
ASAP: "asap",
|
|
821
|
-
SCHEDULED: "scheduled"
|
|
822
|
-
};
|
|
823
|
-
var MOBILE_MONEY_PROVIDER = {
|
|
824
|
-
MTN: "mtn",
|
|
825
|
-
VODAFONE: "vodafone",
|
|
826
|
-
TELECEL: "telecel",
|
|
827
|
-
AIRTEL: "airtel",
|
|
828
|
-
AIRTELTIGO: "airteltigo",
|
|
829
|
-
MPESA: "mpesa"
|
|
830
|
-
};
|
|
831
|
-
var AUTHORIZATION_TYPE = {
|
|
832
|
-
OTP: "otp",
|
|
833
|
-
PIN: "pin",
|
|
834
|
-
PHONE: "phone",
|
|
835
|
-
BIRTHDAY: "birthday",
|
|
836
|
-
ADDRESS: "address"
|
|
837
|
-
};
|
|
838
|
-
var DEVICE_TYPE = {
|
|
839
|
-
MOBILE: "mobile",
|
|
840
|
-
DESKTOP: "desktop",
|
|
841
|
-
TABLET: "tablet",
|
|
842
|
-
UNKNOWN: "unknown"
|
|
843
|
-
};
|
|
844
|
-
var CONTACT_TYPE = {
|
|
845
|
-
PHONE: "phone",
|
|
846
|
-
EMAIL: "email"
|
|
847
|
-
};
|
|
848
|
-
var LINK_QUERY = {
|
|
849
|
-
DATA: "link.data",
|
|
850
|
-
ADDRESSES: "link.addresses",
|
|
851
|
-
MOBILE_MONEY: "link.mobile_money",
|
|
852
|
-
PREFERENCES: "link.preferences",
|
|
853
|
-
SESSIONS: "link.sessions"
|
|
854
|
-
};
|
|
855
|
-
var LINK_MUTATION = {
|
|
856
|
-
CHECK_STATUS: "link.check_status",
|
|
857
|
-
ENROLL: "link.enroll",
|
|
858
|
-
ENROLL_AND_LINK_ORDER: "link.enroll_and_link_order",
|
|
859
|
-
UPDATE_PREFERENCES: "link.update_preferences",
|
|
860
|
-
CREATE_ADDRESS: "link.create_address",
|
|
861
|
-
UPDATE_ADDRESS: "link.update_address",
|
|
862
|
-
DELETE_ADDRESS: "link.delete_address",
|
|
863
|
-
SET_DEFAULT_ADDRESS: "link.set_default_address",
|
|
864
|
-
TRACK_ADDRESS_USAGE: "link.track_address_usage",
|
|
865
|
-
CREATE_MOBILE_MONEY: "link.create_mobile_money",
|
|
866
|
-
DELETE_MOBILE_MONEY: "link.delete_mobile_money",
|
|
867
|
-
SET_DEFAULT_MOBILE_MONEY: "link.set_default_mobile_money",
|
|
868
|
-
TRACK_MOBILE_MONEY_USAGE: "link.track_mobile_money_usage",
|
|
869
|
-
VERIFY_MOBILE_MONEY: "link.verify_mobile_money",
|
|
870
|
-
REVOKE_SESSION: "link.revoke_session",
|
|
871
|
-
REVOKE_ALL_SESSIONS: "link.revoke_all_sessions"
|
|
872
|
-
};
|
|
873
|
-
var AUTH_MUTATION = {
|
|
874
|
-
REQUEST_OTP: "auth.request_otp",
|
|
875
|
-
VERIFY_OTP: "auth.verify_otp"
|
|
876
|
-
};
|
|
877
|
-
var CHECKOUT_MUTATION = {
|
|
878
|
-
PROCESS: "checkout.process"
|
|
879
|
-
};
|
|
880
|
-
var PAYMENT_MUTATION = {
|
|
881
|
-
SUBMIT_AUTHORIZATION: "payment.submit_authorization",
|
|
882
|
-
CHECK_STATUS: "order.poll_payment_status"
|
|
883
|
-
};
|
|
884
|
-
var ORDER_MUTATION = {
|
|
885
|
-
UPDATE_CUSTOMER: "order.update_order_customer"
|
|
886
|
-
};
|
|
887
|
-
var DEFAULT_CURRENCY = "GHS";
|
|
888
|
-
var DEFAULT_COUNTRY = "GHA";
|
|
889
|
-
|
|
890
|
-
// src/utils/paystack.ts
|
|
891
|
-
async function openPaystackPopup(options, signal) {
|
|
892
|
-
if (typeof window === "undefined") {
|
|
893
|
-
return { success: false, error: "PROVIDER_UNAVAILABLE" };
|
|
894
|
-
}
|
|
895
|
-
let PaystackPop;
|
|
896
|
-
try {
|
|
897
|
-
const specifier = "@paystack/inline-js";
|
|
898
|
-
const imported = await import(
|
|
899
|
-
/* webpackIgnore: true */
|
|
900
|
-
/* @vite-ignore */
|
|
901
|
-
specifier
|
|
902
|
-
);
|
|
903
|
-
PaystackPop = imported.default;
|
|
904
|
-
} catch {
|
|
905
|
-
return { success: false, error: "PROVIDER_UNAVAILABLE" };
|
|
906
|
-
}
|
|
907
|
-
return new Promise((resolve) => {
|
|
908
|
-
let settled = false;
|
|
909
|
-
const resolveOnce = (result) => {
|
|
910
|
-
if (settled) {
|
|
911
|
-
return;
|
|
912
|
-
}
|
|
913
|
-
settled = true;
|
|
914
|
-
if (signal) {
|
|
915
|
-
signal.removeEventListener("abort", onAbort);
|
|
916
|
-
}
|
|
917
|
-
resolve(result);
|
|
918
|
-
};
|
|
919
|
-
const onAbort = () => {
|
|
920
|
-
resolveOnce({ success: false, error: "CANCELLED" });
|
|
921
|
-
};
|
|
922
|
-
if (signal?.aborted) {
|
|
923
|
-
resolveOnce({ success: false, error: "CANCELLED" });
|
|
924
|
-
return;
|
|
925
|
-
}
|
|
926
|
-
if (signal) {
|
|
927
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
928
|
-
}
|
|
929
|
-
try {
|
|
930
|
-
const popup = new PaystackPop();
|
|
931
|
-
popup.newTransaction({
|
|
932
|
-
key: options.key,
|
|
933
|
-
email: options.email,
|
|
934
|
-
amount: options.amount,
|
|
935
|
-
currency: options.currency,
|
|
936
|
-
reference: options.reference,
|
|
937
|
-
accessCode: options.accessCode,
|
|
938
|
-
onSuccess: (transaction) => {
|
|
939
|
-
resolveOnce({
|
|
940
|
-
success: true,
|
|
941
|
-
reference: transaction.reference ?? options.reference
|
|
942
|
-
});
|
|
943
|
-
},
|
|
944
|
-
onCancel: () => {
|
|
945
|
-
resolveOnce({ success: false, error: "PAYMENT_CANCELLED" });
|
|
946
|
-
},
|
|
947
|
-
onError: (error) => {
|
|
948
|
-
resolveOnce({
|
|
949
|
-
success: false,
|
|
950
|
-
error: error?.message || "PAYMENT_FAILED"
|
|
951
|
-
});
|
|
952
|
-
}
|
|
953
|
-
});
|
|
954
|
-
} catch {
|
|
955
|
-
resolveOnce({ success: false, error: "POPUP_BLOCKED" });
|
|
956
|
-
}
|
|
957
|
-
});
|
|
958
|
-
}
|
|
959
|
-
|
|
960
788
|
// src/utils/checkout-resolver.ts
|
|
961
789
|
var DEFAULT_POLL_INTERVAL_MS = 3e3;
|
|
962
790
|
var DEFAULT_MAX_POLL_ATTEMPTS = 60;
|
|
963
791
|
var MAX_CONSECUTIVE_NETWORK_ERRORS = 5;
|
|
964
|
-
var CARD_PROVIDER_PAYSTACK = "paystack";
|
|
965
792
|
var NEXT_ACTION_NONE = "none";
|
|
966
793
|
var NEXT_ACTION_CARD_POPUP = "card_popup";
|
|
967
794
|
var NEXT_ACTION_REDIRECT = "redirect";
|
|
968
795
|
var NEXT_ACTION_AUTHORIZATION = "authorization";
|
|
969
|
-
|
|
970
|
-
if (!error || error === "PAYMENT_CANCELLED" || error === "CANCELLED") {
|
|
971
|
-
return "PAYMENT_CANCELLED";
|
|
972
|
-
}
|
|
973
|
-
if (error === "PROVIDER_UNAVAILABLE") {
|
|
974
|
-
return "PROVIDER_UNAVAILABLE";
|
|
975
|
-
}
|
|
976
|
-
if (error === "POPUP_BLOCKED") {
|
|
977
|
-
return "POPUP_BLOCKED";
|
|
978
|
-
}
|
|
979
|
-
return "PAYMENT_FAILED";
|
|
980
|
-
}
|
|
981
|
-
function normalizeCardProvider(value) {
|
|
982
|
-
const normalized = value?.trim().toLowerCase();
|
|
983
|
-
return normalized && normalized.length > 0 ? normalized : CARD_PROVIDER_PAYSTACK;
|
|
984
|
-
}
|
|
985
|
-
async function openCardPopup(provider, checkoutResult, email, currency, signal) {
|
|
986
|
-
if (typeof window === "undefined") {
|
|
987
|
-
return { success: false, error: "PROVIDER_UNAVAILABLE" };
|
|
988
|
-
}
|
|
989
|
-
if (provider === CARD_PROVIDER_PAYSTACK) {
|
|
990
|
-
return openPaystackPopup(
|
|
991
|
-
{
|
|
992
|
-
key: checkoutResult.public_key || "",
|
|
993
|
-
email,
|
|
994
|
-
accessCode: checkoutResult.client_secret,
|
|
995
|
-
reference: checkoutResult.payment_reference || checkoutResult.client_secret,
|
|
996
|
-
currency
|
|
997
|
-
},
|
|
998
|
-
signal
|
|
999
|
-
);
|
|
1000
|
-
}
|
|
1001
|
-
return { success: false, error: "PROVIDER_UNAVAILABLE" };
|
|
1002
|
-
}
|
|
796
|
+
var NEXT_ACTION_POLL = "poll";
|
|
1003
797
|
var VALID_MOBILE_MONEY_PROVIDERS = new Set(Object.values(MOBILE_MONEY_PROVIDER));
|
|
1004
798
|
function isValidMobileMoneyProvider(value) {
|
|
1005
799
|
return VALID_MOBILE_MONEY_PROVIDERS.has(value);
|
|
@@ -1016,6 +810,32 @@ function normalizeAuthorizationType(value) {
|
|
|
1016
810
|
}
|
|
1017
811
|
return void 0;
|
|
1018
812
|
}
|
|
813
|
+
function normalizeAuthorizationSubmission(expectedType, submission) {
|
|
814
|
+
if (!submission || submission.type !== expectedType) {
|
|
815
|
+
throw new Error(`Expected ${expectedType} authorization details.`);
|
|
816
|
+
}
|
|
817
|
+
if (submission.type === "address") {
|
|
818
|
+
const address = submission.address.trim();
|
|
819
|
+
const city = submission.city.trim();
|
|
820
|
+
const state = submission.state.trim();
|
|
821
|
+
const zipCode = submission.zip_code.trim();
|
|
822
|
+
if (!address || !city || !state || !zipCode) {
|
|
823
|
+
throw new Error("Complete all authorization address fields.");
|
|
824
|
+
}
|
|
825
|
+
return {
|
|
826
|
+
type: "address",
|
|
827
|
+
address,
|
|
828
|
+
city,
|
|
829
|
+
state,
|
|
830
|
+
zip_code: zipCode
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
const value = submission.value.trim();
|
|
834
|
+
if (!value) {
|
|
835
|
+
throw new Error("Authorization value is required.");
|
|
836
|
+
}
|
|
837
|
+
return { type: submission.type, value };
|
|
838
|
+
}
|
|
1019
839
|
function formatMoney(value) {
|
|
1020
840
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
1021
841
|
return value.toFixed(2);
|
|
@@ -1036,6 +856,27 @@ function isAbortError(error) {
|
|
|
1036
856
|
}
|
|
1037
857
|
return error instanceof Error && (error.name === "AbortError" || error.message === "CANCELLED");
|
|
1038
858
|
}
|
|
859
|
+
function waitForAbortable(promise, signal) {
|
|
860
|
+
if (!signal) return promise;
|
|
861
|
+
if (signal.aborted) return Promise.reject(createAbortError());
|
|
862
|
+
return new Promise((resolve, reject) => {
|
|
863
|
+
const onAbort = () => {
|
|
864
|
+
signal.removeEventListener("abort", onAbort);
|
|
865
|
+
reject(createAbortError());
|
|
866
|
+
};
|
|
867
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
868
|
+
promise.then(
|
|
869
|
+
(value) => {
|
|
870
|
+
signal.removeEventListener("abort", onAbort);
|
|
871
|
+
resolve(value);
|
|
872
|
+
},
|
|
873
|
+
(error) => {
|
|
874
|
+
signal.removeEventListener("abort", onAbort);
|
|
875
|
+
reject(error);
|
|
876
|
+
}
|
|
877
|
+
);
|
|
878
|
+
});
|
|
879
|
+
}
|
|
1039
880
|
var CheckoutResolver = class {
|
|
1040
881
|
constructor(options) {
|
|
1041
882
|
this.client = options.client;
|
|
@@ -1043,6 +884,7 @@ var CheckoutResolver = class {
|
|
|
1043
884
|
this.pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
1044
885
|
this.maxPollAttempts = options.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS;
|
|
1045
886
|
this.onStatusChange = options.onStatusChange;
|
|
887
|
+
this.onAuthorizationUiChange = options.onAuthorizationUiChange;
|
|
1046
888
|
this.onAuthorizationRequired = options.onAuthorizationRequired;
|
|
1047
889
|
this.signal = options.signal;
|
|
1048
890
|
this.returnUrl = options.returnUrl;
|
|
@@ -1061,116 +903,22 @@ var CheckoutResolver = class {
|
|
|
1061
903
|
if (!checkoutResult.order_id) {
|
|
1062
904
|
return this.fail("CHECKOUT_FAILED", "Checkout did not return an order ID.", false);
|
|
1063
905
|
}
|
|
1064
|
-
if (checkoutResult.next_action) {
|
|
1065
|
-
return this.resolveNextAction(checkoutResult);
|
|
1066
|
-
}
|
|
1067
|
-
let latestCheckoutResult = checkoutResult;
|
|
1068
|
-
let authorizationType = normalizeAuthorizationType(checkoutResult.authorization_type);
|
|
1069
|
-
let paymentReference = checkoutResult.payment_reference;
|
|
1070
906
|
if (this.isSuccessfulStatus(checkoutResult.payment_status)) {
|
|
1071
907
|
return this.finalizeSuccess(checkoutResult);
|
|
1072
908
|
}
|
|
1073
|
-
if (
|
|
1074
|
-
const
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
order_id: checkoutResult.order_id,
|
|
1078
|
-
order_number: checkoutResult.order_number
|
|
909
|
+
if (this.isFailureStatus(checkoutResult.payment_status)) {
|
|
910
|
+
const normalized = normalizeStatusResponse({
|
|
911
|
+
status: checkoutResult.payment_status,
|
|
912
|
+
paid: false
|
|
1079
913
|
});
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
false
|
|
1085
|
-
);
|
|
1086
|
-
}
|
|
1087
|
-
const popupResult = await openCardPopup(
|
|
1088
|
-
provider,
|
|
1089
|
-
checkoutResult,
|
|
1090
|
-
this.checkoutData.customer.email || "customer@cimplify.io",
|
|
1091
|
-
this.getOrderCurrency(checkoutResult),
|
|
1092
|
-
this.signal
|
|
914
|
+
return this.fail(
|
|
915
|
+
normalized.status.toUpperCase(),
|
|
916
|
+
checkoutResult.display_text || "Payment failed before confirmation.",
|
|
917
|
+
false
|
|
1093
918
|
);
|
|
1094
|
-
if (!popupResult.success) {
|
|
1095
|
-
const popupError = normalizeCardPopupError(popupResult.error);
|
|
1096
|
-
if (popupError === "POPUP_BLOCKED") {
|
|
1097
|
-
return this.fail(
|
|
1098
|
-
"POPUP_BLOCKED",
|
|
1099
|
-
"Unable to open card payment popup. Please allow popups and try again.",
|
|
1100
|
-
true
|
|
1101
|
-
);
|
|
1102
|
-
}
|
|
1103
|
-
if (popupError === "PROVIDER_UNAVAILABLE") {
|
|
1104
|
-
return this.fail(
|
|
1105
|
-
"PROVIDER_UNAVAILABLE",
|
|
1106
|
-
"Card payment provider is unavailable.",
|
|
1107
|
-
false
|
|
1108
|
-
);
|
|
1109
|
-
}
|
|
1110
|
-
return this.fail(
|
|
1111
|
-
"PAYMENT_CANCELLED",
|
|
1112
|
-
"Card payment was cancelled before completion.",
|
|
1113
|
-
true
|
|
1114
|
-
);
|
|
1115
|
-
}
|
|
1116
|
-
paymentReference = popupResult.reference || paymentReference;
|
|
1117
919
|
}
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
window.location.assign(checkoutResult.authorization_url);
|
|
1121
|
-
return this.fail(
|
|
1122
|
-
"REDIRECT_REQUIRED",
|
|
1123
|
-
"Redirecting to complete payment authorization.",
|
|
1124
|
-
true
|
|
1125
|
-
);
|
|
1126
|
-
}
|
|
1127
|
-
if (typeof window !== "undefined") {
|
|
1128
|
-
const popup = window.open(
|
|
1129
|
-
checkoutResult.authorization_url,
|
|
1130
|
-
"cimplify-auth",
|
|
1131
|
-
"width=520,height=760,noopener,noreferrer"
|
|
1132
|
-
);
|
|
1133
|
-
if (!popup) {
|
|
1134
|
-
return this.fail(
|
|
1135
|
-
"POPUP_BLOCKED",
|
|
1136
|
-
"Authorization popup was blocked. Please allow popups and retry.",
|
|
1137
|
-
true
|
|
1138
|
-
);
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
if (checkoutResult.requires_authorization || isPaymentStatusRequiresAction(checkoutResult.payment_status)) {
|
|
1143
|
-
const authorization = await this.handleAuthorization({
|
|
1144
|
-
authorizationType,
|
|
1145
|
-
paymentReference,
|
|
1146
|
-
displayText: checkoutResult.display_text,
|
|
1147
|
-
provider: checkoutResult.provider
|
|
1148
|
-
});
|
|
1149
|
-
if (!authorization.ok) {
|
|
1150
|
-
return authorization.result;
|
|
1151
|
-
}
|
|
1152
|
-
if (authorization.value) {
|
|
1153
|
-
latestCheckoutResult = authorization.value;
|
|
1154
|
-
paymentReference = authorization.value.payment_reference || paymentReference;
|
|
1155
|
-
authorizationType = normalizeAuthorizationType(authorization.value.authorization_type) || authorizationType;
|
|
1156
|
-
if (this.isSuccessfulStatus(authorization.value.payment_status)) {
|
|
1157
|
-
return this.finalizeSuccess(authorization.value);
|
|
1158
|
-
}
|
|
1159
|
-
if (this.isFailureStatus(authorization.value.payment_status)) {
|
|
1160
|
-
return this.fail(
|
|
1161
|
-
"AUTHORIZATION_FAILED",
|
|
1162
|
-
authorization.value.display_text || "Payment authorization failed.",
|
|
1163
|
-
false
|
|
1164
|
-
);
|
|
1165
|
-
}
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1168
|
-
return this.pollUntilTerminal({
|
|
1169
|
-
orderId: checkoutResult.order_id,
|
|
1170
|
-
latestCheckoutResult,
|
|
1171
|
-
paymentReference,
|
|
1172
|
-
authorizationType
|
|
1173
|
-
});
|
|
920
|
+
const nextAction = checkoutResult.next_action ?? this.deriveLegacyNextAction(checkoutResult);
|
|
921
|
+
return this.resolveNextAction({ ...checkoutResult, next_action: nextAction });
|
|
1174
922
|
} catch (error) {
|
|
1175
923
|
if (isAbortError(error)) {
|
|
1176
924
|
return this.fail("CANCELLED", "Checkout was cancelled.", true);
|
|
@@ -1179,99 +927,172 @@ var CheckoutResolver = class {
|
|
|
1179
927
|
return this.fail("CHECKOUT_FAILED", message, true);
|
|
1180
928
|
}
|
|
1181
929
|
}
|
|
1182
|
-
|
|
1183
|
-
|
|
930
|
+
deriveLegacyNextAction(checkoutResult) {
|
|
931
|
+
if (checkoutResult.client_secret && checkoutResult.public_key) {
|
|
932
|
+
return {
|
|
933
|
+
type: NEXT_ACTION_CARD_POPUP,
|
|
934
|
+
provider: checkoutResult.provider?.trim().toLowerCase() || "",
|
|
935
|
+
client_secret: checkoutResult.client_secret,
|
|
936
|
+
public_key: checkoutResult.public_key
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
if (checkoutResult.authorization_url) {
|
|
940
|
+
return {
|
|
941
|
+
type: NEXT_ACTION_REDIRECT,
|
|
942
|
+
authorization_url: checkoutResult.authorization_url
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
if (checkoutResult.requires_authorization && checkoutResult.authorization_type) {
|
|
946
|
+
return {
|
|
947
|
+
type: NEXT_ACTION_AUTHORIZATION,
|
|
948
|
+
authorization_type: checkoutResult.authorization_type,
|
|
949
|
+
display_text: checkoutResult.display_text
|
|
950
|
+
};
|
|
951
|
+
}
|
|
952
|
+
return { type: NEXT_ACTION_POLL };
|
|
953
|
+
}
|
|
954
|
+
async runCardPopup(action, checkoutResult) {
|
|
955
|
+
if (typeof action.provider !== "string" || !action.provider.trim() || typeof action.client_secret !== "string" || !action.client_secret.trim() || typeof action.public_key !== "string" || !action.public_key.trim()) {
|
|
956
|
+
return {
|
|
957
|
+
ok: false,
|
|
958
|
+
result: this.fail(
|
|
959
|
+
"INVALID_CARD_AUTHORIZATION",
|
|
960
|
+
"The payment provider returned an incomplete card authorization response.",
|
|
961
|
+
false
|
|
962
|
+
)
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
this.emit("awaiting_authorization", {
|
|
966
|
+
display_text: "Complete payment in the card authorization window.",
|
|
967
|
+
order_id: checkoutResult.order_id,
|
|
968
|
+
order_number: checkoutResult.order_number,
|
|
969
|
+
provider: action.provider
|
|
970
|
+
});
|
|
971
|
+
if (!this.allowPopups) {
|
|
972
|
+
return {
|
|
973
|
+
ok: false,
|
|
974
|
+
result: this.fail(
|
|
975
|
+
"PROVIDER_UNAVAILABLE",
|
|
976
|
+
"Card authorization UI is unavailable in this environment.",
|
|
977
|
+
false
|
|
978
|
+
)
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
const currency = this.getOrderCurrency(checkoutResult);
|
|
982
|
+
if (!currency) {
|
|
983
|
+
return {
|
|
984
|
+
ok: false,
|
|
985
|
+
result: this.fail("INVALID_CURRENCY", "Payment currency is missing or unsupported.", false)
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
let outcome;
|
|
989
|
+
try {
|
|
990
|
+
this.notifyAuthorizationUiChange(true);
|
|
991
|
+
outcome = await this.client.checkout.authorizeCardPopup(action, {
|
|
992
|
+
email: this.checkoutData.customer.email || "customer@cimplify.io",
|
|
993
|
+
currency,
|
|
994
|
+
reference: checkoutResult.payment_reference,
|
|
995
|
+
returnUrl: this.returnUrl,
|
|
996
|
+
signal: this.signal
|
|
997
|
+
});
|
|
998
|
+
} finally {
|
|
999
|
+
this.notifyAuthorizationUiChange(false);
|
|
1000
|
+
}
|
|
1001
|
+
if (outcome.status === "submitted") {
|
|
1002
|
+
return { ok: true, reference: outcome.reference };
|
|
1003
|
+
}
|
|
1004
|
+
if (outcome.status === "cancelled") {
|
|
1005
|
+
return {
|
|
1006
|
+
ok: false,
|
|
1007
|
+
result: this.fail(
|
|
1008
|
+
"PAYMENT_CANCELLED",
|
|
1009
|
+
"Card payment was cancelled before submission.",
|
|
1010
|
+
true
|
|
1011
|
+
)
|
|
1012
|
+
};
|
|
1013
|
+
}
|
|
1014
|
+
return {
|
|
1015
|
+
ok: false,
|
|
1016
|
+
result: this.fail(outcome.code, outcome.message, outcome.recoverable)
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
async resolveNextAction(checkoutResult, resolutionState = {
|
|
1020
|
+
authorizationSteps: 0,
|
|
1021
|
+
pollAttempts: 0,
|
|
1022
|
+
consecutivePollErrors: 0
|
|
1023
|
+
}) {
|
|
1184
1024
|
if (this.isSuccessfulStatus(checkoutResult.payment_status)) {
|
|
1185
1025
|
return this.finalizeSuccess(checkoutResult);
|
|
1186
1026
|
}
|
|
1187
1027
|
let latestCheckoutResult = checkoutResult;
|
|
1188
1028
|
let paymentReference = checkoutResult.payment_reference;
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
"Card payment popup is unavailable in this environment.",
|
|
1203
|
-
false
|
|
1204
|
-
);
|
|
1029
|
+
let action = checkoutResult.next_action;
|
|
1030
|
+
actionLoop: while (true) {
|
|
1031
|
+
this.ensureNotAborted();
|
|
1032
|
+
switch (action.type) {
|
|
1033
|
+
case NEXT_ACTION_NONE:
|
|
1034
|
+
break actionLoop;
|
|
1035
|
+
case NEXT_ACTION_CARD_POPUP: {
|
|
1036
|
+
const limitFailure = this.consumeAuthorizationStep(resolutionState);
|
|
1037
|
+
if (limitFailure) return limitFailure;
|
|
1038
|
+
const popup = await this.runCardPopup(action, latestCheckoutResult);
|
|
1039
|
+
if (!popup.ok) return popup.result;
|
|
1040
|
+
paymentReference = popup.reference || paymentReference;
|
|
1041
|
+
break actionLoop;
|
|
1205
1042
|
}
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
this.signal
|
|
1212
|
-
);
|
|
1213
|
-
if (!popupResult.success) {
|
|
1214
|
-
const popupError = normalizeCardPopupError(popupResult.error);
|
|
1215
|
-
if (popupError === "POPUP_BLOCKED") {
|
|
1043
|
+
case NEXT_ACTION_REDIRECT: {
|
|
1044
|
+
const limitFailure = this.consumeAuthorizationStep(resolutionState);
|
|
1045
|
+
if (limitFailure) return limitFailure;
|
|
1046
|
+
const authorizationUrl = paymentAuthorizationUrl(action.authorization_url);
|
|
1047
|
+
if (!authorizationUrl) {
|
|
1216
1048
|
return this.fail(
|
|
1217
|
-
"
|
|
1218
|
-
"
|
|
1219
|
-
true
|
|
1220
|
-
);
|
|
1221
|
-
}
|
|
1222
|
-
if (popupError === "PROVIDER_UNAVAILABLE") {
|
|
1223
|
-
return this.fail(
|
|
1224
|
-
"PROVIDER_UNAVAILABLE",
|
|
1225
|
-
"Card payment provider is unavailable.",
|
|
1049
|
+
"INVALID_REDIRECT_AUTHORIZATION",
|
|
1050
|
+
"The payment provider returned an invalid authorization URL.",
|
|
1226
1051
|
false
|
|
1227
1052
|
);
|
|
1228
1053
|
}
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
"Card payment was cancelled before completion.",
|
|
1232
|
-
true
|
|
1233
|
-
);
|
|
1234
|
-
}
|
|
1235
|
-
paymentReference = popupResult.reference || paymentReference;
|
|
1236
|
-
break;
|
|
1237
|
-
}
|
|
1238
|
-
case NEXT_ACTION_REDIRECT: {
|
|
1239
|
-
if (typeof window !== "undefined" && this.returnUrl) {
|
|
1240
|
-
window.location.assign(action.authorization_url);
|
|
1241
|
-
return this.fail(
|
|
1242
|
-
"REDIRECT_REQUIRED",
|
|
1243
|
-
"Redirecting to complete payment authorization.",
|
|
1244
|
-
true
|
|
1245
|
-
);
|
|
1246
|
-
}
|
|
1247
|
-
if (typeof window !== "undefined") {
|
|
1248
|
-
const popup = window.open(
|
|
1249
|
-
action.authorization_url,
|
|
1250
|
-
"cimplify-auth",
|
|
1251
|
-
"width=520,height=760,noopener,noreferrer"
|
|
1252
|
-
);
|
|
1253
|
-
if (!popup) {
|
|
1054
|
+
if (typeof window !== "undefined" && this.returnUrl) {
|
|
1055
|
+
window.location.assign(authorizationUrl);
|
|
1254
1056
|
return this.fail(
|
|
1255
|
-
"
|
|
1256
|
-
"
|
|
1057
|
+
"REDIRECT_REQUIRED",
|
|
1058
|
+
"Redirecting to complete payment authorization.",
|
|
1257
1059
|
true
|
|
1258
1060
|
);
|
|
1259
1061
|
}
|
|
1062
|
+
if (typeof window !== "undefined") {
|
|
1063
|
+
const popup = window.open(
|
|
1064
|
+
authorizationUrl,
|
|
1065
|
+
"cimplify-auth",
|
|
1066
|
+
"width=520,height=760,noopener,noreferrer"
|
|
1067
|
+
);
|
|
1068
|
+
if (!popup) {
|
|
1069
|
+
return this.fail(
|
|
1070
|
+
"POPUP_BLOCKED",
|
|
1071
|
+
"Authorization popup was blocked. Please allow popups and retry.",
|
|
1072
|
+
true
|
|
1073
|
+
);
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
break actionLoop;
|
|
1260
1077
|
}
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1078
|
+
case NEXT_ACTION_AUTHORIZATION: {
|
|
1079
|
+
const limitFailure = this.consumeAuthorizationStep(resolutionState);
|
|
1080
|
+
if (limitFailure) return limitFailure;
|
|
1081
|
+
const authType = normalizeAuthorizationType(action.authorization_type);
|
|
1082
|
+
const authorization = await this.handleAuthorization({
|
|
1083
|
+
authorizationType: authType,
|
|
1084
|
+
paymentId: latestCheckoutResult.payment_id,
|
|
1085
|
+
displayText: action.display_text,
|
|
1086
|
+
provider: latestCheckoutResult.provider,
|
|
1087
|
+
orderId: latestCheckoutResult.order_id,
|
|
1088
|
+
orderNumber: latestCheckoutResult.order_number
|
|
1089
|
+
});
|
|
1090
|
+
if (!authorization.ok) {
|
|
1091
|
+
return authorization.result;
|
|
1092
|
+
}
|
|
1093
|
+
if (!authorization.value) {
|
|
1094
|
+
break actionLoop;
|
|
1095
|
+
}
|
|
1275
1096
|
latestCheckoutResult = authorization.value;
|
|
1276
1097
|
paymentReference = authorization.value.payment_reference || paymentReference;
|
|
1277
1098
|
if (this.isSuccessfulStatus(authorization.value.payment_status)) {
|
|
@@ -1284,24 +1105,45 @@ var CheckoutResolver = class {
|
|
|
1284
1105
|
false
|
|
1285
1106
|
);
|
|
1286
1107
|
}
|
|
1108
|
+
action = authorization.value.next_action ?? this.deriveLegacyNextAction(authorization.value);
|
|
1109
|
+
continue actionLoop;
|
|
1287
1110
|
}
|
|
1288
|
-
|
|
1111
|
+
case NEXT_ACTION_POLL:
|
|
1112
|
+
break actionLoop;
|
|
1113
|
+
default:
|
|
1114
|
+
return this.fail(
|
|
1115
|
+
"UNSUPPORTED_NEXT_ACTION",
|
|
1116
|
+
"The payment provider requested an unsupported authorization action.",
|
|
1117
|
+
false
|
|
1118
|
+
);
|
|
1289
1119
|
}
|
|
1290
1120
|
}
|
|
1291
1121
|
return this.pollUntilTerminal({
|
|
1292
|
-
orderId:
|
|
1122
|
+
orderId: latestCheckoutResult.order_id,
|
|
1293
1123
|
latestCheckoutResult,
|
|
1294
1124
|
paymentReference,
|
|
1295
|
-
|
|
1125
|
+
resolutionState
|
|
1296
1126
|
});
|
|
1297
1127
|
}
|
|
1128
|
+
consumeAuthorizationStep(resolutionState) {
|
|
1129
|
+
if (resolutionState.authorizationSteps >= MAX_PAYMENT_AUTHORIZATION_STEPS) {
|
|
1130
|
+
return this.fail(
|
|
1131
|
+
"AUTHORIZATION_LIMIT_EXCEEDED",
|
|
1132
|
+
"The payment provider requested too many authorization steps.",
|
|
1133
|
+
false
|
|
1134
|
+
);
|
|
1135
|
+
}
|
|
1136
|
+
resolutionState.authorizationSteps += 1;
|
|
1137
|
+
return void 0;
|
|
1138
|
+
}
|
|
1298
1139
|
async pollUntilTerminal(input) {
|
|
1299
|
-
|
|
1300
|
-
let latestCheckoutResult = input.latestCheckoutResult;
|
|
1140
|
+
const latestCheckoutResult = input.latestCheckoutResult;
|
|
1301
1141
|
let paymentReference = input.paymentReference;
|
|
1302
|
-
|
|
1303
|
-
|
|
1142
|
+
const { resolutionState } = input;
|
|
1143
|
+
while (resolutionState.pollAttempts < this.maxPollAttempts) {
|
|
1304
1144
|
this.ensureNotAborted();
|
|
1145
|
+
const attempt = resolutionState.pollAttempts;
|
|
1146
|
+
resolutionState.pollAttempts += 1;
|
|
1305
1147
|
this.emit("polling", {
|
|
1306
1148
|
poll_attempt: attempt,
|
|
1307
1149
|
max_poll_attempts: this.maxPollAttempts,
|
|
@@ -1310,8 +1152,8 @@ var CheckoutResolver = class {
|
|
|
1310
1152
|
});
|
|
1311
1153
|
const statusResult = await this.client.checkout.pollPaymentStatus(input.orderId);
|
|
1312
1154
|
if (!statusResult.ok) {
|
|
1313
|
-
|
|
1314
|
-
if (
|
|
1155
|
+
resolutionState.consecutivePollErrors += 1;
|
|
1156
|
+
if (resolutionState.consecutivePollErrors >= MAX_CONSECUTIVE_NETWORK_ERRORS) {
|
|
1315
1157
|
return this.fail(
|
|
1316
1158
|
"NETWORK_ERROR",
|
|
1317
1159
|
"Unable to confirm payment due to repeated network errors.",
|
|
@@ -1321,13 +1163,17 @@ var CheckoutResolver = class {
|
|
|
1321
1163
|
await this.wait(this.pollIntervalMs);
|
|
1322
1164
|
continue;
|
|
1323
1165
|
}
|
|
1324
|
-
|
|
1166
|
+
resolutionState.consecutivePollErrors = 0;
|
|
1325
1167
|
if (statusResult.value.reference) {
|
|
1326
1168
|
paymentReference = statusResult.value.reference;
|
|
1327
1169
|
}
|
|
1328
1170
|
const normalized = normalizeStatusResponse(statusResult.value);
|
|
1329
1171
|
if (normalized.paid || isPaymentStatusSuccess(normalized.status)) {
|
|
1330
|
-
return this.finalizeSuccess(
|
|
1172
|
+
return this.finalizeSuccess({
|
|
1173
|
+
...latestCheckoutResult,
|
|
1174
|
+
payment_status: normalized.status,
|
|
1175
|
+
payment_reference: paymentReference || latestCheckoutResult.payment_reference
|
|
1176
|
+
});
|
|
1331
1177
|
}
|
|
1332
1178
|
if (isPaymentStatusFailure(normalized.status)) {
|
|
1333
1179
|
return this.fail(
|
|
@@ -1337,43 +1183,32 @@ var CheckoutResolver = class {
|
|
|
1337
1183
|
);
|
|
1338
1184
|
}
|
|
1339
1185
|
if (isPaymentStatusRequiresAction(normalized.status)) {
|
|
1340
|
-
const
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
}
|
|
1349
|
-
if (authorization.value) {
|
|
1350
|
-
latestCheckoutResult = authorization.value;
|
|
1351
|
-
paymentReference = authorization.value.payment_reference || paymentReference;
|
|
1352
|
-
authorizationType = normalizeAuthorizationType(authorization.value.authorization_type) || authorizationType;
|
|
1353
|
-
if (this.isSuccessfulStatus(authorization.value.payment_status)) {
|
|
1354
|
-
return this.finalizeSuccess(authorization.value);
|
|
1355
|
-
}
|
|
1356
|
-
if (this.isFailureStatus(authorization.value.payment_status)) {
|
|
1357
|
-
return this.fail(
|
|
1358
|
-
"AUTHORIZATION_FAILED",
|
|
1359
|
-
authorization.value.display_text || "Payment authorization failed.",
|
|
1360
|
-
false
|
|
1361
|
-
);
|
|
1362
|
-
}
|
|
1186
|
+
const authorizationType = latestCheckoutResult.authorization_type;
|
|
1187
|
+
const paymentId = latestCheckoutResult.payment_id;
|
|
1188
|
+
if (!authorizationType || !normalizeAuthorizationType(authorizationType) || !paymentId) {
|
|
1189
|
+
return this.fail(
|
|
1190
|
+
"INVALID_AUTHORIZATION_RESPONSE",
|
|
1191
|
+
"The payment provider returned an incomplete authorization response.",
|
|
1192
|
+
false
|
|
1193
|
+
);
|
|
1363
1194
|
}
|
|
1195
|
+
return this.resolveNextAction(
|
|
1196
|
+
{
|
|
1197
|
+
...latestCheckoutResult,
|
|
1198
|
+
payment_status: normalized.status,
|
|
1199
|
+
payment_reference: paymentReference,
|
|
1200
|
+
display_text: normalized.message || latestCheckoutResult.display_text,
|
|
1201
|
+
next_action: {
|
|
1202
|
+
type: NEXT_ACTION_AUTHORIZATION,
|
|
1203
|
+
authorization_type: authorizationType,
|
|
1204
|
+
display_text: normalized.message || latestCheckoutResult.display_text
|
|
1205
|
+
}
|
|
1206
|
+
},
|
|
1207
|
+
resolutionState
|
|
1208
|
+
);
|
|
1364
1209
|
}
|
|
1365
1210
|
await this.wait(this.pollIntervalMs);
|
|
1366
1211
|
}
|
|
1367
|
-
try {
|
|
1368
|
-
const finalResult = await this.client.checkout.pollPaymentStatus(input.orderId);
|
|
1369
|
-
if (finalResult.ok) {
|
|
1370
|
-
const normalized = normalizeStatusResponse(finalResult.value);
|
|
1371
|
-
if (normalized.paid || isPaymentStatusSuccess(normalized.status)) {
|
|
1372
|
-
return this.finalizeSuccess(latestCheckoutResult);
|
|
1373
|
-
}
|
|
1374
|
-
}
|
|
1375
|
-
} catch {
|
|
1376
|
-
}
|
|
1377
1212
|
return this.fail(
|
|
1378
1213
|
"PAYMENT_TIMEOUT",
|
|
1379
1214
|
"Payment confirmation timed out. Please retry checkout.",
|
|
@@ -1382,35 +1217,61 @@ var CheckoutResolver = class {
|
|
|
1382
1217
|
}
|
|
1383
1218
|
async handleAuthorization(input) {
|
|
1384
1219
|
const authorizationType = input.authorizationType;
|
|
1385
|
-
const
|
|
1386
|
-
if (!authorizationType || !
|
|
1387
|
-
return {
|
|
1220
|
+
const paymentId = input.paymentId;
|
|
1221
|
+
if (!authorizationType || !paymentId) {
|
|
1222
|
+
return {
|
|
1223
|
+
ok: false,
|
|
1224
|
+
result: this.fail(
|
|
1225
|
+
"INVALID_AUTHORIZATION_RESPONSE",
|
|
1226
|
+
"The payment provider returned an incomplete authorization response.",
|
|
1227
|
+
false
|
|
1228
|
+
)
|
|
1229
|
+
};
|
|
1388
1230
|
}
|
|
1389
1231
|
this.emit("awaiting_authorization", {
|
|
1390
1232
|
authorization_type: authorizationType,
|
|
1391
1233
|
display_text: input.displayText,
|
|
1392
|
-
provider: input.provider
|
|
1234
|
+
provider: input.provider,
|
|
1235
|
+
order_id: input.orderId,
|
|
1236
|
+
order_number: input.orderNumber
|
|
1393
1237
|
});
|
|
1394
|
-
let
|
|
1395
|
-
const submit =
|
|
1238
|
+
let authorizationRequest;
|
|
1239
|
+
const submit = (authorization) => {
|
|
1396
1240
|
this.ensureNotAborted();
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1241
|
+
let normalizedAuthorization;
|
|
1242
|
+
try {
|
|
1243
|
+
normalizedAuthorization = normalizeAuthorizationSubmission(
|
|
1244
|
+
authorizationType,
|
|
1245
|
+
authorization
|
|
1246
|
+
);
|
|
1247
|
+
} catch (error) {
|
|
1248
|
+
return Promise.reject(error);
|
|
1400
1249
|
}
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1250
|
+
if (!authorizationRequest) {
|
|
1251
|
+
const request = this.client.checkout.submitAuthorization({
|
|
1252
|
+
payment_id: paymentId,
|
|
1253
|
+
authorization: normalizedAuthorization
|
|
1254
|
+
}).then((submitResult) => {
|
|
1255
|
+
if (!submitResult.ok) {
|
|
1256
|
+
throw new Error(submitResult.error.message || "Authorization failed.");
|
|
1257
|
+
}
|
|
1258
|
+
return submitResult.value;
|
|
1259
|
+
});
|
|
1260
|
+
authorizationRequest = request;
|
|
1261
|
+
void request.catch(() => {
|
|
1262
|
+
if (authorizationRequest === request) {
|
|
1263
|
+
authorizationRequest = void 0;
|
|
1264
|
+
}
|
|
1265
|
+
});
|
|
1408
1266
|
}
|
|
1409
|
-
|
|
1267
|
+
return authorizationRequest.then(() => void 0);
|
|
1410
1268
|
};
|
|
1411
1269
|
try {
|
|
1412
1270
|
if (this.onAuthorizationRequired) {
|
|
1413
|
-
await
|
|
1271
|
+
await waitForAbortable(
|
|
1272
|
+
Promise.resolve(this.onAuthorizationRequired(authorizationType, submit)),
|
|
1273
|
+
this.signal
|
|
1274
|
+
);
|
|
1414
1275
|
} else {
|
|
1415
1276
|
return {
|
|
1416
1277
|
ok: false,
|
|
@@ -1421,6 +1282,20 @@ var CheckoutResolver = class {
|
|
|
1421
1282
|
)
|
|
1422
1283
|
};
|
|
1423
1284
|
}
|
|
1285
|
+
if (!authorizationRequest) {
|
|
1286
|
+
return {
|
|
1287
|
+
ok: false,
|
|
1288
|
+
result: this.fail(
|
|
1289
|
+
"AUTHORIZATION_NOT_SUBMITTED",
|
|
1290
|
+
"The authorization callback returned without submitting a value.",
|
|
1291
|
+
true
|
|
1292
|
+
)
|
|
1293
|
+
};
|
|
1294
|
+
}
|
|
1295
|
+
return {
|
|
1296
|
+
ok: true,
|
|
1297
|
+
value: await waitForAbortable(authorizationRequest, this.signal)
|
|
1298
|
+
};
|
|
1424
1299
|
} catch (error) {
|
|
1425
1300
|
if (isAbortError(error)) {
|
|
1426
1301
|
return {
|
|
@@ -1434,12 +1309,12 @@ var CheckoutResolver = class {
|
|
|
1434
1309
|
result: this.fail("AUTHORIZATION_FAILED", message, true)
|
|
1435
1310
|
};
|
|
1436
1311
|
}
|
|
1437
|
-
return {
|
|
1438
|
-
ok: true,
|
|
1439
|
-
value: authorizationResult
|
|
1440
|
-
};
|
|
1441
1312
|
}
|
|
1442
1313
|
async finalizeSuccess(checkoutResult) {
|
|
1314
|
+
const currency = this.getOrderCurrency(checkoutResult);
|
|
1315
|
+
if (!currency) {
|
|
1316
|
+
return this.fail("INVALID_CURRENCY", "Payment currency is missing or unsupported.", false);
|
|
1317
|
+
}
|
|
1443
1318
|
this.emit("finalizing", {
|
|
1444
1319
|
order_id: checkoutResult.order_id,
|
|
1445
1320
|
order_number: checkoutResult.order_number
|
|
@@ -1456,7 +1331,7 @@ var CheckoutResolver = class {
|
|
|
1456
1331
|
order_number: checkoutResult.order_number || checkoutResult.order_id,
|
|
1457
1332
|
status: checkoutResult.payment_status || "paid",
|
|
1458
1333
|
total: this.getOrderTotal(checkoutResult),
|
|
1459
|
-
currency
|
|
1334
|
+
currency
|
|
1460
1335
|
},
|
|
1461
1336
|
enrolled_in_link: enrolledInLink
|
|
1462
1337
|
};
|
|
@@ -1508,7 +1383,7 @@ var CheckoutResolver = class {
|
|
|
1508
1383
|
};
|
|
1509
1384
|
}
|
|
1510
1385
|
getEnrollmentMobileMoney() {
|
|
1511
|
-
if (this.paymentData?.type ===
|
|
1386
|
+
if (this.paymentData?.type === PAYMENT_METHOD.MOBILE_MONEY && this.paymentData.phone_number && this.paymentData.provider && isValidMobileMoneyProvider(this.paymentData.provider)) {
|
|
1512
1387
|
return {
|
|
1513
1388
|
phone_number: this.paymentData.phone_number,
|
|
1514
1389
|
provider: this.paymentData.provider,
|
|
@@ -1535,15 +1410,15 @@ var CheckoutResolver = class {
|
|
|
1535
1410
|
}
|
|
1536
1411
|
getOrderCurrency(checkoutResult) {
|
|
1537
1412
|
if (checkoutResult.fx?.pay_currency) {
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
if (this.cartCurrency) {
|
|
1541
|
-
return this.cartCurrency;
|
|
1413
|
+
const currency2 = checkoutResult.fx.pay_currency.trim().toUpperCase();
|
|
1414
|
+
return isSupportedCurrency(currency2) ? currency2 : void 0;
|
|
1542
1415
|
}
|
|
1543
1416
|
if (this.checkoutData.pay_currency) {
|
|
1544
|
-
|
|
1417
|
+
const currency2 = this.checkoutData.pay_currency.trim().toUpperCase();
|
|
1418
|
+
return isSupportedCurrency(currency2) ? currency2 : void 0;
|
|
1545
1419
|
}
|
|
1546
|
-
|
|
1420
|
+
const currency = this.cartCurrency.trim().toUpperCase();
|
|
1421
|
+
return isSupportedCurrency(currency) ? currency : void 0;
|
|
1547
1422
|
}
|
|
1548
1423
|
emit(status, context = {}) {
|
|
1549
1424
|
if (!this.onStatusChange) {
|
|
@@ -1554,6 +1429,12 @@ var CheckoutResolver = class {
|
|
|
1554
1429
|
} catch {
|
|
1555
1430
|
}
|
|
1556
1431
|
}
|
|
1432
|
+
notifyAuthorizationUiChange(open) {
|
|
1433
|
+
try {
|
|
1434
|
+
this.onAuthorizationUiChange?.(open);
|
|
1435
|
+
} catch {
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1557
1438
|
fail(code, message, recoverable) {
|
|
1558
1439
|
this.emit("failed", {
|
|
1559
1440
|
display_text: message
|
|
@@ -1618,6 +1499,43 @@ function isValidCustomerName(name) {
|
|
|
1618
1499
|
function isOfflinePaymentMethod(method) {
|
|
1619
1500
|
return method === "cash" || method === "offline";
|
|
1620
1501
|
}
|
|
1502
|
+
function notifyCheckoutStatus(observer, status, context = {}) {
|
|
1503
|
+
try {
|
|
1504
|
+
observer?.(status, context);
|
|
1505
|
+
} catch {
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
var MAX_STOREFRONT_COLLECTION_OPTIONS = 32;
|
|
1509
|
+
function normalizeCollectionOptions(value, expectedCurrency) {
|
|
1510
|
+
if (!value || typeof value !== "object") return null;
|
|
1511
|
+
const response = value;
|
|
1512
|
+
if (response.presentment_currency !== expectedCurrency || !Array.isArray(response.options)) {
|
|
1513
|
+
return null;
|
|
1514
|
+
}
|
|
1515
|
+
if (response.options.length > MAX_STOREFRONT_COLLECTION_OPTIONS) return null;
|
|
1516
|
+
const options = [];
|
|
1517
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1518
|
+
for (const candidate of response.options) {
|
|
1519
|
+
if (!candidate || typeof candidate !== "object") continue;
|
|
1520
|
+
const option = candidate;
|
|
1521
|
+
if (option.method === PAYMENT_METHOD.CARD && option.network == null) {
|
|
1522
|
+
if (!seen.has(PAYMENT_METHOD.CARD)) {
|
|
1523
|
+
seen.add(PAYMENT_METHOD.CARD);
|
|
1524
|
+
options.push({ method: PAYMENT_METHOD.CARD, network: null });
|
|
1525
|
+
}
|
|
1526
|
+
continue;
|
|
1527
|
+
}
|
|
1528
|
+
if (option.method !== PAYMENT_METHOD.MOBILE_MONEY || typeof option.network !== "string" || !option.network.trim()) {
|
|
1529
|
+
continue;
|
|
1530
|
+
}
|
|
1531
|
+
const network = option.network.trim().toLowerCase();
|
|
1532
|
+
const key = `${PAYMENT_METHOD.MOBILE_MONEY}:${network}`;
|
|
1533
|
+
if (seen.has(key)) continue;
|
|
1534
|
+
seen.add(key);
|
|
1535
|
+
options.push({ method: PAYMENT_METHOD.MOBILE_MONEY, network });
|
|
1536
|
+
}
|
|
1537
|
+
return { presentment_currency: expectedCurrency, options };
|
|
1538
|
+
}
|
|
1621
1539
|
var CheckoutService = class {
|
|
1622
1540
|
constructor(client) {
|
|
1623
1541
|
this.client = client;
|
|
@@ -1643,6 +1561,40 @@ var CheckoutService = class {
|
|
|
1643
1561
|
const token = this.client.getOrderToken(orderId);
|
|
1644
1562
|
return token ? `?token=${encodeURIComponent(token)}` : "";
|
|
1645
1563
|
}
|
|
1564
|
+
/** Available storefront collection methods for one presentment currency. */
|
|
1565
|
+
async collectionOptions(currency) {
|
|
1566
|
+
const normalized = currency.trim().toUpperCase();
|
|
1567
|
+
if (!isSupportedCurrency(normalized)) {
|
|
1568
|
+
return err(
|
|
1569
|
+
new CimplifyError(
|
|
1570
|
+
ErrorCode.UNSUPPORTED_CURRENCY,
|
|
1571
|
+
"No online payment method is available for this currency.",
|
|
1572
|
+
false
|
|
1573
|
+
)
|
|
1574
|
+
);
|
|
1575
|
+
}
|
|
1576
|
+
const response = await safe(
|
|
1577
|
+
this.client.get(
|
|
1578
|
+
`/api/v1/payments/collection-options?currency=${encodeURIComponent(normalized)}`
|
|
1579
|
+
)
|
|
1580
|
+
);
|
|
1581
|
+
if (!response.ok) return response;
|
|
1582
|
+
const options = normalizeCollectionOptions(response.value, normalized);
|
|
1583
|
+
return options ? ok(options) : err(
|
|
1584
|
+
new CimplifyError(
|
|
1585
|
+
ErrorCode.PAYMENT_CAPABILITY_MISMATCH,
|
|
1586
|
+
"Payment methods could not be verified for this currency.",
|
|
1587
|
+
false
|
|
1588
|
+
)
|
|
1589
|
+
);
|
|
1590
|
+
}
|
|
1591
|
+
/**
|
|
1592
|
+
* Run provider-owned UI for a backend `card_popup` action. A submitted
|
|
1593
|
+
* outcome is not proof of payment; callers must poll/verify with Cimplify.
|
|
1594
|
+
*/
|
|
1595
|
+
authorizeCardPopup(action, options) {
|
|
1596
|
+
return this.client.authorizationAdapters.authorize(action, options);
|
|
1597
|
+
}
|
|
1646
1598
|
async process(data) {
|
|
1647
1599
|
const invalid = this.validateCheckoutData(data);
|
|
1648
1600
|
if (invalid) {
|
|
@@ -1686,12 +1638,18 @@ var CheckoutService = class {
|
|
|
1686
1638
|
async pollPaymentStatus(orderId) {
|
|
1687
1639
|
const encodedId = encodeURIComponent(orderId);
|
|
1688
1640
|
const tokenParam = this.orderTokenParam(orderId);
|
|
1689
|
-
return safe(
|
|
1641
|
+
return safe(
|
|
1642
|
+
this.client.get(
|
|
1643
|
+
`/api/v1/orders/${encodedId}/payment-status${tokenParam}`
|
|
1644
|
+
)
|
|
1645
|
+
);
|
|
1690
1646
|
}
|
|
1691
1647
|
async updateOrderCustomer(orderId, customer) {
|
|
1692
1648
|
const encodedId = encodeURIComponent(orderId);
|
|
1693
1649
|
const tokenParam = this.orderTokenParam(orderId);
|
|
1694
|
-
return safe(
|
|
1650
|
+
return safe(
|
|
1651
|
+
this.client.post(`/api/v1/orders/${encodedId}/customer${tokenParam}`, customer)
|
|
1652
|
+
);
|
|
1695
1653
|
}
|
|
1696
1654
|
async verifyPayment(orderId) {
|
|
1697
1655
|
const encodedId = encodeURIComponent(orderId);
|
|
@@ -1699,7 +1657,7 @@ var CheckoutService = class {
|
|
|
1699
1657
|
return safe(this.client.post(`/api/v1/orders/${encodedId}/verify-payment${tokenParam}`));
|
|
1700
1658
|
}
|
|
1701
1659
|
async processAndResolve(data) {
|
|
1702
|
-
data.on_status_change
|
|
1660
|
+
notifyCheckoutStatus(data.on_status_change, "preparing");
|
|
1703
1661
|
if (!data.cart_id) {
|
|
1704
1662
|
return ok(
|
|
1705
1663
|
toTerminalFailure(
|
|
@@ -1711,13 +1669,7 @@ var CheckoutService = class {
|
|
|
1711
1669
|
}
|
|
1712
1670
|
const cartResult = await this.client.cart.get();
|
|
1713
1671
|
if (!cartResult.ok || !cartResult.value?.id) {
|
|
1714
|
-
return ok(
|
|
1715
|
-
toTerminalFailure(
|
|
1716
|
-
"INVALID_CART",
|
|
1717
|
-
"Unable to load cart for checkout.",
|
|
1718
|
-
false
|
|
1719
|
-
)
|
|
1720
|
-
);
|
|
1672
|
+
return ok(toTerminalFailure("INVALID_CART", "Unable to load cart for checkout.", false));
|
|
1721
1673
|
}
|
|
1722
1674
|
const cart = cartResult.value;
|
|
1723
1675
|
if (cart.id !== data.cart_id || cart.items.length === 0) {
|
|
@@ -1749,11 +1701,28 @@ var CheckoutService = class {
|
|
|
1749
1701
|
voucher_code: data.voucher_code,
|
|
1750
1702
|
pay_deposit: data.pay_deposit
|
|
1751
1703
|
};
|
|
1752
|
-
const
|
|
1753
|
-
|
|
1754
|
-
|
|
1704
|
+
const rawBaseCurrency = typeof cart.pricing.currency === "string" ? cart.pricing.currency.trim().toUpperCase() : "";
|
|
1705
|
+
if (!isSupportedCurrency(rawBaseCurrency)) {
|
|
1706
|
+
return ok(
|
|
1707
|
+
toTerminalFailure(
|
|
1708
|
+
"INVALID_CURRENCY",
|
|
1709
|
+
"Cart currency is missing or unsupported. Refresh the cart before checkout.",
|
|
1710
|
+
false
|
|
1711
|
+
)
|
|
1712
|
+
);
|
|
1713
|
+
}
|
|
1714
|
+
const baseCurrency = rawBaseCurrency;
|
|
1755
1715
|
const payCurrency = data.pay_currency?.trim().toUpperCase();
|
|
1756
|
-
|
|
1716
|
+
if (payCurrency && !isSupportedCurrency(payCurrency)) {
|
|
1717
|
+
return ok(
|
|
1718
|
+
toTerminalFailure(
|
|
1719
|
+
"INVALID_CURRENCY",
|
|
1720
|
+
"Payment currency is unsupported for checkout.",
|
|
1721
|
+
false
|
|
1722
|
+
)
|
|
1723
|
+
);
|
|
1724
|
+
}
|
|
1725
|
+
const payCurrencyCode = payCurrency && isSupportedCurrency(payCurrency) ? payCurrency : void 0;
|
|
1757
1726
|
const cartTotalAmount = typeof cart.pricing.total_price === "number" ? cart.pricing.total_price : Number.parseFloat(cart.pricing.total_price || "0");
|
|
1758
1727
|
if (payCurrencyCode && payCurrencyCode !== baseCurrency && !checkoutData.fx_quote_id && Number.isFinite(cartTotalAmount) && cartTotalAmount > 0) {
|
|
1759
1728
|
const fxQuoteResult = await this.client.fx.lockQuote({
|
|
@@ -1773,7 +1742,7 @@ var CheckoutService = class {
|
|
|
1773
1742
|
checkoutData.pay_currency = payCurrencyCode;
|
|
1774
1743
|
checkoutData.fx_quote_id = fxQuoteResult.value.id;
|
|
1775
1744
|
}
|
|
1776
|
-
data.on_status_change
|
|
1745
|
+
notifyCheckoutStatus(data.on_status_change, "processing");
|
|
1777
1746
|
const processResult = await this.process(checkoutData);
|
|
1778
1747
|
if (!processResult.ok) {
|
|
1779
1748
|
return ok(
|
|
@@ -1790,12 +1759,13 @@ var CheckoutService = class {
|
|
|
1790
1759
|
pollIntervalMs: data.poll_interval_ms,
|
|
1791
1760
|
maxPollAttempts: data.max_poll_attempts,
|
|
1792
1761
|
onStatusChange: data.on_status_change,
|
|
1762
|
+
onAuthorizationUiChange: data.on_authorization_ui_change,
|
|
1793
1763
|
onAuthorizationRequired: data.on_authorization_required,
|
|
1794
1764
|
signal: data.signal,
|
|
1795
1765
|
returnUrl: data.return_url,
|
|
1796
1766
|
enrollInLink: data.enroll_in_link,
|
|
1797
1767
|
cartTotal: cart.pricing.total_price,
|
|
1798
|
-
cartCurrency: checkoutData.pay_currency ||
|
|
1768
|
+
cartCurrency: checkoutData.pay_currency || baseCurrency,
|
|
1799
1769
|
orderType: checkoutData.order_type,
|
|
1800
1770
|
allowPopups: data.allow_popups
|
|
1801
1771
|
});
|
|
@@ -1863,43 +1833,86 @@ function encodePathSegment(value) {
|
|
|
1863
1833
|
var LinkService = class {
|
|
1864
1834
|
constructor(client) {
|
|
1865
1835
|
this.client = client;
|
|
1836
|
+
this.activationGeneration = 0;
|
|
1837
|
+
}
|
|
1838
|
+
beginActivation() {
|
|
1839
|
+
return {
|
|
1840
|
+
generation: ++this.activationGeneration,
|
|
1841
|
+
sessionEpoch: this.client.getSessionEpoch(),
|
|
1842
|
+
publicKeyEpoch: this.client.getPublicKeyEpoch()
|
|
1843
|
+
};
|
|
1844
|
+
}
|
|
1845
|
+
isActivationFenceCurrent(fence) {
|
|
1846
|
+
return fence.generation === this.activationGeneration && fence.sessionEpoch === this.client.getSessionEpoch() && fence.publicKeyEpoch === this.client.getPublicKeyEpoch();
|
|
1847
|
+
}
|
|
1848
|
+
supersededActivation() {
|
|
1849
|
+
return {
|
|
1850
|
+
ok: false,
|
|
1851
|
+
error: new CimplifyError(
|
|
1852
|
+
"session_superseded",
|
|
1853
|
+
"A newer authentication session replaced this one"
|
|
1854
|
+
)
|
|
1855
|
+
};
|
|
1856
|
+
}
|
|
1857
|
+
async activateAuthenticatedSession(result, fence) {
|
|
1858
|
+
if (!result.ok || !result.value.session_token) return result;
|
|
1859
|
+
if (!this.isActivationFenceCurrent(fence)) return this.supersededActivation();
|
|
1860
|
+
const accessToken = result.value.session_token;
|
|
1861
|
+
this.client.setAccessToken(accessToken);
|
|
1862
|
+
const installedSessionEpoch = this.client.getSessionEpoch();
|
|
1863
|
+
if (!this.client.getPublicKey().trim()) {
|
|
1864
|
+
this.client.activity.refreshIdentity();
|
|
1865
|
+
return result;
|
|
1866
|
+
}
|
|
1867
|
+
const claim = await this.client.support.claimConversation();
|
|
1868
|
+
if (fence.generation !== this.activationGeneration || fence.publicKeyEpoch !== this.client.getPublicKeyEpoch() || this.client.getAccessToken() !== accessToken) {
|
|
1869
|
+
return this.supersededActivation();
|
|
1870
|
+
}
|
|
1871
|
+
if (!claim.ok && claim.error.code !== "already_claimed") {
|
|
1872
|
+
if (this.client.getSessionEpoch() !== installedSessionEpoch) {
|
|
1873
|
+
return this.supersededActivation();
|
|
1874
|
+
}
|
|
1875
|
+
if (this.client.hasClaimedSessionAuthority()) {
|
|
1876
|
+
this.client.clearSession();
|
|
1877
|
+
} else {
|
|
1878
|
+
this.client.setAccessToken(null);
|
|
1879
|
+
}
|
|
1880
|
+
return claim;
|
|
1881
|
+
}
|
|
1882
|
+
this.client.activity.refreshIdentity();
|
|
1883
|
+
return result;
|
|
1866
1884
|
}
|
|
1867
1885
|
async requestOtp(input, opts) {
|
|
1868
1886
|
const idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
1869
1887
|
return safe(
|
|
1870
|
-
this.client.linkPost("/v1/link/auth/request-otp", input, {
|
|
1888
|
+
this.client.linkPost("/v1/link/auth/request-otp", input, {
|
|
1889
|
+
idempotencyKey
|
|
1890
|
+
})
|
|
1871
1891
|
);
|
|
1872
1892
|
}
|
|
1873
1893
|
async verifyOtp(input, opts) {
|
|
1874
1894
|
const idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
1895
|
+
const activationFence = opts?.activateSession === false ? null : this.beginActivation();
|
|
1875
1896
|
const { business_id: _ignoredBusinessId, ...body } = input;
|
|
1876
1897
|
const result = await safe(
|
|
1877
1898
|
this.client.linkPost("/v1/link/auth/verify-otp", body, { idempotencyKey })
|
|
1878
1899
|
);
|
|
1879
|
-
|
|
1880
|
-
this.client.setAccessToken(result.value.session_token);
|
|
1881
|
-
this.client.activity.refreshIdentity();
|
|
1882
|
-
this.client.autoClaimChatIdentity();
|
|
1883
|
-
}
|
|
1884
|
-
return result;
|
|
1900
|
+
return activationFence ? this.activateAuthenticatedSession(result, activationFence) : result;
|
|
1885
1901
|
}
|
|
1886
1902
|
async refreshSession(sessionToken, opts) {
|
|
1887
1903
|
const idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
1904
|
+
const activationFence = opts?.activateSession === false ? null : this.beginActivation();
|
|
1888
1905
|
const body = sessionToken ? { session_token: sessionToken } : {};
|
|
1889
1906
|
const result = await safe(
|
|
1890
1907
|
this.client.linkPost("/v1/link/auth/refresh", body, { idempotencyKey })
|
|
1891
1908
|
);
|
|
1892
|
-
|
|
1893
|
-
this.client.setAccessToken(result.value.session_token);
|
|
1894
|
-
this.client.activity.refreshIdentity();
|
|
1895
|
-
this.client.autoClaimChatIdentity();
|
|
1896
|
-
}
|
|
1897
|
-
return result;
|
|
1909
|
+
return activationFence ? this.activateAuthenticatedSession(result, activationFence) : result;
|
|
1898
1910
|
}
|
|
1899
1911
|
async logout() {
|
|
1900
|
-
|
|
1912
|
+
this.activationGeneration += 1;
|
|
1913
|
+
const request = safe(this.client.linkPost("/v1/link/auth/logout"));
|
|
1901
1914
|
this.client.clearSession();
|
|
1902
|
-
return
|
|
1915
|
+
return request;
|
|
1903
1916
|
}
|
|
1904
1917
|
async checkStatus(contact) {
|
|
1905
1918
|
return safe(this.client.linkPost("/v1/link/check-status", { contact }));
|
|
@@ -1945,11 +1958,9 @@ var LinkService = class {
|
|
|
1945
1958
|
async enrollAndLinkOrder(data, opts) {
|
|
1946
1959
|
const idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
1947
1960
|
return safe(
|
|
1948
|
-
this.client.linkPost(
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
{ idempotencyKey }
|
|
1952
|
-
)
|
|
1961
|
+
this.client.linkPost("/v1/link/enroll-and-link-order", data, {
|
|
1962
|
+
idempotencyKey
|
|
1963
|
+
})
|
|
1953
1964
|
);
|
|
1954
1965
|
}
|
|
1955
1966
|
async updatePreferences(preferences) {
|
|
@@ -2372,6 +2383,7 @@ var MESSAGE_TYPES = {
|
|
|
2372
2383
|
INIT: "init",
|
|
2373
2384
|
SET_TOKEN: "set_token",
|
|
2374
2385
|
SET_SESSION: "set_session",
|
|
2386
|
+
SESSION_CLEARED: "session_cleared",
|
|
2375
2387
|
SET_CART: "set_cart",
|
|
2376
2388
|
GET_DATA: "get_data",
|
|
2377
2389
|
NAVIGATE: "navigate",
|
|
@@ -2388,6 +2400,8 @@ var MESSAGE_TYPES = {
|
|
|
2388
2400
|
LOGOUT_COMPLETE: "logout_complete",
|
|
2389
2401
|
AUTH_REQUESTED: "auth_requested",
|
|
2390
2402
|
SESSION_ESTABLISHED: "session_established",
|
|
2403
|
+
SESSION_ESTABLISHMENT_FAILED: "session_establishment_failed",
|
|
2404
|
+
CONTINUE_WITHOUT_SAVED_DETAILS: "continue_without_saved_details",
|
|
2391
2405
|
CONTACT_PROVIDED: "contact_provided",
|
|
2392
2406
|
CHECKOUT_STATUS: "checkout_status",
|
|
2393
2407
|
CHECKOUT_COMPLETE: "checkout_complete",
|
|
@@ -2751,6 +2765,7 @@ function toCheckoutError(code, message, recoverable) {
|
|
|
2751
2765
|
};
|
|
2752
2766
|
}
|
|
2753
2767
|
var DEFAULT_LINK_URL = "https://link.cimplify.io";
|
|
2768
|
+
var AUTH_ESTABLISHMENT_WAIT_MS = 8e3;
|
|
2754
2769
|
var AUTH_CONTACT_TYPES = new Set(Object.values(ELEMENTS_AUTH_CONTACT_TYPES));
|
|
2755
2770
|
var AUTH_MODES = new Set(Object.values(ELEMENTS_AUTH_MODES));
|
|
2756
2771
|
var AUTH_PROMPTS = new Set(Object.values(ELEMENTS_AUTH_PROMPTS));
|
|
@@ -2801,6 +2816,7 @@ var KNOWN_IFRAME_TYPES = /* @__PURE__ */ new Set([
|
|
|
2801
2816
|
MESSAGE_TYPES.HEIGHT_CHANGE,
|
|
2802
2817
|
MESSAGE_TYPES.AUTH_REQUESTED,
|
|
2803
2818
|
MESSAGE_TYPES.SESSION_ESTABLISHED,
|
|
2819
|
+
MESSAGE_TYPES.CONTINUE_WITHOUT_SAVED_DETAILS,
|
|
2804
2820
|
MESSAGE_TYPES.ERROR,
|
|
2805
2821
|
MESSAGE_TYPES.ADDRESS_CHANGED,
|
|
2806
2822
|
MESSAGE_TYPES.ADDRESS_SELECTED,
|
|
@@ -2845,6 +2861,7 @@ function parseIframeMessage(data) {
|
|
|
2845
2861
|
if (!record.method || typeof record.method !== "object") return null;
|
|
2846
2862
|
break;
|
|
2847
2863
|
case MESSAGE_TYPES.CONTACT_PROVIDED:
|
|
2864
|
+
case MESSAGE_TYPES.CONTINUE_WITHOUT_SAVED_DETAILS:
|
|
2848
2865
|
if (typeof record.contact !== "string" || typeof record.contactType !== "string") return null;
|
|
2849
2866
|
break;
|
|
2850
2867
|
case MESSAGE_TYPES.ERROR:
|
|
@@ -2854,7 +2871,8 @@ function parseIframeMessage(data) {
|
|
|
2854
2871
|
if (typeof record.success !== "boolean") return null;
|
|
2855
2872
|
break;
|
|
2856
2873
|
case MESSAGE_TYPES.CHECKOUT_STATUS:
|
|
2857
|
-
if (typeof record.status !== "string" || !record.context || typeof record.context !== "object")
|
|
2874
|
+
if (typeof record.status !== "string" || !record.context || typeof record.context !== "object")
|
|
2875
|
+
return null;
|
|
2858
2876
|
break;
|
|
2859
2877
|
case MESSAGE_TYPES.READY:
|
|
2860
2878
|
case MESSAGE_TYPES.HEIGHT_CHANGE:
|
|
@@ -2877,6 +2895,8 @@ var CimplifyElements = class {
|
|
|
2877
2895
|
this.paymentData = null;
|
|
2878
2896
|
this.checkoutInProgress = false;
|
|
2879
2897
|
this.authInProgress = false;
|
|
2898
|
+
this.authEstablishmentInProgress = false;
|
|
2899
|
+
this.authGeneration = 0;
|
|
2880
2900
|
this.activeCheckoutAbort = null;
|
|
2881
2901
|
this.businessIdResolvePromise = null;
|
|
2882
2902
|
this.client = client;
|
|
@@ -2911,6 +2931,12 @@ var CimplifyElements = class {
|
|
|
2911
2931
|
}
|
|
2912
2932
|
}
|
|
2913
2933
|
destroy() {
|
|
2934
|
+
this.authGeneration += 1;
|
|
2935
|
+
if (this.authEstablishmentInProgress) {
|
|
2936
|
+
this.client.setAccessToken(null);
|
|
2937
|
+
}
|
|
2938
|
+
this.authInProgress = false;
|
|
2939
|
+
this.authEstablishmentInProgress = false;
|
|
2914
2940
|
this.elements.forEach((element) => element.destroy());
|
|
2915
2941
|
this.elements.clear();
|
|
2916
2942
|
if (typeof window !== "undefined") {
|
|
@@ -2948,16 +2974,27 @@ var CimplifyElements = class {
|
|
|
2948
2974
|
processCheckout(options) {
|
|
2949
2975
|
let abortFn = null;
|
|
2950
2976
|
const task = (async () => {
|
|
2951
|
-
this.debug("[cimplify:checkout] processCheckout called", {
|
|
2977
|
+
this.debug("[cimplify:checkout] processCheckout called", {
|
|
2978
|
+
cart_id: options.cart_id,
|
|
2979
|
+
order_type: options.order_type,
|
|
2980
|
+
location_id: options.location_id
|
|
2981
|
+
});
|
|
2952
2982
|
if (this.checkoutInProgress) {
|
|
2953
2983
|
this.debug("[cimplify:checkout] BLOCKED: already processing");
|
|
2954
|
-
return toCheckoutError(
|
|
2955
|
-
"ALREADY_PROCESSING",
|
|
2956
|
-
"Checkout is already in progress.",
|
|
2957
|
-
false
|
|
2958
|
-
);
|
|
2984
|
+
return toCheckoutError("ALREADY_PROCESSING", "Checkout is already in progress.", false);
|
|
2959
2985
|
}
|
|
2960
2986
|
this.checkoutInProgress = true;
|
|
2987
|
+
if (this.authEstablishmentInProgress) {
|
|
2988
|
+
await this.waitForAuthEstablishment(AUTH_ESTABLISHMENT_WAIT_MS);
|
|
2989
|
+
if (this.authEstablishmentInProgress) {
|
|
2990
|
+
this.checkoutInProgress = false;
|
|
2991
|
+
return toCheckoutError(
|
|
2992
|
+
"AUTH_INCOMPLETE",
|
|
2993
|
+
"Authentication must finish establishing the checkout session.",
|
|
2994
|
+
true
|
|
2995
|
+
);
|
|
2996
|
+
}
|
|
2997
|
+
}
|
|
2961
2998
|
if (!options.cart_id) {
|
|
2962
2999
|
this.debug("[cimplify:checkout] BLOCKED: no cart_id");
|
|
2963
3000
|
this.checkoutInProgress = false;
|
|
@@ -3015,7 +3052,11 @@ var CimplifyElements = class {
|
|
|
3015
3052
|
}
|
|
3016
3053
|
await this.hydrateCustomerData();
|
|
3017
3054
|
}
|
|
3018
|
-
this.debug("[cimplify:checkout] customer data hydrated", {
|
|
3055
|
+
this.debug("[cimplify:checkout] customer data hydrated", {
|
|
3056
|
+
customerData: this.customerData,
|
|
3057
|
+
accountId: this.accountId,
|
|
3058
|
+
isUnifiedCheckout
|
|
3059
|
+
});
|
|
3019
3060
|
const processMessage = {
|
|
3020
3061
|
type: MESSAGE_TYPES.PROCESS_CHECKOUT,
|
|
3021
3062
|
cart_id: options.cart_id,
|
|
@@ -3079,7 +3120,10 @@ var CimplifyElements = class {
|
|
|
3079
3120
|
return;
|
|
3080
3121
|
}
|
|
3081
3122
|
if (message.type === MESSAGE_TYPES.CHECKOUT_COMPLETE) {
|
|
3082
|
-
this.debug("[cimplify:checkout] received checkout_complete", {
|
|
3123
|
+
this.debug("[cimplify:checkout] received checkout_complete", {
|
|
3124
|
+
success: message.success,
|
|
3125
|
+
error: message.error
|
|
3126
|
+
});
|
|
3083
3127
|
settle({
|
|
3084
3128
|
success: message.success,
|
|
3085
3129
|
order: message.order,
|
|
@@ -3090,11 +3134,7 @@ var CimplifyElements = class {
|
|
|
3090
3134
|
if (message.type === MESSAGE_TYPES.LOGOUT_COMPLETE) {
|
|
3091
3135
|
checkoutElement.sendMessage({ type: MESSAGE_TYPES.ABORT_CHECKOUT });
|
|
3092
3136
|
settle(
|
|
3093
|
-
toCheckoutError(
|
|
3094
|
-
"AUTH_LOST",
|
|
3095
|
-
"Authentication was cleared during checkout.",
|
|
3096
|
-
true
|
|
3097
|
-
)
|
|
3137
|
+
toCheckoutError("AUTH_LOST", "Authentication was cleared during checkout.", true)
|
|
3098
3138
|
);
|
|
3099
3139
|
}
|
|
3100
3140
|
};
|
|
@@ -3103,16 +3143,16 @@ var CimplifyElements = class {
|
|
|
3103
3143
|
}
|
|
3104
3144
|
abortFn = () => {
|
|
3105
3145
|
checkoutElement.sendMessage({ type: MESSAGE_TYPES.ABORT_CHECKOUT });
|
|
3106
|
-
settle(
|
|
3107
|
-
toCheckoutError(
|
|
3108
|
-
"CANCELLED",
|
|
3109
|
-
"Checkout was cancelled.",
|
|
3110
|
-
true
|
|
3111
|
-
)
|
|
3112
|
-
);
|
|
3146
|
+
settle(toCheckoutError("CANCELLED", "Checkout was cancelled.", true));
|
|
3113
3147
|
};
|
|
3114
3148
|
this.activeCheckoutAbort = abortFn;
|
|
3115
|
-
this.debug("[cimplify:checkout] sending process_checkout to checkout iframe", {
|
|
3149
|
+
this.debug("[cimplify:checkout] sending process_checkout to checkout iframe", {
|
|
3150
|
+
cart_id: processMessage.cart_id,
|
|
3151
|
+
order_type: processMessage.order_type,
|
|
3152
|
+
hasCustomer: !!processMessage.customer,
|
|
3153
|
+
hasAddress: !!processMessage.address,
|
|
3154
|
+
isUnifiedCheckout
|
|
3155
|
+
});
|
|
3116
3156
|
checkoutElement.sendMessage(processMessage);
|
|
3117
3157
|
this.debug("[cimplify:checkout] postMessage sent, waiting for checkout_complete...");
|
|
3118
3158
|
});
|
|
@@ -3158,11 +3198,16 @@ var CimplifyElements = class {
|
|
|
3158
3198
|
getAppearance() {
|
|
3159
3199
|
return this.options.appearance;
|
|
3160
3200
|
}
|
|
3161
|
-
|
|
3162
|
-
|
|
3201
|
+
isAuthGenerationCurrent(generation, token) {
|
|
3202
|
+
return this.authGeneration === generation && this.client.getAccessToken() === token;
|
|
3203
|
+
}
|
|
3204
|
+
async hydrateCustomerData(generation = this.authGeneration, token = this.accessToken, force = false) {
|
|
3205
|
+
if (!token || !this.isAuthGenerationCurrent(generation, token)) return false;
|
|
3206
|
+
if (this.customerData && !force) return true;
|
|
3163
3207
|
const linkDataResult = await this.client.link.getLinkData();
|
|
3208
|
+
if (!this.isAuthGenerationCurrent(generation, token)) return false;
|
|
3164
3209
|
if (!linkDataResult.ok || !linkDataResult.value?.customer) {
|
|
3165
|
-
return;
|
|
3210
|
+
return true;
|
|
3166
3211
|
}
|
|
3167
3212
|
const customer = linkDataResult.value.customer;
|
|
3168
3213
|
this.customerData = {
|
|
@@ -3171,6 +3216,7 @@ var CimplifyElements = class {
|
|
|
3171
3216
|
phone: customer.phone || null
|
|
3172
3217
|
};
|
|
3173
3218
|
this.customerId = customer.id;
|
|
3219
|
+
return true;
|
|
3174
3220
|
}
|
|
3175
3221
|
sourceElementFor(event, message) {
|
|
3176
3222
|
for (const element of this.elements.values()) {
|
|
@@ -3209,48 +3255,123 @@ var CimplifyElements = class {
|
|
|
3209
3255
|
} catch {
|
|
3210
3256
|
}
|
|
3211
3257
|
}
|
|
3258
|
+
clearClaimedAuthorityAfterRestoreFailure() {
|
|
3259
|
+
if (!this.client.getAccessToken() && !this.client.hasClaimedSessionAuthority()) return;
|
|
3260
|
+
this.accessToken = null;
|
|
3261
|
+
this.accountId = null;
|
|
3262
|
+
this.customerId = null;
|
|
3263
|
+
this.customerData = null;
|
|
3264
|
+
this.addressData = null;
|
|
3265
|
+
this.paymentData = null;
|
|
3266
|
+
this.authEstablishmentInProgress = false;
|
|
3267
|
+
this.client.clearSession();
|
|
3268
|
+
this.broadcastClearedSession();
|
|
3269
|
+
}
|
|
3212
3270
|
async restoreSession() {
|
|
3213
3271
|
if (typeof window === "undefined" || this.accessToken) return;
|
|
3272
|
+
const generation = ++this.authGeneration;
|
|
3214
3273
|
const storageKey = this.sessionStorageKey();
|
|
3215
3274
|
if (!storageKey) return;
|
|
3216
3275
|
let refreshToken = null;
|
|
3217
3276
|
try {
|
|
3218
3277
|
refreshToken = window.localStorage.getItem(storageKey);
|
|
3219
3278
|
} catch {
|
|
3279
|
+
this.clearClaimedAuthorityAfterRestoreFailure();
|
|
3220
3280
|
return;
|
|
3221
3281
|
}
|
|
3222
|
-
if (!refreshToken)
|
|
3223
|
-
|
|
3282
|
+
if (!refreshToken) {
|
|
3283
|
+
this.clearClaimedAuthorityAfterRestoreFailure();
|
|
3284
|
+
return;
|
|
3285
|
+
}
|
|
3286
|
+
const result = await this.client.link.refreshSession(refreshToken, {
|
|
3287
|
+
activateSession: false
|
|
3288
|
+
});
|
|
3289
|
+
if (this.authGeneration !== generation) return;
|
|
3224
3290
|
if (!result.ok || !result.value.session_token) {
|
|
3225
3291
|
this.clearPersistedSession();
|
|
3292
|
+
this.clearClaimedAuthorityAfterRestoreFailure();
|
|
3226
3293
|
return;
|
|
3227
3294
|
}
|
|
3228
3295
|
this.persistRefreshToken(result.value.refresh_token ?? void 0);
|
|
3229
|
-
const
|
|
3230
|
-
|
|
3231
|
-
|
|
3296
|
+
const application = await this.applyAccessToken(result.value.session_token, generation);
|
|
3297
|
+
if (application.kind === "claim_failed") {
|
|
3298
|
+
this.clearPersistedSession();
|
|
3299
|
+
this.broadcastClearedSession();
|
|
3300
|
+
return;
|
|
3301
|
+
}
|
|
3302
|
+
if (application.kind !== "authenticated" || !this.broadcastAccessToken(result.value.session_token, generation)) {
|
|
3303
|
+
return;
|
|
3304
|
+
}
|
|
3305
|
+
this.elements.forEach((element) => element._emitAuthenticated(application.data));
|
|
3232
3306
|
}
|
|
3233
|
-
async applyAccessToken(token) {
|
|
3307
|
+
async applyAccessToken(token, generation) {
|
|
3308
|
+
if (this.authGeneration !== generation) return { kind: "incomplete" };
|
|
3309
|
+
this.authEstablishmentInProgress = true;
|
|
3310
|
+
this.accessToken = null;
|
|
3311
|
+
this.accountId = null;
|
|
3312
|
+
this.customerId = null;
|
|
3313
|
+
this.customerData = null;
|
|
3314
|
+
this.addressData = null;
|
|
3315
|
+
this.paymentData = null;
|
|
3316
|
+
this.client.setAccessToken(token);
|
|
3317
|
+
const claim = await this.client.support.claimConversation();
|
|
3318
|
+
if (!this.isAuthGenerationCurrent(generation, token)) return { kind: "incomplete" };
|
|
3319
|
+
if (!claim.ok && claim.error.code !== "already_claimed") {
|
|
3320
|
+
if (this.client.hasClaimedSessionAuthority()) {
|
|
3321
|
+
this.client.clearSession();
|
|
3322
|
+
} else {
|
|
3323
|
+
this.client.setAccessToken(null);
|
|
3324
|
+
}
|
|
3325
|
+
this.authEstablishmentInProgress = false;
|
|
3326
|
+
return {
|
|
3327
|
+
kind: "claim_failed",
|
|
3328
|
+
code: claim.error.code,
|
|
3329
|
+
message: claim.error.userMessage
|
|
3330
|
+
};
|
|
3331
|
+
}
|
|
3234
3332
|
this.accessToken = token;
|
|
3235
3333
|
this.accountId = decodeJwtSub(token);
|
|
3236
|
-
this.
|
|
3237
|
-
|
|
3238
|
-
|
|
3334
|
+
if (!await this.hydrateCustomerData(generation, token, true)) {
|
|
3335
|
+
return { kind: "incomplete" };
|
|
3336
|
+
}
|
|
3337
|
+
if (!this.isAuthGenerationCurrent(generation, token)) return { kind: "incomplete" };
|
|
3338
|
+
this.authEstablishmentInProgress = false;
|
|
3239
3339
|
return {
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3340
|
+
kind: "authenticated",
|
|
3341
|
+
data: {
|
|
3342
|
+
accountId: this.accountId ?? "",
|
|
3343
|
+
customerId: this.customerId ?? "",
|
|
3344
|
+
token,
|
|
3345
|
+
customer: this.customerData ?? { name: "", email: null, phone: null }
|
|
3346
|
+
}
|
|
3244
3347
|
};
|
|
3245
3348
|
}
|
|
3246
|
-
|
|
3349
|
+
async waitForAuthEstablishment(timeoutMs) {
|
|
3350
|
+
const deadline = Date.now() + timeoutMs;
|
|
3351
|
+
while (this.authEstablishmentInProgress && Date.now() < deadline) {
|
|
3352
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3355
|
+
broadcastAccessToken(token, generation) {
|
|
3356
|
+
if (!this.isAuthGenerationCurrent(generation, token) || this.accessToken !== token || this.authEstablishmentInProgress) {
|
|
3357
|
+
return false;
|
|
3358
|
+
}
|
|
3247
3359
|
const sessionToken = this.client.getSessionToken();
|
|
3248
3360
|
this.elements.forEach((element) => {
|
|
3249
|
-
element.sendMessage({ type: MESSAGE_TYPES.SET_TOKEN, token });
|
|
3250
3361
|
if (sessionToken) {
|
|
3251
3362
|
element.sendMessage({ type: MESSAGE_TYPES.SET_SESSION, sessionToken });
|
|
3252
3363
|
}
|
|
3364
|
+
element.sendMessage({ type: MESSAGE_TYPES.SET_TOKEN, token });
|
|
3365
|
+
});
|
|
3366
|
+
return true;
|
|
3367
|
+
}
|
|
3368
|
+
broadcastClearedSession() {
|
|
3369
|
+
const sessionToken = this.client.getSessionToken();
|
|
3370
|
+
if (!sessionToken) return null;
|
|
3371
|
+
this.elements.forEach((element) => {
|
|
3372
|
+
element.sendMessage({ type: MESSAGE_TYPES.SESSION_CLEARED, sessionToken });
|
|
3253
3373
|
});
|
|
3374
|
+
return sessionToken;
|
|
3254
3375
|
}
|
|
3255
3376
|
startEmbeddedAuth(sourceElement, request) {
|
|
3256
3377
|
if (this.authInProgress) return;
|
|
@@ -3264,6 +3385,7 @@ var CimplifyElements = class {
|
|
|
3264
3385
|
});
|
|
3265
3386
|
return;
|
|
3266
3387
|
}
|
|
3388
|
+
const generation = ++this.authGeneration;
|
|
3267
3389
|
this.authInProgress = true;
|
|
3268
3390
|
void startSignIn({
|
|
3269
3391
|
clientId,
|
|
@@ -3278,6 +3400,7 @@ var CimplifyElements = class {
|
|
|
3278
3400
|
mode: "modal",
|
|
3279
3401
|
silentFirst: request.mode === ELEMENTS_AUTH_MODES.CHECKOUT && request.prompt !== ELEMENTS_AUTH_PROMPTS.LOGIN,
|
|
3280
3402
|
onSuccess: async ({ accessToken }) => {
|
|
3403
|
+
if (this.authGeneration !== generation) return;
|
|
3281
3404
|
this.authInProgress = false;
|
|
3282
3405
|
if (!accessToken) {
|
|
3283
3406
|
sourceElement._emitError({
|
|
@@ -3286,11 +3409,18 @@ var CimplifyElements = class {
|
|
|
3286
3409
|
});
|
|
3287
3410
|
return;
|
|
3288
3411
|
}
|
|
3289
|
-
const
|
|
3290
|
-
this.broadcastAccessToken(accessToken)
|
|
3291
|
-
|
|
3412
|
+
const application = await this.applyAccessToken(accessToken, generation);
|
|
3413
|
+
if (application.kind === "authenticated" && this.broadcastAccessToken(accessToken, generation)) {
|
|
3414
|
+
sourceElement._emitAuthenticated(application.data);
|
|
3415
|
+
} else if (application.kind === "claim_failed") {
|
|
3416
|
+
sourceElement._emitError({
|
|
3417
|
+
code: application.code,
|
|
3418
|
+
message: application.message
|
|
3419
|
+
});
|
|
3420
|
+
}
|
|
3292
3421
|
},
|
|
3293
3422
|
onError: (err2) => {
|
|
3423
|
+
if (this.authGeneration !== generation) return;
|
|
3294
3424
|
this.authInProgress = false;
|
|
3295
3425
|
sourceElement._emitError({
|
|
3296
3426
|
code: err2.error,
|
|
@@ -3298,6 +3428,7 @@ var CimplifyElements = class {
|
|
|
3298
3428
|
});
|
|
3299
3429
|
}
|
|
3300
3430
|
}).catch((error) => {
|
|
3431
|
+
if (this.authGeneration !== generation) return;
|
|
3301
3432
|
this.authInProgress = false;
|
|
3302
3433
|
sourceElement._emitError({
|
|
3303
3434
|
code: "AUTH_START_FAILED",
|
|
@@ -3318,11 +3449,29 @@ var CimplifyElements = class {
|
|
|
3318
3449
|
this.startEmbeddedAuth(sourceElement, message);
|
|
3319
3450
|
break;
|
|
3320
3451
|
case MESSAGE_TYPES.SESSION_ESTABLISHED:
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
this.
|
|
3324
|
-
|
|
3325
|
-
|
|
3452
|
+
{
|
|
3453
|
+
this.authInProgress = false;
|
|
3454
|
+
const generation = ++this.authGeneration;
|
|
3455
|
+
void this.applyAccessToken(message.accessToken, generation).then((application) => {
|
|
3456
|
+
if (this.authGeneration !== generation) return;
|
|
3457
|
+
if (application.kind === "claim_failed") {
|
|
3458
|
+
this.clearPersistedSession();
|
|
3459
|
+
sourceElement.sendMessage({
|
|
3460
|
+
type: MESSAGE_TYPES.SESSION_ESTABLISHMENT_FAILED,
|
|
3461
|
+
accessToken: message.accessToken,
|
|
3462
|
+
code: application.code,
|
|
3463
|
+
message: application.message
|
|
3464
|
+
});
|
|
3465
|
+
this.broadcastClearedSession();
|
|
3466
|
+
return;
|
|
3467
|
+
}
|
|
3468
|
+
if (application.kind !== "authenticated" || !this.broadcastAccessToken(message.accessToken, generation)) {
|
|
3469
|
+
return;
|
|
3470
|
+
}
|
|
3471
|
+
this.persistRefreshToken(message.refreshToken);
|
|
3472
|
+
sourceElement._emitAuthenticated(application.data);
|
|
3473
|
+
});
|
|
3474
|
+
}
|
|
3326
3475
|
break;
|
|
3327
3476
|
case MESSAGE_TYPES.ADDRESS_CHANGED:
|
|
3328
3477
|
case MESSAGE_TYPES.ADDRESS_SELECTED:
|
|
@@ -3341,7 +3490,35 @@ var CimplifyElements = class {
|
|
|
3341
3490
|
this.customerData.phone = message.contact;
|
|
3342
3491
|
}
|
|
3343
3492
|
break;
|
|
3493
|
+
case MESSAGE_TYPES.CONTINUE_WITHOUT_SAVED_DETAILS: {
|
|
3494
|
+
this.authGeneration += 1;
|
|
3495
|
+
this.authInProgress = false;
|
|
3496
|
+
this.authEstablishmentInProgress = false;
|
|
3497
|
+
const carriedIdentityAuthority = Boolean(this.client.getAccessToken()) || this.client.hasClaimedSessionAuthority();
|
|
3498
|
+
this.accessToken = null;
|
|
3499
|
+
this.accountId = null;
|
|
3500
|
+
this.customerId = null;
|
|
3501
|
+
this.customerData = { name: "", email: null, phone: null };
|
|
3502
|
+
this.addressData = null;
|
|
3503
|
+
this.paymentData = null;
|
|
3504
|
+
this.clearPersistedSession();
|
|
3505
|
+
if (carriedIdentityAuthority) {
|
|
3506
|
+
this.client.clearSession();
|
|
3507
|
+
} else {
|
|
3508
|
+
this.client.setAccessToken(null);
|
|
3509
|
+
}
|
|
3510
|
+
this.broadcastClearedSession();
|
|
3511
|
+
if (message.contactType === "email") {
|
|
3512
|
+
this.customerData.email = message.contact;
|
|
3513
|
+
} else {
|
|
3514
|
+
this.customerData.phone = message.contact;
|
|
3515
|
+
}
|
|
3516
|
+
break;
|
|
3517
|
+
}
|
|
3344
3518
|
case MESSAGE_TYPES.LOGOUT_COMPLETE:
|
|
3519
|
+
this.authGeneration += 1;
|
|
3520
|
+
this.authInProgress = false;
|
|
3521
|
+
this.authEstablishmentInProgress = false;
|
|
3345
3522
|
if (this.checkoutInProgress && this.activeCheckoutAbort) {
|
|
3346
3523
|
this.activeCheckoutAbort();
|
|
3347
3524
|
}
|
|
@@ -3353,6 +3530,7 @@ var CimplifyElements = class {
|
|
|
3353
3530
|
this.paymentData = null;
|
|
3354
3531
|
this.clearPersistedSession();
|
|
3355
3532
|
this.client.clearSession();
|
|
3533
|
+
this.broadcastClearedSession();
|
|
3356
3534
|
break;
|
|
3357
3535
|
}
|
|
3358
3536
|
}
|
|
@@ -3486,10 +3664,9 @@ var CimplifyElement = class {
|
|
|
3486
3664
|
const iframe = this.iframe;
|
|
3487
3665
|
if (!iframe || !iframe.isConnected) {
|
|
3488
3666
|
if (iframe && !iframe.isConnected) {
|
|
3489
|
-
console.warn(
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
);
|
|
3667
|
+
console.warn("[cimplify:checkout] sendMessage DROPPED \u2014 iframe detached", {
|
|
3668
|
+
type: message.type
|
|
3669
|
+
});
|
|
3493
3670
|
}
|
|
3494
3671
|
return;
|
|
3495
3672
|
}
|
|
@@ -3588,13 +3765,13 @@ var CimplifyElement = class {
|
|
|
3588
3765
|
submitLabel: this.options.submitLabel
|
|
3589
3766
|
});
|
|
3590
3767
|
const token = this.parent.getAccessToken();
|
|
3591
|
-
if (token) {
|
|
3592
|
-
this.sendMessage({ type: MESSAGE_TYPES.SET_TOKEN, token });
|
|
3593
|
-
}
|
|
3594
3768
|
const sessionToken = this.parent.getSessionToken();
|
|
3595
3769
|
if (sessionToken) {
|
|
3596
3770
|
this.sendMessage({ type: MESSAGE_TYPES.SET_SESSION, sessionToken });
|
|
3597
3771
|
}
|
|
3772
|
+
if (token) {
|
|
3773
|
+
this.sendMessage({ type: MESSAGE_TYPES.SET_TOKEN, token });
|
|
3774
|
+
}
|
|
3598
3775
|
this.pendingInit = null;
|
|
3599
3776
|
}
|
|
3600
3777
|
this.flushPending();
|
|
@@ -3643,4 +3820,4 @@ function createElements(client, businessId, options) {
|
|
|
3643
3820
|
return new CimplifyElements(client, businessId, options);
|
|
3644
3821
|
}
|
|
3645
3822
|
|
|
3646
|
-
export {
|
|
3823
|
+
export { AuthService, BusinessService, CartOperations, CatalogueQueries, CheckoutService, CimplifyElement, CimplifyElements, DEFAULT_ISSUER, ELEMENTS_AUTH_CONTACT_TYPES, ELEMENTS_AUTH_MODES, ELEMENTS_AUTH_PROMPTS, ELEMENT_TYPES, EVENT_TYPES, FxService, InventoryService, LinkService, LiteService, MESSAGE_TYPES, OrderQueries, PKCE_COOKIE, PKCE_COOKIE_PATH, SchedulingService, combine, combineObject, createElements, decodePkceState, err, flatMap, fromPromise, generateIdempotencyKey, generatePkce, generateState, getAuthorizationEndpoint, getOrElse, isErr, isOk, mapError, mapResult, ok, safe, startSignIn, toNullable, tryCatch, unwrap };
|