@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 CHANGED
@@ -142,6 +142,25 @@ if (isOnSale(product)) {
142
142
  }
143
143
  ```
144
144
 
145
+ ### Type-Safe Money
146
+
147
+ All monetary values use the branded `Money` type: string at runtime, distinct from
148
+ plain `string` at compile time.
149
+
150
+ ```typescript
151
+ import { money, type Money } from "@cimplify/sdk";
152
+
153
+ const price = money("29.99");
154
+ const zero = money("0.00");
155
+
156
+ parseFloat(price); // 29.99
157
+ console.log(price); // "29.99"
158
+
159
+ // Compile-time safety:
160
+ // const bad: Money = "29.99"; // Error
161
+ // const bad2: Money = "coffee"; // Error
162
+ ```
163
+
145
164
  ## Error Handling
146
165
 
147
166
  ```typescript
@@ -1,5 +1,5 @@
1
- export { A as AuthService, B as BusinessService, i as CartOperations, b as CatalogueQueries, j as CheckoutOperations, j as CheckoutService, v as CimplifyElement, u as CimplifyElements, x as ELEMENT_TYPES, E as EVENT_TYPES, H as ElementEventType, z as ElementOptions, D as ElementType, y as ElementsOptions, F as FetchQuoteInput, r as FxService, G as GetProductsOptions, I as InventoryService, L as LinkService, q as LiteService, M as MESSAGE_TYPES, O as OrderQueries, P as PriceQuote, d as QuoteBundleSelectionInput, Q as QuoteCompositeSelectionInput, f as QuoteDynamicBuckets, e as QuoteStatus, g as QuoteUiMessage, R as RefreshQuoteInput, h as RefreshQuoteResult, p as SchedulingService, S as SearchOptions, w as createElements, k as generateIdempotencyKey } from './client-CUFdFugo.mjs';
2
- import './payment-D-u3asA8.mjs';
1
+ export { A as AuthService, B as BusinessService, i as CartOperations, b as CatalogueQueries, j as CheckoutOperations, j as CheckoutService, v as CimplifyElement, u as CimplifyElements, x as ELEMENT_TYPES, E as EVENT_TYPES, H as ElementEventType, z as ElementOptions, D as ElementType, y as ElementsOptions, F as FetchQuoteInput, r as FxService, G as GetProductsOptions, I as InventoryService, L as LinkService, q as LiteService, M as MESSAGE_TYPES, O as OrderQueries, P as PriceQuote, d as QuoteBundleSelectionInput, Q as QuoteCompositeSelectionInput, f as QuoteDynamicBuckets, e as QuoteStatus, g as QuoteUiMessage, R as RefreshQuoteInput, h as RefreshQuoteResult, p as SchedulingService, S as SearchOptions, w as createElements, k as generateIdempotencyKey } from './client-FQUyv41r.mjs';
2
+ import './payment-Cu75tmUc.mjs';
3
3
 
4
4
  type Operator = "==" | "!=" | ">" | "<" | ">=" | "<=" | "contains" | "startsWith";
5
5
  type SortOrder = "asc" | "desc";
