@cimplify/sdk 0.104.0 → 0.105.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.
Files changed (71) hide show
  1. package/dist/advanced.d.mts +3 -7
  2. package/dist/advanced.d.ts +3 -7
  3. package/dist/advanced.js +23 -23
  4. package/dist/advanced.mjs +4 -4
  5. package/dist/{client-BuLcOWLv.d.ts → catalogue-D1jkpGcr.d.ts} +415 -763
  6. package/dist/{client-D5AoobFc.d.mts → catalogue-DjutZ0FC.d.mts} +415 -763
  7. package/dist/{payment-g0HFkEDU.d.mts → checkout-XoV4HNg2.d.mts} +4156 -1498
  8. package/dist/{payment-g0HFkEDU.d.ts → checkout-XoV4HNg2.d.ts} +4156 -1498
  9. package/dist/{chunk-GOHSXBKW.mjs → chunk-33VCYWVL.mjs} +25 -1
  10. package/dist/{chunk-OKADBZAI.mjs → chunk-37ZZCE7P.mjs} +808 -574
  11. package/dist/{chunk-5BDYDZ4U.js → chunk-3IMPJEUI.js} +892 -657
  12. package/dist/{chunk-YVAEY3VC.js → chunk-7PMMV5X4.js} +1040 -364
  13. package/dist/{chunk-H3RATH4B.mjs → chunk-AVXA4F6G.js} +293 -2
  14. package/dist/{chunk-CNN7Z2IP.js → chunk-EV2EVOYS.js} +27 -0
  15. package/dist/{chunk-4BKOKHE3.js → chunk-NJYR6GGM.mjs} +244 -19
  16. package/dist/{chunk-DYIAX3WI.mjs → chunk-NYDVVNZI.mjs} +11 -2
  17. package/dist/{chunk-E4K2VQDD.js → chunk-PDTXSUHZ.js} +559 -16
  18. package/dist/{chunk-2WPVUIHX.mjs → chunk-Q5HX7LVE.mjs} +1036 -360
  19. package/dist/{chunk-5RT4HYMP.mjs → chunk-TINYV5E2.mjs} +542 -15
  20. package/dist/{chunk-7PDEX54K.js → chunk-UYFTOIFW.js} +13 -3
  21. package/dist/{chunk-OCCNG6MO.mjs → chunk-X7RPMALQ.mjs} +1310 -722
  22. package/dist/{chunk-IQFFSKE2.js → chunk-XHVQDEVO.js} +1345 -746
  23. package/dist/{client-BVNWjk6W.d.ts → client-BBZj15JJ.d.ts} +2 -2
  24. package/dist/{client-fM716k7G.d.mts → client-CZ8MjJ_o.d.mts} +2 -2
  25. package/dist/index-CZjNWbQf.d.ts +8 -0
  26. package/dist/index-DNxWfRHF.d.mts +8 -0
  27. package/dist/{index-BtcoqrY1.d.ts → index-DRMBo26v.d.mts} +9 -4
  28. package/dist/{index-D7Tf3v7c.d.mts → index-DweR60Cv.d.ts} +9 -4
  29. package/dist/index.d.mts +31 -14
  30. package/dist/index.d.ts +31 -14
  31. package/dist/index.js +325 -133
  32. package/dist/index.mjs +6 -6
  33. package/dist/mock/cli.mjs +1450 -386
  34. package/dist/mock/library.js +1176 -352
  35. package/dist/mock/library.mjs +1176 -352
  36. package/dist/mock/msw.js +1176 -352
  37. package/dist/mock/msw.mjs +1176 -352
  38. package/dist/{price-BLIeAb8K.d.ts → price-CUGIYRtD.d.mts} +1 -1
  39. package/dist/{price-Czq_cTC_.d.mts → price-De-sxcuj.d.ts} +1 -1
  40. package/dist/react.d.mts +10 -5
  41. package/dist/react.d.ts +10 -5
  42. package/dist/react.js +227 -197
  43. package/dist/react.mjs +90 -60
  44. package/dist/{server-DKK_D-PP.d.ts → server-Byr4d0hL.d.mts} +31 -57
  45. package/dist/{server-BkVhOIwn.d.mts → server-C_RIDnHU.d.ts} +31 -57
  46. package/dist/server.d.mts +3 -4
  47. package/dist/server.d.ts +3 -4
  48. package/dist/server.js +11 -11
  49. package/dist/server.mjs +5 -5
  50. package/dist/styles.css +2 -2
  51. package/dist/testing/msw.d.mts +2 -2
  52. package/dist/testing/msw.d.ts +2 -2
  53. package/dist/testing/msw.js +4 -4
  54. package/dist/testing/msw.mjs +3 -3
  55. package/dist/testing/suite.d.mts +5 -6
  56. package/dist/testing/suite.d.ts +5 -6
  57. package/dist/testing/suite.js +29 -28
  58. package/dist/testing/suite.mjs +10 -9
  59. package/dist/testing.d.mts +2478 -14
  60. package/dist/testing.d.ts +2478 -14
  61. package/dist/testing.js +167 -89
  62. package/dist/testing.mjs +24 -10
  63. package/dist/utils.d.mts +3 -4
  64. package/dist/utils.d.ts +3 -4
  65. package/dist/utils.js +35 -31
  66. package/dist/utils.mjs +2 -2
  67. package/package.json +9 -9
  68. package/registry/order-history.json +1 -1
  69. package/registry/order-summary.json +1 -1
  70. package/dist/link-D9iSVxt5.d.mts +0 -308
  71. package/dist/link-D9iSVxt5.d.ts +0 -308
@@ -1,6 +1,6 @@
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';
1
+ import { CHECKOUT_STATUS, PAYMENT_METHOD, CHECKOUT_NEXT_ACTION, CHECKOUT_ORDER_RESULT_STATUS, ORDER_TYPE, AUTHORIZATION_TYPE } from './chunk-33VCYWVL.mjs';
2
+ import { paymentAuthorizationUrl, purchaseIntentMobileMoneyNetwork } from './chunk-NYDVVNZI.mjs';
3
+ import { ErrorCode, PURCHASE_INTENT_RESOLVE_STATUS, CimplifyError, PAYMENT_OPTION_STATUS, isSupportedCurrency, PURCHASE_INTENT_CONFIRM_STATUS, PURCHASE_INTENT_ACTION_DECISION, PURCHASE_INTENT_RESOLUTION_KIND, PURCHASE_INTENT_ERROR_CODE, enrichError, LEGACY_CHECKOUT_PAYMENT_METHOD_ALIAS, PURCHASE_INTENT_PAYMENT_METHOD, PURCHASE_INTENT_SOURCE_KIND, LEGACY_CHECKOUT_PAYMENT_STATUS, getErrorHint, MOBILE_MONEY_TENDER_AUTHORITY_KIND } from './chunk-NJYR6GGM.mjs';
4
4
 
5
5
  // src/types/result.ts
6
6
  function ok(value) {
@@ -785,703 +785,796 @@ var CartOperations = class {
785
785
  }
786
786
  };
787
787
 
