@cimplify/sdk 0.6.6 → 0.6.8
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/README.md +19 -0
- package/dist/advanced.d.mts +2 -2
- package/dist/advanced.d.ts +2 -2
- package/dist/advanced.js +228 -101
- package/dist/advanced.mjs +228 -101
- package/dist/{client-CUFdFugo.d.mts → client-D4vA6FY_.d.ts} +40 -34
- package/dist/{client-CjqNbEM6.d.ts → client-FQUyv41r.d.mts} +40 -34
- package/dist/{index-CJ9GkIXf.d.mts → index-DaKJxoEh.d.mts} +13 -12
- package/dist/{index-B5Bj-Ikg.d.ts → index-pztT_bcJ.d.ts} +13 -12
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +315 -131
- package/dist/index.mjs +309 -132
- package/dist/{payment-D-u3asA8.d.mts → payment-Cu75tmUc.d.mts} +34 -8
- package/dist/{payment-D-u3asA8.d.ts → payment-Cu75tmUc.d.ts} +34 -8
- package/dist/react.d.mts +225 -4
- package/dist/react.d.ts +225 -4
- package/dist/react.js +2097 -63
- package/dist/react.mjs +2086 -65
- package/dist/utils.d.mts +2 -2
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +76 -4
- package/dist/utils.mjs +76 -4
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
// src/types/common.ts
|
|
2
|
+
function money(value) {
|
|
3
|
+
return value;
|
|
4
|
+
}
|
|
5
|
+
function moneyFromNumber(value) {
|
|
6
|
+
return value.toFixed(2);
|
|
7
|
+
}
|
|
8
|
+
var ZERO = "0.00";
|
|
9
|
+
function currencyCode(value) {
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
2
12
|
var ErrorCode = {
|
|
3
13
|
// General
|
|
4
14
|
UNKNOWN_ERROR: "UNKNOWN_ERROR",
|
|
@@ -38,11 +48,72 @@ var ErrorCode = {
|
|
|
38
48
|
OUT_OF_STOCK: "OUT_OF_STOCK",
|
|
39
49
|
INSUFFICIENT_QUANTITY: "INSUFFICIENT_QUANTITY"
|
|
40
50
|
};
|
|
51
|
+
var DOCS_ERROR_BASE_URL = "https://docs.cimplify.io/reference/error-codes";
|
|
52
|
+
function docsUrlForCode(code) {
|
|
53
|
+
return `${DOCS_ERROR_BASE_URL}#${code.toLowerCase().replace(/_/g, "-")}`;
|
|
54
|
+
}
|
|
55
|
+
var ERROR_SUGGESTIONS = {
|
|
56
|
+
UNKNOWN_ERROR: "An unexpected error occurred. Capture the request/response payload and retry with exponential backoff.",
|
|
57
|
+
NETWORK_ERROR: "Check the shopper's connection and retry. If this persists, inspect CORS, DNS, and API reachability.",
|
|
58
|
+
TIMEOUT: "The request exceeded the timeout. Retry once, then poll order status before charging again.",
|
|
59
|
+
UNAUTHORIZED: "Authentication is missing or expired. Ensure a valid access token is set and refresh the session if needed.",
|
|
60
|
+
FORBIDDEN: "The key/session lacks permission for this resource. Verify business ownership and API key scope.",
|
|
61
|
+
NOT_FOUND: "The requested resource does not exist or is not visible in this environment.",
|
|
62
|
+
VALIDATION_ERROR: "One or more fields are invalid. Validate required fields and enum values before retrying.",
|
|
63
|
+
CART_EMPTY: "The cart has no items. Redirect back to menu/catalogue and require at least one line item.",
|
|
64
|
+
CART_EXPIRED: "This cart is no longer active. Recreate a new cart and re-add shopper selections.",
|
|
65
|
+
CART_NOT_FOUND: "Cart could not be located. It may have expired or belongs to a different key/location.",
|
|
66
|
+
ITEM_UNAVAILABLE: "The selected item is unavailable at this location/time. Prompt the shopper to pick an alternative.",
|
|
67
|
+
VARIANT_NOT_FOUND: "The requested variant no longer exists. Refresh product data and require re-selection.",
|
|
68
|
+
VARIANT_OUT_OF_STOCK: "The selected variant is out of stock. Show in-stock variants and block checkout for this line.",
|
|
69
|
+
ADDON_REQUIRED: "A required add-on is missing. Ensure required modifier groups are completed before add-to-cart.",
|
|
70
|
+
ADDON_MAX_EXCEEDED: "Too many add-ons were selected. Enforce max selections client-side before submission.",
|
|
71
|
+
CHECKOUT_VALIDATION_FAILED: "Checkout payload failed validation. Verify customer, order type, and address fields are complete.",
|
|
72
|
+
DELIVERY_ADDRESS_REQUIRED: "Delivery orders require an address. Collect and pass address info before processing checkout.",
|
|
73
|
+
CUSTOMER_INFO_REQUIRED: "Customer details are required. Ensure name/email/phone are available before checkout.",
|
|
74
|
+
PAYMENT_FAILED: "Payment provider rejected or failed processing. Show retry/change-method options to the shopper.",
|
|
75
|
+
PAYMENT_CANCELLED: "Payment was cancelled by the shopper or provider flow. Allow a safe retry path.",
|
|
76
|
+
INSUFFICIENT_FUNDS: "Payment method has insufficient funds. Prompt shopper to use another method.",
|
|
77
|
+
CARD_DECLINED: "Card was declined. Ask shopper to retry or switch payment method.",
|
|
78
|
+
INVALID_OTP: "Authorization code is invalid. Let shopper re-enter OTP/PIN and retry.",
|
|
79
|
+
OTP_EXPIRED: "Authorization code expired. Request a new OTP and re-submit authorization.",
|
|
80
|
+
AUTHORIZATION_FAILED: "Additional payment authorization failed. Retry authorization or change payment method.",
|
|
81
|
+
PAYMENT_ACTION_NOT_COMPLETED: "Required payment action was not completed. Resume provider flow and poll for status.",
|
|
82
|
+
SLOT_UNAVAILABLE: "Selected schedule slot is unavailable. Refresh available slots and ask shopper to reselect.",
|
|
83
|
+
BOOKING_CONFLICT: "The requested booking conflicts with an existing reservation. Pick another slot/resource.",
|
|
84
|
+
SERVICE_NOT_FOUND: "Requested service no longer exists. Refresh service catalogue and retry selection.",
|
|
85
|
+
OUT_OF_STOCK: "Inventory is depleted for this item. Remove it or reduce quantity before checkout.",
|
|
86
|
+
INSUFFICIENT_QUANTITY: "Requested quantity exceeds available inventory. Reduce quantity and retry.",
|
|
87
|
+
BUSINESS_ID_REQUIRED: "Business context could not be resolved. Verify the public key and business bootstrap call.",
|
|
88
|
+
INVALID_CART: "Cart is invalid for checkout. Sync cart state, ensure items exist, then retry.",
|
|
89
|
+
ORDER_TYPE_REQUIRED: "Order type is required. Provide one of delivery, pickup, or dine_in before checkout.",
|
|
90
|
+
NO_PAYMENT_ELEMENT: "PaymentElement is required for processCheckout(). Mount it before triggering checkout.",
|
|
91
|
+
PAYMENT_NOT_MOUNTED: "PaymentElement iframe is not mounted. Mount it in the DOM before processCheckout().",
|
|
92
|
+
AUTH_INCOMPLETE: "AuthElement has not completed authentication. Wait for AUTHENTICATED before checkout.",
|
|
93
|
+
AUTH_LOST: "Session was cleared during checkout. Re-authenticate and restart checkout safely.",
|
|
94
|
+
ALREADY_PROCESSING: "Checkout is already in progress. Disable duplicate submits until completion.",
|
|
95
|
+
CHECKOUT_NOT_READY: "Checkout elements are still initializing. Wait for readiness before submit.",
|
|
96
|
+
CANCELLED: "Checkout was cancelled. Preserve cart state and allow shopper to retry.",
|
|
97
|
+
REQUEST_TIMEOUT: "Provider call timed out. Poll payment/order status before issuing another charge attempt.",
|
|
98
|
+
POPUP_BLOCKED: "Browser blocked provider popup. Ask shopper to enable popups and retry.",
|
|
99
|
+
FX_QUOTE_FAILED: "Failed to lock FX quote. Retry currency quote or fallback to base currency."
|
|
100
|
+
};
|
|
101
|
+
var ERROR_HINTS = Object.fromEntries(
|
|
102
|
+
Object.entries(ERROR_SUGGESTIONS).map(([code, suggestion]) => [
|
|
103
|
+
code,
|
|
104
|
+
{
|
|
105
|
+
docs_url: docsUrlForCode(code),
|
|
106
|
+
suggestion
|
|
107
|
+
}
|
|
108
|
+
])
|
|
109
|
+
);
|
|
41
110
|
var CimplifyError = class extends Error {
|
|
42
|
-
constructor(code, message, retryable = false) {
|
|
111
|
+
constructor(code, message, retryable = false, docs_url, suggestion) {
|
|
43
112
|
super(message);
|
|
44
113
|
this.code = code;
|
|
45
114
|
this.retryable = retryable;
|
|
115
|
+
this.docs_url = docs_url;
|
|
116
|
+
this.suggestion = suggestion;
|
|
46
117
|
this.name = "CimplifyError";
|
|
47
118
|
}
|
|
48
119
|
/** User-friendly message safe to display */
|
|
@@ -53,6 +124,28 @@ var CimplifyError = class extends Error {
|
|
|
53
124
|
function isCimplifyError(error) {
|
|
54
125
|
return error instanceof CimplifyError;
|
|
55
126
|
}
|
|
127
|
+
function getErrorHint(code) {
|
|
128
|
+
return ERROR_HINTS[code];
|
|
129
|
+
}
|
|
130
|
+
function enrichError(error, options = {}) {
|
|
131
|
+
const hint = getErrorHint(error.code);
|
|
132
|
+
if (hint) {
|
|
133
|
+
if (!error.docs_url) {
|
|
134
|
+
error.docs_url = hint.docs_url;
|
|
135
|
+
}
|
|
136
|
+
if (!error.suggestion) {
|
|
137
|
+
error.suggestion = hint.suggestion;
|
|
138
|
+
}
|
|
139
|
+
} else if (!error.docs_url) {
|
|
140
|
+
error.docs_url = docsUrlForCode(error.code || ErrorCode.UNKNOWN_ERROR);
|
|
141
|
+
}
|
|
142
|
+
if (options.isTestMode && !error.message.includes("pk_test_")) {
|
|
143
|
+
error.message = `${error.message}
|
|
144
|
+
|
|
145
|
+
\u2139 Your API key is a test-mode key (pk_test_...). Verify test data/session before retrying.`;
|
|
146
|
+
}
|
|
147
|
+
return error;
|
|
148
|
+
}
|
|
56
149
|
function isRetryableError(error) {
|
|
57
150
|
if (isCimplifyError(error)) {
|
|
58
151
|
return error.retryable;
|
|
@@ -134,13 +227,81 @@ function combineObject(results) {
|
|
|
134
227
|
return ok(values);
|
|
135
228
|
}
|
|
136
229
|
|
|
230
|
+
// src/query/builder.ts
|
|
231
|
+
function escapeQueryValue(value) {
|
|
232
|
+
return value.replace(/'/g, "\\'");
|
|
233
|
+
}
|
|
234
|
+
var QueryBuilder = class {
|
|
235
|
+
constructor(entity) {
|
|
236
|
+
this.filters = [];
|
|
237
|
+
this.modifiers = [];
|
|
238
|
+
this.pathSegments = [];
|
|
239
|
+
this.entity = entity;
|
|
240
|
+
}
|
|
241
|
+
path(segment) {
|
|
242
|
+
this.pathSegments.push(segment);
|
|
243
|
+
return this;
|
|
244
|
+
}
|
|
245
|
+
where(field, op, value) {
|
|
246
|
+
const v = typeof value === "string" ? `'${escapeQueryValue(value)}'` : value;
|
|
247
|
+
if (op === "contains" || op === "startsWith") {
|
|
248
|
+
this.filters.push(`@.${field} ${op} ${v}`);
|
|
249
|
+
} else {
|
|
250
|
+
this.filters.push(`@.${field}${op}${v}`);
|
|
251
|
+
}
|
|
252
|
+
return this;
|
|
253
|
+
}
|
|
254
|
+
and(field, op, value) {
|
|
255
|
+
return this.where(field, op, value);
|
|
256
|
+
}
|
|
257
|
+
sort(field, order = "asc") {
|
|
258
|
+
this.modifiers.push(`sort(${field},${order})`);
|
|
259
|
+
return this;
|
|
260
|
+
}
|
|
261
|
+
limit(n) {
|
|
262
|
+
this.modifiers.push(`limit(${n})`);
|
|
263
|
+
return this;
|
|
264
|
+
}
|
|
265
|
+
offset(n) {
|
|
266
|
+
this.modifiers.push(`offset(${n})`);
|
|
267
|
+
return this;
|
|
268
|
+
}
|
|
269
|
+
count() {
|
|
270
|
+
this.modifiers.push("count");
|
|
271
|
+
return this;
|
|
272
|
+
}
|
|
273
|
+
enriched() {
|
|
274
|
+
this.modifiers.push("enriched");
|
|
275
|
+
return this;
|
|
276
|
+
}
|
|
277
|
+
build() {
|
|
278
|
+
let query2 = this.entity;
|
|
279
|
+
if (this.pathSegments.length > 0) {
|
|
280
|
+
query2 += "." + this.pathSegments.join(".");
|
|
281
|
+
}
|
|
282
|
+
if (this.filters.length > 0) {
|
|
283
|
+
query2 += `[?(${this.filters.join(" && ")})]`;
|
|
284
|
+
}
|
|
285
|
+
for (const mod of this.modifiers) {
|
|
286
|
+
query2 += `#${mod}`;
|
|
287
|
+
}
|
|
288
|
+
return query2;
|
|
289
|
+
}
|
|
290
|
+
toString() {
|
|
291
|
+
return this.build();
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
function query(entity) {
|
|
295
|
+
return new QueryBuilder(entity);
|
|
296
|
+
}
|
|
297
|
+
|
|
137
298
|
// src/catalogue.ts
|
|
138
299
|
function toCimplifyError(error) {
|
|
139
|
-
if (error instanceof CimplifyError) return error;
|
|
300
|
+
if (error instanceof CimplifyError) return enrichError(error);
|
|
140
301
|
if (error instanceof Error) {
|
|
141
|
-
return new CimplifyError(
|
|
302
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
|
|
142
303
|
}
|
|
143
|
-
return new CimplifyError(
|
|
304
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
|
|
144
305
|
}
|
|
145
306
|
async function safe(promise) {
|
|
146
307
|
try {
|
|
@@ -214,7 +375,7 @@ var CatalogueQueries = class {
|
|
|
214
375
|
let query2 = "products";
|
|
215
376
|
const filters = [];
|
|
216
377
|
if (options?.category) {
|
|
217
|
-
filters.push(`@.category_id=='${options.category}'`);
|
|
378
|
+
filters.push(`@.category_id=='${escapeQueryValue(options.category)}'`);
|
|
218
379
|
}
|
|
219
380
|
if (options?.featured !== void 0) {
|
|
220
381
|
filters.push(`@.featured==${options.featured}`);
|
|
@@ -223,7 +384,7 @@ var CatalogueQueries = class {
|
|
|
223
384
|
filters.push(`@.in_stock==${options.in_stock}`);
|
|
224
385
|
}
|
|
225
386
|
if (options?.search) {
|
|
226
|
-
filters.push(`@.name contains '${options.search}'`);
|
|
387
|
+
filters.push(`@.name contains '${escapeQueryValue(options.search)}'`);
|
|
227
388
|
}
|
|
228
389
|
if (options?.min_price !== void 0) {
|
|
229
390
|
filters.push(`@.price>=${options.min_price}`);
|
|
@@ -254,7 +415,9 @@ var CatalogueQueries = class {
|
|
|
254
415
|
}
|
|
255
416
|
async getProductBySlug(slug) {
|
|
256
417
|
const filteredResult = await safe(
|
|
257
|
-
this.client.query(
|
|
418
|
+
this.client.query(
|
|
419
|
+
`products[?(@.slug=='${escapeQueryValue(slug)}')]`
|
|
420
|
+
)
|
|
258
421
|
);
|
|
259
422
|
if (!filteredResult.ok) return filteredResult;
|
|
260
423
|
const exactMatch = findProductBySlug(filteredResult.value, slug);
|
|
@@ -306,7 +469,7 @@ var CatalogueQueries = class {
|
|
|
306
469
|
}
|
|
307
470
|
async getCategoryBySlug(slug) {
|
|
308
471
|
const result = await safe(
|
|
309
|
-
this.client.query(`categories[?(@.slug=='${slug}')]`)
|
|
472
|
+
this.client.query(`categories[?(@.slug=='${escapeQueryValue(slug)}')]`)
|
|
310
473
|
);
|
|
311
474
|
if (!result.ok) return result;
|
|
312
475
|
if (!result.value.length) {
|
|
@@ -315,7 +478,11 @@ var CatalogueQueries = class {
|
|
|
315
478
|
return ok(result.value[0]);
|
|
316
479
|
}
|
|
317
480
|
async getCategoryProducts(categoryId) {
|
|
318
|
-
return safe(
|
|
481
|
+
return safe(
|
|
482
|
+
this.client.query(
|
|
483
|
+
`products[?(@.category_id=='${escapeQueryValue(categoryId)}')]`
|
|
484
|
+
)
|
|
485
|
+
);
|
|
319
486
|
}
|
|
320
487
|
async getCollections() {
|
|
321
488
|
return safe(this.client.query("collections"));
|
|
@@ -325,7 +492,9 @@ var CatalogueQueries = class {
|
|
|
325
492
|
}
|
|
326
493
|
async getCollectionBySlug(slug) {
|
|
327
494
|
const result = await safe(
|
|
328
|
-
this.client.query(
|
|
495
|
+
this.client.query(
|
|
496
|
+
`collections[?(@.slug=='${escapeQueryValue(slug)}')]`
|
|
497
|
+
)
|
|
329
498
|
);
|
|
330
499
|
if (!result.ok) return result;
|
|
331
500
|
if (!result.value.length) {
|
|
@@ -338,7 +507,9 @@ var CatalogueQueries = class {
|
|
|
338
507
|
}
|
|
339
508
|
async searchCollections(query2, limit = 20) {
|
|
340
509
|
return safe(
|
|
341
|
-
this.client.query(
|
|
510
|
+
this.client.query(
|
|
511
|
+
`collections[?(@.name contains '${escapeQueryValue(query2)}')]#limit(${limit})`
|
|
512
|
+
)
|
|
342
513
|
);
|
|
343
514
|
}
|
|
344
515
|
async getBundles() {
|
|
@@ -349,7 +520,9 @@ var CatalogueQueries = class {
|
|
|
349
520
|
}
|
|
350
521
|
async getBundleBySlug(slug) {
|
|
351
522
|
const result = await safe(
|
|
352
|
-
this.client.query(
|
|
523
|
+
this.client.query(
|
|
524
|
+
`bundles[?(@.slug=='${escapeQueryValue(slug)}')]`
|
|
525
|
+
)
|
|
353
526
|
);
|
|
354
527
|
if (!result.ok) return result;
|
|
355
528
|
if (!result.value.length) {
|
|
@@ -359,7 +532,9 @@ var CatalogueQueries = class {
|
|
|
359
532
|
}
|
|
360
533
|
async searchBundles(query2, limit = 20) {
|
|
361
534
|
return safe(
|
|
362
|
-
this.client.query(
|
|
535
|
+
this.client.query(
|
|
536
|
+
`bundles[?(@.name contains '${escapeQueryValue(query2)}')]#limit(${limit})`
|
|
537
|
+
)
|
|
363
538
|
);
|
|
364
539
|
}
|
|
365
540
|
async getComposites(options) {
|
|
@@ -399,9 +574,9 @@ var CatalogueQueries = class {
|
|
|
399
574
|
}
|
|
400
575
|
async search(query2, options) {
|
|
401
576
|
const limit = options?.limit ?? 20;
|
|
402
|
-
let searchQuery = `products[?(@.name contains '${query2}')]`;
|
|
577
|
+
let searchQuery = `products[?(@.name contains '${escapeQueryValue(query2)}')]`;
|
|
403
578
|
if (options?.category) {
|
|
404
|
-
searchQuery = `products[?(@.name contains '${query2}' && @.category_id=='${options.category}')]`;
|
|
579
|
+
searchQuery = `products[?(@.name contains '${escapeQueryValue(query2)}' && @.category_id=='${escapeQueryValue(options.category)}')]`;
|
|
405
580
|
}
|
|
406
581
|
searchQuery += `#limit(${limit})`;
|
|
407
582
|
return safe(this.client.query(searchQuery));
|
|
@@ -418,7 +593,7 @@ var CatalogueQueries = class {
|
|
|
418
593
|
async getMenu(options) {
|
|
419
594
|
let query2 = "menu";
|
|
420
595
|
if (options?.category) {
|
|
421
|
-
query2 = `menu[?(@.category=='${options.category}')]`;
|
|
596
|
+
query2 = `menu[?(@.category=='${escapeQueryValue(options.category)}')]`;
|
|
422
597
|
}
|
|
423
598
|
if (options?.limit) {
|
|
424
599
|
query2 += `#limit(${options.limit})`;
|
|
@@ -435,11 +610,11 @@ var CatalogueQueries = class {
|
|
|
435
610
|
|
|
436
611
|
// src/cart.ts
|
|
437
612
|
function toCimplifyError2(error) {
|
|
438
|
-
if (error instanceof CimplifyError) return error;
|
|
613
|
+
if (error instanceof CimplifyError) return enrichError(error);
|
|
439
614
|
if (error instanceof Error) {
|
|
440
|
-
return new CimplifyError(
|
|
615
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
|
|
441
616
|
}
|
|
442
|
-
return new CimplifyError(
|
|
617
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
|
|
443
618
|
}
|
|
444
619
|
async function safe2(promise) {
|
|
445
620
|
try {
|
|
@@ -735,8 +910,8 @@ var CURRENCY_SYMBOLS = {
|
|
|
735
910
|
KMF: "CF",
|
|
736
911
|
BIF: "FBu"
|
|
737
912
|
};
|
|
738
|
-
function getCurrencySymbol(
|
|
739
|
-
return CURRENCY_SYMBOLS[
|
|
913
|
+
function getCurrencySymbol(currencyCode2) {
|
|
914
|
+
return CURRENCY_SYMBOLS[currencyCode2.toUpperCase()] || currencyCode2;
|
|
740
915
|
}
|
|
741
916
|
function formatNumberCompact(value, decimals = 1) {
|
|
742
917
|
const absValue = Math.abs(value);
|
|
@@ -1060,6 +1235,8 @@ function normalizeStatusResponse(response) {
|
|
|
1060
1235
|
}
|
|
1061
1236
|
const res = response;
|
|
1062
1237
|
const normalizedStatus = normalizePaymentStatusValue(res.status ?? void 0);
|
|
1238
|
+
const normalizedAmount = typeof res.amount === "string" ? money(res.amount) : typeof res.amount === "number" && Number.isFinite(res.amount) ? moneyFromNumber(res.amount) : void 0;
|
|
1239
|
+
const normalizedCurrency = typeof res.currency === "string" && res.currency.trim().length > 0 ? currencyCode(res.currency) : void 0;
|
|
1063
1240
|
const paidValue = res.paid === true;
|
|
1064
1241
|
const derivedPaid = paidValue || [
|
|
1065
1242
|
"success",
|
|
@@ -1072,8 +1249,8 @@ function normalizeStatusResponse(response) {
|
|
|
1072
1249
|
return {
|
|
1073
1250
|
status: normalizedStatus,
|
|
1074
1251
|
paid: derivedPaid,
|
|
1075
|
-
amount:
|
|
1076
|
-
currency:
|
|
1252
|
+
amount: normalizedAmount,
|
|
1253
|
+
currency: normalizedCurrency,
|
|
1077
1254
|
reference: res.reference,
|
|
1078
1255
|
message: res.message || ""
|
|
1079
1256
|
};
|
|
@@ -1654,11 +1831,11 @@ var CheckoutResolver = class {
|
|
|
1654
1831
|
|
|
1655
1832
|
// src/checkout.ts
|
|
1656
1833
|
function toCimplifyError3(error) {
|
|
1657
|
-
if (error instanceof CimplifyError) return error;
|
|
1834
|
+
if (error instanceof CimplifyError) return enrichError(error);
|
|
1658
1835
|
if (error instanceof Error) {
|
|
1659
|
-
return new CimplifyError(
|
|
1836
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
|
|
1660
1837
|
}
|
|
1661
|
-
return new CimplifyError(
|
|
1838
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
|
|
1662
1839
|
}
|
|
1663
1840
|
async function safe3(promise) {
|
|
1664
1841
|
try {
|
|
@@ -1780,14 +1957,17 @@ var CheckoutService = class {
|
|
|
1780
1957
|
pay_currency: data.pay_currency,
|
|
1781
1958
|
fx_quote_id: data.fx_quote_id
|
|
1782
1959
|
};
|
|
1783
|
-
const baseCurrency = (
|
|
1960
|
+
const baseCurrency = currencyCode(
|
|
1961
|
+
(cart.pricing.currency || checkoutData.pay_currency || "GHS").toUpperCase()
|
|
1962
|
+
);
|
|
1784
1963
|
const payCurrency = data.pay_currency?.trim().toUpperCase();
|
|
1964
|
+
const payCurrencyCode = payCurrency ? currencyCode(payCurrency) : void 0;
|
|
1785
1965
|
const cartTotalAmount = Number.parseFloat(cart.pricing.total_price || "0");
|
|
1786
|
-
if (
|
|
1966
|
+
if (payCurrencyCode && payCurrencyCode !== baseCurrency && !checkoutData.fx_quote_id && Number.isFinite(cartTotalAmount) && cartTotalAmount > 0) {
|
|
1787
1967
|
const fxQuoteResult = await this.client.fx.lockQuote({
|
|
1788
1968
|
from: baseCurrency,
|
|
1789
|
-
to:
|
|
1790
|
-
amount:
|
|
1969
|
+
to: payCurrencyCode,
|
|
1970
|
+
amount: cart.pricing.total_price
|
|
1791
1971
|
});
|
|
1792
1972
|
if (!fxQuoteResult.ok) {
|
|
1793
1973
|
return ok(
|
|
@@ -1798,7 +1978,7 @@ var CheckoutService = class {
|
|
|
1798
1978
|
)
|
|
1799
1979
|
);
|
|
1800
1980
|
}
|
|
1801
|
-
checkoutData.pay_currency =
|
|
1981
|
+
checkoutData.pay_currency = payCurrencyCode;
|
|
1802
1982
|
checkoutData.fx_quote_id = fxQuoteResult.value.id;
|
|
1803
1983
|
}
|
|
1804
1984
|
data.on_status_change?.("processing", {});
|
|
@@ -1834,11 +2014,11 @@ var CheckoutService = class {
|
|
|
1834
2014
|
|
|
1835
2015
|
// src/orders.ts
|
|
1836
2016
|
function toCimplifyError4(error) {
|
|
1837
|
-
if (error instanceof CimplifyError) return error;
|
|
2017
|
+
if (error instanceof CimplifyError) return enrichError(error);
|
|
1838
2018
|
if (error instanceof Error) {
|
|
1839
|
-
return new CimplifyError(
|
|
2019
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
|
|
1840
2020
|
}
|
|
1841
|
-
return new CimplifyError(
|
|
2021
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
|
|
1842
2022
|
}
|
|
1843
2023
|
async function safe4(promise) {
|
|
1844
2024
|
try {
|
|
@@ -2095,11 +2275,11 @@ var AuthService = class {
|
|
|
2095
2275
|
|
|
2096
2276
|
// src/business.ts
|
|
2097
2277
|
function toCimplifyError7(error) {
|
|
2098
|
-
if (error instanceof CimplifyError) return error;
|
|
2278
|
+
if (error instanceof CimplifyError) return enrichError(error);
|
|
2099
2279
|
if (error instanceof Error) {
|
|
2100
|
-
return new CimplifyError(
|
|
2280
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
|
|
2101
2281
|
}
|
|
2102
|
-
return new CimplifyError(
|
|
2282
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
|
|
2103
2283
|
}
|
|
2104
2284
|
async function safe7(promise) {
|
|
2105
2285
|
try {
|
|
@@ -2485,12 +2665,15 @@ var EVENT_TYPES = {
|
|
|
2485
2665
|
|
|
2486
2666
|
// src/elements.ts
|
|
2487
2667
|
function toCheckoutError(code, message, recoverable) {
|
|
2668
|
+
const hint = getErrorHint(code);
|
|
2488
2669
|
return {
|
|
2489
2670
|
success: false,
|
|
2490
2671
|
error: {
|
|
2491
2672
|
code,
|
|
2492
2673
|
message,
|
|
2493
|
-
recoverable
|
|
2674
|
+
recoverable,
|
|
2675
|
+
docs_url: hint?.docs_url,
|
|
2676
|
+
suggestion: hint?.suggestion
|
|
2494
2677
|
}
|
|
2495
2678
|
};
|
|
2496
2679
|
}
|
|
@@ -2531,6 +2714,7 @@ var CimplifyElements = class {
|
|
|
2531
2714
|
this.paymentData = null;
|
|
2532
2715
|
this.checkoutInProgress = false;
|
|
2533
2716
|
this.activeCheckoutAbort = null;
|
|
2717
|
+
this.hasWarnedMissingAuthElement = false;
|
|
2534
2718
|
this.businessIdResolvePromise = null;
|
|
2535
2719
|
this.client = client;
|
|
2536
2720
|
this.businessId = businessId ?? null;
|
|
@@ -2626,6 +2810,12 @@ var CimplifyElements = class {
|
|
|
2626
2810
|
);
|
|
2627
2811
|
}
|
|
2628
2812
|
const authElement = this.elements.get(ELEMENT_TYPES.AUTH);
|
|
2813
|
+
if (!authElement && !this.hasWarnedMissingAuthElement) {
|
|
2814
|
+
this.hasWarnedMissingAuthElement = true;
|
|
2815
|
+
console.warn(
|
|
2816
|
+
"[Cimplify] processCheckout() called without AuthElement mounted. For best conversion and Link enrollment, mount <AuthElement> before checkout."
|
|
2817
|
+
);
|
|
2818
|
+
}
|
|
2629
2819
|
if (authElement && !this.accessToken) {
|
|
2630
2820
|
return toCheckoutError(
|
|
2631
2821
|
"AUTH_INCOMPLETE",
|
|
@@ -3062,28 +3252,37 @@ function isRetryable(error) {
|
|
|
3062
3252
|
}
|
|
3063
3253
|
return false;
|
|
3064
3254
|
}
|
|
3065
|
-
function toNetworkError(error) {
|
|
3255
|
+
function toNetworkError(error, isTestMode) {
|
|
3066
3256
|
if (error instanceof DOMException && error.name === "AbortError") {
|
|
3067
|
-
return
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3257
|
+
return enrichError(
|
|
3258
|
+
new CimplifyError(
|
|
3259
|
+
ErrorCode.TIMEOUT,
|
|
3260
|
+
"Request timed out. Please check your connection and try again.",
|
|
3261
|
+
true
|
|
3262
|
+
),
|
|
3263
|
+
{ isTestMode }
|
|
3071
3264
|
);
|
|
3072
3265
|
}
|
|
3073
3266
|
if (error instanceof TypeError && error.message.includes("fetch")) {
|
|
3074
|
-
return
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3267
|
+
return enrichError(
|
|
3268
|
+
new CimplifyError(
|
|
3269
|
+
ErrorCode.NETWORK_ERROR,
|
|
3270
|
+
"Network error. Please check your internet connection.",
|
|
3271
|
+
true
|
|
3272
|
+
),
|
|
3273
|
+
{ isTestMode }
|
|
3078
3274
|
);
|
|
3079
3275
|
}
|
|
3080
3276
|
if (error instanceof CimplifyError) {
|
|
3081
|
-
return error;
|
|
3082
|
-
}
|
|
3083
|
-
return
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3277
|
+
return enrichError(error, { isTestMode });
|
|
3278
|
+
}
|
|
3279
|
+
return enrichError(
|
|
3280
|
+
new CimplifyError(
|
|
3281
|
+
ErrorCode.UNKNOWN_ERROR,
|
|
3282
|
+
error instanceof Error ? error.message : "An unknown error occurred",
|
|
3283
|
+
false
|
|
3284
|
+
),
|
|
3285
|
+
{ isTestMode }
|
|
3087
3286
|
);
|
|
3088
3287
|
}
|
|
3089
3288
|
function deriveUrls() {
|
|
@@ -3145,6 +3344,9 @@ var CimplifyClient = class {
|
|
|
3145
3344
|
getPublicKey() {
|
|
3146
3345
|
return this.publicKey;
|
|
3147
3346
|
}
|
|
3347
|
+
isTestMode() {
|
|
3348
|
+
return this.publicKey.trim().startsWith("pk_test_");
|
|
3349
|
+
}
|
|
3148
3350
|
setAccessToken(token) {
|
|
3149
3351
|
const previous = this.accessToken;
|
|
3150
3352
|
this.accessToken = token;
|
|
@@ -3266,7 +3468,7 @@ var CimplifyClient = class {
|
|
|
3266
3468
|
signal: controller.signal
|
|
3267
3469
|
});
|
|
3268
3470
|
clearTimeout(timeoutId);
|
|
3269
|
-
if (response.ok
|
|
3471
|
+
if (response.ok) {
|
|
3270
3472
|
this.hooks.onRequestSuccess?.({
|
|
3271
3473
|
...context,
|
|
3272
3474
|
status: response.status,
|
|
@@ -3274,6 +3476,21 @@ var CimplifyClient = class {
|
|
|
3274
3476
|
});
|
|
3275
3477
|
return response;
|
|
3276
3478
|
}
|
|
3479
|
+
if (response.status >= 400 && response.status < 500) {
|
|
3480
|
+
this.hooks.onRequestError?.({
|
|
3481
|
+
...context,
|
|
3482
|
+
error: new CimplifyError(
|
|
3483
|
+
`HTTP_${response.status}`,
|
|
3484
|
+
`Request failed with status ${response.status}`,
|
|
3485
|
+
false
|
|
3486
|
+
),
|
|
3487
|
+
status: response.status,
|
|
3488
|
+
durationMs: Date.now() - startTime,
|
|
3489
|
+
retryCount,
|
|
3490
|
+
retryable: false
|
|
3491
|
+
});
|
|
3492
|
+
return response;
|
|
3493
|
+
}
|
|
3277
3494
|
if (response.status >= 500 && attempt < this.maxRetries) {
|
|
3278
3495
|
retryCount++;
|
|
3279
3496
|
const delay = this.retryDelay * Math.pow(2, attempt);
|
|
@@ -3286,15 +3503,22 @@ var CimplifyClient = class {
|
|
|
3286
3503
|
await sleep(delay);
|
|
3287
3504
|
continue;
|
|
3288
3505
|
}
|
|
3289
|
-
this.hooks.
|
|
3506
|
+
this.hooks.onRequestError?.({
|
|
3290
3507
|
...context,
|
|
3508
|
+
error: new CimplifyError(
|
|
3509
|
+
"SERVER_ERROR",
|
|
3510
|
+
`Server error ${response.status} after ${retryCount} retries`,
|
|
3511
|
+
false
|
|
3512
|
+
),
|
|
3291
3513
|
status: response.status,
|
|
3292
|
-
durationMs: Date.now() - startTime
|
|
3514
|
+
durationMs: Date.now() - startTime,
|
|
3515
|
+
retryCount,
|
|
3516
|
+
retryable: false
|
|
3293
3517
|
});
|
|
3294
3518
|
return response;
|
|
3295
3519
|
} catch (error) {
|
|
3296
3520
|
lastError = error;
|
|
3297
|
-
const networkError = toNetworkError(error);
|
|
3521
|
+
const networkError = toNetworkError(error, this.isTestMode());
|
|
3298
3522
|
const errorRetryable = isRetryable(error);
|
|
3299
3523
|
if (!errorRetryable || attempt >= this.maxRetries) {
|
|
3300
3524
|
this.hooks.onRequestError?.({
|
|
@@ -3317,7 +3541,7 @@ var CimplifyClient = class {
|
|
|
3317
3541
|
await sleep(delay);
|
|
3318
3542
|
}
|
|
3319
3543
|
}
|
|
3320
|
-
const finalError = toNetworkError(lastError);
|
|
3544
|
+
const finalError = toNetworkError(lastError, this.isTestMode());
|
|
3321
3545
|
this.hooks.onRequestError?.({
|
|
3322
3546
|
...context,
|
|
3323
3547
|
error: finalError,
|
|
@@ -3435,22 +3659,40 @@ var CimplifyClient = class {
|
|
|
3435
3659
|
async handleRestResponse(response) {
|
|
3436
3660
|
const json = await response.json();
|
|
3437
3661
|
if (!response.ok) {
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3662
|
+
const error = enrichError(
|
|
3663
|
+
new CimplifyError(
|
|
3664
|
+
json.error?.error_code || "API_ERROR",
|
|
3665
|
+
json.error?.error_message || "An error occurred",
|
|
3666
|
+
false
|
|
3667
|
+
),
|
|
3668
|
+
{ isTestMode: this.isTestMode() }
|
|
3442
3669
|
);
|
|
3670
|
+
if (response.status === 401 || error.code === ErrorCode.UNAUTHORIZED) {
|
|
3671
|
+
console.warn(
|
|
3672
|
+
"[Cimplify] Received 401 Unauthorized. Access token may be missing/expired. Refresh authentication and retry the request."
|
|
3673
|
+
);
|
|
3674
|
+
}
|
|
3675
|
+
throw error;
|
|
3443
3676
|
}
|
|
3444
3677
|
return json.data;
|
|
3445
3678
|
}
|
|
3446
3679
|
async handleResponse(response) {
|
|
3447
3680
|
const json = await response.json();
|
|
3448
3681
|
if (!json.success || json.error) {
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3682
|
+
const error = enrichError(
|
|
3683
|
+
new CimplifyError(
|
|
3684
|
+
json.error?.code || "UNKNOWN_ERROR",
|
|
3685
|
+
json.error?.message || "An unknown error occurred",
|
|
3686
|
+
json.error?.retryable || false
|
|
3687
|
+
),
|
|
3688
|
+
{ isTestMode: this.isTestMode() }
|
|
3453
3689
|
);
|
|
3690
|
+
if (response.status === 401 || error.code === ErrorCode.UNAUTHORIZED) {
|
|
3691
|
+
console.warn(
|
|
3692
|
+
"[Cimplify] Received 401 Unauthorized. Access token may be missing/expired. Refresh authentication and retry the request."
|
|
3693
|
+
);
|
|
3694
|
+
}
|
|
3695
|
+
throw error;
|
|
3454
3696
|
}
|
|
3455
3697
|
return json.data;
|
|
3456
3698
|
}
|
|
@@ -3545,69 +3787,4 @@ function createCimplifyClient(config = {}) {
|
|
|
3545
3787
|
return new CimplifyClient(config);
|
|
3546
3788
|
}
|
|
3547
3789
|
|
|
3548
|
-
|
|
3549
|
-
var QueryBuilder = class {
|
|
3550
|
-
constructor(entity) {
|
|
3551
|
-
this.filters = [];
|
|
3552
|
-
this.modifiers = [];
|
|
3553
|
-
this.pathSegments = [];
|
|
3554
|
-
this.entity = entity;
|
|
3555
|
-
}
|
|
3556
|
-
path(segment) {
|
|
3557
|
-
this.pathSegments.push(segment);
|
|
3558
|
-
return this;
|
|
3559
|
-
}
|
|
3560
|
-
where(field, op, value) {
|
|
3561
|
-
const v = typeof value === "string" ? `'${value}'` : value;
|
|
3562
|
-
if (op === "contains" || op === "startsWith") {
|
|
3563
|
-
this.filters.push(`@.${field} ${op} ${v}`);
|
|
3564
|
-
} else {
|
|
3565
|
-
this.filters.push(`@.${field}${op}${v}`);
|
|
3566
|
-
}
|
|
3567
|
-
return this;
|
|
3568
|
-
}
|
|
3569
|
-
and(field, op, value) {
|
|
3570
|
-
return this.where(field, op, value);
|
|
3571
|
-
}
|
|
3572
|
-
sort(field, order = "asc") {
|
|
3573
|
-
this.modifiers.push(`sort(${field},${order})`);
|
|
3574
|
-
return this;
|
|
3575
|
-
}
|
|
3576
|
-
limit(n) {
|
|
3577
|
-
this.modifiers.push(`limit(${n})`);
|
|
3578
|
-
return this;
|
|
3579
|
-
}
|
|
3580
|
-
offset(n) {
|
|
3581
|
-
this.modifiers.push(`offset(${n})`);
|
|
3582
|
-
return this;
|
|
3583
|
-
}
|
|
3584
|
-
count() {
|
|
3585
|
-
this.modifiers.push("count");
|
|
3586
|
-
return this;
|
|
3587
|
-
}
|
|
3588
|
-
enriched() {
|
|
3589
|
-
this.modifiers.push("enriched");
|
|
3590
|
-
return this;
|
|
3591
|
-
}
|
|
3592
|
-
build() {
|
|
3593
|
-
let query2 = this.entity;
|
|
3594
|
-
if (this.pathSegments.length > 0) {
|
|
3595
|
-
query2 += "." + this.pathSegments.join(".");
|
|
3596
|
-
}
|
|
3597
|
-
if (this.filters.length > 0) {
|
|
3598
|
-
query2 += `[?(${this.filters.join(" && ")})]`;
|
|
3599
|
-
}
|
|
3600
|
-
for (const mod of this.modifiers) {
|
|
3601
|
-
query2 += `#${mod}`;
|
|
3602
|
-
}
|
|
3603
|
-
return query2;
|
|
3604
|
-
}
|
|
3605
|
-
toString() {
|
|
3606
|
-
return this.build();
|
|
3607
|
-
}
|
|
3608
|
-
};
|
|
3609
|
-
function query(entity) {
|
|
3610
|
-
return new QueryBuilder(entity);
|
|
3611
|
-
}
|
|
3612
|
-
|
|
3613
|
-
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 };
|
|
3790
|
+
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, ZERO, categorizePaymentError, combine, combineObject, createCimplifyClient, createElements, currencyCode, 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, money, moneyFromNumber, normalizePaymentResponse, normalizeStatusResponse, ok, parsePrice, query, toNullable, tryCatch, unwrap };
|