@@ -1,5 +1,5 @@
1
- export { A as AuthService, B as BusinessService, i as CartOperations, b as CatalogueQueries, j as CheckoutOperations, j as CheckoutService, v as CimplifyElement, u as CimplifyElements, x as ELEMENT_TYPES, E as EVENT_TYPES, H as ElementEventType, z as ElementOptions, D as ElementType, y as ElementsOptions, F as FetchQuoteInput, r as FxService, G as GetProductsOptions, I as InventoryService, L as LinkService, q as LiteService, M as MESSAGE_TYPES, O as OrderQueries, P as PriceQuote, d as QuoteBundleSelectionInput, Q as QuoteCompositeSelectionInput, f as QuoteDynamicBuckets, e as QuoteStatus, g as QuoteUiMessage, R as RefreshQuoteInput, h as RefreshQuoteResult, p as SchedulingService, S as SearchOptions, w as createElements, k as generateIdempotencyKey } from './client-CjqNbEM6.js';
2
- import './payment-D-u3asA8.js';
1
+ export { A as AuthService, B as BusinessService, i as CartOperations, b as CatalogueQueries, j as CheckoutOperations, j as CheckoutService, v as CimplifyElement, u as CimplifyElements, x as ELEMENT_TYPES, E as EVENT_TYPES, H as ElementEventType, z as ElementOptions, D as ElementType, y as ElementsOptions, F as FetchQuoteInput, r as FxService, G as GetProductsOptions, I as InventoryService, L as LinkService, q as LiteService, M as MESSAGE_TYPES, O as OrderQueries, P as PriceQuote, d as QuoteBundleSelectionInput, Q as QuoteCompositeSelectionInput, f as QuoteDynamicBuckets, e as QuoteStatus, g as QuoteUiMessage, R as RefreshQuoteInput, h as RefreshQuoteResult, p as SchedulingService, S as SearchOptions, w as createElements, k as generateIdempotencyKey } from './client-D4vA6FY_.js';
2
+ import './payment-Cu75tmUc.js';
3
3
 
4
4
  type Operator = "==" | "!=" | ">" | "<" | ">=" | "<=" | "contains" | "startsWith";
5
5
  type SortOrder = "asc" | "desc";
package/dist/advanced.js CHANGED
@@ -9,11 +9,84 @@ function err(error) {
9
9
  }
10
10
 
11
11
  // src/types/common.ts