788
- // src/utils/checkout-resolver.ts
789
- var DEFAULT_POLL_INTERVAL_MS = 3e3;
790
- var DEFAULT_MAX_POLL_ATTEMPTS = 60;
791
- var MAX_CONSECUTIVE_NETWORK_ERRORS = 5;
792
- var NEXT_ACTION_NONE = "none";
793
- var NEXT_ACTION_CARD_POPUP = "card_popup";
794
- var NEXT_ACTION_REDIRECT = "redirect";
795
- var NEXT_ACTION_AUTHORIZATION = "authorization";
796
- var NEXT_ACTION_POLL = "poll";
797
- var VALID_MOBILE_MONEY_PROVIDERS = new Set(Object.values(MOBILE_MONEY_PROVIDER));
798
- function isValidMobileMoneyProvider(value) {
799
- return VALID_MOBILE_MONEY_PROVIDERS.has(value);
800
- }
801
- function normalizeAuthorizationType(value) {
802
- if (value && typeof value === "object" && "address" in value) {
803
- return "address";
804
- }
805
- if (typeof value !== "string") return void 0;
806
- const normalized = value.trim().toLowerCase().replace(/[\s-]+/g, "_");
807
- if (normalized === "otp" || normalized === "pin") return normalized;
808
- if (normalized === "phone" || normalized === "birthday" || normalized === "address") {
809
- return normalized;
788
+ // src/payment-authorization/types.ts
789
+ var PAYMENT_AUTHORIZATION_OUTCOME_STATUS = {
790
+ SUBMITTED: "submitted",
791
+ CANCELLED: "cancelled",
792
+ FAILED: "failed"
793
+ };
794
+ var PAYMENT_AUTHORIZATION_PROVIDER = {
795
+ PAYSTACK: "paystack",
796
+ STRIPE: "stripe"
797
+ };
798
+
799
+ // src/payment-authorization/providers/paystack.ts
800
+ var PAYSTACK_POPUP_ERROR = {
801
+ PROVIDER_UNAVAILABLE: ErrorCode.PROVIDER_UNAVAILABLE,
802
+ SUBMISSION_UNKNOWN: "SUBMISSION_UNKNOWN",
803
+ CANCELLED: "CANCELLED",
804
+ PAYMENT_CANCELLED: ErrorCode.PAYMENT_CANCELLED,
805
+ PAYMENT_FAILED: ErrorCode.PAYMENT_FAILED,
806
+ POPUP_BLOCKED: ErrorCode.POPUP_BLOCKED
807
+ };
808
+ async function openPaystackPopup(options, signal) {
809
+ if (typeof window === "undefined") {
810
+ return { success: false, error: PAYSTACK_POPUP_ERROR.PROVIDER_UNAVAILABLE };
810
811
  }
811
- return void 0;
812
- }
813
- function normalizeAuthorizationSubmission(expectedType, submission) {
814
- if (!submission || submission.type !== expectedType) {
815
- throw new Error(`Expected ${expectedType} authorization details.`);
812
+ let PaystackPop;
813
+ try {
814
+ const imported = await import('@paystack/inline-js');
815
+ PaystackPop = imported.default;
816
+ } catch {
817
+ return { success: false, error: PAYSTACK_POPUP_ERROR.PROVIDER_UNAVAILABLE };
816
818
  }
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
819
+ return new Promise((resolve) => {
820
+ let settled = false;
821
+ let providerStarted = false;
822
+ const resolveOnce = (result) => {
823
+ if (settled) {
824
+ return;
825
+ }
826
+ settled = true;
827
+ if (signal) {
828
+ signal.removeEventListener("abort", onAbort);
829
+ }
830
+ resolve(result);
831
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
- }
839
- function formatMoney(value) {
840
- if (typeof value === "number" && Number.isFinite(value)) {
841
- return value.toFixed(2);
842
- }
843
- if (typeof value === "string" && value.trim().length > 0) {
844
- return value;
845
- }
846
- return "0.00";
847
- }
848
- function createAbortError() {
849
- const error = new Error("CANCELLED");
850
- error.name = "AbortError";
851
- return error;
852
- }
853
- function isAbortError(error) {
854
- if (error instanceof DOMException && error.name === "AbortError") {
855
- return true;
856
- }
857
- return error instanceof Error && (error.name === "AbortError" || error.message === "CANCELLED");
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
832
  const onAbort = () => {
864
- signal.removeEventListener("abort", onAbort);
865
- reject(createAbortError());
833
+ resolveOnce({
834
+ success: false,
835
+ // Once Paystack owns the transaction, cancellation is ambiguous. The
836
+ // adapter converts this into submitted so Cimplify polling decides.
837
+ error: providerStarted ? PAYSTACK_POPUP_ERROR.SUBMISSION_UNKNOWN : PAYSTACK_POPUP_ERROR.CANCELLED
838
+ });
866
839
  };
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
- }
880
- var CheckoutResolver = class {
881
- constructor(options) {
882
- this.client = options.client;
883
- this.checkoutData = options.checkoutData;
884
- this.pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
885
- this.maxPollAttempts = options.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS;
886
- this.onStatusChange = options.onStatusChange;
887
- this.onAuthorizationUiChange = options.onAuthorizationUiChange;
888
- this.onAuthorizationRequired = options.onAuthorizationRequired;
889
- this.signal = options.signal;
890
- this.returnUrl = options.returnUrl;
891
- this.enrollInLink = options.enrollInLink !== false;
892
- this.businessId = options.businessId;
893
- this.addressData = options.addressData;
894
- this.paymentData = options.paymentData;
895
- this.orderType = options.orderType;
896
- this.cartTotal = options.cartTotal;
897
- this.cartCurrency = options.cartCurrency;
898
- this.allowPopups = options.allowPopups ?? typeof window !== "undefined";
899
- }
900
- async resolve(checkoutResult) {
840
+ if (signal?.aborted) {
841
+ resolveOnce({ success: false, error: PAYSTACK_POPUP_ERROR.CANCELLED });
842
+ return;
843
+ }
844
+ if (signal) {
845
+ signal.addEventListener("abort", onAbort, { once: true });
846
+ }
901
847
  try {
902
- this.ensureNotAborted();
903
- if (!checkoutResult.order_id) {
904
- return this.fail("CHECKOUT_FAILED", "Checkout did not return an order ID.", false);
905
- }
906
- if (this.isSuccessfulStatus(checkoutResult.payment_status)) {
907
- return this.finalizeSuccess(checkoutResult);
908
- }
909
- if (this.isFailureStatus(checkoutResult.payment_status)) {
910
- const normalized = normalizeStatusResponse({
911
- status: checkoutResult.payment_status,
912
- paid: false
913
- });
914
- return this.fail(
915
- normalized.status.toUpperCase(),
916
- checkoutResult.display_text || "Payment failed before confirmation.",
917
- false
918
- );
919
- }
920
- const nextAction = checkoutResult.next_action ?? this.deriveLegacyNextAction(checkoutResult);
921
- return this.resolveNextAction({ ...checkoutResult, next_action: nextAction });
922
- } catch (error) {
923
- if (isAbortError(error)) {
924
- return this.fail("CANCELLED", "Checkout was cancelled.", true);
925
- }
926
- const message = error instanceof Error ? error.message : "Checkout failed unexpectedly.";
927
- return this.fail("CHECKOUT_FAILED", message, true);
848
+ const popup = new PaystackPop();
849
+ popup.newTransaction({
850
+ key: options.key,
851
+ email: options.email,
852
+ amount: options.amount,
853
+ currency: options.currency,
854
+ reference: options.reference,
855
+ accessCode: options.accessCode,
856
+ onSuccess: (transaction) => {
857
+ resolveOnce({
858
+ success: true,
859
+ reference: transaction.reference ?? options.reference
860
+ });
861
+ },
862
+ onCancel: () => {
863
+ resolveOnce({ success: false, error: PAYSTACK_POPUP_ERROR.PAYMENT_CANCELLED });
864
+ },
865
+ onError: (error) => {
866
+ resolveOnce({
867
+ success: false,
868
+ error: error?.message || PAYSTACK_POPUP_ERROR.PAYMENT_FAILED
869
+ });
870
+ }
871
+ });
872
+ providerStarted = true;
873
+ } catch {
874
+ resolveOnce({ success: false, error: PAYSTACK_POPUP_ERROR.POPUP_BLOCKED });
928
875
  }
876
+ });
877
+ }
878
+ var PaystackAuthorizationAdapter = class {
879
+ constructor(openPopup = openPaystackPopup) {
880
+ this.openPopup = openPopup;
881
+ this.provider = PAYMENT_AUTHORIZATION_PROVIDER.PAYSTACK;
929
882
  }
930
- deriveLegacyNextAction(checkoutResult) {
931
- if (checkoutResult.client_secret && checkoutResult.public_key) {
883
+ async authorize(context) {
884
+ const result = await this.openPopup(
885
+ {
886
+ key: context.action.public_key,
887
+ email: context.email,
888
+ accessCode: context.action.client_secret,
889
+ reference: context.reference || context.action.client_secret,
890
+ currency: context.currency
891
+ },
892
+ context.signal
893
+ );
894
+ if (result.success) {
932
895
  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
896
+ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.SUBMITTED,
897
+ reference: result.reference || context.reference
937
898
  };
938
899
  }
939
- if (checkoutResult.authorization_url) {
900
+ if (result.error === PAYSTACK_POPUP_ERROR.SUBMISSION_UNKNOWN) {
901
+ return {
902
+ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.SUBMITTED,
903
+ reference: context.reference
904
+ };
905
+ }
906
+ if (!result.error || result.error === PAYSTACK_POPUP_ERROR.CANCELLED || result.error === PAYSTACK_POPUP_ERROR.PAYMENT_CANCELLED) {
907
+ return { status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED };
908
+ }
909
+ if (result.error === PAYSTACK_POPUP_ERROR.POPUP_BLOCKED) {
940
910
  return {
941
- type: NEXT_ACTION_REDIRECT,
942
- authorization_url: checkoutResult.authorization_url
911
+ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
912
+ code: ErrorCode.POPUP_BLOCKED,
913
+ message: "Unable to open the Paystack payment popup. Please allow popups and try again.",
914
+ recoverable: true
943
915
  };
944
916
  }
945
- if (checkoutResult.requires_authorization && checkoutResult.authorization_type) {
917
+ if (result.error === PAYSTACK_POPUP_ERROR.PROVIDER_UNAVAILABLE) {
946
918
  return {
947
- type: NEXT_ACTION_AUTHORIZATION,
948
- authorization_type: checkoutResult.authorization_type,
949
- display_text: checkoutResult.display_text
919
+ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
920
+ code: ErrorCode.PROVIDER_UNAVAILABLE,
921
+ message: "Paystack is unavailable in this environment.",
922
+ recoverable: false
950
923
  };
951
924
  }
952
- return { type: NEXT_ACTION_POLL };
925
+ return {
926
+ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
927
+ code: ErrorCode.PAYMENT_FAILED,
928
+ message: result.error || "Paystack payment could not be submitted.",
929
+ recoverable: true
930
+ };
931
+ }
932
+ };
933
+
934
+ // src/payment-authorization/providers/stripe.ts
935
+ var STRIPE_REDIRECT_MODE = "if_required";
936
+ var STRIPE_PAYMENT_ELEMENT_TYPE = "payment";
937
+ async function loadStripeFromPeer(publicKey, options) {
938
+ try {
939
+ const imported = await import('@stripe/stripe-js');
940
+ return imported.loadStripe ? imported.loadStripe(publicKey, options) : null;
941
+ } catch {
942
+ return null;
953
943
  }
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()) {
944
+ }
945
+ function createStripeModal() {
946
+ if (typeof document === "undefined" || !document.body) return null;
947
+ const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
948
+ const root = document.createElement("div");
949
+ root.setAttribute("role", "dialog");
950
+ root.setAttribute("aria-modal", "true");
951
+ root.setAttribute("aria-label", "Secure card payment");
952
+ Object.assign(root.style, {
953
+ position: "fixed",
954
+ inset: "0",
955
+ zIndex: "2147483647",
956
+ display: "grid",
957
+ placeItems: "center",
958
+ padding: "16px",
959
+ background: "rgba(15, 23, 42, 0.58)"
960
+ });
961
+ const form = document.createElement("form");
962
+ Object.assign(form.style, {
963
+ width: "min(100%, 480px)",
964
+ maxHeight: "calc(100vh - 32px)",
965
+ overflow: "auto",
966
+ borderRadius: "12px",
967
+ padding: "24px",
968
+ background: "#fff",
969
+ boxShadow: "0 24px 80px rgba(15, 23, 42, 0.32)"
970
+ });
971
+ const title = document.createElement("h2");
972
+ title.textContent = "Complete card payment";
973
+ Object.assign(title.style, { margin: "0 0 18px", font: "600 18px/1.4 system-ui" });
974
+ const paymentMount = document.createElement("div");
975
+ paymentMount.setAttribute("data-cimplify-stripe-payment-element", "");
976
+ const error = document.createElement("p");
977
+ error.setAttribute("role", "alert");
978
+ Object.assign(error.style, {
979
+ minHeight: "20px",
980
+ margin: "14px 0 0",
981
+ color: "#b91c1c",
982
+ font: "14px/1.4 system-ui"
983
+ });
984
+ const actions = document.createElement("div");
985
+ Object.assign(actions.style, {
986
+ display: "flex",
987
+ justifyContent: "flex-end",
988
+ gap: "10px",
989
+ marginTop: "18px"
990
+ });
991
+ const cancelButton = document.createElement("button");
992
+ cancelButton.type = "button";
993
+ cancelButton.textContent = "Cancel";
994
+ Object.assign(cancelButton.style, {
995
+ border: "1px solid #cbd5e1",
996
+ borderRadius: "8px",
997
+ padding: "10px 16px",
998
+ background: "#fff",
999
+ color: "#0f172a",
1000
+ cursor: "pointer"
1001
+ });
1002
+ const submitButton = document.createElement("button");
1003
+ submitButton.type = "submit";
1004
+ submitButton.textContent = "Pay securely";
1005
+ Object.assign(submitButton.style, {
1006
+ border: "0",
1007
+ borderRadius: "8px",
1008
+ padding: "10px 16px",
1009
+ background: "#0f172a",
1010
+ color: "#fff",
1011
+ cursor: "pointer"
1012
+ });
1013
+ actions.append(cancelButton, submitButton);
1014
+ form.append(title, paymentMount, error, actions);
1015
+ root.append(form);
1016
+ document.body.append(root);
1017
+ cancelButton.focus();
1018
+ return { root, form, paymentMount, submitButton, cancelButton, error, previousFocus };
1019
+ }
1020
+ function stripeFailure(error) {
1021
+ const message = error?.message || "Stripe could not authorize this payment.";
1022
+ if (error?.code === "payment_intent_authentication_failure" || error?.type === "invalid_request_error") {
1023
+ return {
1024
+ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
1025
+ code: ErrorCode.AUTHORIZATION_FAILED,
1026
+ message,
1027
+ recoverable: true
1028
+ };
1029
+ }
1030
+ return {
1031
+ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
1032
+ code: ErrorCode.PAYMENT_FAILED,
1033
+ message,
1034
+ recoverable: true
1035
+ };
1036
+ }
1037
+ var StripeAuthorizationAdapter = class {
1038
+ constructor(loadStripe = loadStripeFromPeer) {
1039
+ this.loadStripe = loadStripe;
1040
+ this.provider = PAYMENT_AUTHORIZATION_PROVIDER.STRIPE;
1041
+ }
1042
+ async authorize(context) {
1043
+ if (typeof window === "undefined" || typeof document === "undefined" || context.signal?.aborted) {
1044
+ return context.signal?.aborted ? { status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED } : {
1045
+ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
1046
+ code: ErrorCode.PROVIDER_UNAVAILABLE,
1047
+ message: "Stripe Payment Element is unavailable in this environment.",
1048
+ recoverable: false
1049
+ };
1050
+ }
1051
+ let stripe;
1052
+ try {
1053
+ stripe = await this.loadStripe(
1054
+ context.action.public_key,
1055
+ context.action.provider_account_id ? { stripeAccount: context.action.provider_account_id } : void 0
1056
+ );
1057
+ } catch (error) {
956
1058
  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
- )
1059
+ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
1060
+ code: ErrorCode.PROVIDER_UNAVAILABLE,
1061
+ message: error instanceof Error ? error.message : "Stripe.js could not be loaded.",
1062
+ recoverable: true
963
1063
  };
964
1064
  }
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) {
1065
+ if (context.signal?.aborted) {
1066
+ return { status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED };
1067
+ }
1068
+ if (!stripe) {
972
1069
  return {
973
- ok: false,
974
- result: this.fail(
975
- "PROVIDER_UNAVAILABLE",
976
- "Card authorization UI is unavailable in this environment.",
977
- false
978
- )
1070
+ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
1071
+ code: ErrorCode.PROVIDER_UNAVAILABLE,
1072
+ message: "Stripe.js could not be loaded.",
1073
+ recoverable: false
979
1074
  };
980
1075
  }
981
- const currency = this.getOrderCurrency(checkoutResult);
982
- if (!currency) {
1076
+ const modal = createStripeModal();
1077
+ if (!modal) {
983
1078
  return {
984
- ok: false,
985
- result: this.fail("INVALID_CURRENCY", "Payment currency is missing or unsupported.", false)
1079
+ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
1080
+ code: ErrorCode.PROVIDER_UNAVAILABLE,
1081
+ message: "Stripe Payment Element could not be mounted.",
1082
+ recoverable: false
986
1083
  };
987
1084
  }
988
- let outcome;
1085
+ let paymentElement;
1086
+ let elements;
989
1087
  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") {
1088
+ elements = stripe.elements({ clientSecret: context.action.client_secret });
1089
+ paymentElement = elements.create(STRIPE_PAYMENT_ELEMENT_TYPE);
1090
+ paymentElement.mount(modal.paymentMount);
1091
+ } catch {
1092
+ modal.root.remove();
1093
+ modal.previousFocus?.focus();
1005
1094
  return {
1006
- ok: false,
1007
- result: this.fail(
1008
- "PAYMENT_CANCELLED",
1009
- "Card payment was cancelled before submission.",
1010
- true
1011
- )
1095
+ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
1096
+ code: ErrorCode.PROVIDER_UNAVAILABLE,
1097
+ message: "Stripe Payment Element could not be initialized.",
1098
+ recoverable: false
1012
1099
  };
1013
1100
  }
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
- }) {
1024
- if (this.isSuccessfulStatus(checkoutResult.payment_status)) {
1025
- return this.finalizeSuccess(checkoutResult);
1026
- }
1027
- let latestCheckoutResult = checkoutResult;
1028
- let paymentReference = checkoutResult.payment_reference;
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;
1101
+ if (context.signal?.aborted) {
1102
+ if (paymentElement.destroy) paymentElement.destroy();
1103
+ else paymentElement.unmount?.();
1104
+ modal.root.remove();
1105
+ modal.previousFocus?.focus();
1106
+ return { status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED };
1107
+ }
1108
+ return new Promise((resolve) => {
1109
+ let settled = false;
1110
+ let submitting = false;
1111
+ let confirmationStarted = false;
1112
+ const cleanup = () => {
1113
+ context.signal?.removeEventListener("abort", onAbort);
1114
+ modal.form.removeEventListener("submit", onSubmit);
1115
+ modal.cancelButton.removeEventListener("click", onCancel);
1116
+ if (paymentElement.destroy) paymentElement.destroy();
1117
+ else paymentElement.unmount?.();
1118
+ modal.root.remove();
1119
+ modal.previousFocus?.focus();
1120
+ };
1121
+ const settle = (outcome) => {
1122
+ if (settled) return;
1123
+ settled = true;
1124
+ cleanup();
1125
+ resolve(outcome);
1126
+ };
1127
+ const onAbort = () => {
1128
+ if (confirmationStarted) {
1129
+ settle({
1130
+ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.SUBMITTED,
1131
+ reference: context.reference
1132
+ });
1133
+ return;
1042
1134
  }
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) {
1048
- return this.fail(
1049
- "INVALID_REDIRECT_AUTHORIZATION",
1050
- "The payment provider returned an invalid authorization URL.",
1051
- false
1052
- );
1053
- }
1054
- if (typeof window !== "undefined" && this.returnUrl) {
1055
- window.location.assign(authorizationUrl);
1056
- return this.fail(
1057
- "REDIRECT_REQUIRED",
1058
- "Redirecting to complete payment authorization.",
1059
- true
1060
- );
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;
1135
+ settle({ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED });
1136
+ };
1137
+ const onCancel = () => {
1138
+ if (!confirmationStarted) {
1139
+ settle({ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED });
1077
1140
  }
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;
1141
+ };
1142
+ const onSubmit = async (event) => {
1143
+ event.preventDefault();
1144
+ if (submitting || settled) return;
1145
+ submitting = true;
1146
+ modal.submitButton.disabled = true;
1147
+ modal.error.textContent = "";
1148
+ try {
1149
+ const validation = elements.submit ? await elements.submit() : {};
1150
+ if (validation.error) {
1151
+ modal.error.textContent = validation.error.message || "Check your payment details.";
1152
+ submitting = false;
1153
+ modal.submitButton.disabled = false;
1154
+ return;
1092
1155
  }
1093
- if (!authorization.value) {
1094
- break actionLoop;
1156
+ if (settled || context.signal?.aborted) {
1157
+ settle({ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED });
1158
+ return;
1095
1159
  }
1096
- latestCheckoutResult = authorization.value;
1097
- paymentReference = authorization.value.payment_reference || paymentReference;
1098
- if (this.isSuccessfulStatus(authorization.value.payment_status)) {
1099
- return this.finalizeSuccess(authorization.value);
1160
+ confirmationStarted = true;
1161
+ modal.cancelButton.disabled = true;
1162
+ const confirmation = await stripe.confirmPayment({
1163
+ elements,
1164
+ confirmParams: { return_url: context.returnUrl || window.location.href },
1165
+ redirect: STRIPE_REDIRECT_MODE
1166
+ });
1167
+ if (settled) return;
1168
+ if (confirmation.error) {
1169
+ settle(stripeFailure(confirmation.error));
1170
+ return;
1100
1171
  }
1101
- if (this.isFailureStatus(authorization.value.payment_status)) {
1102
- return this.fail(
1103
- "AUTHORIZATION_FAILED",
1104
- authorization.value.display_text || "Payment authorization failed.",
1105
- false
1106
- );
1172
+ settle({
1173
+ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.SUBMITTED,
1174
+ reference: confirmation.paymentIntent?.id || context.reference
1175
+ });
1176
+ } catch (error) {
1177
+ if (confirmationStarted) {
1178
+ settle({
1179
+ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.SUBMITTED,
1180
+ reference: context.reference
1181
+ });
1182
+ return;
1107
1183
  }
1108
- action = authorization.value.next_action ?? this.deriveLegacyNextAction(authorization.value);
1109
- continue actionLoop;
1110
- }
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
1184
+ settle(
1185
+ stripeFailure({
1186
+ message: error instanceof Error ? error.message : "Stripe confirmation failed."
1187
+ })
1118
1188
  );
1119
- }
1120
- }
1121
- return this.pollUntilTerminal({
1122
- orderId: latestCheckoutResult.order_id,
1123
- latestCheckoutResult,
1124
- paymentReference,
1125
- resolutionState
1189
+ }
1190
+ };
1191
+ modal.form.addEventListener("submit", onSubmit);
1192
+ modal.cancelButton.addEventListener("click", onCancel);
1193
+ context.signal?.addEventListener("abort", onAbort, { once: true });
1194
+ paymentElement.on?.("escape", onCancel);
1195
+ paymentElement.on?.("loaderror", (event) => {
1196
+ if (confirmationStarted) return;
1197
+ settle({
1198
+ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
1199
+ code: ErrorCode.PROVIDER_UNAVAILABLE,
1200
+ message: event?.error?.message || "Stripe Payment Element failed to load.",
1201
+ recoverable: true
1202
+ });
1203
+ });
1126
1204
  });
1127
1205
  }
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
- );
1206
+ };
1207
+
1208
+ // src/payment-authorization/registry.ts
1209
+ function normalizeProvider(provider) {
1210
+ return typeof provider === "string" ? provider.trim().toLowerCase() : "";
1211
+ }
1212
+ var PaymentAuthorizationAdapterRegistry = class {
1213
+ constructor(adapters = []) {
1214
+ this.adapters = /* @__PURE__ */ new Map();
1215
+ for (const adapter of adapters) {
1216
+ this.register(adapter);
1135
1217
  }
1136
- resolutionState.authorizationSteps += 1;
1137
- return void 0;
1138
1218
  }
1139
- async pollUntilTerminal(input) {
1140
- const latestCheckoutResult = input.latestCheckoutResult;
1141
- let paymentReference = input.paymentReference;
1142
- const { resolutionState } = input;
1143
- while (resolutionState.pollAttempts < this.maxPollAttempts) {
1144
- this.ensureNotAborted();
1145
- const attempt = resolutionState.pollAttempts;
1146
- resolutionState.pollAttempts += 1;
1147
- this.emit("polling", {
1148
- poll_attempt: attempt,
1149
- max_poll_attempts: this.maxPollAttempts,
1150
- order_id: input.orderId,
1151
- order_number: latestCheckoutResult.order_number
1152
- });
1153
- const statusResult = await this.client.checkout.pollPaymentStatus(input.orderId);
1154
- if (!statusResult.ok) {
1155
- resolutionState.consecutivePollErrors += 1;
1156
- if (resolutionState.consecutivePollErrors >= MAX_CONSECUTIVE_NETWORK_ERRORS) {
1157
- return this.fail(
1158
- "NETWORK_ERROR",
1159
- "Unable to confirm payment due to repeated network errors.",
1160
- true
1161
- );
1162
- }
1163
- await this.wait(this.pollIntervalMs);
1164
- continue;
1165
- }
1166
- resolutionState.consecutivePollErrors = 0;
1167
- if (statusResult.value.reference) {
1168
- paymentReference = statusResult.value.reference;
1169
- }
1170
- const normalized = normalizeStatusResponse(statusResult.value);
1171
- if (normalized.paid || isPaymentStatusSuccess(normalized.status)) {
1172
- return this.finalizeSuccess({
1173
- ...latestCheckoutResult,
1174
- payment_status: normalized.status,
1175
- payment_reference: paymentReference || latestCheckoutResult.payment_reference
1176
- });
1177
- }
1178
- if (isPaymentStatusFailure(normalized.status)) {
1179
- return this.fail(
1180
- normalized.status ? normalized.status.toUpperCase() : "PAYMENT_FAILED",
1181
- normalized.message || "Payment failed during confirmation.",
1182
- false
1183
- );
1184
- }
1185
- if (isPaymentStatusRequiresAction(normalized.status)) {
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
- );
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
- );
1209
- }
1210
- await this.wait(this.pollIntervalMs);
1219
+ register(adapter) {
1220
+ const provider = normalizeProvider(adapter.provider);
1221
+ if (!provider) {
1222
+ throw new TypeError("Payment authorization adapter provider cannot be empty.");
1211
1223
  }
1212
- return this.fail(
1213
- "PAYMENT_TIMEOUT",
1214
- "Payment confirmation timed out. Please retry checkout.",
1215
- true
1216
- );
1224
+ this.adapters.set(provider, adapter);
1225
+ return this;
1217
1226
  }
1218
- async handleAuthorization(input) {
1219
- const authorizationType = input.authorizationType;
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
- };
1230
- }
1231
- this.emit("awaiting_authorization", {
1232
- authorization_type: authorizationType,
1233
- display_text: input.displayText,
1234
- provider: input.provider,
1235
- order_id: input.orderId,
1236
- order_number: input.orderNumber
1237
- });
1238
- let authorizationRequest;
1239
- const submit = (authorization) => {
1240
- this.ensureNotAborted();
1241
- let normalizedAuthorization;
1242
- try {
1243
- normalizedAuthorization = normalizeAuthorizationSubmission(
1244
- authorizationType,
1245
- authorization
1246
- );
1247
- } catch (error) {
1248
- return Promise.reject(error);
1249
- }
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
- });
1266
- }
1267
- return authorizationRequest.then(() => void 0);
1268
- };
1269
- try {
1270
- if (this.onAuthorizationRequired) {
1271
- await waitForAbortable(
1272
- Promise.resolve(this.onAuthorizationRequired(authorizationType, submit)),
1273
- this.signal
1274
- );
1275
- } else {
1276
- return {
1277
- ok: false,
1278
- result: this.fail(
1279
- "AUTHORIZATION_REQUIRED",
1280
- "Authorization callback is required in headless checkout mode.",
1281
- false
1282
- )
1283
- };
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
- };
1299
- } catch (error) {
1300
- if (isAbortError(error)) {
1301
- return {
1302
- ok: false,
1303
- result: this.fail("CANCELLED", "Checkout was cancelled.", true)
1304
- };
1305
- }
1306
- const message = error instanceof Error ? error.message : "Payment authorization failed.";
1307
- return {
1308
- ok: false,
1309
- result: this.fail("AUTHORIZATION_FAILED", message, true)
1310
- };
1311
- }
1227
+ unregister(provider) {
1228
+ return this.adapters.delete(normalizeProvider(provider));
1312
1229
  }
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
- }
1318
- this.emit("finalizing", {
1319
- order_id: checkoutResult.order_id,
1320
- order_number: checkoutResult.order_number
1321
- });
1322
- const enrolledInLink = await this.maybeEnrollInLink(checkoutResult.order_id);
1323
- this.emit("success", {
1324
- order_id: checkoutResult.order_id,
1325
- order_number: checkoutResult.order_number
1326
- });
1327
- return {
1328
- success: true,
1329
- order: {
1330
- id: checkoutResult.order_id,
1331
- order_number: checkoutResult.order_number || checkoutResult.order_id,
1332
- status: checkoutResult.payment_status || "paid",
1333
- total: this.getOrderTotal(checkoutResult),
1334
- currency
1335
- },
1336
- enrolled_in_link: enrolledInLink
1337
- };
1230
+ get(provider) {
1231
+ return this.adapters.get(normalizeProvider(provider));
1338
1232
  }
1339
- async maybeEnrollInLink(orderId) {
1340
- if (!this.enrollInLink || !orderId) {
1341
- return false;
1342
- }
1343
- let businessId = this.businessId;
1344
- if (!businessId) {
1345
- const businessResult = await this.client.business.getInfo();
1346
- if (!businessResult.ok || !businessResult.value?.id) {
1347
- return false;
1348
- }
1349
- businessId = businessResult.value.id;
1350
- }
1351
- const address = this.getEnrollmentAddress();
1352
- const mobileMoney = this.getEnrollmentMobileMoney();
1353
- try {
1354
- const enrollment = await this.client.link.enrollAndLinkOrder({
1355
- order_id: orderId,
1356
- business_id: businessId,
1357
- order_type: this.orderType || this.checkoutData.order_type,
1358
- address,
1359
- mobile_money: mobileMoney
1360
- });
1361
- return enrollment.ok && enrollment.value.success;
1362
- } catch {
1363
- return false;
1364
- }
1233
+ supports(provider) {
1234
+ return this.adapters.has(normalizeProvider(provider));
1365
1235
  }
1366
- getEnrollmentAddress() {
1367
- const source = this.addressData ?? this.checkoutData.address_info;
1368
- if (!source?.street_address) {
1369
- return void 0;
1370
- }
1371
- return {
1372
- label: "Default",
1373
- street_address: source.street_address,
1374
- apartment: source.apartment || void 0,
1375
- city: source.city || "",
1376
- region: source.region || "",
1377
- postal_code: source.postal_code || void 0,
1378
- country: source.country || void 0,
1379
- delivery_instructions: source.delivery_instructions || void 0,
1380
- phone_for_delivery: source.phone_for_delivery || void 0,
1381
- latitude: source.latitude,
1382
- longitude: source.longitude
1383
- };
1236
+ providers() {
1237
+ return [...this.adapters.keys()];
1384
1238
  }
1385
- getEnrollmentMobileMoney() {
1386
- if (this.paymentData?.type === PAYMENT_METHOD.MOBILE_MONEY && this.paymentData.phone_number && this.paymentData.provider && isValidMobileMoneyProvider(this.paymentData.provider)) {
1239
+ async authorize(action, options) {
1240
+ const provider = normalizeProvider(action.provider);
1241
+ if (!provider) {
1387
1242
  return {
1388
- phone_number: this.paymentData.phone_number,
1389
- provider: this.paymentData.provider,
1390
- label: this.paymentData.label || "Mobile Money"
1243
+ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
1244
+ code: ErrorCode.PROVIDER_UNAVAILABLE,
1245
+ message: "Card authorization response did not identify a payment provider.",
1246
+ recoverable: false
1391
1247
  };
1392
1248
  }
1393
- if (this.checkoutData.mobile_money_details?.phone_number) {
1249
+ const adapter = this.adapters.get(provider);
1250
+ if (!adapter) {
1394
1251
  return {
1395
- phone_number: this.checkoutData.mobile_money_details.phone_number,
1396
- provider: this.checkoutData.mobile_money_details.provider,
1397
- label: "Mobile Money"
1252
+ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
1253
+ code: ErrorCode.PROVIDER_UNAVAILABLE,
1254
+ message: `Card authorization provider '${provider}' is not supported by this SDK client.`,
1255
+ recoverable: false
1398
1256
  };
1399
1257
  }
1400
- return void 0;
1401
- }
1402
- getOrderTotal(checkoutResult) {
1403
- if (checkoutResult.fx?.pay_amount !== void 0) {
1404
- return formatMoney(checkoutResult.fx.pay_amount);
1405
- }
1406
- if (this.cartTotal !== void 0) {
1407
- return formatMoney(this.cartTotal);
1258
+ try {
1259
+ const normalizedAction = action.provider === provider ? action : { ...action, provider };
1260
+ return await adapter.authorize({ ...options, action: normalizedAction });
1261
+ } catch (error) {
1262
+ return {
1263
+ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
1264
+ code: ErrorCode.PAYMENT_FAILED,
1265
+ message: error instanceof Error ? error.message : `Card authorization provider '${provider}' failed unexpectedly.`,
1266
+ recoverable: true
1267
+ };
1408
1268
  }
1409
- return "0.00";
1410
1269
  }
1411
- getOrderCurrency(checkoutResult) {
1412
- if (checkoutResult.fx?.pay_currency) {
1413
- const currency2 = checkoutResult.fx.pay_currency.trim().toUpperCase();
1414
- return isSupportedCurrency(currency2) ? currency2 : void 0;
1415
- }
1416
- if (this.checkoutData.pay_currency) {
1417
- const currency2 = this.checkoutData.pay_currency.trim().toUpperCase();
1418
- return isSupportedCurrency(currency2) ? currency2 : void 0;
1419
- }
1420
- const currency = this.cartCurrency.trim().toUpperCase();
1421
- return isSupportedCurrency(currency) ? currency : void 0;
1270
+ };
1271
+ function createDefaultPaymentAuthorizationAdapterRegistry() {
1272
+ return new PaymentAuthorizationAdapterRegistry([
1273
+ new PaystackAuthorizationAdapter(),
1274
+ new StripeAuthorizationAdapter()
1275
+ ]);
1276
+ }
1277
+
1278
+ // src/utils/purchase-intent-confirmation.ts
1279
+ var EXACT_ZERO_MONEY = /^[+-]?0+(?:\.0+)?(?:[eE][+-]?\d+)?$/;
1280
+ function isExactlyZeroMoney(value) {
1281
+ if (typeof value === "number") return Object.is(value, 0) || Object.is(value, -0);
1282
+ return EXACT_ZERO_MONEY.test(value.trim());
1283
+ }
1284
+ function selectPurchaseIntentPaymentOption(terms, selection) {
1285
+ return terms.payment_options.filter((option) => option.status === PAYMENT_OPTION_STATUS.ELIGIBLE).sort((left, right) => left.rank - right.rank).find(
1286
+ (option) => option.method_kind === selection.method_kind && (selection.payment_option_id === void 0 || option.id === selection.payment_option_id)
1287
+ );
1288
+ }
1289
+ function createPurchaseIntentConfirmation(terms, paymentOption, idempotencyKey) {
1290
+ const normalizedKey = idempotencyKey.trim();
1291
+ if (!normalizedKey) throw new TypeError("idempotencyKey must not be empty");
1292
+ const requiresOption = purchaseIntentRequiresPaymentOption(terms);
1293
+ if (!paymentOption && requiresOption) {
1294
+ throw new TypeError("Nonzero rail terms require an eligible payment option");
1295
+ }
1296
+ if (paymentOption && !requiresOption) {
1297
+ throw new TypeError("Zero-rail terms must not name a payment option");
1298
+ }
1299
+ const authoritativeOption = paymentOption ? terms.payment_options.find(
1300
+ (candidate) => candidate.id === paymentOption.id && candidate.status === PAYMENT_OPTION_STATUS.ELIGIBLE
1301
+ ) : void 0;
1302
+ if (paymentOption && !authoritativeOption) {
1303
+ throw new TypeError("Payment option is not eligible for these checkout terms");
1422
1304
  }
1423
- emit(status, context = {}) {
1424
- if (!this.onStatusChange) {
1425
- return;
1305
+ return {
1306
+ accepted_intent_revision: terms.intent_revision,
1307
+ accepted_terms_version: terms.terms_version,
1308
+ accepted_due_now: terms.money.due_now,
1309
+ // Rail fees and routes may differ by option. Consent is to the exact
1310
+ // server-issued buyer debit, never an ambiguous principal/fee aggregate.
1311
+ accepted_customer_debit_amount: authoritativeOption?.customer_debit_amount ?? terms.money.rail_amount,
1312
+ currency: terms.money.currency,
1313
+ payment_option_id: authoritativeOption?.id ?? null,
1314
+ idempotency_key: normalizedKey
1315
+ };
1316
+ }
1317
+ function purchaseIntentRequiresPaymentOption(terms) {
1318
+ return terms.payment_options.length > 0 || !isExactlyZeroMoney(terms.money.rail_amount);
1319
+ }
1320
+
1321
+ // src/utils/purchase-intent-adapter.ts
1322
+ function tenderPreference(form) {
1323
+ if (form.payment_method === PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY) {
1324
+ if (form.link_payment_method_id) {
1325
+ return {
1326
+ method_kind: PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY,
1327
+ authority: {
1328
+ authority_kind: MOBILE_MONEY_TENDER_AUTHORITY_KIND.SAVED_REFERENCE,
1329
+ stored_instrument_id: form.link_payment_method_id
1330
+ }
1331
+ };
1426
1332
  }
1427
- try {
1428
- this.onStatusChange(status, context);
1429
- } catch {
1333
+ const details = form.mobile_money_details;
1334
+ if (!details?.phone_number || !details.provider) {
1335
+ throw new CimplifyError(
1336
+ ErrorCode.INVALID_PAYMENT_METHOD,
1337
+ "Mobile money requires a phone number and network.",
1338
+ false
1339
+ );
1430
1340
  }
1431
- }
1432
- notifyAuthorizationUiChange(open) {
1433
- try {
1434
- this.onAuthorizationUiChange?.(open);
1435
- } catch {
1341
+ const network = purchaseIntentMobileMoneyNetwork(details.provider);
1342
+ if (!network) {
1343
+ throw new CimplifyError(
1344
+ ErrorCode.INVALID_PAYMENT_METHOD,
1345
+ "That mobile money network is not available for PurchaseIntent checkout.",
1346
+ false
1347
+ );
1436
1348
  }
1437
- }
1438
- fail(code, message, recoverable) {
1439
- this.emit("failed", {
1440
- display_text: message
1441
- });
1442
1349
  return {
1443
- success: false,
1444
- error: {
1445
- code,
1446
- message,
1447
- recoverable
1350
+ method_kind: PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY,
1351
+ authority: {
1352
+ authority_kind: MOBILE_MONEY_TENDER_AUTHORITY_KIND.TRANSIENT,
1353
+ phone_number: details.phone_number,
1354
+ network
1448
1355
  }
1449
1356
  };
1450
1357
  }
1451
- isSuccessfulStatus(status) {
1452
- const normalized = normalizeStatusResponse({ status, paid: false });
1453
- return normalized.paid || isPaymentStatusSuccess(normalized.status);
1358
+ if (form.payment_method === LEGACY_CHECKOUT_PAYMENT_METHOD_ALIAS.CASH || form.payment_method === PURCHASE_INTENT_PAYMENT_METHOD.OFFLINE) {
1359
+ throw new CimplifyError(
1360
+ ErrorCode.INVALID_PAYMENT_METHOD,
1361
+ "Offline tender requires an authenticated staff checkout.",
1362
+ false
1363
+ );
1454
1364
  }
1455
- isFailureStatus(status) {
1456
- const normalized = normalizeStatusResponse({ status, paid: false });
1457
- return isPaymentStatusFailure(normalized.status);
1365
+ if (form.payment_method === PURCHASE_INTENT_PAYMENT_METHOD.CARD) {
1366
+ return {
1367
+ method_kind: PURCHASE_INTENT_PAYMENT_METHOD.CARD,
1368
+ stored_instrument_id: form.link_payment_method_id
1369
+ };
1458
1370
  }
1459
- ensureNotAborted() {
1460
- if (this.signal?.aborted) {
1461
- throw createAbortError();
1462
- }
1371
+ if (form.payment_method === LEGACY_CHECKOUT_PAYMENT_METHOD_ALIAS.STORE_CREDIT) {
1372
+ return void 0;
1463
1373
  }
1464
- wait(ms) {
1465
- this.ensureNotAborted();
1466
- return new Promise((resolve, reject) => {
1467
- const timer = setTimeout(() => {
1468
- if (this.signal) {
1469
- this.signal.removeEventListener("abort", onAbort);
1374
+ throw new CimplifyError(
1375
+ ErrorCode.INVALID_PAYMENT_METHOD,
1376
+ "Checkout payment method is not supported.",
1377
+ false
1378
+ );
1379
+ }
1380
+ function checkoutFormToIntentRequest(form, clientIntentKey) {
1381
+ return {
1382
+ client_intent_key: clientIntentKey,
1383
+ source: { kind: PURCHASE_INTENT_SOURCE_KIND.CART, cart_id: form.cart_id },
1384
+ checkout: {
1385
+ customer: form.customer,
1386
+ order_type: form.order_type,
1387
+ address_info: form.address_info,
1388
+ location_id: form.location_id,
1389
+ delivery_rate_id: form.delivery_rate_id,
1390
+ special_instructions: form.special_instructions,
1391
+ link_address_id: form.link_address_id,
1392
+ metadata: form.metadata,
1393
+ pay_currency: form.pay_currency,
1394
+ fx_quote_id: form.fx_quote_id,
1395
+ use_store_credit: form.use_store_credit || form.payment_method === LEGACY_CHECKOUT_PAYMENT_METHOD_ALIAS.STORE_CREDIT,
1396
+ voucher_code: form.voucher_code,
1397
+ pay_deposit: form.pay_deposit,
1398
+ tender_preference: tenderPreference(form)
1399
+ }
1400
+ };
1401
+ }
1402
+ function selectCheckoutPaymentOption(terms, form) {
1403
+ const preference = tenderPreference(form);
1404
+ if (!preference) return void 0;
1405
+ return terms.payment_options.filter((option) => option.status === PAYMENT_OPTION_STATUS.ELIGIBLE).sort((left, right) => left.rank - right.rank).find((option) => option.method_kind === preference.method_kind);
1406
+ }
1407
+ function checkoutFormToConfirmation(_form, terms, paymentOption, idempotencyKey) {
1408
+ return createPurchaseIntentConfirmation(terms, paymentOption, idempotencyKey);
1409
+ }
1410
+ function committedBase(response) {
1411
+ return {
1412
+ intent_id: response.intent_id,
1413
+ attempt_id: response.attempt_id,
1414
+ order_id: response.order_id,
1415
+ order_number: response.order_number || response.order_id,
1416
+ payment_id: response.payment_id
1417
+ };
1418
+ }
1419
+ function confirmationToCheckoutResult(response) {
1420
+ switch (response.status) {
1421
+ case PURCHASE_INTENT_CONFIRM_STATUS.ORDER_CREATED:
1422
+ return ok({
1423
+ ...committedBase(response),
1424
+ payment_status: LEGACY_CHECKOUT_PAYMENT_STATUS.SUCCEEDED,
1425
+ requires_authorization: false,
1426
+ next_action: { type: CHECKOUT_NEXT_ACTION.NONE }
1427
+ });
1428
+ case PURCHASE_INTENT_CONFIRM_STATUS.COLLECTION_PROCESSING:
1429
+ return ok({
1430
+ ...committedBase(response),
1431
+ payment_status: LEGACY_CHECKOUT_PAYMENT_STATUS.PROCESSING,
1432
+ requires_authorization: false,
1433
+ next_action: { type: CHECKOUT_NEXT_ACTION.POLL }
1434
+ });
1435
+ case PURCHASE_INTENT_CONFIRM_STATUS.PAYMENT_OUTCOME_UNKNOWN:
1436
+ return ok({
1437
+ ...committedBase(response),
1438
+ payment_status: LEGACY_CHECKOUT_PAYMENT_STATUS.UNKNOWN,
1439
+ requires_authorization: false,
1440
+ next_action: { type: CHECKOUT_NEXT_ACTION.POLL }
1441
+ });
1442
+ case PURCHASE_INTENT_CONFIRM_STATUS.PAYMENT_FAILED:
1443
+ return err(
1444
+ new CimplifyError(
1445
+ PURCHASE_INTENT_ERROR_CODE.PAYMENT_FAILED,
1446
+ "Payment failed. The order remains recorded, but collection did not succeed.",
1447
+ true
1448
+ )
1449
+ );
1450
+ case PURCHASE_INTENT_CONFIRM_STATUS.REDIRECT_REQUIRED:
1451
+ return ok({
1452
+ ...committedBase(response),
1453
+ payment_status: LEGACY_CHECKOUT_PAYMENT_STATUS.REQUIRES_ACTION,
1454
+ requires_authorization: false,
1455
+ authorization_url: response.authorization_url,
1456
+ next_action: {
1457
+ type: CHECKOUT_NEXT_ACTION.REDIRECT,
1458
+ authorization_url: response.authorization_url
1470
1459
  }
1471
- resolve();
1472
- }, ms);
1473
- const onAbort = () => {
1474
- clearTimeout(timer);
1475
- reject(createAbortError());
1476
- };
1477
- if (this.signal) {
1478
- this.signal.addEventListener("abort", onAbort, { once: true });
1479
- }
1480
- });
1460
+ });
1461
+ case PURCHASE_INTENT_CONFIRM_STATUS.CARD_POPUP_REQUIRED:
1462
+ return ok({
1463
+ ...committedBase(response),
1464
+ payment_status: LEGACY_CHECKOUT_PAYMENT_STATUS.REQUIRES_ACTION,
1465
+ requires_authorization: false,
1466
+ provider: response.provider,
1467
+ client_secret: response.client_secret,
1468
+ public_key: response.public_key,
1469
+ next_action: {
1470
+ type: CHECKOUT_NEXT_ACTION.CARD_POPUP,
1471
+ provider: response.provider,
1472
+ client_secret: response.client_secret,
1473
+ public_key: response.public_key,
1474
+ provider_account_id: response.provider_account_id ?? void 0
1475
+ }
1476
+ });
1477
+ case PURCHASE_INTENT_CONFIRM_STATUS.AUTHORIZATION_REQUIRED:
1478
+ return ok({
1479
+ ...committedBase(response),
1480
+ payment_status: LEGACY_CHECKOUT_PAYMENT_STATUS.REQUIRES_ACTION,
1481
+ requires_authorization: true,
1482
+ authorization_type: response.authorization_type,
1483
+ display_text: response.display_text,
1484
+ next_action: {
1485
+ type: CHECKOUT_NEXT_ACTION.AUTHORIZATION,
1486
+ authorization_type: response.authorization_type,
1487
+ display_text: response.display_text
1488
+ }
1489
+ });
1490
+ case PURCHASE_INTENT_CONFIRM_STATUS.TERMS_CHANGED:
1491
+ return err(
1492
+ new CimplifyError(
1493
+ PURCHASE_INTENT_ERROR_CODE.TERMS_CHANGED,
1494
+ "Checkout terms changed. Review the replacement terms before confirming again.",
1495
+ true
1496
+ )
1497
+ );
1498
+ case PURCHASE_INTENT_CONFIRM_STATUS.SELECTION_UNAVAILABLE:
1499
+ return err(
1500
+ new CimplifyError(
1501
+ PURCHASE_INTENT_ERROR_CODE.SELECTION_UNAVAILABLE,
1502
+ "One or more checkout selections are no longer available.",
1503
+ true
1504
+ )
1505
+ );
1506
+ case PURCHASE_INTENT_CONFIRM_STATUS.OFFER_ENDED:
1507
+ return err(
1508
+ new CimplifyError(
1509
+ PURCHASE_INTENT_ERROR_CODE.OFFER_ENDED,
1510
+ "This offer has ended.",
1511
+ false
1512
+ )
1513
+ );
1514
+ case PURCHASE_INTENT_CONFIRM_STATUS.SOURCE_UNAVAILABLE:
1515
+ return err(
1516
+ new CimplifyError(
1517
+ PURCHASE_INTENT_ERROR_CODE.SOURCE_UNAVAILABLE,
1518
+ "This purchase source is unavailable.",
1519
+ false
1520
+ )
1521
+ );
1481
1522
  }
1482
- };
1523
+ }
1483
1524
 
1484
1525
  // src/checkout.ts
1526
+ function checkoutActionAuthority(response) {
1527
+ if (response.status !== PURCHASE_INTENT_CONFIRM_STATUS.CARD_POPUP_REQUIRED && response.status !== PURCHASE_INTENT_CONFIRM_STATUS.AUTHORIZATION_REQUIRED) {
1528
+ return null;
1529
+ }
1530
+ const paymentId = response.payment_id?.trim();
1531
+ return paymentId ? {
1532
+ intentId: response.intent_id,
1533
+ attemptId: response.attempt_id,
1534
+ paymentId
1535
+ } : null;
1536
+ }
1537
+ function isAmbiguousCheckoutError(error) {
1538
+ return error.code === ErrorCode.NETWORK_ERROR || error.code === ErrorCode.TIMEOUT;
1539
+ }
1540
+ function authorizationKind(value) {
1541
+ if (value && typeof value === "object" && AUTHORIZATION_TYPE.ADDRESS in value) {
1542
+ return AUTHORIZATION_TYPE.ADDRESS;
1543
+ }
1544
+ if (value === AUTHORIZATION_TYPE.OTP || value === AUTHORIZATION_TYPE.PIN || value === AUTHORIZATION_TYPE.PHONE || value === AUTHORIZATION_TYPE.BIRTHDAY) {
1545
+ return value;
1546
+ }
1547
+ return void 0;
1548
+ }
1549
+ function normalizeAuthorizationSubmission(expected, submission) {
1550
+ if (submission.type !== expected) throw new Error(`Expected ${expected} authorization details.`);
1551
+ if (submission.type === AUTHORIZATION_TYPE.ADDRESS) {
1552
+ const address = submission.address.trim();
1553
+ const city = submission.city.trim();
1554
+ const state = submission.state.trim();
1555
+ const zipCode = submission.zip_code.trim();
1556
+ if (!address || !city || !state || !zipCode) {
1557
+ throw new Error("Complete all authorization address fields.");
1558
+ }
1559
+ return { type: AUTHORIZATION_TYPE.ADDRESS, address, city, state, zip_code: zipCode };
1560
+ }
1561
+ const value = submission.value.trim();
1562
+ if (!value) throw new Error("Authorization value is required.");
1563
+ return { type: submission.type, value };
1564
+ }
1565
+ var DECIMAL_WIRE_VALUE = /^([+-]?)(\d+)(?:\.(\d+))?(?:[eE][+-]?\d+)?$/;
1566
+ function decimalSign(value) {
1567
+ if (typeof value === "number") {
1568
+ if (!Number.isFinite(value)) return null;
1569
+ if (Object.is(value, 0) || Object.is(value, -0)) return 0;
1570
+ return value > 0 ? 1 : -1;
1571
+ }
1572
+ const match = DECIMAL_WIRE_VALUE.exec(value.trim());
1573
+ if (!match) return null;
1574
+ const nonzero = [...match[2], ...match[3] ?? ""].some((digit) => digit !== "0");
1575
+ if (!nonzero) return 0;
1576
+ return match[1] === "-" ? -1 : 1;
1577
+ }
1485
1578
  function toTerminalFailure(code, message, recoverable) {
1486
1579
  return {
1487
1580
  success: false,
@@ -1497,7 +1590,7 @@ function isValidCustomerName(name) {
1497
1590
  return trimmed.length >= 2 && /\p{L}/u.test(trimmed);
1498
1591
  }
1499
1592
  function isOfflinePaymentMethod(method) {
1500
- return method === "cash" || method === "offline";
1593
+ return method === LEGACY_CHECKOUT_PAYMENT_METHOD_ALIAS.CASH || method === PURCHASE_INTENT_PAYMENT_METHOD.OFFLINE;
1501
1594
  }
1502
1595
  function notifyCheckoutStatus(observer, status, context = {}) {
1503
1596
  try {
@@ -1505,7 +1598,35 @@ function notifyCheckoutStatus(observer, status, context = {}) {
1505
1598
  } catch {
1506
1599
  }
1507
1600
  }
1601
+ function notifyAuthorizationUi(observer, open) {
1602
+ try {
1603
+ observer?.(open);
1604
+ } catch {
1605
+ }
1606
+ }
1508
1607
  var MAX_STOREFRONT_COLLECTION_OPTIONS = 32;
1608
+ var CHECKOUT_INTENT_SCOPE_PREFIX = "checkout:";
1609
+ var CHECKOUT_CONFIRMATION_SCOPE_PREFIX = "checkout-confirm:";
1610
+ var CHECKOUT_INTENT_RECOVERY_FINGERPRINT = "cart-intent-v1";
1611
+ var ABORT_ERROR_NAME = "AbortError";
1612
+ var AUTHORIZATION_POPUP_NAME = "cimplify-auth";
1613
+ var AUTHORIZATION_POPUP_FEATURES = "width=520,height=760,noopener,noreferrer";
1614
+ var ORDER_TOKEN_QUERY_PARAMETER = "token";
1615
+ var CHECKOUT_API_ROUTE = {
1616
+ COLLECTION_OPTIONS: "/api/v1/payments/collection-options",
1617
+ paymentStatus: (orderId) => `/api/v1/orders/${orderId}/payment-status`,
1618
+ updateCustomer: (orderId) => `/api/v1/orders/${orderId}/customer`,
1619
+ verifyPayment: (orderId) => `/api/v1/orders/${orderId}/verify-payment`
1620
+ };
1621
+ var CHECKOUT_STATUS_BY_PURCHASE_INTENT_RESOLVE_STATUS = {
1622
+ [PURCHASE_INTENT_RESOLVE_STATUS.CONFIRMING]: CHECKOUT_STATUS.PROCESSING,
1623
+ [PURCHASE_INTENT_RESOLVE_STATUS.POLLING]: CHECKOUT_STATUS.POLLING,
1624
+ [PURCHASE_INTENT_RESOLVE_STATUS.AWAITING_ACTION]: CHECKOUT_STATUS.AWAITING_AUTHORIZATION,
1625
+ [PURCHASE_INTENT_RESOLVE_STATUS.REVIEWING_TERMS]: CHECKOUT_STATUS.REVIEWING_TERMS,
1626
+ [PURCHASE_INTENT_RESOLVE_STATUS.COMPLETED]: CHECKOUT_STATUS.FINALIZING,
1627
+ [PURCHASE_INTENT_RESOLVE_STATUS.FAILED]: CHECKOUT_STATUS.FAILED,
1628
+ [PURCHASE_INTENT_RESOLVE_STATUS.OUTCOME_UNKNOWN]: CHECKOUT_STATUS.RECOVERING
1629
+ };
1509
1630
  function normalizeCollectionOptions(value, expectedCurrency) {
1510
1631
  if (!value || typeof value !== "object") return null;
1511
1632
  const response = value;
@@ -1528,7 +1649,8 @@ function normalizeCollectionOptions(value, expectedCurrency) {
1528
1649
  if (option.method !== PAYMENT_METHOD.MOBILE_MONEY || typeof option.network !== "string" || !option.network.trim()) {
1529
1650
  continue;
1530
1651
  }
1531
- const network = option.network.trim().toLowerCase();
1652
+ const network = purchaseIntentMobileMoneyNetwork(option.network);
1653
+ if (!network) continue;
1532
1654
  const key = `${PAYMENT_METHOD.MOBILE_MONEY}:${network}`;
1533
1655
  if (seen.has(key)) continue;
1534
1656
  seen.add(key);
@@ -1539,18 +1661,22 @@ function normalizeCollectionOptions(value, expectedCurrency) {
1539
1661
  var CheckoutService = class {
1540
1662
  constructor(client) {
1541
1663
  this.client = client;
1664
+ /** Raw checkout material is component-lifetime only, never browser storage. */
1665
+ this.intentCommands = /* @__PURE__ */ new Map();
1666
+ /** Opaque owner/attempt authority for deprecated action submission. */
1667
+ this.actionAuthorities = /* @__PURE__ */ new Map();
1542
1668
  }
1543
1669
  validateCheckoutData(data) {
1544
1670
  if (isOfflinePaymentMethod(data.payment_method)) {
1545
1671
  return new CimplifyError(
1546
- "INVALID_PAYMENT_METHOD",
1672
+ ErrorCode.INVALID_PAYMENT_METHOD,
1547
1673
  "Offline payment isn't available for online checkout. Please pay by card or mobile money.",
1548
1674
  false
1549
1675
  );
1550
1676
  }
1551
1677
  if (!isValidCustomerName(data.customer?.name)) {
1552
1678
  return new CimplifyError(
1553
- "INVALID_CUSTOMER_NAME",
1679
+ ErrorCode.INVALID_CUSTOMER_NAME,
1554
1680
  "Enter your name, not a phone number.",
1555
1681
  false
1556
1682
  );
@@ -1559,7 +1685,7 @@ var CheckoutService = class {
1559
1685
  }
1560
1686
  orderTokenParam(orderId) {
1561
1687
  const token = this.client.getOrderToken(orderId);
1562
- return token ? `?token=${encodeURIComponent(token)}` : "";
1688
+ return token ? `?${ORDER_TOKEN_QUERY_PARAMETER}=${encodeURIComponent(token)}` : "";
1563
1689
  }
1564
1690
  /** Available storefront collection methods for one presentment currency. */
1565
1691
  async collectionOptions(currency) {
@@ -1575,7 +1701,7 @@ var CheckoutService = class {
1575
1701
  }
1576
1702
  const response = await safe(
1577
1703
  this.client.get(
1578
- `/api/v1/payments/collection-options?currency=${encodeURIComponent(normalized)}`
1704
+ `${CHECKOUT_API_ROUTE.COLLECTION_OPTIONS}?currency=${encodeURIComponent(normalized)}`
1579
1705
  )
1580
1706
  );
1581
1707
  if (!response.ok) return response;
@@ -1595,52 +1721,181 @@ var CheckoutService = class {
1595
1721
  authorizeCardPopup(action, options) {
1596
1722
  return this.client.authorizationAdapters.authorize(action, options);
1597
1723
  }
1598
- async process(data) {
1724
+ async startIntentCheckout(data, options) {
1599
1725
  const invalid = this.validateCheckoutData(data);
1600
- if (invalid) {
1601
- return err(invalid);
1602
- }
1603
- const intentScope = `checkout:${data.cart_id}`;
1604
- const intentFingerprint = JSON.stringify([
1605
- data.payment_method,
1606
- data.mobile_money_details,
1607
- data.pay_currency,
1608
- data.voucher_code,
1609
- data.pay_deposit
1610
- ]);
1611
- const checkoutData = {
1612
- ...data,
1613
- idempotency_key: data.idempotency_key || intentIdempotencyKey(intentScope, intentFingerprint)
1614
- };
1615
- const result = await safe(this.client.post("/api/v1/checkout", checkoutData));
1616
- if (result.ok) {
1726
+ if (invalid) return err(invalid);
1727
+ const intentScope = `${CHECKOUT_INTENT_SCOPE_PREFIX}${data.cart_id}`;
1728
+ const inMemoryCommand = JSON.stringify(data);
1729
+ const previousCommand = this.intentCommands.get(intentScope);
1730
+ if (previousCommand !== void 0 && previousCommand !== inMemoryCommand) {
1731
+ clearIntentIdempotencyKey(intentScope);
1732
+ }
1733
+ this.intentCommands.set(intentScope, inMemoryCommand);
1734
+ const clientIntentKey = data.idempotency_key || intentIdempotencyKey(intentScope, CHECKOUT_INTENT_RECOVERY_FINGERPRINT);
1735
+ const checkoutData = { ...data, idempotency_key: clientIntentKey };
1736
+ let mintRequest;
1737
+ try {
1738
+ mintRequest = checkoutFormToIntentRequest(checkoutData, clientIntentKey);
1739
+ } catch (error) {
1617
1740
  clearIntentIdempotencyKey(intentScope);
1618
- if (result.value.bill_token) {
1619
- this.client.setOrderToken(result.value.order_id, result.value.bill_token);
1741
+ this.intentCommands.delete(intentScope);
1742
+ return err(
1743
+ error instanceof CimplifyError ? error : new CimplifyError(
1744
+ ErrorCode.CHECKOUT_VALIDATION_FAILED,
1745
+ "Checkout details are invalid.",
1746
+ false
1747
+ )
1748
+ );
1749
+ }
1750
+ const minted = await this.client.purchaseIntents.mint(mintRequest, options);
1751
+ if (!minted.ok) {
1752
+ if (!isAmbiguousCheckoutError(minted.error)) {
1753
+ clearIntentIdempotencyKey(intentScope);
1754
+ this.intentCommands.delete(intentScope);
1620
1755
  }
1621
- } else if (result.error.code !== ErrorCode.NETWORK_ERROR && result.error.code !== ErrorCode.TIMEOUT) {
1756
+ return minted;
1757
+ }
1758
+ const terms = minted.value.current_terms;
1759
+ if (!terms) {
1622
1760
  clearIntentIdempotencyKey(intentScope);
1761
+ this.intentCommands.delete(intentScope);
1762
+ return err(
1763
+ new CimplifyError(
1764
+ ErrorCode.CHECKOUT_TERMS_UNAVAILABLE,
1765
+ "Checkout terms are not available for this purchase intent.",
1766
+ true
1767
+ )
1768
+ );
1769
+ }
1770
+ let paymentOption;
1771
+ try {
1772
+ paymentOption = selectCheckoutPaymentOption(terms, checkoutData);
1773
+ } catch (error) {
1774
+ return err(
1775
+ error instanceof CimplifyError ? error : new CimplifyError(
1776
+ ErrorCode.INVALID_PAYMENT_METHOD,
1777
+ "Payment details are invalid.",
1778
+ false
1779
+ )
1780
+ );
1781
+ }
1782
+ if (!paymentOption && purchaseIntentRequiresPaymentOption(terms)) {
1783
+ return err(
1784
+ new CimplifyError(
1785
+ ErrorCode.PAYMENT_CAPABILITY_MISMATCH,
1786
+ "The selected payment method is not eligible for these checkout terms.",
1787
+ true
1788
+ )
1789
+ );
1790
+ }
1791
+ const confirmationScope = `${CHECKOUT_CONFIRMATION_SCOPE_PREFIX}${minted.value.id}`;
1792
+ const confirmationFingerprint = JSON.stringify([
1793
+ terms.intent_revision,
1794
+ terms.terms_version,
1795
+ terms.terms_digest,
1796
+ paymentOption?.id ?? null,
1797
+ terms.money.due_now,
1798
+ paymentOption?.customer_debit_amount ?? terms.money.rail_amount,
1799
+ terms.money.currency
1800
+ ]);
1801
+ const confirmationKey = intentIdempotencyKey(
1802
+ confirmationScope,
1803
+ confirmationFingerprint
1804
+ );
1805
+ const confirmation = checkoutFormToConfirmation(
1806
+ checkoutData,
1807
+ terms,
1808
+ paymentOption,
1809
+ confirmationKey
1810
+ );
1811
+ const confirmed = await this.client.purchaseIntents.confirm(
1812
+ minted.value.id,
1813
+ confirmation,
1814
+ options
1815
+ );
1816
+ if (!confirmed.ok) {
1817
+ if (!isAmbiguousCheckoutError(confirmed.error)) {
1818
+ clearIntentIdempotencyKey(confirmationScope);
1819
+ }
1820
+ return confirmed;
1821
+ }
1822
+ return ok({
1823
+ intentId: minted.value.id,
1824
+ intentScope,
1825
+ confirmationScope,
1826
+ confirmation,
1827
+ initialResponse: confirmed.value,
1828
+ terms
1829
+ });
1830
+ }
1831
+ /** @deprecated Use `client.purchaseIntents.mint()` then `confirm()`. */
1832
+ async process(data, options) {
1833
+ const started = await this.startIntentCheckout(data, options);
1834
+ if (!started.ok) return started;
1835
+ this.reconcileActionAuthority(started.value.initialResponse);
1836
+ const result = confirmationToCheckoutResult(started.value.initialResponse);
1837
+ if (started.value.initialResponse.status === PURCHASE_INTENT_CONFIRM_STATUS.ORDER_CREATED || started.value.initialResponse.status === PURCHASE_INTENT_CONFIRM_STATUS.PAYMENT_FAILED) {
1838
+ clearIntentIdempotencyKey(started.value.intentScope);
1839
+ clearIntentIdempotencyKey(started.value.confirmationScope);
1840
+ this.intentCommands.delete(started.value.intentScope);
1623
1841
  }
1624
1842
  return result;
1625
1843
  }
1626
1844
  async initializePayment(_orderId, _method) {
1627
1845
  return err(
1628
1846
  new CimplifyError(
1629
- "NOT_IMPLEMENTED",
1847
+ ErrorCode.NOT_IMPLEMENTED,
1630
1848
  "initializePayment is not available in REST mode.",
1631
1849
  false
1632
1850
  )
1633
1851
  );
1634
1852
  }
1635
- async submitAuthorization(input) {
1636
- return safe(this.client.post("/api/v1/payments/authorization", input));
1853
+ /**
1854
+ * @deprecated Use `client.purchaseIntents.submitAction()`. This adapter works
1855
+ * only while this CheckoutService instance retains the opaque authority
1856
+ * returned by its own `process()` call; it never falls back to a payment-id
1857
+ * mutation.
1858
+ */
1859
+ async submitAuthorization(input, options) {
1860
+ const paymentId = input.payment_id.trim();
1861
+ const authority = this.actionAuthorities.get(paymentId);
1862
+ if (!authority) {
1863
+ return err(
1864
+ new CimplifyError(
1865
+ ErrorCode.CHECKOUT_AUTHORITY_REQUIRED,
1866
+ "The purchase-intent action authority is unavailable. Restart checkout before submitting authorization.",
1867
+ false
1868
+ )
1869
+ );
1870
+ }
1871
+ const submitted = await this.client.purchaseIntents.submitAction(
1872
+ authority.intentId,
1873
+ authority.attemptId,
1874
+ { authorization: input.authorization },
1875
+ {
1876
+ signal: options?.signal,
1877
+ timeoutMs: options?.timeoutMs
1878
+ }
1879
+ );
1880
+ if (!submitted.ok) return submitted;
1881
+ this.reconcileActionAuthority(submitted.value, paymentId);
1882
+ return confirmationToCheckoutResult(submitted.value);
1883
+ }
1884
+ reconcileActionAuthority(response, previousPaymentId) {
1885
+ if (previousPaymentId) this.actionAuthorities.delete(previousPaymentId);
1886
+ if ("payment_id" in response && typeof response.payment_id === "string" && response.payment_id.trim()) {
1887
+ this.actionAuthorities.delete(response.payment_id.trim());
1888
+ }
1889
+ const authority = checkoutActionAuthority(response);
1890
+ if (authority) this.actionAuthorities.set(authority.paymentId, authority);
1637
1891
  }
1638
- async pollPaymentStatus(orderId) {
1892
+ async pollPaymentStatus(orderId, options) {
1639
1893
  const encodedId = encodeURIComponent(orderId);
1640
1894
  const tokenParam = this.orderTokenParam(orderId);
1641
1895
  return safe(
1642
1896
  this.client.get(
1643
- `/api/v1/orders/${encodedId}/payment-status${tokenParam}`
1897
+ `${CHECKOUT_API_ROUTE.paymentStatus(encodedId)}${tokenParam}`,
1898
+ options
1644
1899
  )
1645
1900
  );
1646
1901
  }
@@ -1648,20 +1903,58 @@ var CheckoutService = class {
1648
1903
  const encodedId = encodeURIComponent(orderId);
1649
1904
  const tokenParam = this.orderTokenParam(orderId);
1650
1905
  return safe(
1651
- this.client.post(`/api/v1/orders/${encodedId}/customer${tokenParam}`, customer)
1906
+ this.client.post(`${CHECKOUT_API_ROUTE.updateCustomer(encodedId)}${tokenParam}`, customer)
1652
1907
  );
1653
1908
  }
1654
1909
  async verifyPayment(orderId) {
1655
1910
  const encodedId = encodeURIComponent(orderId);
1656
1911
  const tokenParam = this.orderTokenParam(orderId);
1657
- return safe(this.client.post(`/api/v1/orders/${encodedId}/verify-payment${tokenParam}`));
1912
+ return safe(
1913
+ this.client.post(`${CHECKOUT_API_ROUTE.verifyPayment(encodedId)}${tokenParam}`)
1914
+ );
1658
1915
  }
1916
+ async maybeEnrollResolvedOrder(orderId, data) {
1917
+ if (data.enroll_in_link === false) return false;
1918
+ const business = await safe(this.client.resolveBusinessId());
1919
+ if (!business.ok) return false;
1920
+ const address = data.address_info.street_address ? {
1921
+ label: "Default",
1922
+ street_address: data.address_info.street_address,
1923
+ apartment: data.address_info.apartment,
1924
+ city: data.address_info.city ?? "",
1925
+ region: data.address_info.region ?? "",
1926
+ postal_code: data.address_info.postal_code,
1927
+ country: data.address_info.country,
1928
+ delivery_instructions: data.address_info.delivery_instructions,
1929
+ phone_for_delivery: data.address_info.phone_for_delivery,
1930
+ latitude: data.address_info.latitude,
1931
+ longitude: data.address_info.longitude
1932
+ } : void 0;
1933
+ const mobileMoney = data.payment_method === PAYMENT_METHOD.MOBILE_MONEY && data.mobile_money_details ? {
1934
+ phone_number: data.mobile_money_details.phone_number,
1935
+ provider: data.mobile_money_details.provider,
1936
+ label: "Mobile Money"
1937
+ } : void 0;
1938
+ try {
1939
+ const enrollment = await this.client.link.enrollAndLinkOrder({
1940
+ order_id: orderId,
1941
+ business_id: business.value,
1942
+ order_type: data.order_type,
1943
+ address,
1944
+ mobile_money: mobileMoney
1945
+ });
1946
+ return enrollment.ok && enrollment.value.success;
1947
+ } catch {
1948
+ return false;
1949
+ }
1950
+ }
1951
+ /** @deprecated Use `client.purchaseIntents.resolve()`. */
1659
1952
  async processAndResolve(data) {
1660
- notifyCheckoutStatus(data.on_status_change, "preparing");
1953
+ notifyCheckoutStatus(data.on_status_change, CHECKOUT_STATUS.PREPARING);
1661
1954
  if (!data.cart_id) {
1662
1955
  return ok(
1663
1956
  toTerminalFailure(
1664
- "INVALID_CART",
1957
+ ErrorCode.INVALID_CART,
1665
1958
  "A valid cart is required before checkout can start.",
1666
1959
  false
1667
1960
  )
@@ -1669,13 +1962,19 @@ var CheckoutService = class {
1669
1962
  }
1670
1963
  const cartResult = await this.client.cart.get();
1671
1964
  if (!cartResult.ok || !cartResult.value?.id) {
1672
- return ok(toTerminalFailure("INVALID_CART", "Unable to load cart for checkout.", false));
1965
+ return ok(
1966
+ toTerminalFailure(
1967
+ ErrorCode.INVALID_CART,
1968
+ "Unable to load cart for checkout.",
1969
+ false
1970
+ )
1971
+ );
1673
1972
  }
1674
1973
  const cart = cartResult.value;
1675
1974
  if (cart.id !== data.cart_id || cart.items.length === 0) {
1676
1975
  return ok(
1677
1976
  toTerminalFailure(
1678
- "INVALID_CART",
1977
+ ErrorCode.INVALID_CART,
1679
1978
  "Cart is empty or no longer valid. Please refresh and try again.",
1680
1979
  false
1681
1980
  )
@@ -1705,7 +2004,7 @@ var CheckoutService = class {
1705
2004
  if (!isSupportedCurrency(rawBaseCurrency)) {
1706
2005
  return ok(
1707
2006
  toTerminalFailure(
1708
- "INVALID_CURRENCY",
2007
+ ErrorCode.UNSUPPORTED_CURRENCY,
1709
2008
  "Cart currency is missing or unsupported. Refresh the cart before checkout.",
1710
2009
  false
1711
2010
  )
@@ -1716,15 +2015,24 @@ var CheckoutService = class {
1716
2015
  if (payCurrency && !isSupportedCurrency(payCurrency)) {
1717
2016
  return ok(
1718
2017
  toTerminalFailure(
1719
- "INVALID_CURRENCY",
2018
+ ErrorCode.UNSUPPORTED_CURRENCY,
1720
2019
  "Payment currency is unsupported for checkout.",
1721
2020
  false
1722
2021
  )
1723
2022
  );
1724
2023
  }
1725
2024
  const payCurrencyCode = payCurrency && isSupportedCurrency(payCurrency) ? payCurrency : void 0;
1726
- const cartTotalAmount = typeof cart.pricing.total_price === "number" ? cart.pricing.total_price : Number.parseFloat(cart.pricing.total_price || "0");
1727
- if (payCurrencyCode && payCurrencyCode !== baseCurrency && !checkoutData.fx_quote_id && Number.isFinite(cartTotalAmount) && cartTotalAmount > 0) {
2025
+ const cartTotalSign = decimalSign(cart.pricing.total_price);
2026
+ if (cartTotalSign === null || cartTotalSign < 0) {
2027
+ return ok(
2028
+ toTerminalFailure(
2029
+ ErrorCode.CHECKOUT_VALIDATION_FAILED,
2030
+ "Cart total is not a valid non-negative decimal amount.",
2031
+ false
2032
+ )
2033
+ );
2034
+ }
2035
+ if (payCurrencyCode && payCurrencyCode !== baseCurrency && !checkoutData.fx_quote_id && cartTotalSign > 0) {
1728
2036
  const fxQuoteResult = await this.client.fx.lockQuote({
1729
2037
  from: baseCurrency,
1730
2038
  to: payCurrencyCode,
@@ -1733,7 +2041,7 @@ var CheckoutService = class {
1733
2041
  if (!fxQuoteResult.ok) {
1734
2042
  return ok(
1735
2043
  toTerminalFailure(
1736
- "FX_QUOTE_FAILED",
2044
+ ErrorCode.FX_QUOTE_FAILED,
1737
2045
  fxQuoteResult.error.message || "Unable to lock FX quote for checkout.",
1738
2046
  true
1739
2047
  )
@@ -1742,35 +2050,266 @@ var CheckoutService = class {
1742
2050
  checkoutData.pay_currency = payCurrencyCode;
1743
2051
  checkoutData.fx_quote_id = fxQuoteResult.value.id;
1744
2052
  }
1745
- notifyCheckoutStatus(data.on_status_change, "processing");
1746
- const processResult = await this.process(checkoutData);
1747
- if (!processResult.ok) {
2053
+ notifyCheckoutStatus(data.on_status_change, CHECKOUT_STATUS.PROCESSING);
2054
+ const started = await this.startIntentCheckout(checkoutData, { signal: data.signal });
2055
+ if (!started.ok) {
1748
2056
  return ok(
1749
2057
  toTerminalFailure(
1750
- processResult.error.code || "CHECKOUT_FAILED",
1751
- processResult.error.message || "Unable to process checkout.",
1752
- processResult.error.retryable ?? true
2058
+ started.error.code || ErrorCode.CHECKOUT_FAILED,
2059
+ started.error.message || "Unable to process checkout.",
2060
+ started.error.retryable ?? true
2061
+ )
2062
+ );
2063
+ }
2064
+ let actionFailure;
2065
+ try {
2066
+ const resolved = await this.client.purchaseIntents.resolve(started.value.intentId, {
2067
+ confirmation: started.value.confirmation,
2068
+ initialResponse: started.value.initialResponse,
2069
+ pollIntervalMs: data.poll_interval_ms,
2070
+ maxPollAttempts: data.max_poll_attempts,
2071
+ signal: data.signal,
2072
+ onStatusChange: (status, response) => {
2073
+ const context = {};
2074
+ if (response && "order_id" in response) context.order_id = response.order_id;
2075
+ if (response?.status === PURCHASE_INTENT_CONFIRM_STATUS.TERMS_CHANGED) {
2076
+ context.replacement_terms = response.replacement;
2077
+ context.terms_deltas = response.deltas;
2078
+ }
2079
+ if (response?.status === PURCHASE_INTENT_CONFIRM_STATUS.SELECTION_UNAVAILABLE) {
2080
+ context.unavailable_lines = response.lines;
2081
+ }
2082
+ const checkoutStatus = CHECKOUT_STATUS_BY_PURCHASE_INTENT_RESOLVE_STATUS[status];
2083
+ notifyCheckoutStatus(data.on_status_change, checkoutStatus, context);
2084
+ },
2085
+ onActionRequired: async (action) => {
2086
+ switch (action.status) {
2087
+ case PURCHASE_INTENT_CONFIRM_STATUS.CARD_POPUP_REQUIRED: {
2088
+ const allowPopups = data.allow_popups ?? typeof window !== "undefined";
2089
+ if (!allowPopups) {
2090
+ actionFailure = {
2091
+ code: ErrorCode.PROVIDER_UNAVAILABLE,
2092
+ message: "Card authorization UI is unavailable in this environment.",
2093
+ recoverable: false
2094
+ };
2095
+ return PURCHASE_INTENT_ACTION_DECISION.STOP;
2096
+ }
2097
+ let outcome;
2098
+ try {
2099
+ notifyAuthorizationUi(data.on_authorization_ui_change, true);
2100
+ outcome = await this.authorizeCardPopup(
2101
+ {
2102
+ type: CHECKOUT_NEXT_ACTION.CARD_POPUP,
2103
+ provider: action.provider,
2104
+ client_secret: action.client_secret,
2105
+ public_key: action.public_key,
2106
+ provider_account_id: action.provider_account_id ?? void 0
2107
+ },
2108
+ {
2109
+ email: checkoutData.customer.email,
2110
+ currency: started.value.terms.money.currency,
2111
+ returnUrl: data.return_url,
2112
+ signal: data.signal
2113
+ }
2114
+ );
2115
+ } finally {
2116
+ notifyAuthorizationUi(data.on_authorization_ui_change, false);
2117
+ }
2118
+ if (outcome.status === PAYMENT_AUTHORIZATION_OUTCOME_STATUS.SUBMITTED) {
2119
+ return PURCHASE_INTENT_ACTION_DECISION.CONTINUE;
2120
+ }
2121
+ actionFailure = outcome.status === PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED ? {
2122
+ code: ErrorCode.PAYMENT_CANCELLED,
2123
+ message: "Card payment was cancelled before submission.",
2124
+ recoverable: true
2125
+ } : {
2126
+ code: outcome.code,
2127
+ message: outcome.message,
2128
+ recoverable: outcome.recoverable
2129
+ };
2130
+ return PURCHASE_INTENT_ACTION_DECISION.STOP;
2131
+ }
2132
+ case PURCHASE_INTENT_CONFIRM_STATUS.REDIRECT_REQUIRED: {
2133
+ const authorizationUrl = paymentAuthorizationUrl(action.authorization_url);
2134
+ if (!authorizationUrl) {
2135
+ actionFailure = {
2136
+ code: ErrorCode.AUTHORIZATION_FAILED,
2137
+ message: "The provider returned an invalid authorization URL.",
2138
+ recoverable: false
2139
+ };
2140
+ return PURCHASE_INTENT_ACTION_DECISION.STOP;
2141
+ }
2142
+ if (typeof window !== "undefined") {
2143
+ if (data.allow_popups === false) {
2144
+ window.location.assign(authorizationUrl);
2145
+ } else {
2146
+ const popup = window.open(
2147
+ authorizationUrl,
2148
+ AUTHORIZATION_POPUP_NAME,
2149
+ AUTHORIZATION_POPUP_FEATURES
2150
+ );
2151
+ if (!popup) {
2152
+ actionFailure = {
2153
+ code: ErrorCode.POPUP_BLOCKED,
2154
+ message: "Authorization popup was blocked.",
2155
+ recoverable: true
2156
+ };
2157
+ return PURCHASE_INTENT_ACTION_DECISION.STOP;
2158
+ }
2159
+ }
2160
+ }
2161
+ actionFailure = {
2162
+ code: ErrorCode.REDIRECT_REQUIRED,
2163
+ message: "Complete authorization at the payment provider, then resume checkout.",
2164
+ recoverable: true
2165
+ };
2166
+ return PURCHASE_INTENT_ACTION_DECISION.STOP;
2167
+ }
2168
+ case PURCHASE_INTENT_CONFIRM_STATUS.AUTHORIZATION_REQUIRED: {
2169
+ const expected = authorizationKind(action.authorization_type);
2170
+ if (!expected || !data.on_authorization_required) {
2171
+ actionFailure = {
2172
+ code: ErrorCode.AUTHORIZATION_REQUIRED,
2173
+ message: "Additional payment authorization is required.",
2174
+ recoverable: true
2175
+ };
2176
+ return PURCHASE_INTENT_ACTION_DECISION.STOP;
2177
+ }
2178
+ let submission;
2179
+ await data.on_authorization_required(expected, async (candidate) => {
2180
+ if (submission) throw new Error("Authorization was already submitted.");
2181
+ submission = normalizeAuthorizationSubmission(expected, candidate);
2182
+ });
2183
+ if (!submission) {
2184
+ actionFailure = {
2185
+ code: ErrorCode.AUTHORIZATION_REQUIRED,
2186
+ message: "Payment authorization was not submitted.",
2187
+ recoverable: true
2188
+ };
2189
+ return PURCHASE_INTENT_ACTION_DECISION.STOP;
2190
+ }
2191
+ return {
2192
+ kind: PURCHASE_INTENT_ACTION_DECISION.SUBMIT,
2193
+ request: { authorization: submission }
2194
+ };
2195
+ }
2196
+ }
2197
+ }
2198
+ });
2199
+ if (!resolved.ok) {
2200
+ return ok(
2201
+ toTerminalFailure(
2202
+ resolved.error.code || ErrorCode.CHECKOUT_FAILED,
2203
+ resolved.error.message || "Unable to resolve checkout.",
2204
+ resolved.error.retryable ?? true
2205
+ )
2206
+ );
2207
+ }
2208
+ switch (resolved.value.kind) {
2209
+ case PURCHASE_INTENT_RESOLUTION_KIND.COMPLETED: {
2210
+ clearIntentIdempotencyKey(started.value.intentScope);
2211
+ clearIntentIdempotencyKey(started.value.confirmationScope);
2212
+ const response = resolved.value.response;
2213
+ notifyCheckoutStatus(data.on_status_change, CHECKOUT_STATUS.FINALIZING, {
2214
+ order_id: response.order_id
2215
+ });
2216
+ const enrolledInLink = await this.maybeEnrollResolvedOrder(response.order_id, data);
2217
+ notifyCheckoutStatus(data.on_status_change, CHECKOUT_STATUS.SUCCESS, {
2218
+ order_id: response.order_id
2219
+ });
2220
+ return ok({
2221
+ success: true,
2222
+ order: {
2223
+ id: response.order_id,
2224
+ order_number: response.order_number ?? response.order_id,
2225
+ status: CHECKOUT_ORDER_RESULT_STATUS.CONFIRMED,
2226
+ total: String(cart.pricing.total_price),
2227
+ currency: started.value.terms.money.currency
2228
+ },
2229
+ enrolled_in_link: enrolledInLink
2230
+ });
2231
+ }
2232
+ case PURCHASE_INTENT_RESOLUTION_KIND.FAILED:
2233
+ clearIntentIdempotencyKey(started.value.confirmationScope);
2234
+ return ok(
2235
+ toTerminalFailure(
2236
+ PURCHASE_INTENT_ERROR_CODE.PAYMENT_FAILED,
2237
+ "Payment failed. Choose another method or retry collection.",
2238
+ true
2239
+ )
2240
+ );
2241
+ case PURCHASE_INTENT_RESOLUTION_KIND.OUTCOME_UNKNOWN:
2242
+ return ok(
2243
+ toTerminalFailure(
2244
+ ErrorCode.PAYMENT_OUTCOME_UNKNOWN,
2245
+ "Payment outcome is still unknown. Resume this intent before retrying.",
2246
+ true
2247
+ )
2248
+ );
2249
+ case PURCHASE_INTENT_RESOLUTION_KIND.TIMED_OUT:
2250
+ return ok(
2251
+ toTerminalFailure(
2252
+ ErrorCode.TIMEOUT,
2253
+ "Payment is still processing. Resume this intent to continue polling.",
2254
+ true
2255
+ )
2256
+ );
2257
+ case PURCHASE_INTENT_RESOLUTION_KIND.ACTION_REQUIRED:
2258
+ return ok(
2259
+ toTerminalFailure(
2260
+ actionFailure?.code ?? ErrorCode.AUTHORIZATION_REQUIRED,
2261
+ actionFailure?.message ?? "Checkout requires additional authorization.",
2262
+ actionFailure?.recoverable ?? true
2263
+ )
2264
+ );
2265
+ case PURCHASE_INTENT_RESOLUTION_KIND.REVIEW_REQUIRED: {
2266
+ const response = resolved.value.response;
2267
+ switch (response.status) {
2268
+ case PURCHASE_INTENT_CONFIRM_STATUS.TERMS_CHANGED:
2269
+ return ok(
2270
+ toTerminalFailure(
2271
+ PURCHASE_INTENT_ERROR_CODE.TERMS_CHANGED,
2272
+ "Checkout terms changed and require explicit review.",
2273
+ true
2274
+ )
2275
+ );
2276
+ case PURCHASE_INTENT_CONFIRM_STATUS.SELECTION_UNAVAILABLE:
2277
+ return ok(
2278
+ toTerminalFailure(
2279
+ PURCHASE_INTENT_ERROR_CODE.SELECTION_UNAVAILABLE,
2280
+ "One or more checkout selections are unavailable.",
2281
+ true
2282
+ )
2283
+ );
2284
+ case PURCHASE_INTENT_CONFIRM_STATUS.OFFER_ENDED:
2285
+ return ok(
2286
+ toTerminalFailure(
2287
+ PURCHASE_INTENT_ERROR_CODE.OFFER_ENDED,
2288
+ "This offer has ended.",
2289
+ false
2290
+ )
2291
+ );
2292
+ case PURCHASE_INTENT_CONFIRM_STATUS.SOURCE_UNAVAILABLE:
2293
+ return ok(
2294
+ toTerminalFailure(
2295
+ PURCHASE_INTENT_ERROR_CODE.SOURCE_UNAVAILABLE,
2296
+ "This purchase source is unavailable.",
2297
+ false
2298
+ )
2299
+ );
2300
+ }
2301
+ }
2302
+ }
2303
+ } catch (error) {
2304
+ const cancelled = data.signal?.aborted || error instanceof Error && error.name === ABORT_ERROR_NAME;
2305
+ return ok(
2306
+ toTerminalFailure(
2307
+ cancelled ? ErrorCode.CANCELLED : ErrorCode.AUTHORIZATION_FAILED,
2308
+ cancelled ? "Checkout was cancelled." : error instanceof Error ? error.message : "Checkout authorization failed.",
2309
+ true
1753
2310
  )
1754
2311
  );
1755
2312
  }
1756
- const resolver = new CheckoutResolver({
1757
- client: this.client,
1758
- checkoutData,
1759
- pollIntervalMs: data.poll_interval_ms,
1760
- maxPollAttempts: data.max_poll_attempts,
1761
- onStatusChange: data.on_status_change,
1762
- onAuthorizationUiChange: data.on_authorization_ui_change,
1763
- onAuthorizationRequired: data.on_authorization_required,
1764
- signal: data.signal,
1765
- returnUrl: data.return_url,
1766
- enrollInLink: data.enroll_in_link,
1767
- cartTotal: cart.pricing.total_price,
1768
- cartCurrency: checkoutData.pay_currency || baseCurrency,
1769
- orderType: checkoutData.order_type,
1770
- allowPopups: data.allow_popups
1771
- });
1772
- const resolved = await resolver.resolve(processResult.value);
1773
- return ok(resolved);
1774
2313
  }
1775
2314
  };
1776
2315
 
@@ -2405,6 +2944,8 @@ var MESSAGE_TYPES = {
2405
2944
  CONTACT_PROVIDED: "contact_provided",
2406
2945
  CHECKOUT_STATUS: "checkout_status",
2407
2946
  CHECKOUT_COMPLETE: "checkout_complete",
2947
+ TERMS_CHANGED: "terms_changed",
2948
+ SELECTION_UNAVAILABLE: "selection_unavailable",
2408
2949
  ORDER_TYPE_CHANGED: "order_type_changed",
2409
2950
  REQUEST_SUBMIT: "request_submit"
2410
2951
  };
@@ -2825,6 +3366,8 @@ var KNOWN_IFRAME_TYPES = /* @__PURE__ */ new Set([
2825
3366
  MESSAGE_TYPES.LOGOUT_COMPLETE,
2826
3367
  MESSAGE_TYPES.CHECKOUT_STATUS,
2827
3368
  MESSAGE_TYPES.CHECKOUT_COMPLETE,
3369
+ MESSAGE_TYPES.TERMS_CHANGED,
3370
+ MESSAGE_TYPES.SELECTION_UNAVAILABLE,
2828
3371
  MESSAGE_TYPES.ORDER_TYPE_CHANGED,
2829
3372
  MESSAGE_TYPES.REQUEST_SUBMIT
2830
3373
  ]);
@@ -2874,6 +3417,13 @@ function parseIframeMessage(data) {
2874
3417
  if (typeof record.status !== "string" || !record.context || typeof record.context !== "object")
2875
3418
  return null;
2876
3419
  break;
3420
+ case MESSAGE_TYPES.TERMS_CHANGED:
3421
+ if (typeof record.intent_id !== "string" || !record.replacement || typeof record.replacement !== "object" || !Array.isArray(record.deltas))
3422
+ return null;
3423
+ break;
3424
+ case MESSAGE_TYPES.SELECTION_UNAVAILABLE:
3425
+ if (typeof record.intent_id !== "string" || !Array.isArray(record.lines)) return null;
3426
+ break;
2877
3427
  case MESSAGE_TYPES.READY:
2878
3428
  case MESSAGE_TYPES.HEIGHT_CHANGE:
2879
3429
  if (typeof record.height !== "number") return null;
@@ -2946,7 +3496,10 @@ var CimplifyElements = class {
2946
3496
  async submitCheckout(data) {
2947
3497
  const result = await this.processCheckout({
2948
3498
  cart_id: data.cart_id,
2949
- order_type: data.order_type ?? "delivery",
3499
+ intent_id: data.intent_id,
3500
+ hosted_session_id: data.hosted_session_id,
3501
+ initial_terms: data.initial_terms,
3502
+ order_type: data.order_type ?? ORDER_TYPE.DELIVERY,
2950
3503
  location_id: data.location_id,
2951
3504
  notes: data.notes,
2952
3505
  scheduled_time: data.scheduled_time,
@@ -2958,7 +3511,7 @@ var CimplifyElements = class {
2958
3511
  success: true,
2959
3512
  order: {
2960
3513
  id: result.order?.id || "",
2961
- status: result.order?.status || "unknown",
3514
+ status: result.order?.status || CHECKOUT_ORDER_RESULT_STATUS.UNKNOWN,
2962
3515
  total: result.order?.total || ""
2963
3516
  }
2964
3517
  };
@@ -2966,7 +3519,7 @@ var CimplifyElements = class {
2966
3519
  return {
2967
3520
  success: false,
2968
3521
  error: {
2969
- code: result.error?.code || "CHECKOUT_FAILED",
3522
+ code: result.error?.code || ErrorCode.CHECKOUT_FAILED,
2970
3523
  message: result.error?.message || "Checkout failed"
2971
3524
  }
2972
3525
  };
@@ -2976,12 +3529,18 @@ var CimplifyElements = class {
2976
3529
  const task = (async () => {
2977
3530
  this.debug("[cimplify:checkout] processCheckout called", {
2978
3531
  cart_id: options.cart_id,
3532
+ intent_id: options.intent_id,
3533
+ hosted_session_id: options.hosted_session_id,
2979
3534
  order_type: options.order_type,
2980
3535
  location_id: options.location_id
2981
3536
  });
2982
3537
  if (this.checkoutInProgress) {
2983
3538
  this.debug("[cimplify:checkout] BLOCKED: already processing");
2984
- return toCheckoutError("ALREADY_PROCESSING", "Checkout is already in progress.", false);
3539
+ return toCheckoutError(
3540
+ ErrorCode.ALREADY_PROCESSING,
3541
+ "Checkout is already in progress.",
3542
+ false
3543
+ );
2985
3544
  }
2986
3545
  this.checkoutInProgress = true;
2987
3546
  if (this.authEstablishmentInProgress) {
@@ -2989,18 +3548,18 @@ var CimplifyElements = class {
2989
3548
  if (this.authEstablishmentInProgress) {
2990
3549
  this.checkoutInProgress = false;
2991
3550
  return toCheckoutError(
2992
- "AUTH_INCOMPLETE",
3551
+ ErrorCode.AUTH_INCOMPLETE,
2993
3552
  "Authentication must finish establishing the checkout session.",
2994
3553
  true
2995
3554
  );
2996
3555
  }
2997
3556
  }
2998
- if (!options.cart_id) {
2999
- this.debug("[cimplify:checkout] BLOCKED: no cart_id");
3557
+ if (!options.cart_id && !options.intent_id) {
3558
+ this.debug("[cimplify:checkout] BLOCKED: no cart_id or intent_id");
3000
3559
  this.checkoutInProgress = false;
3001
3560
  return toCheckoutError(
3002
- "INVALID_CART",
3003
- "A valid cart is required before checkout can start.",
3561
+ ErrorCode.CHECKOUT_AUTHORITY_REQUIRED,
3562
+ "A cart or existing purchase intent is required before checkout can start.",
3004
3563
  false
3005
3564
  );
3006
3565
  }
@@ -3008,7 +3567,7 @@ var CimplifyElements = class {
3008
3567
  this.debug("[cimplify:checkout] BLOCKED: no order_type");
3009
3568
  this.checkoutInProgress = false;
3010
3569
  return toCheckoutError(
3011
- "ORDER_TYPE_REQUIRED",
3570
+ ErrorCode.ORDER_TYPE_REQUIRED,
3012
3571
  "Order type is required before checkout can start.",
3013
3572
  false
3014
3573
  );
@@ -3018,7 +3577,7 @@ var CimplifyElements = class {
3018
3577
  this.debug("[cimplify:checkout] BLOCKED: no checkout element");
3019
3578
  this.checkoutInProgress = false;
3020
3579
  return toCheckoutError(
3021
- "NO_PAYMENT_ELEMENT",
3580
+ ErrorCode.NO_PAYMENT_ELEMENT,
3022
3581
  "Checkout element must be mounted before checkout.",
3023
3582
  false
3024
3583
  );
@@ -3027,7 +3586,7 @@ var CimplifyElements = class {
3027
3586
  this.debug("[cimplify:checkout] BLOCKED: checkout element not mounted");
3028
3587
  this.checkoutInProgress = false;
3029
3588
  return toCheckoutError(
3030
- "PAYMENT_NOT_MOUNTED",
3589
+ ErrorCode.PAYMENT_NOT_MOUNTED,
3031
3590
  "Checkout element must be mounted before checkout.",
3032
3591
  false
3033
3592
  );
@@ -3039,7 +3598,7 @@ var CimplifyElements = class {
3039
3598
  this.debug("[cimplify:checkout] BLOCKED: auth incomplete");
3040
3599
  this.checkoutInProgress = false;
3041
3600
  return toCheckoutError(
3042
- "AUTH_INCOMPLETE",
3601
+ ErrorCode.AUTH_INCOMPLETE,
3043
3602
  "Authentication must complete before checkout can start.",
3044
3603
  true
3045
3604
  );
@@ -3059,7 +3618,12 @@ var CimplifyElements = class {
3059
3618
  });
3060
3619
  const processMessage = {
3061
3620
  type: MESSAGE_TYPES.PROCESS_CHECKOUT,
3062
- cart_id: options.cart_id,
3621
+ // Existing intent authority wins if a compatibility caller supplied
3622
+ // both values; the iframe must never mint a replacement.
3623
+ cart_id: options.intent_id ? void 0 : options.cart_id,
3624
+ intent_id: options.intent_id,
3625
+ hosted_session_id: options.hosted_session_id,
3626
+ initial_terms: options.intent_id ? options.initial_terms : void 0,
3063
3627
  order_type: options.order_type,
3064
3628
  location_id: options.location_id,
3065
3629
  notes: options.notes,
@@ -3098,7 +3662,7 @@ var CimplifyElements = class {
3098
3662
  const timeout = setTimeout(() => {
3099
3663
  settle(
3100
3664
  toCheckoutError(
3101
- "TIMEOUT",
3665
+ ErrorCode.TIMEOUT,
3102
3666
  "Checkout timed out before receiving a terminal response.",
3103
3667
  true
3104
3668
  )
@@ -3119,6 +3683,21 @@ var CimplifyElements = class {
3119
3683
  options.on_status_change?.(message.status, message.context);
3120
3684
  return;
3121
3685
  }
3686
+ if (message.type === MESSAGE_TYPES.TERMS_CHANGED) {
3687
+ options.on_status_change?.(CHECKOUT_STATUS.REVIEWING_TERMS, {
3688
+ intent_id: message.intent_id,
3689
+ replacement_terms: message.replacement,
3690
+ terms_deltas: message.deltas
3691
+ });
3692
+ return;
3693
+ }
3694
+ if (message.type === MESSAGE_TYPES.SELECTION_UNAVAILABLE) {
3695
+ options.on_status_change?.(CHECKOUT_STATUS.REVIEWING_TERMS, {
3696
+ intent_id: message.intent_id,
3697
+ unavailable_lines: message.lines
3698
+ });
3699
+ return;
3700
+ }
3122
3701
  if (message.type === MESSAGE_TYPES.CHECKOUT_COMPLETE) {
3123
3702
  this.debug("[cimplify:checkout] received checkout_complete", {
3124
3703
  success: message.success,
@@ -3134,7 +3713,11 @@ var CimplifyElements = class {
3134
3713
  if (message.type === MESSAGE_TYPES.LOGOUT_COMPLETE) {
3135
3714
  checkoutElement.sendMessage({ type: MESSAGE_TYPES.ABORT_CHECKOUT });
3136
3715
  settle(
3137
- toCheckoutError("AUTH_LOST", "Authentication was cleared during checkout.", true)
3716
+ toCheckoutError(
3717
+ ErrorCode.AUTH_LOST,
3718
+ "Authentication was cleared during checkout.",
3719
+ true
3720
+ )
3138
3721
  );
3139
3722
  }
3140
3723
  };
@@ -3143,11 +3726,13 @@ var CimplifyElements = class {
3143
3726
  }
3144
3727
  abortFn = () => {
3145
3728
  checkoutElement.sendMessage({ type: MESSAGE_TYPES.ABORT_CHECKOUT });
3146
- settle(toCheckoutError("CANCELLED", "Checkout was cancelled.", true));
3729
+ settle(toCheckoutError(ErrorCode.CANCELLED, "Checkout was cancelled.", true));
3147
3730
  };
3148
3731
  this.activeCheckoutAbort = abortFn;
3149
3732
  this.debug("[cimplify:checkout] sending process_checkout to checkout iframe", {
3150
3733
  cart_id: processMessage.cart_id,
3734
+ intent_id: processMessage.intent_id,
3735
+ hosted_session_id: processMessage.hosted_session_id,
3151
3736
  order_type: processMessage.order_type,
3152
3737
  hasCustomer: !!processMessage.customer,
3153
3738
  hasAddress: !!processMessage.address,
@@ -3380,7 +3965,7 @@ var CimplifyElements = class {
3380
3965
  const redirectUri = auth.redirectUri ?? readPublicEnv("NEXT_PUBLIC_CIMPLIFY_REDIRECT_URI");
3381
3966
  if (!clientId || !redirectUri) {
3382
3967
  sourceElement._emitError({
3383
- code: "AUTH_CONFIG_REQUIRED",
3968
+ code: ErrorCode.AUTH_CONFIG_REQUIRED,
3384
3969
  message: "Cimplify OAuth clientId and redirectUri are required."
3385
3970
  });
3386
3971
  return;
@@ -3404,7 +3989,7 @@ var CimplifyElements = class {
3404
3989
  this.authInProgress = false;
3405
3990
  if (!accessToken) {
3406
3991
  sourceElement._emitError({
3407
- code: "AUTH_CALLBACK_MISSING_TOKEN",
3992
+ code: ErrorCode.AUTH_CALLBACK_MISSING_TOKEN,
3408
3993
  message: "Sign-in callback did not return an access token."
3409
3994
  });
3410
3995
  return;
@@ -3431,7 +4016,7 @@ var CimplifyElements = class {
3431
4016
  if (this.authGeneration !== generation) return;
3432
4017
  this.authInProgress = false;
3433
4018
  sourceElement._emitError({
3434
- code: "AUTH_START_FAILED",
4019
+ code: ErrorCode.AUTH_START_FAILED,
3435
4020
  message: error instanceof Error ? error.message : "Unable to start sign-in."
3436
4021
  });
3437
4022
  });
@@ -3484,7 +4069,7 @@ var CimplifyElements = class {
3484
4069
  if (!this.customerData) {
3485
4070
  this.customerData = { name: "", email: null, phone: null };
3486
4071
  }
3487
- if (message.contactType === "email") {
4072
+ if (message.contactType === ELEMENTS_AUTH_CONTACT_TYPES.EMAIL) {
3488
4073
  this.customerData.email = message.contact;
3489
4074
  } else {
3490
4075
  this.customerData.phone = message.contact;
@@ -3508,7 +4093,7 @@ var CimplifyElements = class {
3508
4093
  this.client.setAccessToken(null);
3509
4094
  }
3510
4095
  this.broadcastClearedSession();
3511
- if (message.contactType === "email") {
4096
+ if (message.contactType === ELEMENTS_AUTH_CONTACT_TYPES.EMAIL) {
3512
4097
  this.customerData.email = message.contact;
3513
4098
  } else {
3514
4099
  this.customerData.phone = message.contact;
@@ -3544,7 +4129,7 @@ var CimplifyElements = class {
3544
4129
  if (!this.customerData) {
3545
4130
  this.customerData = { name: "", email: null, phone: null };
3546
4131
  }
3547
- if (contactType === "email") {
4132
+ if (contactType === ELEMENTS_AUTH_CONTACT_TYPES.EMAIL) {
3548
4133
  this.customerData.email = contact;
3549
4134
  } else {
3550
4135
  this.customerData.phone = contact;
@@ -3707,7 +4292,7 @@ var CimplifyElement = class {
3707
4292
  if (!resolvedBusinessId || !this.container || !this.mounted) {
3708
4293
  console.error("Unable to mount element without a resolved business ID");
3709
4294
  this.emit(EVENT_TYPES.ERROR, {
3710
- code: "BUSINESS_ID_REQUIRED",
4295
+ code: ErrorCode.BUSINESS_ID_REQUIRED,
3711
4296
  message: "Unable to initialize checkout without a business ID."
3712
4297
  });
3713
4298
  return;
@@ -3762,7 +4347,10 @@ var CimplifyElement = class {
3762
4347
  orderTypes: this.options.orderTypes,
3763
4348
  defaultOrderType: this.options.defaultOrderType,
3764
4349
  renderSubmitButton: true,
3765
- submitLabel: this.options.submitLabel
4350
+ submitLabel: this.options.submitLabel,
4351
+ intentId: this.options.intentId,
4352
+ hostedSessionId: this.options.hostedSessionId,
4353
+ initialTerms: this.options.initialTerms
3766
4354
  });
3767
4355
  const token = this.parent.getAccessToken();
3768
4356
  const sessionToken = this.parent.getSessionToken();
@@ -3820,4 +4408,4 @@ function createElements(client, businessId, options) {
3820
4408
  return new CimplifyElements(client, businessId, options);
3821
4409
  }
3822
4410
 
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 };
4411
+ 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, PAYMENT_AUTHORIZATION_OUTCOME_STATUS, PAYMENT_AUTHORIZATION_PROVIDER, PKCE_COOKIE, PKCE_COOKIE_PATH, PaymentAuthorizationAdapterRegistry, PaystackAuthorizationAdapter, SchedulingService, StripeAuthorizationAdapter, clearIntentIdempotencyKey, combine, combineObject, createDefaultPaymentAuthorizationAdapterRegistry, createElements, createPurchaseIntentConfirmation, decodePkceState, err, flatMap, fromPromise, generateIdempotencyKey, generatePkce, generateState, getAuthorizationEndpoint, getOrElse, intentIdempotencyKey, isErr, isOk, mapError, mapResult, ok, purchaseIntentRequiresPaymentOption, safe, selectPurchaseIntentPaymentOption, startSignIn, toNullable, tryCatch, unwrap };