@cimplify/sdk 0.6.5 → 0.6.7
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/ads-t3FBTU8p.d.mts +20 -0
- package/dist/ads-t3FBTU8p.d.ts +20 -0
- package/dist/advanced.d.mts +25 -0
- package/dist/advanced.d.ts +25 -0
- package/dist/advanced.js +2735 -0
- package/dist/advanced.mjs +2713 -0
- package/dist/{ads-CmO7VVPP.d.mts → client-B4etj3AD.d.mts} +25 -193
- package/dist/{ads-CmO7VVPP.d.ts → client-CYVVuP5J.d.ts} +25 -193
- package/dist/index-BOYF-efj.d.ts +325 -0
- package/dist/index-DzNb32O3.d.mts +325 -0
- package/dist/index.d.mts +7 -346
- package/dist/index.d.ts +7 -346
- package/dist/index.js +249 -48
- package/dist/index.mjs +247 -49
- package/dist/payment-pjpfIKX8.d.mts +181 -0
- package/dist/payment-pjpfIKX8.d.ts +181 -0
- package/dist/react.d.mts +155 -7
- package/dist/react.d.ts +155 -7
- package/dist/react.js +4650 -44
- package/dist/react.mjs +4643 -46
- package/dist/utils.d.mts +2 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +457 -0
- package/dist/utils.mjs +433 -0
- package/package.json +11 -1
package/dist/index.mjs
CHANGED
|
@@ -38,11 +38,72 @@ var ErrorCode = {
|
|
|
38
38
|
OUT_OF_STOCK: "OUT_OF_STOCK",
|
|
39
39
|
INSUFFICIENT_QUANTITY: "INSUFFICIENT_QUANTITY"
|
|
40
40
|
};
|
|
41
|
+
var DOCS_ERROR_BASE_URL = "https://docs.cimplify.io/reference/error-codes";
|
|
42
|
+
function docsUrlForCode(code) {
|
|
43
|
+
return `${DOCS_ERROR_BASE_URL}#${code.toLowerCase().replace(/_/g, "-")}`;
|
|
44
|
+
}
|
|
45
|
+
var ERROR_SUGGESTIONS = {
|
|
46
|
+
UNKNOWN_ERROR: "An unexpected error occurred. Capture the request/response payload and retry with exponential backoff.",
|
|
47
|
+
NETWORK_ERROR: "Check the shopper's connection and retry. If this persists, inspect CORS, DNS, and API reachability.",
|
|
48
|
+
TIMEOUT: "The request exceeded the timeout. Retry once, then poll order status before charging again.",
|
|
49
|
+
UNAUTHORIZED: "Authentication is missing or expired. Ensure a valid access token is set and refresh the session if needed.",
|
|
50
|
+
FORBIDDEN: "The key/session lacks permission for this resource. Verify business ownership and API key scope.",
|
|
51
|
+
NOT_FOUND: "The requested resource does not exist or is not visible in this environment.",
|
|
52
|
+
VALIDATION_ERROR: "One or more fields are invalid. Validate required fields and enum values before retrying.",
|
|
53
|
+
CART_EMPTY: "The cart has no items. Redirect back to menu/catalogue and require at least one line item.",
|
|
54
|
+
CART_EXPIRED: "This cart is no longer active. Recreate a new cart and re-add shopper selections.",
|
|
55
|
+
CART_NOT_FOUND: "Cart could not be located. It may have expired or belongs to a different key/location.",
|
|
56
|
+
ITEM_UNAVAILABLE: "The selected item is unavailable at this location/time. Prompt the shopper to pick an alternative.",
|
|
57
|
+
VARIANT_NOT_FOUND: "The requested variant no longer exists. Refresh product data and require re-selection.",
|
|
58
|
+
VARIANT_OUT_OF_STOCK: "The selected variant is out of stock. Show in-stock variants and block checkout for this line.",
|
|
59
|
+
ADDON_REQUIRED: "A required add-on is missing. Ensure required modifier groups are completed before add-to-cart.",
|
|
60
|
+
ADDON_MAX_EXCEEDED: "Too many add-ons were selected. Enforce max selections client-side before submission.",
|
|
61
|
+
CHECKOUT_VALIDATION_FAILED: "Checkout payload failed validation. Verify customer, order type, and address fields are complete.",
|
|
62
|
+
DELIVERY_ADDRESS_REQUIRED: "Delivery orders require an address. Collect and pass address info before processing checkout.",
|
|
63
|
+
CUSTOMER_INFO_REQUIRED: "Customer details are required. Ensure name/email/phone are available before checkout.",
|
|
64
|
+
PAYMENT_FAILED: "Payment provider rejected or failed processing. Show retry/change-method options to the shopper.",
|
|
65
|
+
PAYMENT_CANCELLED: "Payment was cancelled by the shopper or provider flow. Allow a safe retry path.",
|
|
66
|
+
INSUFFICIENT_FUNDS: "Payment method has insufficient funds. Prompt shopper to use another method.",
|
|
67
|
+
CARD_DECLINED: "Card was declined. Ask shopper to retry or switch payment method.",
|
|
68
|
+
INVALID_OTP: "Authorization code is invalid. Let shopper re-enter OTP/PIN and retry.",
|
|
69
|
+
OTP_EXPIRED: "Authorization code expired. Request a new OTP and re-submit authorization.",
|
|
70
|
+
AUTHORIZATION_FAILED: "Additional payment authorization failed. Retry authorization or change payment method.",
|
|
71
|
+
PAYMENT_ACTION_NOT_COMPLETED: "Required payment action was not completed. Resume provider flow and poll for status.",
|
|
72
|
+
SLOT_UNAVAILABLE: "Selected schedule slot is unavailable. Refresh available slots and ask shopper to reselect.",
|
|
73
|
+
BOOKING_CONFLICT: "The requested booking conflicts with an existing reservation. Pick another slot/resource.",
|
|
74
|
+
SERVICE_NOT_FOUND: "Requested service no longer exists. Refresh service catalogue and retry selection.",
|
|
75
|
+
OUT_OF_STOCK: "Inventory is depleted for this item. Remove it or reduce quantity before checkout.",
|
|
76
|
+
INSUFFICIENT_QUANTITY: "Requested quantity exceeds available inventory. Reduce quantity and retry.",
|
|
77
|
+
BUSINESS_ID_REQUIRED: "Business context could not be resolved. Verify the public key and business bootstrap call.",
|
|
78
|
+
INVALID_CART: "Cart is invalid for checkout. Sync cart state, ensure items exist, then retry.",
|
|
79
|
+
ORDER_TYPE_REQUIRED: "Order type is required. Provide one of delivery, pickup, or dine_in before checkout.",
|
|
80
|
+
NO_PAYMENT_ELEMENT: "PaymentElement is required for processCheckout(). Mount it before triggering checkout.",
|
|
81
|
+
PAYMENT_NOT_MOUNTED: "PaymentElement iframe is not mounted. Mount it in the DOM before processCheckout().",
|
|
82
|
+
AUTH_INCOMPLETE: "AuthElement has not completed authentication. Wait for AUTHENTICATED before checkout.",
|
|
83
|
+
AUTH_LOST: "Session was cleared during checkout. Re-authenticate and restart checkout safely.",
|
|
84
|
+
ALREADY_PROCESSING: "Checkout is already in progress. Disable duplicate submits until completion.",
|
|
85
|
+
CHECKOUT_NOT_READY: "Checkout elements are still initializing. Wait for readiness before submit.",
|
|
86
|
+
CANCELLED: "Checkout was cancelled. Preserve cart state and allow shopper to retry.",
|
|
87
|
+
REQUEST_TIMEOUT: "Provider call timed out. Poll payment/order status before issuing another charge attempt.",
|
|
88
|
+
POPUP_BLOCKED: "Browser blocked provider popup. Ask shopper to enable popups and retry.",
|
|
89
|
+
FX_QUOTE_FAILED: "Failed to lock FX quote. Retry currency quote or fallback to base currency."
|
|
90
|
+
};
|
|
91
|
+
var ERROR_HINTS = Object.fromEntries(
|
|
92
|
+
Object.entries(ERROR_SUGGESTIONS).map(([code, suggestion]) => [
|
|
93
|
+
code,
|
|
94
|
+
{
|
|
95
|
+
docs_url: docsUrlForCode(code),
|
|
96
|
+
suggestion
|
|
97
|
+
}
|
|
98
|
+
])
|
|
99
|
+
);
|
|
41
100
|
var CimplifyError = class extends Error {
|
|
42
|
-
constructor(code, message, retryable = false) {
|
|
101
|
+
constructor(code, message, retryable = false, docs_url, suggestion) {
|
|
43
102
|
super(message);
|
|
44
103
|
this.code = code;
|
|
45
104
|
this.retryable = retryable;
|
|
105
|
+
this.docs_url = docs_url;
|
|
106
|
+
this.suggestion = suggestion;
|
|
46
107
|
this.name = "CimplifyError";
|
|
47
108
|
}
|
|
48
109
|
/** User-friendly message safe to display */
|
|
@@ -53,6 +114,28 @@ var CimplifyError = class extends Error {
|
|
|
53
114
|
function isCimplifyError(error) {
|
|
54
115
|
return error instanceof CimplifyError;
|
|
55
116
|
}
|
|
117
|
+
function getErrorHint(code) {
|
|
118
|
+
return ERROR_HINTS[code];
|
|
119
|
+
}
|
|
120
|
+
function enrichError(error, options = {}) {
|
|
121
|
+
const hint = getErrorHint(error.code);
|
|
122
|
+
if (hint) {
|
|
123
|
+
if (!error.docs_url) {
|
|
124
|
+
error.docs_url = hint.docs_url;
|
|
125
|
+
}
|
|
126
|
+
if (!error.suggestion) {
|
|
127
|
+
error.suggestion = hint.suggestion;
|
|
128
|
+
}
|
|
129
|
+
} else if (!error.docs_url) {
|
|
130
|
+
error.docs_url = docsUrlForCode(error.code || ErrorCode.UNKNOWN_ERROR);
|
|
131
|
+
}
|
|
132
|
+
if (options.isTestMode && !error.message.includes("pk_test_")) {
|
|
133
|
+
error.message = `${error.message}
|
|
134
|
+
|
|
135
|
+
\u2139 Your API key is a test-mode key (pk_test_...). Verify test data/session before retrying.`;
|
|
136
|
+
}
|
|
137
|
+
return error;
|
|
138
|
+
}
|
|
56
139
|
function isRetryableError(error) {
|
|
57
140
|
if (isCimplifyError(error)) {
|
|
58
141
|
return error.retryable;
|
|
@@ -136,11 +219,11 @@ function combineObject(results) {
|
|
|
136
219
|
|
|
137
220
|
// src/catalogue.ts
|
|
138
221
|
function toCimplifyError(error) {
|
|
139
|
-
if (error instanceof CimplifyError) return error;
|
|
222
|
+
if (error instanceof CimplifyError) return enrichError(error);
|
|
140
223
|
if (error instanceof Error) {
|
|
141
|
-
return new CimplifyError(
|
|
224
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
|
|
142
225
|
}
|
|
143
|
-
return new CimplifyError(
|
|
226
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
|
|
144
227
|
}
|
|
145
228
|
async function safe(promise) {
|
|
146
229
|
try {
|
|
@@ -435,11 +518,11 @@ var CatalogueQueries = class {
|
|
|
435
518
|
|
|
436
519
|
// src/cart.ts
|
|
437
520
|
function toCimplifyError2(error) {
|
|
438
|
-
if (error instanceof CimplifyError) return error;
|
|
521
|
+
if (error instanceof CimplifyError) return enrichError(error);
|
|
439
522
|
if (error instanceof Error) {
|
|
440
|
-
return new CimplifyError(
|
|
523
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
|
|
441
524
|
}
|
|
442
|
-
return new CimplifyError(
|
|
525
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
|
|
443
526
|
}
|
|
444
527
|
async function safe2(promise) {
|
|
445
528
|
try {
|
|
@@ -1654,11 +1737,11 @@ var CheckoutResolver = class {
|
|
|
1654
1737
|
|
|
1655
1738
|
// src/checkout.ts
|
|
1656
1739
|
function toCimplifyError3(error) {
|
|
1657
|
-
if (error instanceof CimplifyError) return error;
|
|
1740
|
+
if (error instanceof CimplifyError) return enrichError(error);
|
|
1658
1741
|
if (error instanceof Error) {
|
|
1659
|
-
return new CimplifyError(
|
|
1742
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
|
|
1660
1743
|
}
|
|
1661
|
-
return new CimplifyError(
|
|
1744
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
|
|
1662
1745
|
}
|
|
1663
1746
|
async function safe3(promise) {
|
|
1664
1747
|
try {
|
|
@@ -1834,11 +1917,11 @@ var CheckoutService = class {
|
|
|
1834
1917
|
|
|
1835
1918
|
// src/orders.ts
|
|
1836
1919
|
function toCimplifyError4(error) {
|
|
1837
|
-
if (error instanceof CimplifyError) return error;
|
|
1920
|
+
if (error instanceof CimplifyError) return enrichError(error);
|
|
1838
1921
|
if (error instanceof Error) {
|
|
1839
|
-
return new CimplifyError(
|
|
1922
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
|
|
1840
1923
|
}
|
|
1841
|
-
return new CimplifyError(
|
|
1924
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
|
|
1842
1925
|
}
|
|
1843
1926
|
async function safe4(promise) {
|
|
1844
1927
|
try {
|
|
@@ -2095,11 +2178,11 @@ var AuthService = class {
|
|
|
2095
2178
|
|
|
2096
2179
|
// src/business.ts
|
|
2097
2180
|
function toCimplifyError7(error) {
|
|
2098
|
-
if (error instanceof CimplifyError) return error;
|
|
2181
|
+
if (error instanceof CimplifyError) return enrichError(error);
|
|
2099
2182
|
if (error instanceof Error) {
|
|
2100
|
-
return new CimplifyError(
|
|
2183
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
|
|
2101
2184
|
}
|
|
2102
|
-
return new CimplifyError(
|
|
2185
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
|
|
2103
2186
|
}
|
|
2104
2187
|
async function safe7(promise) {
|
|
2105
2188
|
try {
|
|
@@ -2485,12 +2568,15 @@ var EVENT_TYPES = {
|
|
|
2485
2568
|
|
|
2486
2569
|
// src/elements.ts
|
|
2487
2570
|
function toCheckoutError(code, message, recoverable) {
|
|
2571
|
+
const hint = getErrorHint(code);
|
|
2488
2572
|
return {
|
|
2489
2573
|
success: false,
|
|
2490
2574
|
error: {
|
|
2491
2575
|
code,
|
|
2492
2576
|
message,
|
|
2493
|
-
recoverable
|
|
2577
|
+
recoverable,
|
|
2578
|
+
docs_url: hint?.docs_url,
|
|
2579
|
+
suggestion: hint?.suggestion
|
|
2494
2580
|
}
|
|
2495
2581
|
};
|
|
2496
2582
|
}
|
|
@@ -2531,8 +2617,10 @@ var CimplifyElements = class {
|
|
|
2531
2617
|
this.paymentData = null;
|
|
2532
2618
|
this.checkoutInProgress = false;
|
|
2533
2619
|
this.activeCheckoutAbort = null;
|
|
2620
|
+
this.hasWarnedMissingAuthElement = false;
|
|
2621
|
+
this.businessIdResolvePromise = null;
|
|
2534
2622
|
this.client = client;
|
|
2535
|
-
this.businessId = businessId;
|
|
2623
|
+
this.businessId = businessId ?? null;
|
|
2536
2624
|
this.linkUrl = options.linkUrl || DEFAULT_LINK_URL;
|
|
2537
2625
|
this.options = options;
|
|
2538
2626
|
this.boundHandleMessage = this.handleMessage.bind(this);
|
|
@@ -2625,6 +2713,12 @@ var CimplifyElements = class {
|
|
|
2625
2713
|
);
|
|
2626
2714
|
}
|
|
2627
2715
|
const authElement = this.elements.get(ELEMENT_TYPES.AUTH);
|
|
2716
|
+
if (!authElement && !this.hasWarnedMissingAuthElement) {
|
|
2717
|
+
this.hasWarnedMissingAuthElement = true;
|
|
2718
|
+
console.warn(
|
|
2719
|
+
"[Cimplify] processCheckout() called without AuthElement mounted. For best conversion and Link enrollment, mount <AuthElement> before checkout."
|
|
2720
|
+
);
|
|
2721
|
+
}
|
|
2628
2722
|
if (authElement && !this.accessToken) {
|
|
2629
2723
|
return toCheckoutError(
|
|
2630
2724
|
"AUTH_INCOMPLETE",
|
|
@@ -2755,6 +2849,24 @@ var CimplifyElements = class {
|
|
|
2755
2849
|
getPublicKey() {
|
|
2756
2850
|
return this.client.getPublicKey();
|
|
2757
2851
|
}
|
|
2852
|
+
getBusinessId() {
|
|
2853
|
+
return this.businessId;
|
|
2854
|
+
}
|
|
2855
|
+
async resolveBusinessId() {
|
|
2856
|
+
if (this.businessId) {
|
|
2857
|
+
return this.businessId;
|
|
2858
|
+
}
|
|
2859
|
+
if (this.businessIdResolvePromise) {
|
|
2860
|
+
return this.businessIdResolvePromise;
|
|
2861
|
+
}
|
|
2862
|
+
this.businessIdResolvePromise = this.client.resolveBusinessId().then((resolvedBusinessId) => {
|
|
2863
|
+
this.businessId = resolvedBusinessId;
|
|
2864
|
+
return resolvedBusinessId;
|
|
2865
|
+
}).catch(() => null).finally(() => {
|
|
2866
|
+
this.businessIdResolvePromise = null;
|
|
2867
|
+
});
|
|
2868
|
+
return this.businessIdResolvePromise;
|
|
2869
|
+
}
|
|
2758
2870
|
getAppearance() {
|
|
2759
2871
|
return this.options.appearance;
|
|
2760
2872
|
}
|
|
@@ -2859,8 +2971,8 @@ var CimplifyElement = class {
|
|
|
2859
2971
|
return;
|
|
2860
2972
|
}
|
|
2861
2973
|
this.container = target;
|
|
2862
|
-
this.createIframe();
|
|
2863
2974
|
this.mounted = true;
|
|
2975
|
+
void this.createIframe();
|
|
2864
2976
|
}
|
|
2865
2977
|
destroy() {
|
|
2866
2978
|
if (this.iframe) {
|
|
@@ -2914,11 +3026,21 @@ var CimplifyElement = class {
|
|
|
2914
3026
|
isMounted() {
|
|
2915
3027
|
return this.mounted && Boolean(this.iframe) && this.iframe?.isConnected === true;
|
|
2916
3028
|
}
|
|
2917
|
-
createIframe() {
|
|
3029
|
+
async createIframe() {
|
|
2918
3030
|
if (!this.container) return;
|
|
3031
|
+
const resolvedBusinessId = this.businessId ?? await this.parent.resolveBusinessId();
|
|
3032
|
+
if (!resolvedBusinessId || !this.container || !this.mounted) {
|
|
3033
|
+
console.error("Unable to mount element without a resolved business ID");
|
|
3034
|
+
this.emit(EVENT_TYPES.ERROR, {
|
|
3035
|
+
code: "BUSINESS_ID_REQUIRED",
|
|
3036
|
+
message: "Unable to initialize checkout without a business ID."
|
|
3037
|
+
});
|
|
3038
|
+
return;
|
|
3039
|
+
}
|
|
3040
|
+
this.businessId = resolvedBusinessId;
|
|
2919
3041
|
const iframe = document.createElement("iframe");
|
|
2920
3042
|
const url = new URL(`${this.linkUrl}/elements/${this.type}`);
|
|
2921
|
-
url.searchParams.set("businessId",
|
|
3043
|
+
url.searchParams.set("businessId", resolvedBusinessId);
|
|
2922
3044
|
if (this.options.prefillEmail) url.searchParams.set("email", this.options.prefillEmail);
|
|
2923
3045
|
if (this.options.mode) url.searchParams.set("mode", this.options.mode);
|
|
2924
3046
|
iframe.src = url.toString();
|
|
@@ -2938,7 +3060,7 @@ var CimplifyElement = class {
|
|
|
2938
3060
|
const publicKey = this.parent.getPublicKey();
|
|
2939
3061
|
this.sendMessage({
|
|
2940
3062
|
type: MESSAGE_TYPES.INIT,
|
|
2941
|
-
businessId:
|
|
3063
|
+
businessId: resolvedBusinessId,
|
|
2942
3064
|
publicKey,
|
|
2943
3065
|
demoMode: publicKey.length === 0,
|
|
2944
3066
|
prefillEmail: this.options.prefillEmail,
|
|
@@ -3033,28 +3155,37 @@ function isRetryable(error) {
|
|
|
3033
3155
|
}
|
|
3034
3156
|
return false;
|
|
3035
3157
|
}
|
|
3036
|
-
function toNetworkError(error) {
|
|
3158
|
+
function toNetworkError(error, isTestMode) {
|
|
3037
3159
|
if (error instanceof DOMException && error.name === "AbortError") {
|
|
3038
|
-
return
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3160
|
+
return enrichError(
|
|
3161
|
+
new CimplifyError(
|
|
3162
|
+
ErrorCode.TIMEOUT,
|
|
3163
|
+
"Request timed out. Please check your connection and try again.",
|
|
3164
|
+
true
|
|
3165
|
+
),
|
|
3166
|
+
{ isTestMode }
|
|
3042
3167
|
);
|
|
3043
3168
|
}
|
|
3044
3169
|
if (error instanceof TypeError && error.message.includes("fetch")) {
|
|
3045
|
-
return
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3170
|
+
return enrichError(
|
|
3171
|
+
new CimplifyError(
|
|
3172
|
+
ErrorCode.NETWORK_ERROR,
|
|
3173
|
+
"Network error. Please check your internet connection.",
|
|
3174
|
+
true
|
|
3175
|
+
),
|
|
3176
|
+
{ isTestMode }
|
|
3049
3177
|
);
|
|
3050
3178
|
}
|
|
3051
3179
|
if (error instanceof CimplifyError) {
|
|
3052
|
-
return error;
|
|
3053
|
-
}
|
|
3054
|
-
return
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3180
|
+
return enrichError(error, { isTestMode });
|
|
3181
|
+
}
|
|
3182
|
+
return enrichError(
|
|
3183
|
+
new CimplifyError(
|
|
3184
|
+
ErrorCode.UNKNOWN_ERROR,
|
|
3185
|
+
error instanceof Error ? error.message : "An unknown error occurred",
|
|
3186
|
+
false
|
|
3187
|
+
),
|
|
3188
|
+
{ isTestMode }
|
|
3058
3189
|
);
|
|
3059
3190
|
}
|
|
3060
3191
|
function deriveUrls() {
|
|
@@ -3083,6 +3214,8 @@ var CimplifyClient = class {
|
|
|
3083
3214
|
constructor(config = {}) {
|
|
3084
3215
|
this.accessToken = null;
|
|
3085
3216
|
this.context = {};
|
|
3217
|
+
this.businessId = null;
|
|
3218
|
+
this.businessIdResolvePromise = null;
|
|
3086
3219
|
this.inflightRequests = /* @__PURE__ */ new Map();
|
|
3087
3220
|
this.publicKey = config.publicKey || getEnvPublicKey() || "";
|
|
3088
3221
|
const urls = deriveUrls();
|
|
@@ -3114,6 +3247,9 @@ var CimplifyClient = class {
|
|
|
3114
3247
|
getPublicKey() {
|
|
3115
3248
|
return this.publicKey;
|
|
3116
3249
|
}
|
|
3250
|
+
isTestMode() {
|
|
3251
|
+
return this.publicKey.trim().startsWith("pk_test_");
|
|
3252
|
+
}
|
|
3117
3253
|
setAccessToken(token) {
|
|
3118
3254
|
const previous = this.accessToken;
|
|
3119
3255
|
this.accessToken = token;
|
|
@@ -3146,6 +3282,47 @@ var CimplifyClient = class {
|
|
|
3146
3282
|
getLocationId() {
|
|
3147
3283
|
return this.context.location_id ?? null;
|
|
3148
3284
|
}
|
|
3285
|
+
/** Cache a resolved business ID for future element/checkouts initialization. */
|
|
3286
|
+
setBusinessId(businessId) {
|
|
3287
|
+
const normalized = businessId.trim();
|
|
3288
|
+
if (!normalized) {
|
|
3289
|
+
return;
|
|
3290
|
+
}
|
|
3291
|
+
this.businessId = normalized;
|
|
3292
|
+
}
|
|
3293
|
+
/** Get cached business ID if available. */
|
|
3294
|
+
getBusinessId() {
|
|
3295
|
+
return this.businessId;
|
|
3296
|
+
}
|
|
3297
|
+
/**
|
|
3298
|
+
* Resolve business ID from public key once and cache it.
|
|
3299
|
+
* Subsequent calls return the cached value (or shared in-flight promise).
|
|
3300
|
+
*/
|
|
3301
|
+
async resolveBusinessId() {
|
|
3302
|
+
if (this.businessId) {
|
|
3303
|
+
return this.businessId;
|
|
3304
|
+
}
|
|
3305
|
+
if (this.businessIdResolvePromise) {
|
|
3306
|
+
return this.businessIdResolvePromise;
|
|
3307
|
+
}
|
|
3308
|
+
this.businessIdResolvePromise = (async () => {
|
|
3309
|
+
const result = await this.business.getInfo();
|
|
3310
|
+
if (!result.ok || !result.value?.id) {
|
|
3311
|
+
throw new CimplifyError(
|
|
3312
|
+
ErrorCode.NOT_FOUND,
|
|
3313
|
+
"Unable to resolve business ID from the current public key.",
|
|
3314
|
+
true
|
|
3315
|
+
);
|
|
3316
|
+
}
|
|
3317
|
+
this.businessId = result.value.id;
|
|
3318
|
+
return result.value.id;
|
|
3319
|
+
})();
|
|
3320
|
+
try {
|
|
3321
|
+
return await this.businessIdResolvePromise;
|
|
3322
|
+
} finally {
|
|
3323
|
+
this.businessIdResolvePromise = null;
|
|
3324
|
+
}
|
|
3325
|
+
}
|
|
3149
3326
|
loadAccessToken() {
|
|
3150
3327
|
if (typeof window !== "undefined" && window.localStorage) {
|
|
3151
3328
|
return localStorage.getItem(ACCESS_TOKEN_STORAGE_KEY);
|
|
@@ -3222,7 +3399,7 @@ var CimplifyClient = class {
|
|
|
3222
3399
|
return response;
|
|
3223
3400
|
} catch (error) {
|
|
3224
3401
|
lastError = error;
|
|
3225
|
-
const networkError = toNetworkError(error);
|
|
3402
|
+
const networkError = toNetworkError(error, this.isTestMode());
|
|
3226
3403
|
const errorRetryable = isRetryable(error);
|
|
3227
3404
|
if (!errorRetryable || attempt >= this.maxRetries) {
|
|
3228
3405
|
this.hooks.onRequestError?.({
|
|
@@ -3245,7 +3422,7 @@ var CimplifyClient = class {
|
|
|
3245
3422
|
await sleep(delay);
|
|
3246
3423
|
}
|
|
3247
3424
|
}
|
|
3248
|
-
const finalError = toNetworkError(lastError);
|
|
3425
|
+
const finalError = toNetworkError(lastError, this.isTestMode());
|
|
3249
3426
|
this.hooks.onRequestError?.({
|
|
3250
3427
|
...context,
|
|
3251
3428
|
error: finalError,
|
|
@@ -3363,22 +3540,40 @@ var CimplifyClient = class {
|
|
|
3363
3540
|
async handleRestResponse(response) {
|
|
3364
3541
|
const json = await response.json();
|
|
3365
3542
|
if (!response.ok) {
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3543
|
+
const error = enrichError(
|
|
3544
|
+
new CimplifyError(
|
|
3545
|
+
json.error?.error_code || "API_ERROR",
|
|
3546
|
+
json.error?.error_message || "An error occurred",
|
|
3547
|
+
false
|
|
3548
|
+
),
|
|
3549
|
+
{ isTestMode: this.isTestMode() }
|
|
3370
3550
|
);
|
|
3551
|
+
if (response.status === 401 || error.code === ErrorCode.UNAUTHORIZED) {
|
|
3552
|
+
console.warn(
|
|
3553
|
+
"[Cimplify] Received 401 Unauthorized. Access token may be missing/expired. Refresh authentication and retry the request."
|
|
3554
|
+
);
|
|
3555
|
+
}
|
|
3556
|
+
throw error;
|
|
3371
3557
|
}
|
|
3372
3558
|
return json.data;
|
|
3373
3559
|
}
|
|
3374
3560
|
async handleResponse(response) {
|
|
3375
3561
|
const json = await response.json();
|
|
3376
3562
|
if (!json.success || json.error) {
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3563
|
+
const error = enrichError(
|
|
3564
|
+
new CimplifyError(
|
|
3565
|
+
json.error?.code || "UNKNOWN_ERROR",
|
|
3566
|
+
json.error?.message || "An unknown error occurred",
|
|
3567
|
+
json.error?.retryable || false
|
|
3568
|
+
),
|
|
3569
|
+
{ isTestMode: this.isTestMode() }
|
|
3381
3570
|
);
|
|
3571
|
+
if (response.status === 401 || error.code === ErrorCode.UNAUTHORIZED) {
|
|
3572
|
+
console.warn(
|
|
3573
|
+
"[Cimplify] Received 401 Unauthorized. Access token may be missing/expired. Refresh authentication and retry the request."
|
|
3574
|
+
);
|
|
3575
|
+
}
|
|
3576
|
+
throw error;
|
|
3382
3577
|
}
|
|
3383
3578
|
return json.data;
|
|
3384
3579
|
}
|
|
@@ -3463,7 +3658,10 @@ var CimplifyClient = class {
|
|
|
3463
3658
|
* ```
|
|
3464
3659
|
*/
|
|
3465
3660
|
elements(businessId, options) {
|
|
3466
|
-
|
|
3661
|
+
if (businessId) {
|
|
3662
|
+
this.setBusinessId(businessId);
|
|
3663
|
+
}
|
|
3664
|
+
return createElements(this, businessId ?? this.businessId ?? void 0, options);
|
|
3467
3665
|
}
|
|
3468
3666
|
};
|
|
3469
3667
|
function createCimplifyClient(config = {}) {
|
|
@@ -3535,4 +3733,4 @@ function query(entity) {
|
|
|
3535
3733
|
return new QueryBuilder(entity);
|
|
3536
3734
|
}
|
|
3537
3735
|
|
|
3538
|
-
export { AUTHORIZATION_TYPE, AUTH_MUTATION, AuthService, BusinessService, CHECKOUT_MODE, CHECKOUT_MUTATION, CHECKOUT_STEP, CONTACT_TYPE, CURRENCY_SYMBOLS, CartOperations, CatalogueQueries, CheckoutService as CheckoutOperations, CheckoutService, CimplifyClient, CimplifyElement, CimplifyElements, CimplifyError, DEFAULT_COUNTRY, DEFAULT_CURRENCY, DEVICE_TYPE, ELEMENT_TYPES, EVENT_TYPES, ErrorCode, FxService, InventoryService, LINK_MUTATION, LINK_QUERY, LinkService, LiteService, MESSAGE_TYPES, MOBILE_MONEY_PROVIDER, MOBILE_MONEY_PROVIDERS, ORDER_MUTATION, ORDER_TYPE, OrderQueries, PAYMENT_METHOD, PAYMENT_MUTATION, PAYMENT_STATE, PICKUP_TIME_TYPE, QueryBuilder, SchedulingService, categorizePaymentError, combine, combineObject, createCimplifyClient, createElements, detectMobileMoneyProvider, err, flatMap, formatMoney, formatNumberCompact, formatPrice, formatPriceAdjustment, formatPriceCompact, formatProductPrice, fromPromise, generateIdempotencyKey, getBasePrice, getCurrencySymbol, getDiscountPercentage, getDisplayPrice, getMarkupPercentage, getOrElse, getProductCurrency, isCimplifyError, isErr, isOk, isOnSale, isPaymentStatusFailure, isPaymentStatusRequiresAction, isPaymentStatusSuccess, isRetryableError, mapError, mapResult, normalizePaymentResponse, normalizeStatusResponse, ok, parsePrice, query, toNullable, tryCatch, unwrap };
|
|
3736
|
+
export { AUTHORIZATION_TYPE, AUTH_MUTATION, AuthService, BusinessService, CHECKOUT_MODE, CHECKOUT_MUTATION, CHECKOUT_STEP, CONTACT_TYPE, CURRENCY_SYMBOLS, CartOperations, CatalogueQueries, CheckoutService as CheckoutOperations, CheckoutService, CimplifyClient, CimplifyElement, CimplifyElements, CimplifyError, DEFAULT_COUNTRY, DEFAULT_CURRENCY, DEVICE_TYPE, ELEMENT_TYPES, ERROR_HINTS, EVENT_TYPES, ErrorCode, FxService, InventoryService, LINK_MUTATION, LINK_QUERY, LinkService, LiteService, MESSAGE_TYPES, MOBILE_MONEY_PROVIDER, MOBILE_MONEY_PROVIDERS, ORDER_MUTATION, ORDER_TYPE, OrderQueries, PAYMENT_METHOD, PAYMENT_MUTATION, PAYMENT_STATE, PICKUP_TIME_TYPE, QueryBuilder, SchedulingService, categorizePaymentError, combine, combineObject, createCimplifyClient, createElements, detectMobileMoneyProvider, enrichError, err, flatMap, formatMoney, formatNumberCompact, formatPrice, formatPriceAdjustment, formatPriceCompact, formatProductPrice, fromPromise, generateIdempotencyKey, getBasePrice, getCurrencySymbol, getDiscountPercentage, getDisplayPrice, getErrorHint, getMarkupPercentage, getOrElse, getProductCurrency, isCimplifyError, isErr, isOk, isOnSale, isPaymentStatusFailure, isPaymentStatusRequiresAction, isPaymentStatusSuccess, isRetryableError, mapError, mapResult, normalizePaymentResponse, normalizeStatusResponse, ok, parsePrice, query, toNullable, tryCatch, unwrap };
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/** Decimal value represented as string for precision */
|
|
2
|
+
type Money = string;
|
|
3
|
+
/** Supported currencies */
|
|
4
|
+
type Currency = "GHS" | "USD" | "NGN" | "KES" | "ZAR" | string;
|
|
5
|
+
/** Pagination parameters */
|
|
6
|
+
interface PaginationParams {
|
|
7
|
+
page?: number;
|
|
8
|
+
limit?: number;
|
|
9
|
+
offset?: number;
|
|
10
|
+
}
|
|
11
|
+
/** Pagination metadata in response */
|
|
12
|
+
interface Pagination {
|
|
13
|
+
total_count: number;
|
|
14
|
+
current_page: number;
|
|
15
|
+
page_size: number;
|
|
16
|
+
total_pages: number;
|
|
17
|
+
}
|
|
18
|
+
/** Strongly-typed error codes for better DX */
|
|
19
|
+
declare const ErrorCode: {
|
|
20
|
+
readonly UNKNOWN_ERROR: "UNKNOWN_ERROR";
|
|
21
|
+
readonly NETWORK_ERROR: "NETWORK_ERROR";
|
|
22
|
+
readonly TIMEOUT: "TIMEOUT";
|
|
23
|
+
readonly UNAUTHORIZED: "UNAUTHORIZED";
|
|
24
|
+
readonly FORBIDDEN: "FORBIDDEN";
|
|
25
|
+
readonly NOT_FOUND: "NOT_FOUND";
|
|
26
|
+
readonly VALIDATION_ERROR: "VALIDATION_ERROR";
|
|
27
|
+
readonly CART_EMPTY: "CART_EMPTY";
|
|
28
|
+
readonly CART_EXPIRED: "CART_EXPIRED";
|
|
29
|
+
readonly CART_NOT_FOUND: "CART_NOT_FOUND";
|
|
30
|
+
readonly ITEM_UNAVAILABLE: "ITEM_UNAVAILABLE";
|
|
31
|
+
readonly VARIANT_NOT_FOUND: "VARIANT_NOT_FOUND";
|
|
32
|
+
readonly VARIANT_OUT_OF_STOCK: "VARIANT_OUT_OF_STOCK";
|
|
33
|
+
readonly ADDON_REQUIRED: "ADDON_REQUIRED";
|
|
34
|
+
readonly ADDON_MAX_EXCEEDED: "ADDON_MAX_EXCEEDED";
|
|
35
|
+
readonly CHECKOUT_VALIDATION_FAILED: "CHECKOUT_VALIDATION_FAILED";
|
|
36
|
+
readonly DELIVERY_ADDRESS_REQUIRED: "DELIVERY_ADDRESS_REQUIRED";
|
|
37
|
+
readonly CUSTOMER_INFO_REQUIRED: "CUSTOMER_INFO_REQUIRED";
|
|
38
|
+
readonly PAYMENT_FAILED: "PAYMENT_FAILED";
|
|
39
|
+
readonly PAYMENT_CANCELLED: "PAYMENT_CANCELLED";
|
|
40
|
+
readonly INSUFFICIENT_FUNDS: "INSUFFICIENT_FUNDS";
|
|
41
|
+
readonly CARD_DECLINED: "CARD_DECLINED";
|
|
42
|
+
readonly INVALID_OTP: "INVALID_OTP";
|
|
43
|
+
readonly OTP_EXPIRED: "OTP_EXPIRED";
|
|
44
|
+
readonly AUTHORIZATION_FAILED: "AUTHORIZATION_FAILED";
|
|
45
|
+
readonly PAYMENT_ACTION_NOT_COMPLETED: "PAYMENT_ACTION_NOT_COMPLETED";
|
|
46
|
+
readonly SLOT_UNAVAILABLE: "SLOT_UNAVAILABLE";
|
|
47
|
+
readonly BOOKING_CONFLICT: "BOOKING_CONFLICT";
|
|
48
|
+
readonly SERVICE_NOT_FOUND: "SERVICE_NOT_FOUND";
|
|
49
|
+
readonly OUT_OF_STOCK: "OUT_OF_STOCK";
|
|
50
|
+
readonly INSUFFICIENT_QUANTITY: "INSUFFICIENT_QUANTITY";
|
|
51
|
+
};
|
|
52
|
+
type ErrorCodeType = (typeof ErrorCode)[keyof typeof ErrorCode];
|
|
53
|
+
/** API error structure */
|
|
54
|
+
interface ApiError {
|
|
55
|
+
code: string;
|
|
56
|
+
message: string;
|
|
57
|
+
retryable: boolean;
|
|
58
|
+
}
|
|
59
|
+
interface ErrorHint {
|
|
60
|
+
docs_url: string;
|
|
61
|
+
suggestion: string;
|
|
62
|
+
}
|
|
63
|
+
declare const ERROR_HINTS: Record<string, ErrorHint>;
|
|
64
|
+
/**
|
|
65
|
+
* Custom error class for SDK errors with typed error codes.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* try {
|
|
70
|
+
* await client.cart.addItem({ item_id: "prod_123" });
|
|
71
|
+
* } catch (error) {
|
|
72
|
+
* if (isCimplifyError(error)) {
|
|
73
|
+
* switch (error.code) {
|
|
74
|
+
* case ErrorCode.ITEM_UNAVAILABLE:
|
|
75
|
+
* toast.error("This item is no longer available");
|
|
76
|
+
* break;
|
|
77
|
+
* case ErrorCode.VARIANT_OUT_OF_STOCK:
|
|
78
|
+
* toast.error("Selected option is out of stock");
|
|
79
|
+
* break;
|
|
80
|
+
* default:
|
|
81
|
+
* toast.error(error.message);
|
|
82
|
+
* }
|
|
83
|
+
* }
|
|
84
|
+
* }
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
declare class CimplifyError extends Error {
|
|
88
|
+
code: string;
|
|
89
|
+
retryable: boolean;
|
|
90
|
+
docs_url?: string | undefined;
|
|
91
|
+
suggestion?: string | undefined;
|
|
92
|
+
constructor(code: string, message: string, retryable?: boolean, docs_url?: string | undefined, suggestion?: string | undefined);
|
|
93
|
+
/** User-friendly message safe to display */
|
|
94
|
+
get userMessage(): string;
|
|
95
|
+
}
|
|
96
|
+
/** Type guard for CimplifyError */
|
|
97
|
+
declare function isCimplifyError(error: unknown): error is CimplifyError;
|
|
98
|
+
declare function getErrorHint(code: string): ErrorHint | undefined;
|
|
99
|
+
declare function enrichError(error: CimplifyError, options?: {
|
|
100
|
+
isTestMode?: boolean;
|
|
101
|
+
}): CimplifyError;
|
|
102
|
+
/** Check if error is retryable */
|
|
103
|
+
declare function isRetryableError(error: unknown): boolean;
|
|
104
|
+
|
|
105
|
+
type PaymentStatus = "pending" | "processing" | "created" | "pending_confirmation" | "success" | "succeeded" | "failed" | "declined" | "authorized" | "refunded" | "partially_refunded" | "partially_paid" | "paid" | "unpaid" | "requires_action" | "requires_payment_method" | "requires_capture" | "captured" | "cancelled" | "completed" | "voided" | "error" | "unknown";
|
|
106
|
+
type PaymentProvider = "stripe" | "paystack" | "mtn" | "vodafone" | "airtel" | "cellulant" | "offline" | "cash" | "manual";
|
|
107
|
+
type PaymentMethodType = "card" | "mobile_money" | "bank_transfer" | "cash" | "custom";
|
|
108
|
+
/** Authorization types for payment verification (OTP, PIN, etc.) */
|
|
109
|
+
type AuthorizationType = "otp" | "pin" | "phone" | "birthday" | "address";
|
|
110
|
+
/** Payment processing state machine states (for UI) */
|
|
111
|
+
type PaymentProcessingState = "initial" | "preparing" | "processing" | "verifying" | "awaiting_authorization" | "success" | "error" | "timeout";
|
|
112
|
+
interface PaymentMethod {
|
|
113
|
+
type: PaymentMethodType;
|
|
114
|
+
provider?: string;
|
|
115
|
+
phone_number?: string;
|
|
116
|
+
card_last_four?: string;
|
|
117
|
+
custom_value?: string;
|
|
118
|
+
}
|
|
119
|
+
interface Payment {
|
|
120
|
+
id: string;
|
|
121
|
+
order_id: string;
|
|
122
|
+
business_id: string;
|
|
123
|
+
amount: Money;
|
|
124
|
+
currency: Currency;
|
|
125
|
+
payment_method: PaymentMethod;
|
|
126
|
+
status: PaymentStatus;
|
|
127
|
+
provider: PaymentProvider;
|
|
128
|
+
provider_reference?: string;
|
|
129
|
+
failure_reason?: string;
|
|
130
|
+
created_at: string;
|
|
131
|
+
updated_at: string;
|
|
132
|
+
}
|
|
133
|
+
interface InitializePaymentResult {
|
|
134
|
+
payment_id: string;
|
|
135
|
+
status: PaymentStatus;
|
|
136
|
+
redirect_url?: string;
|
|
137
|
+
authorization_url?: string;
|
|
138
|
+
reference: string;
|
|
139
|
+
provider: PaymentProvider;
|
|
140
|
+
}
|
|
141
|
+
/** Normalized payment response from checkout or payment initialization */
|
|
142
|
+
interface PaymentResponse {
|
|
143
|
+
method: string;
|
|
144
|
+
provider: string;
|
|
145
|
+
requires_action: boolean;
|
|
146
|
+
public_key?: string;
|
|
147
|
+
client_secret?: string;
|
|
148
|
+
access_code?: string;
|
|
149
|
+
redirect_url?: string;
|
|
150
|
+
transaction_id?: string;
|
|
151
|
+
order_id?: string;
|
|
152
|
+
reference?: string;
|
|
153
|
+
metadata?: Record<string, unknown>;
|
|
154
|
+
instructions?: string;
|
|
155
|
+
display_text?: string;
|
|
156
|
+
requires_authorization?: boolean;
|
|
157
|
+
authorization_type?: AuthorizationType;
|
|
158
|
+
provider_payment_id?: string;
|
|
159
|
+
}
|
|
160
|
+
/** Payment status polling response */
|
|
161
|
+
interface PaymentStatusResponse {
|
|
162
|
+
status: PaymentStatus;
|
|
163
|
+
paid: boolean;
|
|
164
|
+
amount?: Money;
|
|
165
|
+
currency?: string;
|
|
166
|
+
reference?: string;
|
|
167
|
+
message?: string;
|
|
168
|
+
}
|
|
169
|
+
interface PaymentErrorDetails {
|
|
170
|
+
code: string;
|
|
171
|
+
message: string;
|
|
172
|
+
recoverable: boolean;
|
|
173
|
+
technical?: string;
|
|
174
|
+
}
|
|
175
|
+
interface SubmitAuthorizationInput {
|
|
176
|
+
reference: string;
|
|
177
|
+
auth_type: AuthorizationType;
|
|
178
|
+
value: string;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export { type ApiError as A, type Currency as C, ErrorCode as E, type InitializePaymentResult as I, type Money as M, type PaginationParams as P, type SubmitAuthorizationInput as S, type Pagination as a, type ErrorCodeType as b, type ErrorHint as c, ERROR_HINTS as d, CimplifyError as e, enrichError as f, getErrorHint as g, isRetryableError as h, isCimplifyError as i, type PaymentStatus as j, type PaymentProvider as k, type PaymentMethodType as l, type AuthorizationType as m, type PaymentProcessingState as n, type PaymentMethod as o, type Payment as p, type PaymentResponse as q, type PaymentStatusResponse as r, type PaymentErrorDetails as s };
|