12
+ function money(value) {
13
+ return value;
14
+ }
15
+ function moneyFromNumber(value) {
16
+ return value.toFixed(2);
17
+ }
18
+ function currencyCode(value) {
19
+ return value;
20
+ }
21
+ var ErrorCode = {
22
+ // General
23
+ UNKNOWN_ERROR: "UNKNOWN_ERROR"};
24
+ var DOCS_ERROR_BASE_URL = "https://docs.cimplify.io/reference/error-codes";
25
+ function docsUrlForCode(code) {
26
+ return `${DOCS_ERROR_BASE_URL}#${code.toLowerCase().replace(/_/g, "-")}`;
27
+ }
28
+ var ERROR_SUGGESTIONS = {
29
+ UNKNOWN_ERROR: "An unexpected error occurred. Capture the request/response payload and retry with exponential backoff.",
30
+ NETWORK_ERROR: "Check the shopper's connection and retry. If this persists, inspect CORS, DNS, and API reachability.",
31
+ TIMEOUT: "The request exceeded the timeout. Retry once, then poll order status before charging again.",
32
+ UNAUTHORIZED: "Authentication is missing or expired. Ensure a valid access token is set and refresh the session if needed.",
33
+ FORBIDDEN: "The key/session lacks permission for this resource. Verify business ownership and API key scope.",
34
+ NOT_FOUND: "The requested resource does not exist or is not visible in this environment.",
35
+ VALIDATION_ERROR: "One or more fields are invalid. Validate required fields and enum values before retrying.",
36
+ CART_EMPTY: "The cart has no items. Redirect back to menu/catalogue and require at least one line item.",
37
+ CART_EXPIRED: "This cart is no longer active. Recreate a new cart and re-add shopper selections.",
38
+ CART_NOT_FOUND: "Cart could not be located. It may have expired or belongs to a different key/location.",
39
+ ITEM_UNAVAILABLE: "The selected item is unavailable at this location/time. Prompt the shopper to pick an alternative.",
40
+ VARIANT_NOT_FOUND: "The requested variant no longer exists. Refresh product data and require re-selection.",
41
+ VARIANT_OUT_OF_STOCK: "The selected variant is out of stock. Show in-stock variants and block checkout for this line.",
42
+ ADDON_REQUIRED: "A required add-on is missing. Ensure required modifier groups are completed before add-to-cart.",
43
+ ADDON_MAX_EXCEEDED: "Too many add-ons were selected. Enforce max selections client-side before submission.",
44
+ CHECKOUT_VALIDATION_FAILED: "Checkout payload failed validation. Verify customer, order type, and address fields are complete.",
45
+ DELIVERY_ADDRESS_REQUIRED: "Delivery orders require an address. Collect and pass address info before processing checkout.",
46
+ CUSTOMER_INFO_REQUIRED: "Customer details are required. Ensure name/email/phone are available before checkout.",
47
+ PAYMENT_FAILED: "Payment provider rejected or failed processing. Show retry/change-method options to the shopper.",
48
+ PAYMENT_CANCELLED: "Payment was cancelled by the shopper or provider flow. Allow a safe retry path.",
49
+ INSUFFICIENT_FUNDS: "Payment method has insufficient funds. Prompt shopper to use another method.",
50
+ CARD_DECLINED: "Card was declined. Ask shopper to retry or switch payment method.",
51
+ INVALID_OTP: "Authorization code is invalid. Let shopper re-enter OTP/PIN and retry.",
52
+ OTP_EXPIRED: "Authorization code expired. Request a new OTP and re-submit authorization.",
53
+ AUTHORIZATION_FAILED: "Additional payment authorization failed. Retry authorization or change payment method.",
54
+ PAYMENT_ACTION_NOT_COMPLETED: "Required payment action was not completed. Resume provider flow and poll for status.",
55
+ SLOT_UNAVAILABLE: "Selected schedule slot is unavailable. Refresh available slots and ask shopper to reselect.",
56
+ BOOKING_CONFLICT: "The requested booking conflicts with an existing reservation. Pick another slot/resource.",
57
+ SERVICE_NOT_FOUND: "Requested service no longer exists. Refresh service catalogue and retry selection.",
58
+ OUT_OF_STOCK: "Inventory is depleted for this item. Remove it or reduce quantity before checkout.",
59
+ INSUFFICIENT_QUANTITY: "Requested quantity exceeds available inventory. Reduce quantity and retry.",
60
+ BUSINESS_ID_REQUIRED: "Business context could not be resolved. Verify the public key and business bootstrap call.",
61
+ INVALID_CART: "Cart is invalid for checkout. Sync cart state, ensure items exist, then retry.",
62
+ ORDER_TYPE_REQUIRED: "Order type is required. Provide one of delivery, pickup, or dine_in before checkout.",
63
+ NO_PAYMENT_ELEMENT: "PaymentElement is required for processCheckout(). Mount it before triggering checkout.",
64
+ PAYMENT_NOT_MOUNTED: "PaymentElement iframe is not mounted. Mount it in the DOM before processCheckout().",
65
+ AUTH_INCOMPLETE: "AuthElement has not completed authentication. Wait for AUTHENTICATED before checkout.",
66
+ AUTH_LOST: "Session was cleared during checkout. Re-authenticate and restart checkout safely.",
67
+ ALREADY_PROCESSING: "Checkout is already in progress. Disable duplicate submits until completion.",
68
+ CHECKOUT_NOT_READY: "Checkout elements are still initializing. Wait for readiness before submit.",
69
+ CANCELLED: "Checkout was cancelled. Preserve cart state and allow shopper to retry.",
70
+ REQUEST_TIMEOUT: "Provider call timed out. Poll payment/order status before issuing another charge attempt.",
71
+ POPUP_BLOCKED: "Browser blocked provider popup. Ask shopper to enable popups and retry.",
72
+ FX_QUOTE_FAILED: "Failed to lock FX quote. Retry currency quote or fallback to base currency."
73
+ };
74
+ var ERROR_HINTS = Object.fromEntries(
75
+ Object.entries(ERROR_SUGGESTIONS).map(([code, suggestion]) => [
76
+ code,
77
+ {
78
+ docs_url: docsUrlForCode(code),
79
+ suggestion
80
+ }
81
+ ])
82
+ );
12
83
  var CimplifyError = class extends Error {
13
- constructor(code, message, retryable = false) {
84
+ constructor(code, message, retryable = false, docs_url, suggestion) {
14
85
  super(message);
15
86
  this.code = code;
16
87
  this.retryable = retryable;
88
+ this.docs_url = docs_url;
89
+ this.suggestion = suggestion;
17
90
  this.name = "CimplifyError";
18
91
  }
19
92
  /** User-friendly message safe to display */
@@ -21,14 +94,104 @@ var CimplifyError = class extends Error {
21
94
  return this.message;
22
95
  }
23
96
  };
97
+ function getErrorHint(code) {
98
+ return ERROR_HINTS[code];
99
+ }
100
+ function enrichError(error, options = {}) {
101
+ const hint = getErrorHint(error.code);
102
+ if (hint) {
103
+ if (!error.docs_url) {
104
+ error.docs_url = hint.docs_url;
105
+ }
106
+ if (!error.suggestion) {
107
+ error.suggestion = hint.suggestion;
108
+ }
109
+ } else if (!error.docs_url) {
110
+ error.docs_url = docsUrlForCode(error.code || ErrorCode.UNKNOWN_ERROR);
111
+ }
112
+ if (options.isTestMode && !error.message.includes("pk_test_")) {
113
+ error.message = `${error.message}
114
+
115
+ \u2139 Your API key is a test-mode key (pk_test_...). Verify test data/session before retrying.`;
116
+ }
117
+ return error;
118
+ }
119
+
120
+ // src/query/builder.ts
121
+ function escapeQueryValue(value) {
122
+ return value.replace(/'/g, "\\'");
123
+ }
124
+ var QueryBuilder = class {
125
+ constructor(entity) {
126
+ this.filters = [];
127
+ this.modifiers = [];
128
+ this.pathSegments = [];
129
+ this.entity = entity;
130
+ }
131
+ path(segment) {
132
+ this.pathSegments.push(segment);
133
+ return this;
134
+ }
135
+ where(field, op, value) {
136
+ const v = typeof value === "string" ? `'${escapeQueryValue(value)}'` : value;
137
+ if (op === "contains" || op === "startsWith") {
138
+ this.filters.push(`@.${field} ${op} ${v}`);
139
+ } else {
140
+ this.filters.push(`@.${field}${op}${v}`);
141
+ }
142
+ return this;
143
+ }
144
+ and(field, op, value) {
145
+ return this.where(field, op, value);
146
+ }
147
+ sort(field, order = "asc") {
148
+ this.modifiers.push(`sort(${field},${order})`);
149
+ return this;
150
+ }
151
+ limit(n) {
152
+ this.modifiers.push(`limit(${n})`);
153
+ return this;
154
+ }
155
+ offset(n) {
156
+ this.modifiers.push(`offset(${n})`);
157
+ return this;
158
+ }
159
+ count() {
160
+ this.modifiers.push("count");
161
+ return this;
162
+ }
163
+ enriched() {
164
+ this.modifiers.push("enriched");
165
+ return this;
166
+ }
167
+ build() {
168
+ let query2 = this.entity;
169
+ if (this.pathSegments.length > 0) {
170
+ query2 += "." + this.pathSegments.join(".");
171
+ }
172
+ if (this.filters.length > 0) {
173
+ query2 += `[?(${this.filters.join(" && ")})]`;
174
+ }
175
+ for (const mod of this.modifiers) {
176
+ query2 += `#${mod}`;
177
+ }
178
+ return query2;
179
+ }
180
+ toString() {
181
+ return this.build();
182
+ }
183
+ };
184
+ function query(entity) {
185
+ return new QueryBuilder(entity);
186
+ }
24
187
 
25
188
  // src/catalogue.ts
26
189
  function toCimplifyError(error) {
27
- if (error instanceof CimplifyError) return error;
190
+ if (error instanceof CimplifyError) return enrichError(error);
28
191
  if (error instanceof Error) {
29
- return new CimplifyError("UNKNOWN_ERROR", error.message, false);
192
+ return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
30
193
  }
31
- return new CimplifyError("UNKNOWN_ERROR", String(error), false);
194
+ return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
32
195
  }
33
196
  async function safe(promise) {
34
197
  try {
@@ -102,7 +265,7 @@ var CatalogueQueries = class {
102
265
  let query2 = "products";
103
266
  const filters = [];
104
267
  if (options?.category) {
105
- filters.push(`@.category_id=='${options.category}'`);
268
+ filters.push(`@.category_id=='${escapeQueryValue(options.category)}'`);
106
269
  }
107
270
  if (options?.featured !== void 0) {
108
271
  filters.push(`@.featured==${options.featured}`);
@@ -111,7 +274,7 @@ var CatalogueQueries = class {
111
274
  filters.push(`@.in_stock==${options.in_stock}`);
112
275
  }
113
276
  if (options?.search) {
114
- filters.push(`@.name contains '${options.search}'`);
277
+ filters.push(`@.name contains '${escapeQueryValue(options.search)}'`);
115
278
  }
116
279
  if (options?.min_price !== void 0) {
117
280
  filters.push(`@.price>=${options.min_price}`);
@@ -142,7 +305,9 @@ var CatalogueQueries = class {
142
305
  }
143
306
  async getProductBySlug(slug) {
144
307
  const filteredResult = await safe(
145
- this.client.query(`products[?(@.slug=='${slug}')]`)
308
+ this.client.query(
309
+ `products[?(@.slug=='${escapeQueryValue(slug)}')]`
310
+ )
146
311
  );
147
312
  if (!filteredResult.ok) return filteredResult;
148
313
  const exactMatch = findProductBySlug(filteredResult.value, slug);
@@ -194,7 +359,7 @@ var CatalogueQueries = class {
194
359
  }
195
360
  async getCategoryBySlug(slug) {
196
361
  const result = await safe(
197
- this.client.query(`categories[?(@.slug=='${slug}')]`)
362
+ this.client.query(`categories[?(@.slug=='${escapeQueryValue(slug)}')]`)
198
363
  );
199
364
  if (!result.ok) return result;
200
365
  if (!result.value.length) {
@@ -203,7 +368,11 @@ var CatalogueQueries = class {
203
368
  return ok(result.value[0]);
204
369
  }
205
370
  async getCategoryProducts(categoryId) {
206
- return safe(this.client.query(`products[?(@.category_id=='${categoryId}')]`));
371
+ return safe(
372
+ this.client.query(
373
+ `products[?(@.category_id=='${escapeQueryValue(categoryId)}')]`
374
+ )
375
+ );
207
376
  }
208
377
  async getCollections() {
209
378
  return safe(this.client.query("collections"));
@@ -213,7 +382,9 @@ var CatalogueQueries = class {
213
382
  }
214
383
  async getCollectionBySlug(slug) {
215
384
  const result = await safe(
216
- this.client.query(`collections[?(@.slug=='${slug}')]`)
385
+ this.client.query(
386
+ `collections[?(@.slug=='${escapeQueryValue(slug)}')]`
387
+ )
217
388
  );
218
389
  if (!result.ok) return result;
219
390
  if (!result.value.length) {
@@ -226,7 +397,9 @@ var CatalogueQueries = class {
226
397
  }
227
398
  async searchCollections(query2, limit = 20) {
228
399
  return safe(
229
- this.client.query(`collections[?(@.name contains '${query2}')]#limit(${limit})`)
400
+ this.client.query(
401
+ `collections[?(@.name contains '${escapeQueryValue(query2)}')]#limit(${limit})`
402
+ )
230
403
  );
231
404
  }
232
405
  async getBundles() {
@@ -237,7 +410,9 @@ var CatalogueQueries = class {
237
410
  }
238
411
  async getBundleBySlug(slug) {
239
412
  const result = await safe(
240
- this.client.query(`bundles[?(@.slug=='${slug}')]`)
413
+ this.client.query(
414
+ `bundles[?(@.slug=='${escapeQueryValue(slug)}')]`
415
+ )
241
416
  );
242
417
  if (!result.ok) return result;
243
418
  if (!result.value.length) {
@@ -247,7 +422,9 @@ var CatalogueQueries = class {
247
422
  }
248
423
  async searchBundles(query2, limit = 20) {
249
424
  return safe(
250
- this.client.query(`bundles[?(@.name contains '${query2}')]#limit(${limit})`)
425
+ this.client.query(
426
+ `bundles[?(@.name contains '${escapeQueryValue(query2)}')]#limit(${limit})`
427
+ )
251
428
  );
252
429
  }
253
430
  async getComposites(options) {
@@ -287,9 +464,9 @@ var CatalogueQueries = class {
287
464
  }
288
465
  async search(query2, options) {
289
466
  const limit = options?.limit ?? 20;
290
- let searchQuery = `products[?(@.name contains '${query2}')]`;
467
+ let searchQuery = `products[?(@.name contains '${escapeQueryValue(query2)}')]`;
291
468
  if (options?.category) {
292
- searchQuery = `products[?(@.name contains '${query2}' && @.category_id=='${options.category}')]`;
469
+ searchQuery = `products[?(@.name contains '${escapeQueryValue(query2)}' && @.category_id=='${escapeQueryValue(options.category)}')]`;
293
470
  }
294
471
  searchQuery += `#limit(${limit})`;
295
472
  return safe(this.client.query(searchQuery));
@@ -306,7 +483,7 @@ var CatalogueQueries = class {
306
483
  async getMenu(options) {
307
484
  let query2 = "menu";
308
485
  if (options?.category) {
309
- query2 = `menu[?(@.category=='${options.category}')]`;
486
+ query2 = `menu[?(@.category=='${escapeQueryValue(options.category)}')]`;
310
487
  }
311
488
  if (options?.limit) {
312
489
  query2 += `#limit(${options.limit})`;
@@ -323,11 +500,11 @@ var CatalogueQueries = class {
323
500
 
324
501
  // src/cart.ts
325
502
  function toCimplifyError2(error) {
326
- if (error instanceof CimplifyError) return error;
503
+ if (error instanceof CimplifyError) return enrichError(error);
327
504
  if (error instanceof Error) {
328
- return new CimplifyError("UNKNOWN_ERROR", error.message, false);
505
+ return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
329
506
  }
330
- return new CimplifyError("UNKNOWN_ERROR", String(error), false);
507
+ return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
331
508
  }
332
509
  async function safe2(promise) {
333
510
  try {
@@ -587,6 +764,8 @@ function normalizeStatusResponse(response) {
587
764
  }
588
765
  const res = response;
589
766
  const normalizedStatus = normalizePaymentStatusValue(res.status ?? void 0);
767
+ const normalizedAmount = typeof res.amount === "string" ? money(res.amount) : typeof res.amount === "number" && Number.isFinite(res.amount) ? moneyFromNumber(res.amount) : void 0;
768
+ const normalizedCurrency = typeof res.currency === "string" && res.currency.trim().length > 0 ? currencyCode(res.currency) : void 0;
590
769
  const paidValue = res.paid === true;
591
770
  const derivedPaid = paidValue || [
592
771
  "success",
@@ -599,8 +778,8 @@ function normalizeStatusResponse(response) {
599
778
  return {
600
779
  status: normalizedStatus,
601
780
  paid: derivedPaid,
602
- amount: res.amount,
603
- currency: res.currency,
781
+ amount: normalizedAmount,
782
+ currency: normalizedCurrency,
604
783
  reference: res.reference,
605
784
  message: res.message || ""
606
785
  };
@@ -1166,11 +1345,11 @@ var CheckoutResolver = class {
1166
1345
 
1167
1346
  // src/checkout.ts
1168
1347
  function toCimplifyError3(error) {
1169
- if (error instanceof CimplifyError) return error;
1348
+ if (error instanceof CimplifyError) return enrichError(error);
1170
1349
  if (error instanceof Error) {
1171
- return new CimplifyError("UNKNOWN_ERROR", error.message, false);
1350
+ return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
1172
1351
  }
1173
- return new CimplifyError("UNKNOWN_ERROR", String(error), false);
1352
+ return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
1174
1353
  }
1175
1354
  async function safe3(promise) {
1176
1355
  try {
@@ -1292,14 +1471,17 @@ var CheckoutService = class {
1292
1471
  pay_currency: data.pay_currency,
1293
1472
  fx_quote_id: data.fx_quote_id
1294
1473
  };
1295
- const baseCurrency = (cart.pricing.currency || checkoutData.pay_currency || "GHS").toUpperCase();
1474
+ const baseCurrency = currencyCode(
1475
+ (cart.pricing.currency || checkoutData.pay_currency || "GHS").toUpperCase()
1476
+ );
1296
1477
  const payCurrency = data.pay_currency?.trim().toUpperCase();
1478
+ const payCurrencyCode = payCurrency ? currencyCode(payCurrency) : void 0;
1297
1479
  const cartTotalAmount = Number.parseFloat(cart.pricing.total_price || "0");
1298
- if (payCurrency && payCurrency !== baseCurrency && !checkoutData.fx_quote_id && Number.isFinite(cartTotalAmount) && cartTotalAmount > 0) {
1480
+ if (payCurrencyCode && payCurrencyCode !== baseCurrency && !checkoutData.fx_quote_id && Number.isFinite(cartTotalAmount) && cartTotalAmount > 0) {
1299
1481
  const fxQuoteResult = await this.client.fx.lockQuote({
1300
1482
  from: baseCurrency,
1301
- to: payCurrency,
1302
- amount: cartTotalAmount
1483
+ to: payCurrencyCode,
1484
+ amount: cart.pricing.total_price
1303
1485
  });
1304
1486
  if (!fxQuoteResult.ok) {
1305
1487
  return ok(
@@ -1310,7 +1492,7 @@ var CheckoutService = class {
1310
1492
  )
1311
1493
  );
1312
1494
  }
1313
- checkoutData.pay_currency = payCurrency;
1495
+ checkoutData.pay_currency = payCurrencyCode;
1314
1496
  checkoutData.fx_quote_id = fxQuoteResult.value.id;
1315
1497
  }
1316
1498
  data.on_status_change?.("processing", {});
@@ -1346,11 +1528,11 @@ var CheckoutService = class {
1346
1528
 
1347
1529
  // src/orders.ts
1348
1530
  function toCimplifyError4(error) {
1349
- if (error instanceof CimplifyError) return error;
1531
+ if (error instanceof CimplifyError) return enrichError(error);
1350
1532
  if (error instanceof Error) {
1351
- return new CimplifyError("UNKNOWN_ERROR", error.message, false);
1533
+ return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
1352
1534
  }
1353
- return new CimplifyError("UNKNOWN_ERROR", String(error), false);
1535
+ return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
1354
1536
  }
1355
1537
  async function safe4(promise) {
1356
1538
  try {
@@ -1607,11 +1789,11 @@ var AuthService = class {
1607
1789
 
1608
1790
  // src/business.ts
1609
1791
  function toCimplifyError7(error) {
1610
- if (error instanceof CimplifyError) return error;
1792
+ if (error instanceof CimplifyError) return enrichError(error);
1611
1793
  if (error instanceof Error) {
1612
- return new CimplifyError("UNKNOWN_ERROR", error.message, false);
1794
+ return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
1613
1795
  }
1614
- return new CimplifyError("UNKNOWN_ERROR", String(error), false);
1796
+ return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
1615
1797
  }
1616
1798
  async function safe7(promise) {
1617
1799
  try {
@@ -1997,12 +2179,15 @@ var EVENT_TYPES = {
1997
2179
 
1998
2180
  // src/elements.ts
1999
2181
  function toCheckoutError(code, message, recoverable) {
2182
+ const hint = getErrorHint(code);
2000
2183
  return {
2001
2184
  success: false,
2002
2185
  error: {
2003
2186
  code,
2004
2187
  message,
2005
- recoverable
2188
+ recoverable,
2189
+ docs_url: hint?.docs_url,
2190
+ suggestion: hint?.suggestion
2006
2191
  }
2007
2192
  };
2008
2193
  }
@@ -2043,6 +2228,7 @@ var CimplifyElements = class {
2043
2228
  this.paymentData = null;
2044
2229
  this.checkoutInProgress = false;
2045
2230
  this.activeCheckoutAbort = null;
2231
+ this.hasWarnedMissingAuthElement = false;
2046
2232
  this.businessIdResolvePromise = null;
2047
2233
  this.client = client;
2048
2234
  this.businessId = businessId ?? null;
@@ -2138,6 +2324,12 @@ var CimplifyElements = class {
2138
2324
  );
2139
2325
  }
2140
2326
  const authElement = this.elements.get(ELEMENT_TYPES.AUTH);
2327
+ if (!authElement && !this.hasWarnedMissingAuthElement) {
2328
+ this.hasWarnedMissingAuthElement = true;
2329
+ console.warn(
2330
+ "[Cimplify] processCheckout() called without AuthElement mounted. For best conversion and Link enrollment, mount <AuthElement> before checkout."
2331
+ );
2332
+ }
2141
2333
  if (authElement && !this.accessToken) {
2142
2334
  return toCheckoutError(
2143
2335
  "AUTH_INCOMPLETE",
@@ -2551,71 +2743,6 @@ function createElements(client, businessId, options) {
2551
2743
  return new CimplifyElements(client, businessId, options);
2552
2744
  }
2553
2745
 
2554
- // src/query/builder.ts
2555
- var QueryBuilder = class {
2556
- constructor(entity) {
2557
- this.filters = [];
2558
- this.modifiers = [];
2559
- this.pathSegments = [];
2560
- this.entity = entity;
2561
- }
2562
- path(segment) {
2563
- this.pathSegments.push(segment);
2564
- return this;
2565
- }
2566
- where(field, op, value) {
2567
- const v = typeof value === "string" ? `'${value}'` : value;
2568
- if (op === "contains" || op === "startsWith") {
2569
- this.filters.push(`@.${field} ${op} ${v}`);
2570
- } else {
2571
- this.filters.push(`@.${field}${op}${v}`);
2572
- }
2573
- return this;
2574
- }
2575
- and(field, op, value) {
2576
- return this.where(field, op, value);
2577
- }
2578
- sort(field, order = "asc") {
2579
- this.modifiers.push(`sort(${field},${order})`);
2580
- return this;
2581
- }
2582
- limit(n) {
2583
- this.modifiers.push(`limit(${n})`);
2584
- return this;
2585
- }
2586
- offset(n) {
2587
- this.modifiers.push(`offset(${n})`);
2588
- return this;
2589
- }
2590
- count() {
2591
- this.modifiers.push("count");
2592
- return this;
2593
- }
2594
- enriched() {
2595
- this.modifiers.push("enriched");
2596
- return this;
2597
- }
2598
- build() {
2599
- let query2 = this.entity;
2600
- if (this.pathSegments.length > 0) {
2601
- query2 += "." + this.pathSegments.join(".");
2602
- }
2603
- if (this.filters.length > 0) {
2604
- query2 += `[?(${this.filters.join(" && ")})]`;
2605
- }
2606
- for (const mod of this.modifiers) {
2607
- query2 += `#${mod}`;
2608
- }
2609
- return query2;
2610
- }
2611
- toString() {
2612
- return this.build();
2613
- }
2614
- };
2615
- function query(entity) {
2616
- return new QueryBuilder(entity);
2617
- }
2618
-
2619
2746
  exports.AuthService = AuthService;
2620
2747
  exports.BusinessService = BusinessService;
2621
2748
  exports.CartOperations = CartOperations;