@cimplify/sdk 0.101.1 → 0.103.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/advanced.d.mts +3 -3
- package/dist/advanced.d.ts +3 -3
- package/dist/advanced.js +23 -22
- package/dist/advanced.mjs +4 -3
- package/dist/{chunk-QPRI2NII.js → chunk-2P4KXFB6.js} +6 -0
- package/dist/{chunk-4G5UWFC3.mjs → chunk-3V4DVXV3.mjs} +6 -1
- package/dist/{chunk-YHPMFTMN.mjs → chunk-C2JSNJUC.mjs} +406 -95
- package/dist/chunk-CNN7Z2IP.js +125 -0
- package/dist/{chunk-DKLHCZ5M.mjs → chunk-GERXZQSX.mjs} +487 -11
- package/dist/chunk-GOHSXBKW.mjs +105 -0
- package/dist/{chunk-7H6IL7CX.mjs → chunk-H7ACMHM3.mjs} +40 -15
- package/dist/{chunk-Z3K2D3TE.mjs → chunk-J6PNHDHL.mjs} +453 -483
- package/dist/{chunk-NIOUSKQQ.js → chunk-JG5CQNCB.js} +5 -0
- package/dist/{chunk-YER7DIOM.js → chunk-JSWJ4XDE.js} +471 -519
- package/dist/{chunk-DLW3RWRK.mjs → chunk-M4URVKHE.mjs} +46 -12
- package/dist/{chunk-WMEC5JWN.js → chunk-NNG6IFFX.js} +50 -13
- package/dist/{chunk-ICCCSVN3.js → chunk-QOWPGS7Z.js} +42 -16
- package/dist/{chunk-YDA46OZ6.js → chunk-R6OLQ33I.js} +560 -80
- package/dist/{chunk-H5SSGN7W.js → chunk-VIL6IQCG.js} +408 -97
- package/dist/{chunk-O3YUHLZL.mjs → chunk-VNPEYLB2.mjs} +5 -0
- package/dist/{client-Db554902.d.ts → client-BfpNjJ_a.d.mts} +93 -299
- package/dist/{client-CdTx7X_X.d.mts → client-DHBwvh7U.d.ts} +93 -299
- package/dist/{client-WkUcvRvO.d.mts → client-DpqRobY9.d.mts} +2 -2
- package/dist/{client-D40kI8z2.d.ts → client-Dqg2mc-7.d.ts} +2 -2
- package/dist/{index-D3UXgAYl.d.ts → index-C8uDqLwJ.d.ts} +14 -4
- package/dist/{index-BjWUkYgY.d.mts → index-e2y6AK70.d.mts} +14 -4
- package/dist/index.d.mts +92 -8
- package/dist/index.d.ts +92 -8
- package/dist/index.js +225 -188
- package/dist/index.mjs +7 -6
- package/dist/link-cuNVYc2s.d.mts +297 -0
- package/dist/link-cuNVYc2s.d.ts +297 -0
- package/dist/mock/cli.mjs +412 -94
- package/dist/mock/library.js +412 -94
- package/dist/mock/library.mjs +412 -94
- package/dist/mock/msw.js +412 -94
- package/dist/mock/msw.mjs +412 -94
- package/dist/{product-DwKdC_to.d.mts → payment-H5LoIvXU.d.mts} +207 -7
- package/dist/{product-DwKdC_to.d.ts → payment-H5LoIvXU.d.ts} +207 -7
- package/dist/{price-CiQUd_XX.d.mts → price-BvePgDXe.d.mts} +1 -1
- package/dist/{price-D9EOj8y8.d.ts → price-C2RqscMY.d.ts} +1 -1
- package/dist/react.d.mts +6 -4
- package/dist/react.d.ts +6 -4
- package/dist/react.js +203 -198
- package/dist/react.mjs +11 -6
- package/dist/{server-CeDb93WA.d.ts → server-C7FyLdrz.d.mts} +11 -9
- package/dist/{server-D-nSkrUr.d.mts → server-DoXIpSd7.d.ts} +11 -9
- package/dist/server.d.mts +4 -4
- package/dist/server.d.ts +4 -4
- package/dist/server.js +11 -10
- package/dist/server.mjs +5 -4
- package/dist/testing/msw.d.mts +2 -2
- package/dist/testing/msw.d.ts +2 -2
- package/dist/testing/msw.js +4 -3
- package/dist/testing/msw.mjs +3 -2
- package/dist/testing/suite.d.mts +6 -6
- package/dist/testing/suite.d.ts +6 -6
- package/dist/testing/suite.js +26 -25
- package/dist/testing/suite.mjs +7 -6
- package/dist/testing.d.mts +175 -45
- package/dist/testing.d.ts +175 -45
- package/dist/testing.js +86 -81
- package/dist/testing.mjs +8 -7
- package/dist/utils.d.mts +4 -4
- package/dist/utils.d.ts +4 -4
- package/dist/utils.js +37 -29
- package/dist/utils.mjs +2 -2
- package/package.json +7 -1
- package/dist/payment-CRqjGrx6.d.mts +0 -113
- package/dist/payment-DO1Z1Ip6.d.ts +0 -113
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/constants.ts
|
|
4
|
+
var CHECKOUT_MODE = {
|
|
5
|
+
LINK: "link",
|
|
6
|
+
GUEST: "guest"
|
|
7
|
+
};
|
|
8
|
+
var ORDER_TYPE = {
|
|
9
|
+
DELIVERY: "delivery",
|
|
10
|
+
PICKUP: "pickup",
|
|
11
|
+
DINE_IN: "dine-in",
|
|
12
|
+
WALK_IN: "walk-in"
|
|
13
|
+
};
|
|
14
|
+
var PAYMENT_METHOD = {
|
|
15
|
+
MOBILE_MONEY: "mobile_money",
|
|
16
|
+
CARD: "card"
|
|
17
|
+
};
|
|
18
|
+
var CHECKOUT_STEP = {
|
|
19
|
+
AUTHENTICATION: "authentication",
|
|
20
|
+
ORDER_DETAILS: "order_details",
|
|
21
|
+
PAYMENT_METHOD: "payment_method",
|
|
22
|
+
PAYMENT: "payment",
|
|
23
|
+
CONFIRMATION: "confirmation"
|
|
24
|
+
};
|
|
25
|
+
var PAYMENT_STATE = {
|
|
26
|
+
INITIAL: "initial",
|
|
27
|
+
PREPARING: "preparing",
|
|
28
|
+
PROCESSING: "processing",
|
|
29
|
+
VERIFYING: "verifying",
|
|
30
|
+
AWAITING_AUTHORIZATION: "awaiting_authorization",
|
|
31
|
+
SUCCESS: "success",
|
|
32
|
+
ERROR: "error",
|
|
33
|
+
TIMEOUT: "timeout"
|
|
34
|
+
};
|
|
35
|
+
var PICKUP_TIME_TYPE = {
|
|
36
|
+
ASAP: "asap",
|
|
37
|
+
SCHEDULED: "scheduled"
|
|
38
|
+
};
|
|
39
|
+
var MOBILE_MONEY_PROVIDER = {
|
|
40
|
+
MTN: "mtn",
|
|
41
|
+
VODAFONE: "vodafone",
|
|
42
|
+
TELECEL: "telecel",
|
|
43
|
+
AIRTEL: "airtel",
|
|
44
|
+
AIRTELTIGO: "airteltigo",
|
|
45
|
+
MPESA: "mpesa"
|
|
46
|
+
};
|
|
47
|
+
var AUTHORIZATION_TYPE = {
|
|
48
|
+
OTP: "otp",
|
|
49
|
+
PIN: "pin",
|
|
50
|
+
PHONE: "phone",
|
|
51
|
+
BIRTHDAY: "birthday",
|
|
52
|
+
ADDRESS: "address"
|
|
53
|
+
};
|
|
54
|
+
var MAX_PAYMENT_AUTHORIZATION_STEPS = 8;
|
|
55
|
+
var DEVICE_TYPE = {
|
|
56
|
+
MOBILE: "mobile",
|
|
57
|
+
DESKTOP: "desktop",
|
|
58
|
+
TABLET: "tablet",
|
|
59
|
+
UNKNOWN: "unknown"
|
|
60
|
+
};
|
|
61
|
+
var CONTACT_TYPE = {
|
|
62
|
+
PHONE: "phone",
|
|
63
|
+
EMAIL: "email"
|
|
64
|
+
};
|
|
65
|
+
var LINK_QUERY = {
|
|
66
|
+
DATA: "link.data",
|
|
67
|
+
ADDRESSES: "link.addresses",
|
|
68
|
+
MOBILE_MONEY: "link.mobile_money",
|
|
69
|
+
PREFERENCES: "link.preferences",
|
|
70
|
+
SESSIONS: "link.sessions"
|
|
71
|
+
};
|
|
72
|
+
var LINK_MUTATION = {
|
|
73
|
+
CHECK_STATUS: "link.check_status",
|
|
74
|
+
ENROLL: "link.enroll",
|
|
75
|
+
ENROLL_AND_LINK_ORDER: "link.enroll_and_link_order",
|
|
76
|
+
UPDATE_PREFERENCES: "link.update_preferences",
|
|
77
|
+
CREATE_ADDRESS: "link.create_address",
|
|
78
|
+
UPDATE_ADDRESS: "link.update_address",
|
|
79
|
+
DELETE_ADDRESS: "link.delete_address",
|
|
80
|
+
SET_DEFAULT_ADDRESS: "link.set_default_address",
|
|
81
|
+
TRACK_ADDRESS_USAGE: "link.track_address_usage",
|
|
82
|
+
CREATE_MOBILE_MONEY: "link.create_mobile_money",
|
|
83
|
+
DELETE_MOBILE_MONEY: "link.delete_mobile_money",
|
|
84
|
+
SET_DEFAULT_MOBILE_MONEY: "link.set_default_mobile_money",
|
|
85
|
+
TRACK_MOBILE_MONEY_USAGE: "link.track_mobile_money_usage",
|
|
86
|
+
VERIFY_MOBILE_MONEY: "link.verify_mobile_money",
|
|
87
|
+
REVOKE_SESSION: "link.revoke_session",
|
|
88
|
+
REVOKE_ALL_SESSIONS: "link.revoke_all_sessions"
|
|
89
|
+
};
|
|
90
|
+
var AUTH_MUTATION = {
|
|
91
|
+
REQUEST_OTP: "auth.request_otp",
|
|
92
|
+
VERIFY_OTP: "auth.verify_otp"
|
|
93
|
+
};
|
|
94
|
+
var CHECKOUT_MUTATION = {
|
|
95
|
+
PROCESS: "checkout.process"
|
|
96
|
+
};
|
|
97
|
+
var PAYMENT_MUTATION = {
|
|
98
|
+
SUBMIT_AUTHORIZATION: "payment.submit_authorization",
|
|
99
|
+
CHECK_STATUS: "order.poll_payment_status"
|
|
100
|
+
};
|
|
101
|
+
var ORDER_MUTATION = {
|
|
102
|
+
UPDATE_CUSTOMER: "order.update_order_customer"
|
|
103
|
+
};
|
|
104
|
+
var DEFAULT_CURRENCY = "GHS";
|
|
105
|
+
var DEFAULT_COUNTRY = "GHA";
|
|
106
|
+
|
|
107
|
+
exports.AUTHORIZATION_TYPE = AUTHORIZATION_TYPE;
|
|
108
|
+
exports.AUTH_MUTATION = AUTH_MUTATION;
|
|
109
|
+
exports.CHECKOUT_MODE = CHECKOUT_MODE;
|
|
110
|
+
exports.CHECKOUT_MUTATION = CHECKOUT_MUTATION;
|
|
111
|
+
exports.CHECKOUT_STEP = CHECKOUT_STEP;
|
|
112
|
+
exports.CONTACT_TYPE = CONTACT_TYPE;
|
|
113
|
+
exports.DEFAULT_COUNTRY = DEFAULT_COUNTRY;
|
|
114
|
+
exports.DEFAULT_CURRENCY = DEFAULT_CURRENCY;
|
|
115
|
+
exports.DEVICE_TYPE = DEVICE_TYPE;
|
|
116
|
+
exports.LINK_MUTATION = LINK_MUTATION;
|
|
117
|
+
exports.LINK_QUERY = LINK_QUERY;
|
|
118
|
+
exports.MAX_PAYMENT_AUTHORIZATION_STEPS = MAX_PAYMENT_AUTHORIZATION_STEPS;
|
|
119
|
+
exports.MOBILE_MONEY_PROVIDER = MOBILE_MONEY_PROVIDER;
|
|
120
|
+
exports.ORDER_MUTATION = ORDER_MUTATION;
|
|
121
|
+
exports.ORDER_TYPE = ORDER_TYPE;
|
|
122
|
+
exports.PAYMENT_METHOD = PAYMENT_METHOD;
|
|
123
|
+
exports.PAYMENT_MUTATION = PAYMENT_MUTATION;
|
|
124
|
+
exports.PAYMENT_STATE = PAYMENT_STATE;
|
|
125
|
+
exports.PICKUP_TIME_TYPE = PICKUP_TIME_TYPE;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { safe, generateIdempotencyKey, err, ok, CatalogueQueries, CartOperations, CheckoutService, OrderQueries, LinkService, AuthService, BusinessService, InventoryService, SchedulingService, LiteService, FxService, createElements } from './chunk-
|
|
2
|
-
import { CimplifyError, ErrorCode, IdempotencyMismatchError, enrichError } from './chunk-
|
|
1
|
+
import { safe, generateIdempotencyKey, err, ok, CatalogueQueries, CartOperations, CheckoutService, OrderQueries, LinkService, AuthService, BusinessService, InventoryService, SchedulingService, LiteService, FxService, createElements } from './chunk-J6PNHDHL.mjs';
|
|
2
|
+
import { CimplifyError, ErrorCode, IdempotencyMismatchError, enrichError } from './chunk-VNPEYLB2.mjs';
|
|
3
3
|
|
|
4
4
|
// src/store-credit.ts
|
|
5
5
|
var StoreCreditQueries = class {
|
|
@@ -721,6 +721,453 @@ var SupportService = class {
|
|
|
721
721
|
}
|
|
722
722
|
};
|
|
723
723
|
|
|
724
|
+
// src/payment-authorization/providers/paystack.ts
|
|
725
|
+
async function openPaystackPopup(options, signal) {
|
|
726
|
+
if (typeof window === "undefined") {
|
|
727
|
+
return { success: false, error: "PROVIDER_UNAVAILABLE" };
|
|
728
|
+
}
|
|
729
|
+
let PaystackPop;
|
|
730
|
+
try {
|
|
731
|
+
const imported = await import('@paystack/inline-js');
|
|
732
|
+
PaystackPop = imported.default;
|
|
733
|
+
} catch {
|
|
734
|
+
return { success: false, error: "PROVIDER_UNAVAILABLE" };
|
|
735
|
+
}
|
|
736
|
+
return new Promise((resolve) => {
|
|
737
|
+
let settled = false;
|
|
738
|
+
let providerStarted = false;
|
|
739
|
+
const resolveOnce = (result) => {
|
|
740
|
+
if (settled) {
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
settled = true;
|
|
744
|
+
if (signal) {
|
|
745
|
+
signal.removeEventListener("abort", onAbort);
|
|
746
|
+
}
|
|
747
|
+
resolve(result);
|
|
748
|
+
};
|
|
749
|
+
const onAbort = () => {
|
|
750
|
+
resolveOnce({
|
|
751
|
+
success: false,
|
|
752
|
+
// Once Paystack owns the transaction, cancellation is ambiguous. The
|
|
753
|
+
// adapter converts this into submitted so Cimplify polling decides.
|
|
754
|
+
error: providerStarted ? "SUBMISSION_UNKNOWN" : "CANCELLED"
|
|
755
|
+
});
|
|
756
|
+
};
|
|
757
|
+
if (signal?.aborted) {
|
|
758
|
+
resolveOnce({ success: false, error: "CANCELLED" });
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
if (signal) {
|
|
762
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
763
|
+
}
|
|
764
|
+
try {
|
|
765
|
+
const popup = new PaystackPop();
|
|
766
|
+
popup.newTransaction({
|
|
767
|
+
key: options.key,
|
|
768
|
+
email: options.email,
|
|
769
|
+
amount: options.amount,
|
|
770
|
+
currency: options.currency,
|
|
771
|
+
reference: options.reference,
|
|
772
|
+
accessCode: options.accessCode,
|
|
773
|
+
onSuccess: (transaction) => {
|
|
774
|
+
resolveOnce({
|
|
775
|
+
success: true,
|
|
776
|
+
reference: transaction.reference ?? options.reference
|
|
777
|
+
});
|
|
778
|
+
},
|
|
779
|
+
onCancel: () => {
|
|
780
|
+
resolveOnce({ success: false, error: "PAYMENT_CANCELLED" });
|
|
781
|
+
},
|
|
782
|
+
onError: (error) => {
|
|
783
|
+
resolveOnce({
|
|
784
|
+
success: false,
|
|
785
|
+
error: error?.message || "PAYMENT_FAILED"
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
});
|
|
789
|
+
providerStarted = true;
|
|
790
|
+
} catch {
|
|
791
|
+
resolveOnce({ success: false, error: "POPUP_BLOCKED" });
|
|
792
|
+
}
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
var PaystackAuthorizationAdapter = class {
|
|
796
|
+
constructor(openPopup = openPaystackPopup) {
|
|
797
|
+
this.openPopup = openPopup;
|
|
798
|
+
this.provider = "paystack";
|
|
799
|
+
}
|
|
800
|
+
async authorize(context) {
|
|
801
|
+
const result = await this.openPopup(
|
|
802
|
+
{
|
|
803
|
+
key: context.action.public_key,
|
|
804
|
+
email: context.email,
|
|
805
|
+
accessCode: context.action.client_secret,
|
|
806
|
+
reference: context.reference || context.action.client_secret,
|
|
807
|
+
currency: context.currency
|
|
808
|
+
},
|
|
809
|
+
context.signal
|
|
810
|
+
);
|
|
811
|
+
if (result.success) {
|
|
812
|
+
return { status: "submitted", reference: result.reference || context.reference };
|
|
813
|
+
}
|
|
814
|
+
if (result.error === "SUBMISSION_UNKNOWN") {
|
|
815
|
+
return { status: "submitted", reference: context.reference };
|
|
816
|
+
}
|
|
817
|
+
if (!result.error || result.error === "CANCELLED" || result.error === "PAYMENT_CANCELLED") {
|
|
818
|
+
return { status: "cancelled" };
|
|
819
|
+
}
|
|
820
|
+
if (result.error === "POPUP_BLOCKED") {
|
|
821
|
+
return {
|
|
822
|
+
status: "failed",
|
|
823
|
+
code: "POPUP_BLOCKED",
|
|
824
|
+
message: "Unable to open the Paystack payment popup. Please allow popups and try again.",
|
|
825
|
+
recoverable: true
|
|
826
|
+
};
|
|
827
|
+
}
|
|
828
|
+
if (result.error === "PROVIDER_UNAVAILABLE") {
|
|
829
|
+
return {
|
|
830
|
+
status: "failed",
|
|
831
|
+
code: "PROVIDER_UNAVAILABLE",
|
|
832
|
+
message: "Paystack is unavailable in this environment.",
|
|
833
|
+
recoverable: false
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
return {
|
|
837
|
+
status: "failed",
|
|
838
|
+
code: "PAYMENT_FAILED",
|
|
839
|
+
message: result.error || "Paystack payment could not be submitted.",
|
|
840
|
+
recoverable: true
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
};
|
|
844
|
+
|
|
845
|
+
// src/payment-authorization/providers/stripe.ts
|
|
846
|
+
async function loadStripeFromPeer(publicKey) {
|
|
847
|
+
try {
|
|
848
|
+
const imported = await import('@stripe/stripe-js');
|
|
849
|
+
return imported.loadStripe ? imported.loadStripe(publicKey) : null;
|
|
850
|
+
} catch {
|
|
851
|
+
return null;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
function createStripeModal() {
|
|
855
|
+
if (typeof document === "undefined" || !document.body) return null;
|
|
856
|
+
const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
857
|
+
const root = document.createElement("div");
|
|
858
|
+
root.setAttribute("role", "dialog");
|
|
859
|
+
root.setAttribute("aria-modal", "true");
|
|
860
|
+
root.setAttribute("aria-label", "Secure card payment");
|
|
861
|
+
Object.assign(root.style, {
|
|
862
|
+
position: "fixed",
|
|
863
|
+
inset: "0",
|
|
864
|
+
zIndex: "2147483647",
|
|
865
|
+
display: "grid",
|
|
866
|
+
placeItems: "center",
|
|
867
|
+
padding: "16px",
|
|
868
|
+
background: "rgba(15, 23, 42, 0.58)"
|
|
869
|
+
});
|
|
870
|
+
const form = document.createElement("form");
|
|
871
|
+
Object.assign(form.style, {
|
|
872
|
+
width: "min(100%, 480px)",
|
|
873
|
+
maxHeight: "calc(100vh - 32px)",
|
|
874
|
+
overflow: "auto",
|
|
875
|
+
borderRadius: "12px",
|
|
876
|
+
padding: "24px",
|
|
877
|
+
background: "#fff",
|
|
878
|
+
boxShadow: "0 24px 80px rgba(15, 23, 42, 0.32)"
|
|
879
|
+
});
|
|
880
|
+
const title = document.createElement("h2");
|
|
881
|
+
title.textContent = "Complete card payment";
|
|
882
|
+
Object.assign(title.style, { margin: "0 0 18px", font: "600 18px/1.4 system-ui" });
|
|
883
|
+
const paymentMount = document.createElement("div");
|
|
884
|
+
paymentMount.setAttribute("data-cimplify-stripe-payment-element", "");
|
|
885
|
+
const error = document.createElement("p");
|
|
886
|
+
error.setAttribute("role", "alert");
|
|
887
|
+
Object.assign(error.style, {
|
|
888
|
+
minHeight: "20px",
|
|
889
|
+
margin: "14px 0 0",
|
|
890
|
+
color: "#b91c1c",
|
|
891
|
+
font: "14px/1.4 system-ui"
|
|
892
|
+
});
|
|
893
|
+
const actions = document.createElement("div");
|
|
894
|
+
Object.assign(actions.style, {
|
|
895
|
+
display: "flex",
|
|
896
|
+
justifyContent: "flex-end",
|
|
897
|
+
gap: "10px",
|
|
898
|
+
marginTop: "18px"
|
|
899
|
+
});
|
|
900
|
+
const cancelButton = document.createElement("button");
|
|
901
|
+
cancelButton.type = "button";
|
|
902
|
+
cancelButton.textContent = "Cancel";
|
|
903
|
+
Object.assign(cancelButton.style, {
|
|
904
|
+
border: "1px solid #cbd5e1",
|
|
905
|
+
borderRadius: "8px",
|
|
906
|
+
padding: "10px 16px",
|
|
907
|
+
background: "#fff",
|
|
908
|
+
color: "#0f172a",
|
|
909
|
+
cursor: "pointer"
|
|
910
|
+
});
|
|
911
|
+
const submitButton = document.createElement("button");
|
|
912
|
+
submitButton.type = "submit";
|
|
913
|
+
submitButton.textContent = "Pay securely";
|
|
914
|
+
Object.assign(submitButton.style, {
|
|
915
|
+
border: "0",
|
|
916
|
+
borderRadius: "8px",
|
|
917
|
+
padding: "10px 16px",
|
|
918
|
+
background: "#0f172a",
|
|
919
|
+
color: "#fff",
|
|
920
|
+
cursor: "pointer"
|
|
921
|
+
});
|
|
922
|
+
actions.append(cancelButton, submitButton);
|
|
923
|
+
form.append(title, paymentMount, error, actions);
|
|
924
|
+
root.append(form);
|
|
925
|
+
document.body.append(root);
|
|
926
|
+
cancelButton.focus();
|
|
927
|
+
return { root, form, paymentMount, submitButton, cancelButton, error, previousFocus };
|
|
928
|
+
}
|
|
929
|
+
function stripeFailure(error) {
|
|
930
|
+
const message = error?.message || "Stripe could not authorize this payment.";
|
|
931
|
+
if (error?.code === "payment_intent_authentication_failure" || error?.type === "invalid_request_error") {
|
|
932
|
+
return {
|
|
933
|
+
status: "failed",
|
|
934
|
+
code: "AUTHORIZATION_FAILED",
|
|
935
|
+
message,
|
|
936
|
+
recoverable: true
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
return { status: "failed", code: "PAYMENT_FAILED", message, recoverable: true };
|
|
940
|
+
}
|
|
941
|
+
var StripeAuthorizationAdapter = class {
|
|
942
|
+
constructor(loadStripe = loadStripeFromPeer) {
|
|
943
|
+
this.loadStripe = loadStripe;
|
|
944
|
+
this.provider = "stripe";
|
|
945
|
+
}
|
|
946
|
+
async authorize(context) {
|
|
947
|
+
if (typeof window === "undefined" || typeof document === "undefined" || context.signal?.aborted) {
|
|
948
|
+
return context.signal?.aborted ? { status: "cancelled" } : {
|
|
949
|
+
status: "failed",
|
|
950
|
+
code: "PROVIDER_UNAVAILABLE",
|
|
951
|
+
message: "Stripe Payment Element is unavailable in this environment.",
|
|
952
|
+
recoverable: false
|
|
953
|
+
};
|
|
954
|
+
}
|
|
955
|
+
let stripe;
|
|
956
|
+
try {
|
|
957
|
+
stripe = await this.loadStripe(context.action.public_key);
|
|
958
|
+
} catch (error) {
|
|
959
|
+
return {
|
|
960
|
+
status: "failed",
|
|
961
|
+
code: "PROVIDER_UNAVAILABLE",
|
|
962
|
+
message: error instanceof Error ? error.message : "Stripe.js could not be loaded.",
|
|
963
|
+
recoverable: true
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
if (context.signal?.aborted) {
|
|
967
|
+
return { status: "cancelled" };
|
|
968
|
+
}
|
|
969
|
+
if (!stripe) {
|
|
970
|
+
return {
|
|
971
|
+
status: "failed",
|
|
972
|
+
code: "PROVIDER_UNAVAILABLE",
|
|
973
|
+
message: "Stripe.js could not be loaded.",
|
|
974
|
+
recoverable: false
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
const modal = createStripeModal();
|
|
978
|
+
if (!modal) {
|
|
979
|
+
return {
|
|
980
|
+
status: "failed",
|
|
981
|
+
code: "PROVIDER_UNAVAILABLE",
|
|
982
|
+
message: "Stripe Payment Element could not be mounted.",
|
|
983
|
+
recoverable: false
|
|
984
|
+
};
|
|
985
|
+
}
|
|
986
|
+
let paymentElement;
|
|
987
|
+
let elements;
|
|
988
|
+
try {
|
|
989
|
+
elements = stripe.elements({ clientSecret: context.action.client_secret });
|
|
990
|
+
paymentElement = elements.create("payment");
|
|
991
|
+
paymentElement.mount(modal.paymentMount);
|
|
992
|
+
} catch {
|
|
993
|
+
modal.root.remove();
|
|
994
|
+
modal.previousFocus?.focus();
|
|
995
|
+
return {
|
|
996
|
+
status: "failed",
|
|
997
|
+
code: "PROVIDER_UNAVAILABLE",
|
|
998
|
+
message: "Stripe Payment Element could not be initialized.",
|
|
999
|
+
recoverable: false
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
if (context.signal?.aborted) {
|
|
1003
|
+
if (paymentElement.destroy) paymentElement.destroy();
|
|
1004
|
+
else paymentElement.unmount?.();
|
|
1005
|
+
modal.root.remove();
|
|
1006
|
+
modal.previousFocus?.focus();
|
|
1007
|
+
return { status: "cancelled" };
|
|
1008
|
+
}
|
|
1009
|
+
return new Promise((resolve) => {
|
|
1010
|
+
let settled = false;
|
|
1011
|
+
let submitting = false;
|
|
1012
|
+
let confirmationStarted = false;
|
|
1013
|
+
const cleanup = () => {
|
|
1014
|
+
context.signal?.removeEventListener("abort", onAbort);
|
|
1015
|
+
modal.form.removeEventListener("submit", onSubmit);
|
|
1016
|
+
modal.cancelButton.removeEventListener("click", onCancel);
|
|
1017
|
+
if (paymentElement.destroy) paymentElement.destroy();
|
|
1018
|
+
else paymentElement.unmount?.();
|
|
1019
|
+
modal.root.remove();
|
|
1020
|
+
modal.previousFocus?.focus();
|
|
1021
|
+
};
|
|
1022
|
+
const settle = (outcome) => {
|
|
1023
|
+
if (settled) return;
|
|
1024
|
+
settled = true;
|
|
1025
|
+
cleanup();
|
|
1026
|
+
resolve(outcome);
|
|
1027
|
+
};
|
|
1028
|
+
const onAbort = () => {
|
|
1029
|
+
if (confirmationStarted) {
|
|
1030
|
+
settle({ status: "submitted", reference: context.reference });
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
settle({ status: "cancelled" });
|
|
1034
|
+
};
|
|
1035
|
+
const onCancel = () => {
|
|
1036
|
+
if (!confirmationStarted) settle({ status: "cancelled" });
|
|
1037
|
+
};
|
|
1038
|
+
const onSubmit = async (event) => {
|
|
1039
|
+
event.preventDefault();
|
|
1040
|
+
if (submitting || settled) return;
|
|
1041
|
+
submitting = true;
|
|
1042
|
+
modal.submitButton.disabled = true;
|
|
1043
|
+
modal.error.textContent = "";
|
|
1044
|
+
try {
|
|
1045
|
+
const validation = elements.submit ? await elements.submit() : {};
|
|
1046
|
+
if (validation.error) {
|
|
1047
|
+
modal.error.textContent = validation.error.message || "Check your payment details.";
|
|
1048
|
+
submitting = false;
|
|
1049
|
+
modal.submitButton.disabled = false;
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
if (settled || context.signal?.aborted) {
|
|
1053
|
+
settle({ status: "cancelled" });
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
1056
|
+
confirmationStarted = true;
|
|
1057
|
+
modal.cancelButton.disabled = true;
|
|
1058
|
+
const confirmation = await stripe.confirmPayment({
|
|
1059
|
+
elements,
|
|
1060
|
+
confirmParams: { return_url: context.returnUrl || window.location.href },
|
|
1061
|
+
redirect: "if_required"
|
|
1062
|
+
});
|
|
1063
|
+
if (settled) return;
|
|
1064
|
+
if (confirmation.error) {
|
|
1065
|
+
settle(stripeFailure(confirmation.error));
|
|
1066
|
+
return;
|
|
1067
|
+
}
|
|
1068
|
+
settle({
|
|
1069
|
+
status: "submitted",
|
|
1070
|
+
reference: confirmation.paymentIntent?.id || context.reference
|
|
1071
|
+
});
|
|
1072
|
+
} catch (error) {
|
|
1073
|
+
if (confirmationStarted) {
|
|
1074
|
+
settle({ status: "submitted", reference: context.reference });
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
1077
|
+
settle(
|
|
1078
|
+
stripeFailure({
|
|
1079
|
+
message: error instanceof Error ? error.message : "Stripe confirmation failed."
|
|
1080
|
+
})
|
|
1081
|
+
);
|
|
1082
|
+
}
|
|
1083
|
+
};
|
|
1084
|
+
modal.form.addEventListener("submit", onSubmit);
|
|
1085
|
+
modal.cancelButton.addEventListener("click", onCancel);
|
|
1086
|
+
context.signal?.addEventListener("abort", onAbort, { once: true });
|
|
1087
|
+
paymentElement.on?.("escape", onCancel);
|
|
1088
|
+
paymentElement.on?.("loaderror", (event) => {
|
|
1089
|
+
if (confirmationStarted) return;
|
|
1090
|
+
settle({
|
|
1091
|
+
status: "failed",
|
|
1092
|
+
code: "PROVIDER_UNAVAILABLE",
|
|
1093
|
+
message: event?.error?.message || "Stripe Payment Element failed to load.",
|
|
1094
|
+
recoverable: true
|
|
1095
|
+
});
|
|
1096
|
+
});
|
|
1097
|
+
});
|
|
1098
|
+
}
|
|
1099
|
+
};
|
|
1100
|
+
|
|
1101
|
+
// src/payment-authorization/registry.ts
|
|
1102
|
+
function normalizeProvider(provider) {
|
|
1103
|
+
return typeof provider === "string" ? provider.trim().toLowerCase() : "";
|
|
1104
|
+
}
|
|
1105
|
+
var PaymentAuthorizationAdapterRegistry = class {
|
|
1106
|
+
constructor(adapters = []) {
|
|
1107
|
+
this.adapters = /* @__PURE__ */ new Map();
|
|
1108
|
+
for (const adapter of adapters) {
|
|
1109
|
+
this.register(adapter);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
register(adapter) {
|
|
1113
|
+
const provider = normalizeProvider(adapter.provider);
|
|
1114
|
+
if (!provider) {
|
|
1115
|
+
throw new TypeError("Payment authorization adapter provider cannot be empty.");
|
|
1116
|
+
}
|
|
1117
|
+
this.adapters.set(provider, adapter);
|
|
1118
|
+
return this;
|
|
1119
|
+
}
|
|
1120
|
+
unregister(provider) {
|
|
1121
|
+
return this.adapters.delete(normalizeProvider(provider));
|
|
1122
|
+
}
|
|
1123
|
+
get(provider) {
|
|
1124
|
+
return this.adapters.get(normalizeProvider(provider));
|
|
1125
|
+
}
|
|
1126
|
+
supports(provider) {
|
|
1127
|
+
return this.adapters.has(normalizeProvider(provider));
|
|
1128
|
+
}
|
|
1129
|
+
providers() {
|
|
1130
|
+
return [...this.adapters.keys()];
|
|
1131
|
+
}
|
|
1132
|
+
async authorize(action, options) {
|
|
1133
|
+
const provider = normalizeProvider(action.provider);
|
|
1134
|
+
if (!provider) {
|
|
1135
|
+
return {
|
|
1136
|
+
status: "failed",
|
|
1137
|
+
code: "PROVIDER_UNAVAILABLE",
|
|
1138
|
+
message: "Card authorization response did not identify a payment provider.",
|
|
1139
|
+
recoverable: false
|
|
1140
|
+
};
|
|
1141
|
+
}
|
|
1142
|
+
const adapter = this.adapters.get(provider);
|
|
1143
|
+
if (!adapter) {
|
|
1144
|
+
return {
|
|
1145
|
+
status: "failed",
|
|
1146
|
+
code: "PROVIDER_UNAVAILABLE",
|
|
1147
|
+
message: `Card authorization provider '${provider}' is not supported by this SDK client.`,
|
|
1148
|
+
recoverable: false
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1151
|
+
try {
|
|
1152
|
+
const normalizedAction = action.provider === provider ? action : { ...action, provider };
|
|
1153
|
+
return await adapter.authorize({ ...options, action: normalizedAction });
|
|
1154
|
+
} catch (error) {
|
|
1155
|
+
return {
|
|
1156
|
+
status: "failed",
|
|
1157
|
+
code: "PAYMENT_FAILED",
|
|
1158
|
+
message: error instanceof Error ? error.message : `Card authorization provider '${provider}' failed unexpectedly.`,
|
|
1159
|
+
recoverable: true
|
|
1160
|
+
};
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
};
|
|
1164
|
+
function createDefaultPaymentAuthorizationAdapterRegistry() {
|
|
1165
|
+
return new PaymentAuthorizationAdapterRegistry([
|
|
1166
|
+
new PaystackAuthorizationAdapter(),
|
|
1167
|
+
new StripeAuthorizationAdapter()
|
|
1168
|
+
]);
|
|
1169
|
+
}
|
|
1170
|
+
|
|
724
1171
|
// src/client.ts
|
|
725
1172
|
var SESSION_TOKEN_STORAGE_KEY = "cimplify_session_token";
|
|
726
1173
|
var SESSION_SYNC_STORAGE_KEY = "cimplify_session_sync";
|
|
@@ -845,6 +1292,7 @@ var CimplifyClient = class {
|
|
|
845
1292
|
this.context = {};
|
|
846
1293
|
this.businessId = null;
|
|
847
1294
|
this.businessIdResolvePromise = null;
|
|
1295
|
+
this.publicKeyEpoch = 0;
|
|
848
1296
|
this.inflightRequests = /* @__PURE__ */ new Map();
|
|
849
1297
|
/**
|
|
850
1298
|
* App-level event channel. Subscribe to surface mutation rollbacks, outbox
|
|
@@ -863,6 +1311,7 @@ var CimplifyClient = class {
|
|
|
863
1311
|
this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
864
1312
|
this.retryDelay = config.retryDelay ?? DEFAULT_RETRY_DELAY_MS;
|
|
865
1313
|
this.hooks = config.hooks ?? {};
|
|
1314
|
+
this.authorizationAdapters = config.authorizationAdapterRegistry ?? createDefaultPaymentAuthorizationAdapterRegistry();
|
|
866
1315
|
this.fetchImpl = (config.fetch ?? globalThis.fetch).bind(globalThis);
|
|
867
1316
|
this.sessionToken = this.loadSessionToken() ?? this.mintSessionToken();
|
|
868
1317
|
this.watchCrossTabSession();
|
|
@@ -1079,10 +1528,18 @@ var CimplifyClient = class {
|
|
|
1079
1528
|
// X-API-Key and the business can't be resolved.
|
|
1080
1529
|
setPublicKey(publicKey) {
|
|
1081
1530
|
const normalized = publicKey.trim();
|
|
1082
|
-
if (
|
|
1083
|
-
return;
|
|
1084
|
-
}
|
|
1531
|
+
if (normalized === this.publicKey) return;
|
|
1085
1532
|
this.publicKey = normalized;
|
|
1533
|
+
this.publicKeyEpoch += 1;
|
|
1534
|
+
this.businessId = null;
|
|
1535
|
+
this.businessIdResolvePromise = null;
|
|
1536
|
+
this.inflightRequests.clear();
|
|
1537
|
+
this._activity?.resetSession();
|
|
1538
|
+
delete this.context.location_id;
|
|
1539
|
+
if (this.accessToken !== null) {
|
|
1540
|
+
this.setAccessToken(null);
|
|
1541
|
+
}
|
|
1542
|
+
this.events.emit(SESSION_CLEARED, {});
|
|
1086
1543
|
}
|
|
1087
1544
|
getBusinessId() {
|
|
1088
1545
|
return this.businessId;
|
|
@@ -1094,7 +1551,8 @@ var CimplifyClient = class {
|
|
|
1094
1551
|
if (this.businessIdResolvePromise) {
|
|
1095
1552
|
return this.businessIdResolvePromise;
|
|
1096
1553
|
}
|
|
1097
|
-
|
|
1554
|
+
const publicKeyEpoch = this.publicKeyEpoch;
|
|
1555
|
+
const resolution = (async () => {
|
|
1098
1556
|
const result = await this.business.getInfo();
|
|
1099
1557
|
if (!result.ok || !result.value?.id) {
|
|
1100
1558
|
throw new CimplifyError(
|
|
@@ -1103,13 +1561,23 @@ var CimplifyClient = class {
|
|
|
1103
1561
|
true
|
|
1104
1562
|
);
|
|
1105
1563
|
}
|
|
1564
|
+
if (this.publicKeyEpoch !== publicKeyEpoch) {
|
|
1565
|
+
throw new CimplifyError(
|
|
1566
|
+
ErrorCode.TENANT_CONTEXT_CHANGED,
|
|
1567
|
+
"The storefront tenant changed while resolving its business identity.",
|
|
1568
|
+
true
|
|
1569
|
+
);
|
|
1570
|
+
}
|
|
1106
1571
|
this.businessId = result.value.id;
|
|
1107
1572
|
return result.value.id;
|
|
1108
1573
|
})();
|
|
1574
|
+
this.businessIdResolvePromise = resolution;
|
|
1109
1575
|
try {
|
|
1110
|
-
return await
|
|
1576
|
+
return await resolution;
|
|
1111
1577
|
} finally {
|
|
1112
|
-
this.businessIdResolvePromise
|
|
1578
|
+
if (this.businessIdResolvePromise === resolution) {
|
|
1579
|
+
this.businessIdResolvePromise = null;
|
|
1580
|
+
}
|
|
1113
1581
|
}
|
|
1114
1582
|
}
|
|
1115
1583
|
async authedFetch(url, options, timeoutMs) {
|
|
@@ -1312,7 +1780,13 @@ var CimplifyClient = class {
|
|
|
1312
1780
|
}
|
|
1313
1781
|
getDedupeKey(type, payload, cacheOptions) {
|
|
1314
1782
|
const cacheKey = cacheOptions ? `|${JSON.stringify(cacheOptions)}` : "";
|
|
1315
|
-
|
|
1783
|
+
const identityKey = JSON.stringify([
|
|
1784
|
+
this.publicKey.trim(),
|
|
1785
|
+
this.publicKeyEpoch,
|
|
1786
|
+
this.sessionEpoch,
|
|
1787
|
+
this.context.location_id ?? null
|
|
1788
|
+
]);
|
|
1789
|
+
return `${type}:${identityKey}:${JSON.stringify(payload)}${cacheKey}`;
|
|
1316
1790
|
}
|
|
1317
1791
|
async deduplicatedRequest(key, requestFn) {
|
|
1318
1792
|
const existing = this.inflightRequests.get(key);
|
|
@@ -1320,7 +1794,9 @@ var CimplifyClient = class {
|
|
|
1320
1794
|
return existing;
|
|
1321
1795
|
}
|
|
1322
1796
|
const request = requestFn().finally(() => {
|
|
1323
|
-
this.inflightRequests.
|
|
1797
|
+
if (this.inflightRequests.get(key) === request) {
|
|
1798
|
+
this.inflightRequests.delete(key);
|
|
1799
|
+
}
|
|
1324
1800
|
});
|
|
1325
1801
|
this.inflightRequests.set(key, request);
|
|
1326
1802
|
return request;
|
|
@@ -1572,4 +2048,4 @@ function createCimplifyClient(config = {}) {
|
|
|
1572
2048
|
return new CimplifyClient(config);
|
|
1573
2049
|
}
|
|
1574
2050
|
|
|
1575
|
-
export { AUTH_TOKEN_CHANGED, ActivityService, CimplifyClient, DeliveryService, MUTATION_ERROR, PlacesService, SESSION_CLAIMED, SESSION_CLEARED, StoreCreditQueries, SubscriptionService, SupportService, UploadService, createCimplifyClient };
|
|
2051
|
+
export { AUTH_TOKEN_CHANGED, ActivityService, CimplifyClient, DeliveryService, MUTATION_ERROR, PaymentAuthorizationAdapterRegistry, PaystackAuthorizationAdapter, PlacesService, SESSION_CLAIMED, SESSION_CLEARED, StoreCreditQueries, StripeAuthorizationAdapter, SubscriptionService, SupportService, UploadService, createCimplifyClient, createDefaultPaymentAuthorizationAdapterRegistry };
|