@cimplify/sdk 0.6.6 → 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/index.js CHANGED
@@ -40,11 +40,72 @@ var ErrorCode = {
40
40
  OUT_OF_STOCK: "OUT_OF_STOCK",
41
41
  INSUFFICIENT_QUANTITY: "INSUFFICIENT_QUANTITY"
42
42
  };
43
+ var DOCS_ERROR_BASE_URL = "https://docs.cimplify.io/reference/error-codes";
44
+ function docsUrlForCode(code) {
45
+ return `${DOCS_ERROR_BASE_URL}#${code.toLowerCase().replace(/_/g, "-")}`;
46
+ }
47
+ var ERROR_SUGGESTIONS = {
48
+ UNKNOWN_ERROR: "An unexpected error occurred. Capture the request/response payload and retry with exponential backoff.",
49
+ NETWORK_ERROR: "Check the shopper's connection and retry. If this persists, inspect CORS, DNS, and API reachability.",
50
+ TIMEOUT: "The request exceeded the timeout. Retry once, then poll order status before charging again.",
51
+ UNAUTHORIZED: "Authentication is missing or expired. Ensure a valid access token is set and refresh the session if needed.",
52
+ FORBIDDEN: "The key/session lacks permission for this resource. Verify business ownership and API key scope.",
53
+ NOT_FOUND: "The requested resource does not exist or is not visible in this environment.",
54
+ VALIDATION_ERROR: "One or more fields are invalid. Validate required fields and enum values before retrying.",
55
+ CART_EMPTY: "The cart has no items. Redirect back to menu/catalogue and require at least one line item.",
56
+ CART_EXPIRED: "This cart is no longer active. Recreate a new cart and re-add shopper selections.",
57
+ CART_NOT_FOUND: "Cart could not be located. It may have expired or belongs to a different key/location.",
58
+ ITEM_UNAVAILABLE: "The selected item is unavailable at this location/time. Prompt the shopper to pick an alternative.",
59
+ VARIANT_NOT_FOUND: "The requested variant no longer exists. Refresh product data and require re-selection.",
60
+ VARIANT_OUT_OF_STOCK: "The selected variant is out of stock. Show in-stock variants and block checkout for this line.",
61
+ ADDON_REQUIRED: "A required add-on is missing. Ensure required modifier groups are completed before add-to-cart.",
62
+ ADDON_MAX_EXCEEDED: "Too many add-ons were selected. Enforce max selections client-side before submission.",
63
+ CHECKOUT_VALIDATION_FAILED: "Checkout payload failed validation. Verify customer, order type, and address fields are complete.",
64
+ DELIVERY_ADDRESS_REQUIRED: "Delivery orders require an address. Collect and pass address info before processing checkout.",
65
+ CUSTOMER_INFO_REQUIRED: "Customer details are required. Ensure name/email/phone are available before checkout.",
66
+ PAYMENT_FAILED: "Payment provider rejected or failed processing. Show retry/change-method options to the shopper.",
67
+ PAYMENT_CANCELLED: "Payment was cancelled by the shopper or provider flow. Allow a safe retry path.",
68
+ INSUFFICIENT_FUNDS: "Payment method has insufficient funds. Prompt shopper to use another method.",
69
+ CARD_DECLINED: "Card was declined. Ask shopper to retry or switch payment method.",
70
+ INVALID_OTP: "Authorization code is invalid. Let shopper re-enter OTP/PIN and retry.",
71
+ OTP_EXPIRED: "Authorization code expired. Request a new OTP and re-submit authorization.",
72
+ AUTHORIZATION_FAILED: "Additional payment authorization failed. Retry authorization or change payment method.",
73
+ PAYMENT_ACTION_NOT_COMPLETED: "Required payment action was not completed. Resume provider flow and poll for status.",
74
+ SLOT_UNAVAILABLE: "Selected schedule slot is unavailable. Refresh available slots and ask shopper to reselect.",
75
+ BOOKING_CONFLICT: "The requested booking conflicts with an existing reservation. Pick another slot/resource.",
76
+ SERVICE_NOT_FOUND: "Requested service no longer exists. Refresh service catalogue and retry selection.",
77
+ OUT_OF_STOCK: "Inventory is depleted for this item. Remove it or reduce quantity before checkout.",
78
+ INSUFFICIENT_QUANTITY: "Requested quantity exceeds available inventory. Reduce quantity and retry.",
79
+ BUSINESS_ID_REQUIRED: "Business context could not be resolved. Verify the public key and business bootstrap call.",
80
+ INVALID_CART: "Cart is invalid for checkout. Sync cart state, ensure items exist, then retry.",
81
+ ORDER_TYPE_REQUIRED: "Order type is required. Provide one of delivery, pickup, or dine_in before checkout.",
82
+ NO_PAYMENT_ELEMENT: "PaymentElement is required for processCheckout(). Mount it before triggering checkout.",
83
+ PAYMENT_NOT_MOUNTED: "PaymentElement iframe is not mounted. Mount it in the DOM before processCheckout().",
84
+ AUTH_INCOMPLETE: "AuthElement has not completed authentication. Wait for AUTHENTICATED before checkout.",
85
+ AUTH_LOST: "Session was cleared during checkout. Re-authenticate and restart checkout safely.",
86
+ ALREADY_PROCESSING: "Checkout is already in progress. Disable duplicate submits until completion.",
87
+ CHECKOUT_NOT_READY: "Checkout elements are still initializing. Wait for readiness before submit.",
88
+ CANCELLED: "Checkout was cancelled. Preserve cart state and allow shopper to retry.",
89
+ REQUEST_TIMEOUT: "Provider call timed out. Poll payment/order status before issuing another charge attempt.",
90
+ POPUP_BLOCKED: "Browser blocked provider popup. Ask shopper to enable popups and retry.",
91
+ FX_QUOTE_FAILED: "Failed to lock FX quote. Retry currency quote or fallback to base currency."
92
+ };
93
+ var ERROR_HINTS = Object.fromEntries(
94
+ Object.entries(ERROR_SUGGESTIONS).map(([code, suggestion]) => [
95
+ code,
96
+ {
97
+ docs_url: docsUrlForCode(code),
98
+ suggestion
99
+ }
100
+ ])
101
+ );
43
102
  var CimplifyError = class extends Error {
44
- constructor(code, message, retryable = false) {
103
+ constructor(code, message, retryable = false, docs_url, suggestion) {
45
104
  super(message);
46
105
  this.code = code;
47
106
  this.retryable = retryable;
107
+ this.docs_url = docs_url;
108
+ this.suggestion = suggestion;
48
109
  this.name = "CimplifyError";
49
110
  }
50
111
  /** User-friendly message safe to display */
@@ -55,6 +116,28 @@ var CimplifyError = class extends Error {
55
116
  function isCimplifyError(error) {
56
117
  return error instanceof CimplifyError;
57
118
  }
119
+ function getErrorHint(code) {
120
+ return ERROR_HINTS[code];
121
+ }
122
+ function enrichError(error, options = {}) {
123
+ const hint = getErrorHint(error.code);
124
+ if (hint) {
125
+ if (!error.docs_url) {
126
+ error.docs_url = hint.docs_url;
127
+ }
128
+ if (!error.suggestion) {
129
+ error.suggestion = hint.suggestion;
130
+ }
131
+ } else if (!error.docs_url) {
132
+ error.docs_url = docsUrlForCode(error.code || ErrorCode.UNKNOWN_ERROR);
133
+ }
134
+ if (options.isTestMode && !error.message.includes("pk_test_")) {
135
+ error.message = `${error.message}
136
+
137
+ \u2139 Your API key is a test-mode key (pk_test_...). Verify test data/session before retrying.`;
138
+ }
139
+ return error;
140
+ }
58
141
  function isRetryableError(error) {
59
142
  if (isCimplifyError(error)) {
60
143
  return error.retryable;
@@ -138,11 +221,11 @@ function combineObject(results) {
138
221
 
139
222
  // src/catalogue.ts
140
223
  function toCimplifyError(error) {
141
- if (error instanceof CimplifyError) return error;
224
+ if (error instanceof CimplifyError) return enrichError(error);
142
225
  if (error instanceof Error) {
143
- return new CimplifyError("UNKNOWN_ERROR", error.message, false);
226
+ return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
144
227
  }
145
- return new CimplifyError("UNKNOWN_ERROR", String(error), false);
228
+ return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
146
229
  }
147
230
  async function safe(promise) {
148
231
  try {
@@ -437,11 +520,11 @@ var CatalogueQueries = class {
437
520
 
438
521
  // src/cart.ts
439
522
  function toCimplifyError2(error) {
440
- if (error instanceof CimplifyError) return error;
523
+ if (error instanceof CimplifyError) return enrichError(error);
441
524
  if (error instanceof Error) {
442
- return new CimplifyError("UNKNOWN_ERROR", error.message, false);
525
+ return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
443
526
  }
444
- return new CimplifyError("UNKNOWN_ERROR", String(error), false);
527
+ return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
445
528
  }
446
529
  async function safe2(promise) {
447
530
  try {
@@ -1656,11 +1739,11 @@ var CheckoutResolver = class {
1656
1739
 
1657
1740
  // src/checkout.ts
1658
1741
  function toCimplifyError3(error) {
1659
- if (error instanceof CimplifyError) return error;
1742
+ if (error instanceof CimplifyError) return enrichError(error);
1660
1743
  if (error instanceof Error) {
1661
- return new CimplifyError("UNKNOWN_ERROR", error.message, false);
1744
+ return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
1662
1745
  }
1663
- return new CimplifyError("UNKNOWN_ERROR", String(error), false);
1746
+ return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
1664
1747
  }
1665
1748
  async function safe3(promise) {
1666
1749
  try {
@@ -1836,11 +1919,11 @@ var CheckoutService = class {
1836
1919
 
1837
1920
  // src/orders.ts
1838
1921
  function toCimplifyError4(error) {
1839
- if (error instanceof CimplifyError) return error;
1922
+ if (error instanceof CimplifyError) return enrichError(error);
1840
1923
  if (error instanceof Error) {
1841
- return new CimplifyError("UNKNOWN_ERROR", error.message, false);
1924
+ return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
1842
1925
  }
1843
- return new CimplifyError("UNKNOWN_ERROR", String(error), false);
1926
+ return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
1844
1927
  }
1845
1928
  async function safe4(promise) {
1846
1929
  try {
@@ -2097,11 +2180,11 @@ var AuthService = class {
2097
2180
 
2098
2181
  // src/business.ts
2099
2182
  function toCimplifyError7(error) {
2100
- if (error instanceof CimplifyError) return error;
2183
+ if (error instanceof CimplifyError) return enrichError(error);
2101
2184
  if (error instanceof Error) {
2102
- return new CimplifyError("UNKNOWN_ERROR", error.message, false);
2185
+ return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
2103
2186
  }
2104
- return new CimplifyError("UNKNOWN_ERROR", String(error), false);
2187
+ return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
2105
2188
  }
2106
2189
  async function safe7(promise) {
2107
2190
  try {
@@ -2487,12 +2570,15 @@ var EVENT_TYPES = {
2487
2570
 
2488
2571
  // src/elements.ts
2489
2572
  function toCheckoutError(code, message, recoverable) {
2573
+ const hint = getErrorHint(code);
2490
2574
  return {
2491
2575
  success: false,
2492
2576
  error: {
2493
2577
  code,
2494
2578
  message,
2495
- recoverable
2579
+ recoverable,
2580
+ docs_url: hint?.docs_url,
2581
+ suggestion: hint?.suggestion
2496
2582
  }
2497
2583
  };
2498
2584
  }
@@ -2533,6 +2619,7 @@ var CimplifyElements = class {
2533
2619
  this.paymentData = null;
2534
2620
  this.checkoutInProgress = false;
2535
2621
  this.activeCheckoutAbort = null;
2622
+ this.hasWarnedMissingAuthElement = false;
2536
2623
  this.businessIdResolvePromise = null;
2537
2624
  this.client = client;
2538
2625
  this.businessId = businessId ?? null;
@@ -2628,6 +2715,12 @@ var CimplifyElements = class {
2628
2715
  );
2629
2716
  }
2630
2717
  const authElement = this.elements.get(ELEMENT_TYPES.AUTH);
2718
+ if (!authElement && !this.hasWarnedMissingAuthElement) {
2719
+ this.hasWarnedMissingAuthElement = true;
2720
+ console.warn(
2721
+ "[Cimplify] processCheckout() called without AuthElement mounted. For best conversion and Link enrollment, mount <AuthElement> before checkout."
2722
+ );
2723
+ }
2631
2724
  if (authElement && !this.accessToken) {
2632
2725
  return toCheckoutError(
2633
2726
  "AUTH_INCOMPLETE",
@@ -3064,28 +3157,37 @@ function isRetryable(error) {
3064
3157
  }
3065
3158
  return false;
3066
3159
  }
3067
- function toNetworkError(error) {
3160
+ function toNetworkError(error, isTestMode) {
3068
3161
  if (error instanceof DOMException && error.name === "AbortError") {
3069
- return new CimplifyError(
3070
- ErrorCode.TIMEOUT,
3071
- "Request timed out. Please check your connection and try again.",
3072
- true
3162
+ return enrichError(
3163
+ new CimplifyError(
3164
+ ErrorCode.TIMEOUT,
3165
+ "Request timed out. Please check your connection and try again.",
3166
+ true
3167
+ ),
3168
+ { isTestMode }
3073
3169
  );
3074
3170
  }
3075
3171
  if (error instanceof TypeError && error.message.includes("fetch")) {
3076
- return new CimplifyError(
3077
- ErrorCode.NETWORK_ERROR,
3078
- "Network error. Please check your internet connection.",
3079
- true
3172
+ return enrichError(
3173
+ new CimplifyError(
3174
+ ErrorCode.NETWORK_ERROR,
3175
+ "Network error. Please check your internet connection.",
3176
+ true
3177
+ ),
3178
+ { isTestMode }
3080
3179
  );
3081
3180
  }
3082
3181
  if (error instanceof CimplifyError) {
3083
- return error;
3084
- }
3085
- return new CimplifyError(
3086
- ErrorCode.UNKNOWN_ERROR,
3087
- error instanceof Error ? error.message : "An unknown error occurred",
3088
- false
3182
+ return enrichError(error, { isTestMode });
3183
+ }
3184
+ return enrichError(
3185
+ new CimplifyError(
3186
+ ErrorCode.UNKNOWN_ERROR,
3187
+ error instanceof Error ? error.message : "An unknown error occurred",
3188
+ false
3189
+ ),
3190
+ { isTestMode }
3089
3191
  );
3090
3192
  }
3091
3193
  function deriveUrls() {
@@ -3147,6 +3249,9 @@ var CimplifyClient = class {
3147
3249
  getPublicKey() {
3148
3250
  return this.publicKey;
3149
3251
  }
3252
+ isTestMode() {
3253
+ return this.publicKey.trim().startsWith("pk_test_");
3254
+ }
3150
3255
  setAccessToken(token) {
3151
3256
  const previous = this.accessToken;
3152
3257
  this.accessToken = token;
@@ -3296,7 +3401,7 @@ var CimplifyClient = class {
3296
3401
  return response;
3297
3402
  } catch (error) {
3298
3403
  lastError = error;
3299
- const networkError = toNetworkError(error);
3404
+ const networkError = toNetworkError(error, this.isTestMode());
3300
3405
  const errorRetryable = isRetryable(error);
3301
3406
  if (!errorRetryable || attempt >= this.maxRetries) {
3302
3407
  this.hooks.onRequestError?.({
@@ -3319,7 +3424,7 @@ var CimplifyClient = class {
3319
3424
  await sleep(delay);
3320
3425
  }
3321
3426
  }
3322
- const finalError = toNetworkError(lastError);
3427
+ const finalError = toNetworkError(lastError, this.isTestMode());
3323
3428
  this.hooks.onRequestError?.({
3324
3429
  ...context,
3325
3430
  error: finalError,
@@ -3437,22 +3542,40 @@ var CimplifyClient = class {
3437
3542
  async handleRestResponse(response) {
3438
3543
  const json = await response.json();
3439
3544
  if (!response.ok) {
3440
- throw new CimplifyError(
3441
- json.error?.error_code || "API_ERROR",
3442
- json.error?.error_message || "An error occurred",
3443
- false
3545
+ const error = enrichError(
3546
+ new CimplifyError(
3547
+ json.error?.error_code || "API_ERROR",
3548
+ json.error?.error_message || "An error occurred",
3549
+ false
3550
+ ),
3551
+ { isTestMode: this.isTestMode() }
3444
3552
  );
3553
+ if (response.status === 401 || error.code === ErrorCode.UNAUTHORIZED) {
3554
+ console.warn(
3555
+ "[Cimplify] Received 401 Unauthorized. Access token may be missing/expired. Refresh authentication and retry the request."
3556
+ );
3557
+ }
3558
+ throw error;
3445
3559
  }
3446
3560
  return json.data;
3447
3561
  }
3448
3562
  async handleResponse(response) {
3449
3563
  const json = await response.json();
3450
3564
  if (!json.success || json.error) {
3451
- throw new CimplifyError(
3452
- json.error?.code || "UNKNOWN_ERROR",
3453
- json.error?.message || "An unknown error occurred",
3454
- json.error?.retryable || false
3565
+ const error = enrichError(
3566
+ new CimplifyError(
3567
+ json.error?.code || "UNKNOWN_ERROR",
3568
+ json.error?.message || "An unknown error occurred",
3569
+ json.error?.retryable || false
3570
+ ),
3571
+ { isTestMode: this.isTestMode() }
3455
3572
  );
3573
+ if (response.status === 401 || error.code === ErrorCode.UNAUTHORIZED) {
3574
+ console.warn(
3575
+ "[Cimplify] Received 401 Unauthorized. Access token may be missing/expired. Refresh authentication and retry the request."
3576
+ );
3577
+ }
3578
+ throw error;
3456
3579
  }
3457
3580
  return json.data;
3458
3581
  }
@@ -3633,6 +3756,7 @@ exports.DEFAULT_COUNTRY = DEFAULT_COUNTRY;
3633
3756
  exports.DEFAULT_CURRENCY = DEFAULT_CURRENCY;
3634
3757
  exports.DEVICE_TYPE = DEVICE_TYPE;
3635
3758
  exports.ELEMENT_TYPES = ELEMENT_TYPES;
3759
+ exports.ERROR_HINTS = ERROR_HINTS;
3636
3760
  exports.EVENT_TYPES = EVENT_TYPES;
3637
3761
  exports.ErrorCode = ErrorCode;
3638
3762
  exports.FxService = FxService;
@@ -3659,6 +3783,7 @@ exports.combineObject = combineObject;
3659
3783
  exports.createCimplifyClient = createCimplifyClient;
3660
3784
  exports.createElements = createElements;
3661
3785
  exports.detectMobileMoneyProvider = detectMobileMoneyProvider;
3786
+ exports.enrichError = enrichError;
3662
3787
  exports.err = err;
3663
3788
  exports.flatMap = flatMap;
3664
3789
  exports.formatMoney = formatMoney;
@@ -3673,6 +3798,7 @@ exports.getBasePrice = getBasePrice;
3673
3798
  exports.getCurrencySymbol = getCurrencySymbol;
3674
3799
  exports.getDiscountPercentage = getDiscountPercentage;
3675
3800
  exports.getDisplayPrice = getDisplayPrice;
3801
+ exports.getErrorHint = getErrorHint;
3676
3802
  exports.getMarkupPercentage = getMarkupPercentage;
3677
3803
  exports.getOrElse = getOrElse;
3678
3804
  exports.getProductCurrency = getProductCurrency;