@cimplify/sdk 0.103.0 → 0.104.1

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