@cimplify/sdk 0.16.3 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4425 +1,406 @@
1
1
  'use strict';
2
2
 
3
- var libphonenumberJs = require('libphonenumber-js');
3
+ var chunkOITG2SEN_js = require('./chunk-OITG2SEN.js');
4
+ var chunkS6TU55KP_js = require('./chunk-S6TU55KP.js');
5
+ var chunkFLPI2VVJ_js = require('./chunk-FLPI2VVJ.js');
6
+ var chunkREPTMTQ4_js = require('./chunk-REPTMTQ4.js');
7
+ var chunkJ65U5SED_js = require('./chunk-J65U5SED.js');
4
8
 
5
- // src/types/common.ts
6
- function money(value) {
7
- return typeof value === "string" ? parseFloat(value) || 0 : value;
8
- }
9
- function moneyFromNumber(value) {
10
- return value;
11
- }
12
- var ZERO = 0;
13
- var SUPPORTED_CURRENCY_CODES = /* @__PURE__ */ new Set([
14
- "USD",
15
- "EUR",
16
- "GBP",
17
- "JPY",
18
- "CNY",
19
- "CHF",
20
- "CAD",
21
- "AUD",
22
- "GHS",
23
- "NGN",
24
- "KES",
25
- "ZAR",
26
- "XOF",
27
- "XAF",
28
- "EGP",
29
- "TZS",
30
- "UGX",
31
- "RWF",
32
- "ETB",
33
- "ZMW",
34
- "BWP",
35
- "MUR",
36
- "NAD",
37
- "MWK",
38
- "AOA",
39
- "CDF",
40
- "GMD",
41
- "GNF",
42
- "LRD",
43
- "SLL",
44
- "MZN",
45
- "BIF",
46
- "INR",
47
- "BRL",
48
- "MXN",
49
- "KRW",
50
- "TRY",
51
- "THB",
52
- "MYR",
53
- "PHP",
54
- "IDR",
55
- "VND",
56
- "SGD",
57
- "HKD",
58
- "TWD",
59
- "AED",
60
- "SAR",
61
- "ILS"
62
- ]);
63
- function isSupportedCurrency(code) {
64
- return SUPPORTED_CURRENCY_CODES.has(code);
65
- }
66
- function currencyCode(value) {
67
- return value;
68
- }
69
- var ErrorCode = {
70
- UNKNOWN_ERROR: "UNKNOWN_ERROR",
71
- NETWORK_ERROR: "NETWORK_ERROR",
72
- TIMEOUT: "TIMEOUT",
73
- UNAUTHORIZED: "UNAUTHORIZED",
74
- FORBIDDEN: "FORBIDDEN",
75
- NOT_FOUND: "NOT_FOUND",
76
- VALIDATION_ERROR: "VALIDATION_ERROR",
77
- CART_EMPTY: "CART_EMPTY",
78
- CART_EXPIRED: "CART_EXPIRED",
79
- CART_NOT_FOUND: "CART_NOT_FOUND",
80
- ITEM_UNAVAILABLE: "ITEM_UNAVAILABLE",
81
- VARIANT_NOT_FOUND: "VARIANT_NOT_FOUND",
82
- VARIANT_OUT_OF_STOCK: "VARIANT_OUT_OF_STOCK",
83
- ADDON_REQUIRED: "ADDON_REQUIRED",
84
- ADDON_MAX_EXCEEDED: "ADDON_MAX_EXCEEDED",
85
- CHECKOUT_VALIDATION_FAILED: "CHECKOUT_VALIDATION_FAILED",
86
- DELIVERY_ADDRESS_REQUIRED: "DELIVERY_ADDRESS_REQUIRED",
87
- CUSTOMER_INFO_REQUIRED: "CUSTOMER_INFO_REQUIRED",
88
- QUOTE_NOT_FOUND: "QUOTE_NOT_FOUND",
89
- QUOTE_EXPIRED: "QUOTE_EXPIRED",
90
- QUOTE_CONSUMED: "QUOTE_CONSUMED",
91
- QUOTE_STORAGE_UNAVAILABLE: "QUOTE_STORAGE_UNAVAILABLE",
92
- PAYMENT_FAILED: "PAYMENT_FAILED",
93
- PAYMENT_CANCELLED: "PAYMENT_CANCELLED",
94
- INSUFFICIENT_FUNDS: "INSUFFICIENT_FUNDS",
95
- CARD_DECLINED: "CARD_DECLINED",
96
- INVALID_OTP: "INVALID_OTP",
97
- OTP_EXPIRED: "OTP_EXPIRED",
98
- AUTHORIZATION_FAILED: "AUTHORIZATION_FAILED",
99
- PAYMENT_ACTION_NOT_COMPLETED: "PAYMENT_ACTION_NOT_COMPLETED",
100
- SLOT_UNAVAILABLE: "SLOT_UNAVAILABLE",
101
- BOOKING_CONFLICT: "BOOKING_CONFLICT",
102
- SERVICE_NOT_FOUND: "SERVICE_NOT_FOUND",
103
- OUT_OF_STOCK: "OUT_OF_STOCK",
104
- INSUFFICIENT_QUANTITY: "INSUFFICIENT_QUANTITY"
105
- };
106
- var DOCS_ERROR_BASE_URL = "https://docs.cimplify.io/reference/error-codes";
107
- function docsUrlForCode(code) {
108
- return `${DOCS_ERROR_BASE_URL}#${code.toLowerCase().replace(/_/g, "-")}`;
109
- }
110
- var ERROR_SUGGESTIONS = {
111
- UNKNOWN_ERROR: "An unexpected error occurred. Capture the request/response payload and retry with exponential backoff.",
112
- NETWORK_ERROR: "Check the shopper's connection and retry. If this persists, inspect CORS, DNS, and API reachability.",
113
- TIMEOUT: "The request exceeded the timeout. Retry once, then poll order status before charging again.",
114
- UNAUTHORIZED: "Authentication is missing or expired. Ensure a valid access token is set and refresh the session if needed.",
115
- FORBIDDEN: "The key/session lacks permission for this resource. Verify business ownership and API key scope.",
116
- NOT_FOUND: "The requested resource does not exist or is not visible in this environment.",
117
- VALIDATION_ERROR: "One or more fields are invalid. Validate required fields and enum values before retrying.",
118
- CART_EMPTY: "The cart has no items. Redirect back to menu/catalogue and require at least one line item.",
119
- CART_EXPIRED: "This cart is no longer active. Recreate a new cart and re-add shopper selections.",
120
- CART_NOT_FOUND: "Cart could not be located. It may have expired or belongs to a different key/location.",
121
- ITEM_UNAVAILABLE: "The selected item is unavailable at this location/time. Prompt the shopper to pick an alternative.",
122
- VARIANT_NOT_FOUND: "The requested variant no longer exists. Refresh product data and require re-selection.",
123
- VARIANT_OUT_OF_STOCK: "The selected variant is out of stock. Show in-stock variants and block checkout for this line.",
124
- ADDON_REQUIRED: "A required add-on is missing. Ensure required modifier groups are completed before add-to-cart.",
125
- ADDON_MAX_EXCEEDED: "Too many add-ons were selected. Enforce max selections client-side before submission.",
126
- CHECKOUT_VALIDATION_FAILED: "Checkout payload failed validation. Verify customer, order type, and address fields are complete.",
127
- DELIVERY_ADDRESS_REQUIRED: "Delivery orders require an address. Collect and pass address info before processing checkout.",
128
- CUSTOMER_INFO_REQUIRED: "Customer details are required. Ensure name/email/phone are available before checkout.",
129
- QUOTE_NOT_FOUND: "Quote could not be found. Refresh pricing and create a new quote before checkout.",
130
- QUOTE_EXPIRED: "Quote has expired. Re-fetch pricing to generate a new quote with a valid expiry window.",
131
- QUOTE_CONSUMED: "Quote has already been used. Request a fresh quote to prevent duplicate checkout attempts.",
132
- QUOTE_STORAGE_UNAVAILABLE: "Quote storage is temporarily unavailable. Retry shortly and avoid charging until quote fetch succeeds.",
133
- PAYMENT_FAILED: "Payment provider rejected or failed processing. Show retry/change-method options to the shopper.",
134
- PAYMENT_CANCELLED: "Payment was cancelled by the shopper or provider flow. Allow a safe retry path.",
135
- INSUFFICIENT_FUNDS: "Payment method has insufficient funds. Prompt shopper to use another method.",
136
- CARD_DECLINED: "Card was declined. Ask shopper to retry or switch payment method.",
137
- INVALID_OTP: "Authorization code is invalid. Let shopper re-enter OTP/PIN and retry.",
138
- OTP_EXPIRED: "Authorization code expired. Request a new OTP and re-submit authorization.",
139
- AUTHORIZATION_FAILED: "Additional payment authorization failed. Retry authorization or change payment method.",
140
- PAYMENT_ACTION_NOT_COMPLETED: "Required payment action was not completed. Resume provider flow and poll for status.",
141
- SLOT_UNAVAILABLE: "Selected schedule slot is unavailable. Refresh available slots and ask shopper to reselect.",
142
- BOOKING_CONFLICT: "The requested booking conflicts with an existing reservation. Pick another slot/resource.",
143
- SERVICE_NOT_FOUND: "Requested service no longer exists. Refresh service catalogue and retry selection.",
144
- OUT_OF_STOCK: "Inventory is depleted for this item. Remove it or reduce quantity before checkout.",
145
- INSUFFICIENT_QUANTITY: "Requested quantity exceeds available inventory. Reduce quantity and retry.",
146
- BUSINESS_ID_REQUIRED: "Business context could not be resolved. Verify the public key and business bootstrap call.",
147
- INVALID_CART: "Cart is invalid for checkout. Sync cart state, ensure items exist, then retry.",
148
- ORDER_TYPE_REQUIRED: "Order type is required. Provide one of delivery, pickup, or dine_in before checkout.",
149
- NO_PAYMENT_ELEMENT: "PaymentElement is required for processCheckout(). Mount it before triggering checkout.",
150
- PAYMENT_NOT_MOUNTED: "PaymentElement iframe is not mounted. Mount it in the DOM before processCheckout().",
151
- AUTH_INCOMPLETE: "AuthElement has not completed authentication. Wait for AUTHENTICATED before checkout.",
152
- AUTH_LOST: "Session was cleared during checkout. Re-authenticate and restart checkout safely.",
153
- ALREADY_PROCESSING: "Checkout is already in progress. Disable duplicate submits until completion.",
154
- CHECKOUT_NOT_READY: "Checkout elements are still initializing. Wait for readiness before submit.",
155
- CANCELLED: "Checkout was cancelled. Preserve cart state and allow shopper to retry.",
156
- REQUEST_TIMEOUT: "Provider call timed out. Poll payment/order status before issuing another charge attempt.",
157
- POPUP_BLOCKED: "Browser blocked provider popup. Ask shopper to enable popups and retry.",
158
- FX_QUOTE_FAILED: "Failed to lock FX quote. Retry currency quote or fallback to base currency."
159
- };
160
- var ERROR_HINTS = Object.fromEntries(
161
- Object.entries(ERROR_SUGGESTIONS).map(([code, suggestion]) => [
162
- code,
163
- {
164
- docs_url: docsUrlForCode(code),
165
- suggestion
166
- }
167
- ])
168
- );
169
- var CimplifyError = class extends Error {
170
- constructor(code, message, retryable = false, docs_url, suggestion) {
171
- super(message);
172
- this.code = code;
173
- this.retryable = retryable;
174
- this.docs_url = docs_url;
175
- this.suggestion = suggestion;
176
- this.name = "CimplifyError";
177
- }
178
- get userMessage() {
179
- return this.message;
180
- }
181
- };
182
- function isCimplifyError(error) {
183
- return error instanceof CimplifyError;
184
- }
185
- function getErrorHint(code) {
186
- return ERROR_HINTS[code];
187
- }
188
- function enrichError(error, options = {}) {
189
- const hint = getErrorHint(error.code);
190
- if (hint) {
191
- if (!error.docs_url) {
192
- error.docs_url = hint.docs_url;
193
- }
194
- if (!error.suggestion) {
195
- error.suggestion = hint.suggestion;
196
- }
197
- } else if (!error.docs_url) {
198
- error.docs_url = docsUrlForCode(error.code || ErrorCode.UNKNOWN_ERROR);
199
- }
200
- if (options.isTestMode && !error.message.includes("pk_test_")) {
201
- error.message = `${error.message}
202
9
 
203
- \u2139 Your API key is a test-mode key (pk_test_...). Verify test data/session before retrying.`;
204
- }
205
- return error;
206
- }
207
- function isRetryableError(error) {
208
- if (isCimplifyError(error)) {
209
- return error.retryable;
210
- }
211
- if (error instanceof Error) {
212
- const msg = error.message.toLowerCase();
213
- return msg.includes("network") || msg.includes("timeout") || msg.includes("fetch");
214
- }
215
- return false;
216
- }
217
10
 
218
- // src/types/result.ts
219
- function ok(value) {
220
- return { ok: true, value };
221
- }
222
- function err(error) {
223
- return { ok: false, error };
224
- }
225
- function isOk(result) {
226
- return result.ok === true;
227
- }
228
- function isErr(result) {
229
- return result.ok === false;
230
- }
231
- function mapResult(result, fn) {
232
- return result.ok ? ok(fn(result.value)) : result;
233
- }
234
- function mapError(result, fn) {
235
- return result.ok ? result : err(fn(result.error));
236
- }
237
- function flatMap(result, fn) {
238
- return result.ok ? fn(result.value) : result;
239
- }
240
- function getOrElse(result, defaultFn) {
241
- return result.ok ? result.value : defaultFn();
242
- }
243
- function unwrap(result) {
244
- if (result.ok) {
245
- return result.value;
246
- }
247
- throw result.error;
248
- }
249
- function toNullable(result) {
250
- return result.ok ? result.value : void 0;
251
- }
252
- async function fromPromise(promise, mapError2) {
253
- try {
254
- const value = await promise;
255
- return ok(value);
256
- } catch (error) {
257
- return err(mapError2(error));
258
- }
259
- }
260
- function tryCatch(fn, mapError2) {
261
- try {
262
- return ok(fn());
263
- } catch (error) {
264
- return err(mapError2(error));
265
- }
266
- }
267
- function combine(results) {
268
- const values = [];
269
- for (const result of results) {
270
- if (!result.ok) {
271
- return result;
272
- }
273
- values.push(result.value);
274
- }
275
- return ok(values);
276
- }
277
- function combineObject(results) {
278
- const values = {};
279
- for (const [key, result] of Object.entries(results)) {
280
- if (!result.ok) {
281
- return result;
282
- }
283
- values[key] = result.value;
284
- }
285
- return ok(values);
286
- }
287
-
288
- // src/internal/safe.ts
289
- function toCimplifyError(error) {
290
- if (error instanceof CimplifyError) return enrichError(error);
291
- if (error instanceof Error) {
292
- return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
293
- }
294
- return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
295
- }
296
- async function safe(promise) {
297
- try {
298
- return ok(await promise);
299
- } catch (error) {
300
- return err(toCimplifyError(error));
301
- }
302
- }
303
-
304
- // src/catalogue.ts
305
- function withQuery(path, params) {
306
- const query2 = new URLSearchParams();
307
- for (const [key, value] of Object.entries(params)) {
308
- if (value === void 0) continue;
309
- query2.set(key, String(value));
310
- }
311
- const queryString = query2.toString();
312
- return queryString ? `${path}?${queryString}` : path;
313
- }
314
- function isRecord(value) {
315
- return typeof value === "object" && value !== null;
316
- }
317
- function readFinalPrice(value) {
318
- if (!isRecord(value)) return void 0;
319
- const finalPrice = value.final_price;
320
- if (typeof finalPrice === "string" || typeof finalPrice === "number") {
321
- return finalPrice;
322
- }
323
- return void 0;
324
- }
325
- function normalizeAddOnPayload(addOn) {
326
- if (!isRecord(addOn)) return addOn;
327
- const normalizedAddOn = { ...addOn };
328
- const options = normalizedAddOn["options"];
329
- if (!Array.isArray(options)) return normalizedAddOn;
330
- normalizedAddOn["options"] = options.map((option) => {
331
- if (!isRecord(option)) return option;
332
- const normalizedOption = { ...option };
333
- const optionPrice = normalizedOption["default_price"];
334
- if (optionPrice === void 0 || optionPrice === null || optionPrice === "") {
335
- normalizedOption["default_price"] = readFinalPrice(normalizedOption["default_price_info"]) || readFinalPrice(normalizedOption["price_info"]) || "0";
336
- }
337
- return normalizedOption;
338
- });
339
- return normalizedAddOn;
340
- }
341
- function normalizeCatalogueProductPayload(product) {
342
- const normalized = { ...product };
343
- const defaultPrice = normalized["default_price"];
344
- if (defaultPrice === void 0 || defaultPrice === null || defaultPrice === "") {
345
- const derivedDefaultPrice = readFinalPrice(normalized["default_price_info"]) || readFinalPrice(normalized["price_info"]) || (typeof normalized["final_price"] === "string" || typeof normalized["final_price"] === "number" ? normalized["final_price"] : void 0);
346
- normalized["default_price"] = derivedDefaultPrice ?? "0";
347
- }
348
- const addOns = normalized["add_ons"];
349
- if (Array.isArray(addOns)) {
350
- normalized["add_ons"] = addOns.map((addOn) => normalizeAddOnPayload(addOn));
351
- }
352
- return normalized;
353
- }
354
- function toFiniteNumber(value) {
355
- if (typeof value === "number" && Number.isFinite(value)) {
356
- return value;
357
- }
358
- if (typeof value === "string" && value.trim().length > 0) {
359
- const parsed = Number(value);
360
- if (Number.isFinite(parsed)) {
361
- return parsed;
362
- }
363
- }
364
- return void 0;
365
- }
366
- function normalizePagination(value) {
367
- if (!isRecord(value)) {
368
- return void 0;
369
- }
370
- const totalCount = toFiniteNumber(value.total_count);
371
- const currentPage = toFiniteNumber(value.current_page);
372
- const pageSize = toFiniteNumber(value.page_size);
373
- const totalPages = toFiniteNumber(value.total_pages);
374
- if (totalCount === void 0 || currentPage === void 0 || pageSize === void 0 || totalPages === void 0) {
375
- return void 0;
376
- }
377
- return {
378
- total_count: totalCount,
379
- current_page: currentPage,
380
- page_size: pageSize,
381
- total_pages: totalPages,
382
- has_more: value.has_more === true,
383
- next_cursor: typeof value.next_cursor === "string" ? value.next_cursor : void 0
384
- };
385
- }
386
- function normalizeCatalogueResult(payload) {
387
- if (Array.isArray(payload)) {
388
- return {
389
- items: payload.map((product) => normalizeCatalogueProductPayload(product)),
390
- is_complete: true
391
- };
392
- }
393
- if (!isRecord(payload)) {
394
- return {
395
- items: [],
396
- is_complete: true
397
- };
398
- }
399
- const rawItems = Array.isArray(payload.products) ? payload.products : Array.isArray(payload.items) ? payload.items : [];
400
- return {
401
- items: rawItems.map((product) => normalizeCatalogueProductPayload(product)),
402
- is_complete: typeof payload.is_complete === "boolean" ? payload.is_complete : true,
403
- total_available: toFiniteNumber(payload.total_available),
404
- pagination: normalizePagination(payload.pagination)
405
- };
406
- }
407
- function normalizeCatalogueSnapshot(payload) {
408
- if (Array.isArray(payload)) {
409
- return {
410
- categories: [],
411
- products: payload.map((product) => normalizeCatalogueProductPayload(product)),
412
- add_ons: [],
413
- is_complete: true
414
- };
415
- }
416
- if (!isRecord(payload)) {
417
- return {
418
- categories: [],
419
- products: [],
420
- add_ons: [],
421
- is_complete: true
422
- };
423
- }
424
- const rawProducts = Array.isArray(payload.products) ? payload.products : Array.isArray(payload.items) ? payload.items : [];
425
- const rawCategories = Array.isArray(payload.categories) ? payload.categories : [];
426
- const rawAddOns = Array.isArray(payload.add_ons) ? payload.add_ons : [];
427
- return {
428
- categories: rawCategories,
429
- products: rawProducts.map((product) => normalizeCatalogueProductPayload(product)),
430
- add_ons: rawAddOns.map((addOn) => normalizeAddOnPayload(addOn)),
431
- is_complete: typeof payload.is_complete === "boolean" ? payload.is_complete : true,
432
- total_available: toFiniteNumber(payload.total_available),
433
- pagination: normalizePagination(payload.pagination)
434
- };
435
- }
436
- var CatalogueQueries = class {
437
- constructor(client) {
438
- this.client = client;
439
- }
440
- async getCatalogue() {
441
- const result = await safe(this.client.get("/api/v1/catalogue"));
442
- if (!result.ok) return result;
443
- return ok(normalizeCatalogueSnapshot(result.value));
444
- }
445
- async getProducts(options) {
446
- const path = withQuery("/api/v1/catalogue/products", {
447
- category_id: options?.category,
448
- taxonomy_id: options?.taxonomy,
449
- search: options?.search,
450
- page: options?.page,
451
- tags: options?.tags?.join(","),
452
- featured: options?.featured,
453
- in_stock: options?.in_stock,
454
- min_price: options?.min_price,
455
- max_price: options?.max_price,
456
- sort_by: options?.sort_by,
457
- sort_order: options?.sort_order,
458
- limit: options?.limit,
459
- offset: options?.offset,
460
- cursor: options?.cursor
461
- });
462
- const result = await safe(this.client.get(path));
463
- if (!result.ok) return result;
464
- return ok(normalizeCatalogueResult(result.value));
465
- }
466
- async getProduct(id) {
467
- const encodedId = encodeURIComponent(id);
468
- const result = await safe(this.client.get(`/api/v1/catalogue/products/${encodedId}`));
469
- if (!result.ok) return result;
470
- return ok(normalizeCatalogueProductPayload(result.value));
471
- }
472
- async getProductBySlug(slug) {
473
- const encodedSlug = encodeURIComponent(slug);
474
- const result = await safe(this.client.get(`/api/v1/catalogue/products/slug/${encodedSlug}`));
475
- if (!result.ok) return result;
476
- return ok(normalizeCatalogueProductPayload(result.value));
477
- }
478
- async getVariants(productId) {
479
- const encodedId = encodeURIComponent(productId);
480
- return safe(this.client.get(`/api/v1/catalogue/products/${encodedId}/variants`));
481
- }
482
- async getVariantAxes(productId) {
483
- const encodedId = encodeURIComponent(productId);
484
- return safe(this.client.get(`/api/v1/catalogue/products/${encodedId}/variant-axes`));
485
- }
486
- async getVariantByAxisSelections(productId, selections) {
487
- const encodedId = encodeURIComponent(productId);
488
- return safe(
489
- this.client.post(
490
- `/api/v1/catalogue/products/${encodedId}/variants/find`,
491
- { axis_selections: selections }
492
- )
493
- );
494
- }
495
- async getVariantById(productId, variantId) {
496
- const encodedProductId = encodeURIComponent(productId);
497
- const encodedVariantId = encodeURIComponent(variantId);
498
- return safe(
499
- this.client.get(
500
- `/api/v1/catalogue/products/${encodedProductId}/variants/${encodedVariantId}`
501
- )
502
- );
503
- }
504
- async getAddOns(productId) {
505
- const encodedId = encodeURIComponent(productId);
506
- return safe(this.client.get(`/api/v1/catalogue/products/${encodedId}/add-ons`));
507
- }
508
- async getCategories() {
509
- return safe(this.client.get("/api/v1/catalogue/categories"));
510
- }
511
- async getCategory(id) {
512
- const encodedId = encodeURIComponent(id);
513
- return safe(this.client.get(`/api/v1/catalogue/categories/${encodedId}`));
514
- }
515
- async getCategoryBySlug(slug) {
516
- const encodedSlug = encodeURIComponent(slug);
517
- return safe(this.client.get(`/api/v1/catalogue/categories/slug/${encodedSlug}`));
518
- }
519
- async getCategoryProducts(categoryId) {
520
- const encodedId = encodeURIComponent(categoryId);
521
- return safe(this.client.get(`/api/v1/catalogue/categories/${encodedId}/products`));
522
- }
523
- async getCollections() {
524
- return safe(this.client.get("/api/v1/catalogue/collections"));
525
- }
526
- async getCollection(id) {
527
- const encodedId = encodeURIComponent(id);
528
- return safe(this.client.get(`/api/v1/catalogue/collections/${encodedId}`));
529
- }
530
- async getCollectionBySlug(slug) {
531
- const encodedSlug = encodeURIComponent(slug);
532
- return safe(this.client.get(`/api/v1/catalogue/collections/slug/${encodedSlug}`));
533
- }
534
- async getCollectionProducts(collectionId) {
535
- const encodedId = encodeURIComponent(collectionId);
536
- return safe(this.client.get(`/api/v1/catalogue/collections/${encodedId}/products`));
537
- }
538
- async searchCollections(query2, limit = 20) {
539
- const path = withQuery("/api/v1/catalogue/collections", { search: query2, limit });
540
- return safe(this.client.get(path));
541
- }
542
- async getBundles() {
543
- return safe(this.client.get("/api/v1/catalogue/bundles"));
544
- }
545
- async searchBundles(query2, limit = 20) {
546
- const path = withQuery("/api/v1/catalogue/bundles", { search: query2, limit });
547
- return safe(this.client.get(path));
548
- }
549
- async getComposites(options) {
550
- const path = withQuery("/api/v1/catalogue/composites", { limit: options?.limit });
551
- return safe(this.client.get(path));
552
- }
553
- async calculateCompositePrice(compositeId, selections, locationId) {
554
- const encodedId = encodeURIComponent(compositeId);
555
- return safe(
556
- this.client.post(
557
- `/api/v1/catalogue/composites/${encodedId}/calculate-price`,
558
- {
559
- selections,
560
- location_id: locationId
561
- }
562
- )
563
- );
564
- }
565
- async fetchQuote(input) {
566
- return safe(this.client.post("/api/v1/catalogue/quotes", input));
567
- }
568
- async getQuote(quoteId) {
569
- const encodedQuoteId = encodeURIComponent(quoteId);
570
- return safe(this.client.get(`/api/v1/catalogue/quotes/${encodedQuoteId}`));
571
- }
572
- async refreshQuote(input) {
573
- const encodedQuoteId = encodeURIComponent(input.quote_id);
574
- return safe(
575
- this.client.post(
576
- `/api/v1/catalogue/quotes/${encodedQuoteId}/refresh`,
577
- input
578
- )
579
- );
580
- }
581
- async getTaxonomies(parentId) {
582
- const path = withQuery("/api/v1/catalogue/taxonomies", { parent_id: parentId });
583
- return safe(this.client.get(path));
584
- }
585
- async getTaxonomy(id) {
586
- const encodedId = encodeURIComponent(id);
587
- return safe(this.client.get(`/api/v1/catalogue/taxonomies/${encodedId}`));
588
- }
589
- async getTaxonomyPath(id) {
590
- const encodedId = encodeURIComponent(id);
591
- return safe(this.client.get(`/api/v1/catalogue/taxonomies/${encodedId}/path`));
592
- }
593
- async searchTaxonomies(query2, limit) {
594
- const path = withQuery("/api/v1/catalogue/taxonomies/search", { q: query2, limit });
595
- return safe(this.client.get(path));
596
- }
597
- async getProductSchedules(productId) {
598
- const encodedId = encodeURIComponent(productId);
599
- return safe(this.client.get(`/api/v1/catalogue/products/${encodedId}/schedules`));
600
- }
601
- async checkProductAvailableNow(productId, locationId) {
602
- const encodedId = encodeURIComponent(productId);
603
- const path = withQuery(`/api/v1/catalogue/products/${encodedId}/available-now`, { location_id: locationId });
604
- return safe(this.client.get(path));
605
- }
606
- async getDeals(locationId) {
607
- const path = withQuery("/api/v1/catalogue/deals", { location_id: locationId });
608
- return safe(this.client.get(path));
609
- }
610
- async getProductsOnSale() {
611
- return safe(this.client.get("/api/v1/catalogue/deals/on-sale"));
612
- }
613
- async getProductDeals(productId) {
614
- const encodedId = encodeURIComponent(productId);
615
- return safe(this.client.get(`/api/v1/catalogue/products/${encodedId}/deals`));
616
- }
617
- async getCategoryDeals(categoryId) {
618
- const encodedId = encodeURIComponent(categoryId);
619
- return safe(this.client.get(`/api/v1/catalogue/categories/${encodedId}/deals`));
620
- }
621
- async getCollectionDeals(collectionId) {
622
- const encodedId = encodeURIComponent(collectionId);
623
- return safe(this.client.get(`/api/v1/catalogue/collections/${encodedId}/deals`));
624
- }
625
- async validateDiscountCode(code, orderSubtotal, locationId) {
626
- return safe(
627
- this.client.post("/api/v1/catalogue/deals/validate", {
628
- discount_code: code,
629
- order_subtotal: orderSubtotal,
630
- location_id: locationId
631
- })
632
- );
633
- }
634
- async search(query2, options) {
635
- const result = await this.getProducts({
636
- search: query2,
637
- category: options?.category,
638
- limit: options?.limit ?? 20
639
- });
640
- if (!result.ok) return result;
641
- return ok(result.value.items);
642
- }
643
- async searchProducts(query2, options) {
644
- return this.search(query2, options);
645
- }
646
- async getMenu(options) {
647
- const path = withQuery("/api/v1/catalogue/menu", {
648
- category_id: options?.category,
649
- limit: options?.limit
650
- });
651
- return safe(this.client.get(path));
652
- }
653
- async getMenuCategory(categoryId) {
654
- const encodedId = encodeURIComponent(categoryId);
655
- return safe(this.client.get(`/api/v1/catalogue/menu/categories/${encodedId}`));
656
- }
657
- async getMenuItem(itemId) {
658
- const encodedId = encodeURIComponent(itemId);
659
- return safe(this.client.get(`/api/v1/catalogue/menu/items/${encodedId}`));
660
- }
661
- async getTags(options) {
662
- const path = withQuery("/api/v1/catalogue/tags", {
663
- tag_group: options?.tag_group,
664
- search: options?.search,
665
- min_usage: options?.min_usage,
666
- limit: options?.limit,
667
- offset: options?.offset
668
- });
669
- return safe(this.client.get(path));
670
- }
671
- };
672
-
673
- // src/cart.ts
674
- function isUICartResponse(value) {
675
- return "cart" in value;
676
- }
677
- function unwrapEnrichedCart(value) {
678
- return isUICartResponse(value) ? value.cart : value;
679
- }
680
- var CartOperations = class {
681
- constructor(client) {
682
- this.client = client;
683
- }
684
- async get() {
685
- const result = await safe(this.client.get("/api/v1/cart"));
686
- if (!result.ok) return result;
687
- return ok(unwrapEnrichedCart(result.value));
688
- }
689
- async getRaw() {
690
- return safe(this.client.get("/api/v1/cart"));
691
- }
692
- async getItems() {
693
- return safe(this.client.get("/api/v1/cart/items"));
694
- }
695
- async getCount() {
696
- return safe(this.client.get("/api/v1/cart/count"));
697
- }
698
- async getTotal() {
699
- return safe(this.client.get("/api/v1/cart/total"));
700
- }
701
- async getSummary() {
702
- const cartResult = await this.get();
703
- if (!cartResult.ok) return cartResult;
704
- const cart = cartResult.value;
705
- return ok({
706
- item_count: cart.items.length,
707
- total_items: cart.items.reduce((sum, item) => sum + item.quantity, 0),
708
- subtotal: cart.pricing.subtotal,
709
- discount_amount: cart.pricing.total_discounts,
710
- tax_amount: cart.pricing.tax_amount,
711
- total: cart.pricing.total_price,
712
- currency: cart.pricing.currency
713
- });
714
- }
715
- async addItem(input) {
716
- return safe(this.client.post("/api/v1/cart/items", input));
717
- }
718
- async updateItem(cartItemId, updates) {
719
- if (typeof updates.quantity === "number") {
720
- return this.updateQuantity(cartItemId, updates.quantity);
721
- }
722
- const encodedId = encodeURIComponent(cartItemId);
723
- return safe(this.client.patch(`/api/v1/cart/items/${encodedId}`, updates));
724
- }
725
- async updateQuantity(cartItemId, quantity) {
726
- const encodedId = encodeURIComponent(cartItemId);
727
- return safe(
728
- this.client.patch(`/api/v1/cart/items/${encodedId}`, {
729
- quantity
730
- })
731
- );
732
- }
733
- async removeItem(cartItemId) {
734
- const encodedId = encodeURIComponent(cartItemId);
735
- return safe(this.client.delete(`/api/v1/cart/items/${encodedId}`));
736
- }
737
- async clear() {
738
- return safe(this.client.delete("/api/v1/cart"));
739
- }
740
- async applyCoupon(code) {
741
- return safe(
742
- this.client.post("/api/v1/cart/coupons", {
743
- coupon_code: code
744
- })
745
- );
746
- }
747
- async removeCoupon() {
748
- return safe(this.client.delete("/api/v1/cart/coupons/current"));
749
- }
750
- async isEmpty() {
751
- const countResult = await this.getCount();
752
- if (!countResult.ok) return countResult;
753
- return ok(countResult.value === 0);
754
- }
755
- async hasItem(productId, variantId) {
756
- const itemsResult = await this.getItems();
757
- if (!itemsResult.ok) return itemsResult;
758
- const found = itemsResult.value.some((item) => {
759
- const matchesProduct = item.item_id === productId;
760
- if (!variantId) return matchesProduct;
761
- const config = item.configuration;
762
- if ("variant" in config && config.variant) {
763
- return matchesProduct && config.variant.variant_id === variantId;
764
- }
765
- return matchesProduct;
766
- });
767
- return ok(found);
768
- }
769
- async findItem(productId, variantId) {
770
- const itemsResult = await this.getItems();
771
- if (!itemsResult.ok) return itemsResult;
772
- const found = itemsResult.value.find((item) => {
773
- const matchesProduct = item.item_id === productId;
774
- if (!variantId) return matchesProduct;
775
- const config = item.configuration;
776
- if ("variant" in config && config.variant) {
777
- return matchesProduct && config.variant.variant_id === variantId;
778
- }
779
- return matchesProduct;
780
- });
781
- return ok(found);
782
- }
783
- };
784
-
785
- // src/constants.ts
786
- var CHECKOUT_MODE = {
787
- LINK: "link",
788
- GUEST: "guest"
789
- };
790
- var ORDER_TYPE = {
791
- DELIVERY: "delivery",
792
- PICKUP: "pickup",
793
- DINE_IN: "dine-in",
794
- WALK_IN: "walk-in"
795
- };
796
- var PAYMENT_METHOD = {
797
- MOBILE_MONEY: "mobile_money",
798
- CARD: "card"
799
- };
800
- var CHECKOUT_STEP = {
801
- AUTHENTICATION: "authentication",
802
- ORDER_DETAILS: "order_details",
803
- PAYMENT_METHOD: "payment_method",
804
- PAYMENT: "payment",
805
- CONFIRMATION: "confirmation"
806
- };
807
- var PAYMENT_STATE = {
808
- INITIAL: "initial",
809
- PREPARING: "preparing",
810
- PROCESSING: "processing",
811
- VERIFYING: "verifying",
812
- AWAITING_AUTHORIZATION: "awaiting_authorization",
813
- SUCCESS: "success",
814
- ERROR: "error",
815
- TIMEOUT: "timeout"
816
- };
817
- var PICKUP_TIME_TYPE = {
818
- ASAP: "asap",
819
- SCHEDULED: "scheduled"
820
- };
821
- var MOBILE_MONEY_PROVIDER = {
822
- MTN: "mtn",
823
- VODAFONE: "vodafone",
824
- AIRTEL: "airtel"
825
- };
826
- var AUTHORIZATION_TYPE = {
827
- OTP: "otp",
828
- PIN: "pin",
829
- PHONE: "phone",
830
- BIRTHDAY: "birthday",
831
- ADDRESS: "address"
832
- };
833
- var DEVICE_TYPE = {
834
- MOBILE: "mobile",
835
- DESKTOP: "desktop",
836
- TABLET: "tablet"
837
- };
838
- var CONTACT_TYPE = {
839
- PHONE: "phone",
840
- EMAIL: "email"
841
- };
842
- var LINK_QUERY = {
843
- DATA: "link.data",
844
- ADDRESSES: "link.addresses",
845
- MOBILE_MONEY: "link.mobile_money",
846
- PREFERENCES: "link.preferences",
847
- SESSIONS: "link.sessions"
848
- };
849
- var LINK_MUTATION = {
850
- CHECK_STATUS: "link.check_status",
851
- ENROLL: "link.enroll",
852
- ENROLL_AND_LINK_ORDER: "link.enroll_and_link_order",
853
- UPDATE_PREFERENCES: "link.update_preferences",
854
- CREATE_ADDRESS: "link.create_address",
855
- UPDATE_ADDRESS: "link.update_address",
856
- DELETE_ADDRESS: "link.delete_address",
857
- SET_DEFAULT_ADDRESS: "link.set_default_address",
858
- TRACK_ADDRESS_USAGE: "link.track_address_usage",
859
- CREATE_MOBILE_MONEY: "link.create_mobile_money",
860
- DELETE_MOBILE_MONEY: "link.delete_mobile_money",
861
- SET_DEFAULT_MOBILE_MONEY: "link.set_default_mobile_money",
862
- TRACK_MOBILE_MONEY_USAGE: "link.track_mobile_money_usage",
863
- VERIFY_MOBILE_MONEY: "link.verify_mobile_money",
864
- REVOKE_SESSION: "link.revoke_session",
865
- REVOKE_ALL_SESSIONS: "link.revoke_all_sessions"
866
- };
867
- var AUTH_MUTATION = {
868
- REQUEST_OTP: "auth.request_otp",
869
- VERIFY_OTP: "auth.verify_otp"
870
- };
871
- var CHECKOUT_MUTATION = {
872
- PROCESS: "checkout.process"
873
- };
874
- var PAYMENT_MUTATION = {
875
- SUBMIT_AUTHORIZATION: "payment.submit_authorization",
876
- CHECK_STATUS: "order.poll_payment_status"
877
- };
878
- var ORDER_MUTATION = {
879
- UPDATE_CUSTOMER: "order.update_order_customer"
880
- };
881
- var DEFAULT_CURRENCY = "GHS";
882
- var DEFAULT_COUNTRY = "GHA";
883
-
884
- // src/utils/price.ts
885
- var CURRENCY_SYMBOLS = {
886
- USD: "$",
887
- EUR: "\u20AC",
888
- GBP: "\xA3",
889
- JPY: "\xA5",
890
- CNY: "\xA5",
891
- CHF: "CHF",
892
- CAD: "C$",
893
- AUD: "A$",
894
- NZD: "NZ$",
895
- HKD: "HK$",
896
- SGD: "S$",
897
- INR: "\u20B9",
898
- BRL: "R$",
899
- MXN: "MX$",
900
- KRW: "\u20A9",
901
- RUB: "\u20BD",
902
- TRY: "\u20BA",
903
- THB: "\u0E3F",
904
- PLN: "z\u0142",
905
- SEK: "kr",
906
- NOK: "kr",
907
- DKK: "kr",
908
- CZK: "K\u010D",
909
- HUF: "Ft",
910
- ILS: "\u20AA",
911
- AED: "\u062F.\u0625",
912
- SAR: "\uFDFC",
913
- MYR: "RM",
914
- PHP: "\u20B1",
915
- IDR: "Rp",
916
- VND: "\u20AB",
917
- TWD: "NT$",
918
- GHS: "GH\u20B5",
919
- NGN: "\u20A6",
920
- KES: "KSh",
921
- ZAR: "R",
922
- XOF: "CFA",
923
- XAF: "FCFA",
924
- EGP: "E\xA3",
925
- MAD: "MAD",
926
- TZS: "TSh",
927
- UGX: "USh",
928
- RWF: "FRw",
929
- ETB: "Br",
930
- ZMW: "ZK",
931
- BWP: "P",
932
- MUR: "\u20A8",
933
- SCR: "\u20A8",
934
- NAD: "N$",
935
- SZL: "E",
936
- LSL: "L",
937
- MWK: "MK",
938
- AOA: "Kz",
939
- CDF: "FC",
940
- GMD: "D",
941
- GNF: "FG",
942
- LRD: "L$",
943
- SLL: "Le",
944
- MZN: "MT",
945
- SDG: "SDG",
946
- SSP: "SSP",
947
- SOS: "Sh.So.",
948
- DJF: "Fdj",
949
- ERN: "Nfk",
950
- CVE: "$",
951
- STN: "Db",
952
- KMF: "CF",
953
- BIF: "FBu"
954
- };
955
- function getCurrencySymbol(currencyCode3) {
956
- return CURRENCY_SYMBOLS[currencyCode3.toUpperCase()] || currencyCode3;
957
- }
958
- function formatNumberCompact(value, decimals = 1) {
959
- const absValue = Math.abs(value);
960
- const sign = value < 0 ? "-" : "";
961
- if (absValue >= 1e9) {
962
- return `${sign}${(absValue / 1e9).toFixed(decimals)}B`;
963
- }
964
- if (absValue >= 1e6) {
965
- return `${sign}${(absValue / 1e6).toFixed(decimals)}M`;
966
- }
967
- if (absValue >= 1e3) {
968
- return `${sign}${(absValue / 1e3).toFixed(decimals)}K`;
969
- }
970
- return `${sign}${absValue.toFixed(decimals)}`;
971
- }
972
- function formatPrice(amount, currency = "GHS", locale = "en-US") {
973
- const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
974
- if (isNaN(numAmount)) {
975
- return `${getCurrencySymbol(currency)}0.00`;
976
- }
977
- try {
978
- return new Intl.NumberFormat(locale, {
979
- style: "currency",
980
- currency: currency.toUpperCase(),
981
- minimumFractionDigits: 2,
982
- maximumFractionDigits: 2
983
- }).format(numAmount);
984
- } catch {
985
- return `${getCurrencySymbol(currency)}${numAmount.toFixed(2)}`;
986
- }
987
- }
988
- function formatPriceAdjustment(amount, currency = "GHS", locale = "en-US") {
989
- const formatted = formatPrice(Math.abs(amount), currency, locale);
990
- if (amount > 0) {
991
- return `+${formatted}`;
992
- } else if (amount < 0) {
993
- return `-${formatted}`;
994
- }
995
- return formatted;
996
- }
997
- function formatPriceCompact(amount, currency = "GHS", decimals = 1) {
998
- const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
999
- if (isNaN(numAmount)) {
1000
- return `${getCurrencySymbol(currency)}0`;
1001
- }
1002
- const symbol = getCurrencySymbol(currency);
1003
- if (Math.abs(numAmount) < 1e3) {
1004
- return `${symbol}${numAmount.toFixed(2)}`;
1005
- }
1006
- return `${symbol}${formatNumberCompact(numAmount, decimals)}`;
1007
- }
1008
- function formatMoney(amount, currency = "GHS") {
1009
- const symbol = getCurrencySymbol(currency);
1010
- const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
1011
- if (isNaN(numAmount)) {
1012
- return `${symbol}0.00`;
1013
- }
1014
- return `${symbol}${numAmount.toFixed(2)}`;
1015
- }
1016
- function parsePrice(value) {
1017
- if (value === void 0 || value === null) {
1018
- return 0;
1019
- }
1020
- if (typeof value === "number") {
1021
- return isNaN(value) ? 0 : value;
1022
- }
1023
- const cleaned = value.replace(/[^\d.-]/g, "");
1024
- const parsed = parseFloat(cleaned);
1025
- return isNaN(parsed) ? 0 : parsed;
1026
- }
1027
- function hasTaxInfo(priceInfo) {
1028
- return priceInfo.tax_info !== void 0 && priceInfo.tax_info !== null;
1029
- }
1030
- function getTaxAmount(priceInfo) {
1031
- return parsePrice(priceInfo.tax_info?.tax_amount);
1032
- }
1033
- function isTaxInclusive(priceInfo) {
1034
- return priceInfo.tax_info?.is_inclusive === true;
1035
- }
1036
- function formatPriceWithTax(priceInfo, currency = "GHS") {
1037
- const finalPrice = formatPrice(priceInfo.final_price, currency);
1038
- if (!hasTaxInfo(priceInfo)) {
1039
- return finalPrice;
1040
- }
1041
- if (isTaxInclusive(priceInfo)) {
1042
- return `${finalPrice} (incl. tax)`;
1043
- }
1044
- return `${finalPrice} + ${formatPrice(getTaxAmount(priceInfo), currency)} tax`;
1045
- }
1046
- function getDisplayPrice(product) {
1047
- if (product.price_info) {
1048
- return parsePrice(product.price_info.final_price);
1049
- }
1050
- if (product.final_price !== void 0 && product.final_price !== null) {
1051
- return parsePrice(product.final_price);
1052
- }
1053
- if (product.default_price !== void 0 && product.default_price !== null) {
1054
- return parsePrice(product.default_price);
1055
- }
1056
- return 0;
1057
- }
1058
- function getBasePrice(product) {
1059
- if (product.price_info) {
1060
- return parsePrice(product.price_info.base_price);
1061
- }
1062
- if (product.base_price !== void 0 && product.base_price !== null) {
1063
- return parsePrice(product.base_price);
1064
- }
1065
- if (product.default_price !== void 0 && product.default_price !== null) {
1066
- return parsePrice(product.default_price);
1067
- }
1068
- return 0;
1069
- }
1070
- function isOnSale(product) {
1071
- const basePrice = getBasePrice(product);
1072
- const finalPrice = getDisplayPrice(product);
1073
- return basePrice > finalPrice && basePrice > 0;
1074
- }
1075
- function getDiscountPercentage(product) {
1076
- const basePrice = getBasePrice(product);
1077
- const finalPrice = getDisplayPrice(product);
1078
- if (basePrice > finalPrice && basePrice > 0) {
1079
- return Math.round((basePrice - finalPrice) / basePrice * 100);
1080
- }
1081
- return 0;
1082
- }
1083
- function getMarkupPercentage(product) {
1084
- const basePrice = getBasePrice(product);
1085
- const finalPrice = getDisplayPrice(product);
1086
- if (finalPrice > basePrice && basePrice > 0) {
1087
- return Math.round((finalPrice - basePrice) / basePrice * 100);
1088
- }
1089
- return 0;
1090
- }
1091
- function getProductCurrency(product) {
1092
- if (product.price_info?.currency) {
1093
- return product.price_info.currency;
1094
- }
1095
- if (product.currency) {
1096
- return product.currency;
1097
- }
1098
- return "GHS";
1099
- }
1100
- function formatProductPrice(product, locale = "en-US") {
1101
- const price = getDisplayPrice(product);
1102
- const currency = getProductCurrency(product);
1103
- return formatPrice(price, currency, locale);
1104
- }
1105
-
1106
- // src/utils/payment.ts
1107
- function categorizePaymentError(error, errorCode) {
1108
- let message = "An unexpected error occurred during payment processing. Please try again or contact support.";
1109
- let recoverable = true;
1110
- let code = errorCode || "PAYMENT_ERROR";
1111
- const technical = error.stack;
1112
- const errorMessage = error.message?.toLowerCase() || "";
1113
- if (errorCode === "INSUFFICIENT_FUNDS" || errorMessage.includes("insufficient") || errorMessage.includes("funds")) {
1114
- code = "INSUFFICIENT_FUNDS";
1115
- message = "Your payment method has insufficient funds. Please try another payment method.";
1116
- } else if (errorCode === "CARD_DECLINED" || errorMessage.includes("declined")) {
1117
- code = "CARD_DECLINED";
1118
- message = "Your card was declined. Please try another card or payment method.";
1119
- } else if (errorMessage.includes("cancelled") || errorMessage.includes("canceled") || errorCode === "PAYMENT_CANCELLED") {
1120
- code = "PAYMENT_CANCELLED";
1121
- message = "Payment was cancelled. You can try again when ready.";
1122
- } else if (errorMessage.includes("network") || errorMessage.includes("connection") || errorCode === "NETWORK_ERROR") {
1123
- code = "NETWORK_ERROR";
1124
- message = "Network connection issue. Please check your internet connection and try again.";
1125
- } else if (errorMessage.includes("timeout") || errorCode === "TIMEOUT") {
1126
- code = "TIMEOUT";
1127
- message = "Payment processing timed out. Please try again.";
1128
- } else if (errorCode === "PAYMENT_ACTION_NOT_COMPLETED") {
1129
- code = "PAYMENT_ACTION_NOT_COMPLETED";
1130
- message = "Payment action was not completed. Please try again.";
1131
- } else if (errorCode === "AUTHORIZATION_FAILED") {
1132
- code = "AUTHORIZATION_FAILED";
1133
- message = "Authorization failed. Please check your code and try again.";
1134
- } else if (errorCode === "INVALID_OTP") {
1135
- code = "INVALID_OTP";
1136
- message = "Invalid verification code. Please check and try again.";
1137
- }
1138
- return { code, message, recoverable, technical };
1139
- }
1140
- function isQuickPaymentResponse(response) {
1141
- return response !== null && typeof response === "object" && "payment" in response && typeof response.payment === "object";
1142
- }
1143
- function isWebPaymentResponse(response) {
1144
- return response !== null && typeof response === "object" && "transaction" in response && typeof response.transaction === "object";
1145
- }
1146
- function normalizePaymentResponse(response) {
1147
- if (!response) {
1148
- return {
1149
- method: "unknown",
1150
- provider: "unknown",
1151
- requires_action: false,
1152
- metadata: {}
1153
- };
1154
- }
1155
- if (isQuickPaymentResponse(response)) {
1156
- return {
1157
- method: response.payment.type?.toLowerCase() || "unknown",
1158
- provider: response.payment.provider?.toLowerCase() || "unknown",
1159
- requires_action: !!response.payment.redirect_url || !!response.payment.access_code,
1160
- public_key: response.payment.public_key,
1161
- client_secret: response.payment.access_code,
1162
- access_code: response.payment.access_code,
1163
- redirect_url: response.payment.redirect_url,
1164
- transaction_id: response.payment.reference,
1165
- order_id: response.order_id,
1166
- reference: response.payment.reference,
1167
- instructions: response.payment.instructions,
1168
- metadata: response.payment.metadata
1169
- };
1170
- }
1171
- if (isWebPaymentResponse(response)) {
1172
- const objectAuthType = response.authorization_type && typeof response.authorization_type === "object" && "address" in response.authorization_type ? "address" : void 0;
1173
- const authType = typeof response.authorization_type === "string" ? response.authorization_type.trim().toLowerCase().replace(/[\s-]+/g, "_") : void 0;
1174
- const validStringAuthTypes = ["otp", "pin", "phone", "birthday", "address"];
1175
- const safeAuthType = objectAuthType || (authType && validStringAuthTypes.includes(authType) ? authType : void 0);
1176
- return {
1177
- provider: response.transaction.provider_type?.toLowerCase() || "unknown",
1178
- requires_action: response.requires_action || false,
1179
- public_key: response.public_key,
1180
- client_secret: response.client_secret,
1181
- redirect_url: response.authorization_url,
1182
- transaction_id: response.transaction.id,
1183
- order_id: response.transaction.order_id,
1184
- reference: response.transaction.provider_reference,
1185
- metadata: response.transaction.metadata,
1186
- method: response.transaction.payment_method?.toLowerCase() || "unknown",
1187
- instructions: response.display_text,
1188
- display_text: response.display_text,
1189
- requires_authorization: response.requires_authorization,
1190
- authorization_type: safeAuthType,
1191
- provider_payment_id: response.provider_payment_id || response.transaction.provider_reference
1192
- };
1193
- }
1194
- return {
1195
- method: "unknown",
1196
- provider: "unknown",
1197
- requires_action: false,
1198
- metadata: {}
1199
- };
1200
- }
1201
- var PAYMENT_SUCCESS_STATUSES = /* @__PURE__ */ new Set([
1202
- "success",
1203
- "succeeded",
1204
- "paid",
1205
- "captured",
1206
- "completed",
1207
- "authorized"
1208
- ]);
1209
- var PAYMENT_FAILURE_STATUSES = /* @__PURE__ */ new Set([
1210
- "failed",
1211
- "declined",
1212
- "cancelled",
1213
- "voided",
1214
- "error",
1215
- "abandoned"
1216
- ]);
1217
- var PAYMENT_REQUIRES_ACTION_STATUSES = /* @__PURE__ */ new Set([
1218
- "requires_action",
1219
- "requires_payment_method",
1220
- "requires_capture"
1221
- ]);
1222
- var PAYMENT_STATUS_ALIAS_MAP = {
1223
- ok: "success",
1224
- done: "success",
1225
- paid: "paid",
1226
- paid_in_full: "paid",
1227
- paid_successfully: "paid",
1228
- succeeded: "success",
1229
- captured: "captured",
1230
- completed: "completed",
1231
- pending_confirmation: "pending_confirmation",
1232
- requires_authorization: "requires_action",
1233
- requires_action: "requires_action",
1234
- requires_payment_method: "requires_payment_method",
1235
- requires_capture: "requires_capture",
1236
- partially_paid: "partially_paid",
1237
- partially_refunded: "partially_refunded",
1238
- card_declined: "declined",
1239
- canceled: "cancelled",
1240
- authorized: "authorized",
1241
- cancelled: "cancelled",
1242
- unresolved: "pending"
1243
- };
1244
- var KNOWN_PAYMENT_STATUSES = /* @__PURE__ */ new Set([
1245
- "initialized",
1246
- "pending",
1247
- "processing",
1248
- "authorized",
1249
- "captured",
1250
- "failed",
1251
- "cancelled",
1252
- "refunded",
1253
- "unknown",
1254
- "voided",
1255
- "requires_action",
1256
- "abandoned",
1257
- "reversed",
1258
- "disputed",
1259
- "refund_pending",
1260
- "created",
1261
- "pending_confirmation",
1262
- "success",
1263
- "succeeded",
1264
- "declined",
1265
- "partially_refunded",
1266
- "partially_paid",
1267
- "paid",
1268
- "unpaid",
1269
- "requires_payment_method",
1270
- "requires_capture",
1271
- "completed",
1272
- "error"
1273
- ]);
1274
- function normalizeStatusToken(status) {
1275
- return status?.trim().toLowerCase().replace(/[\s-]+/g, "_") ?? "";
1276
- }
1277
- function normalizePaymentStatusValue(status) {
1278
- const normalized = normalizeStatusToken(status);
1279
- if (Object.prototype.hasOwnProperty.call(PAYMENT_STATUS_ALIAS_MAP, normalized)) {
1280
- return PAYMENT_STATUS_ALIAS_MAP[normalized];
1281
- }
1282
- return KNOWN_PAYMENT_STATUSES.has(normalized) ? normalized : "unknown";
1283
- }
1284
- function isPaymentStatusSuccess(status) {
1285
- const normalizedStatus = normalizePaymentStatusValue(status);
1286
- return PAYMENT_SUCCESS_STATUSES.has(normalizedStatus);
1287
- }
1288
- function isPaymentStatusFailure(status) {
1289
- const normalizedStatus = normalizePaymentStatusValue(status);
1290
- return PAYMENT_FAILURE_STATUSES.has(normalizedStatus);
1291
- }
1292
- function isPaymentStatusRequiresAction(status) {
1293
- const normalizedStatus = normalizePaymentStatusValue(status);
1294
- return PAYMENT_REQUIRES_ACTION_STATUSES.has(normalizedStatus);
1295
- }
1296
- function normalizeStatusResponse(response) {
1297
- if (!response || typeof response !== "object") {
1298
- return {
1299
- status: "pending",
1300
- paid: false,
1301
- amount: moneyFromNumber(0),
1302
- currency: "",
1303
- message: "No status available"
1304
- };
1305
- }
1306
- const res = response;
1307
- const normalizedStatus = normalizePaymentStatusValue(res.status ?? void 0);
1308
- const normalizedAmount = typeof res.amount === "string" ? money(res.amount) : typeof res.amount === "number" && Number.isFinite(res.amount) ? moneyFromNumber(res.amount) : moneyFromNumber(0);
1309
- const normalizedCurrency = typeof res.currency === "string" && res.currency.trim().length > 0 ? res.currency : "";
1310
- const paidValue = res.paid === true;
1311
- const derivedPaid = paidValue || [
1312
- "success",
1313
- "succeeded",
1314
- "paid",
1315
- "captured",
1316
- "authorized",
1317
- "completed"
1318
- ].includes(normalizedStatus);
1319
- return {
1320
- status: normalizedStatus,
1321
- paid: derivedPaid,
1322
- amount: normalizedAmount,
1323
- currency: normalizedCurrency,
1324
- reference: res.reference,
1325
- message: res.message || ""
1326
- };
1327
- }
1328
- var MOBILE_MONEY_PROVIDERS = {
1329
- mtn: { name: "MTN Mobile Money", prefix: ["024", "054", "055", "059"] },
1330
- vodafone: { name: "Vodafone Cash", prefix: ["020", "050"] },
1331
- airtel: { name: "AirtelTigo Money", prefix: ["027", "057", "026", "056"] }
1332
- };
1333
- function detectMobileMoneyProvider(phoneNumber) {
1334
- const cleaned = phoneNumber.replace(/\D/g, "");
1335
- const prefix = cleaned.slice(-9, -6);
1336
- for (const [provider, info] of Object.entries(MOBILE_MONEY_PROVIDERS)) {
1337
- if (info.prefix.some((p) => prefix.startsWith(p.slice(1)))) {
1338
- return provider;
1339
- }
1340
- }
1341
- return null;
1342
- }
1343
-
1344
- // src/utils/paystack.ts
1345
- async function openPaystackPopup(options, signal) {
1346
- if (typeof window === "undefined") {
1347
- return { success: false, error: "PROVIDER_UNAVAILABLE" };
1348
- }
1349
- let PaystackPop;
1350
- try {
1351
- const imported = await import('@paystack/inline-js');
1352
- PaystackPop = imported.default;
1353
- } catch {
1354
- return { success: false, error: "PROVIDER_UNAVAILABLE" };
1355
- }
1356
- return new Promise((resolve) => {
1357
- let settled = false;
1358
- const resolveOnce = (result) => {
1359
- if (settled) {
1360
- return;
1361
- }
1362
- settled = true;
1363
- if (signal) {
1364
- signal.removeEventListener("abort", onAbort);
1365
- }
1366
- resolve(result);
1367
- };
1368
- const onAbort = () => {
1369
- resolveOnce({ success: false, error: "CANCELLED" });
1370
- };
1371
- if (signal?.aborted) {
1372
- resolveOnce({ success: false, error: "CANCELLED" });
1373
- return;
1374
- }
1375
- if (signal) {
1376
- signal.addEventListener("abort", onAbort, { once: true });
1377
- }
1378
- try {
1379
- const popup = new PaystackPop();
1380
- popup.newTransaction({
1381
- key: options.key,
1382
- email: options.email,
1383
- amount: options.amount,
1384
- currency: options.currency,
1385
- reference: options.reference,
1386
- accessCode: options.accessCode,
1387
- onSuccess: (transaction) => {
1388
- resolveOnce({
1389
- success: true,
1390
- reference: transaction.reference ?? options.reference
1391
- });
1392
- },
1393
- onCancel: () => {
1394
- resolveOnce({ success: false, error: "PAYMENT_CANCELLED" });
1395
- },
1396
- onError: (error) => {
1397
- resolveOnce({
1398
- success: false,
1399
- error: error?.message || "PAYMENT_FAILED"
1400
- });
1401
- }
1402
- });
1403
- } catch {
1404
- resolveOnce({ success: false, error: "POPUP_BLOCKED" });
1405
- }
1406
- });
1407
- }
1408
-
1409
- // src/utils/checkout-resolver.ts
1410
- var DEFAULT_POLL_INTERVAL_MS = 3e3;
1411
- var DEFAULT_MAX_POLL_ATTEMPTS = 60;
1412
- var MAX_CONSECUTIVE_NETWORK_ERRORS = 5;
1413
- var CARD_PROVIDER_PAYSTACK = "paystack";
1414
- var NEXT_ACTION_NONE = "none";
1415
- var NEXT_ACTION_CARD_POPUP = "card_popup";
1416
- var NEXT_ACTION_REDIRECT = "redirect";
1417
- var NEXT_ACTION_AUTHORIZATION = "authorization";
1418
- function normalizeCardPopupError(error) {
1419
- if (!error || error === "PAYMENT_CANCELLED" || error === "CANCELLED") {
1420
- return "PAYMENT_CANCELLED";
1421
- }
1422
- if (error === "PROVIDER_UNAVAILABLE") {
1423
- return "PROVIDER_UNAVAILABLE";
1424
- }
1425
- if (error === "POPUP_BLOCKED") {
1426
- return "POPUP_BLOCKED";
1427
- }
1428
- return "PAYMENT_FAILED";
1429
- }
1430
- function normalizeCardProvider(value) {
1431
- const normalized = value?.trim().toLowerCase();
1432
- return normalized && normalized.length > 0 ? normalized : CARD_PROVIDER_PAYSTACK;
1433
- }
1434
- async function openCardPopup(provider, checkoutResult, email, currency, signal) {
1435
- if (typeof window === "undefined") {
1436
- return { success: false, error: "PROVIDER_UNAVAILABLE" };
1437
- }
1438
- if (provider === CARD_PROVIDER_PAYSTACK) {
1439
- return openPaystackPopup(
1440
- {
1441
- key: checkoutResult.public_key || "",
1442
- email,
1443
- accessCode: checkoutResult.client_secret,
1444
- reference: checkoutResult.payment_reference || checkoutResult.client_secret,
1445
- currency
1446
- },
1447
- signal
1448
- );
1449
- }
1450
- return { success: false, error: "PROVIDER_UNAVAILABLE" };
1451
- }
1452
- var VALID_MOBILE_MONEY_PROVIDERS = new Set(Object.values(MOBILE_MONEY_PROVIDER));
1453
- function isValidMobileMoneyProvider(value) {
1454
- return VALID_MOBILE_MONEY_PROVIDERS.has(value);
1455
- }
1456
- function normalizeAuthorizationType(value) {
1457
- if (value && typeof value === "object" && "address" in value) {
1458
- return "address";
1459
- }
1460
- if (typeof value !== "string") return void 0;
1461
- const normalized = value.trim().toLowerCase().replace(/[\s-]+/g, "_");
1462
- if (normalized === "otp" || normalized === "pin") return normalized;
1463
- if (normalized === "phone" || normalized === "birthday" || normalized === "address") {
1464
- return normalized;
1465
- }
1466
- return void 0;
1467
- }
1468
- function formatMoney2(value) {
1469
- if (typeof value === "number" && Number.isFinite(value)) {
1470
- return value.toFixed(2);
1471
- }
1472
- if (typeof value === "string" && value.trim().length > 0) {
1473
- return value;
1474
- }
1475
- return "0.00";
1476
- }
1477
- function createAbortError() {
1478
- const error = new Error("CANCELLED");
1479
- error.name = "AbortError";
1480
- return error;
1481
- }
1482
- function isAbortError(error) {
1483
- if (error instanceof DOMException && error.name === "AbortError") {
1484
- return true;
1485
- }
1486
- return error instanceof Error && (error.name === "AbortError" || error.message === "CANCELLED");
1487
- }
1488
- var CheckoutResolver = class {
1489
- constructor(options) {
1490
- this.client = options.client;
1491
- this.checkoutData = options.checkoutData;
1492
- this.pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
1493
- this.maxPollAttempts = options.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS;
1494
- this.onStatusChange = options.onStatusChange;
1495
- this.onAuthorizationRequired = options.onAuthorizationRequired;
1496
- this.signal = options.signal;
1497
- this.returnUrl = options.returnUrl;
1498
- this.enrollInLink = options.enrollInLink !== false;
1499
- this.businessId = options.businessId;
1500
- this.addressData = options.addressData;
1501
- this.paymentData = options.paymentData;
1502
- this.orderType = options.orderType;
1503
- this.cartTotal = options.cartTotal;
1504
- this.cartCurrency = options.cartCurrency;
1505
- this.allowPopups = options.allowPopups ?? typeof window !== "undefined";
1506
- }
1507
- async resolve(checkoutResult) {
1508
- try {
1509
- this.ensureNotAborted();
1510
- if (!checkoutResult.order_id) {
1511
- return this.fail("CHECKOUT_FAILED", "Checkout did not return an order ID.", false);
1512
- }
1513
- if (checkoutResult.next_action) {
1514
- return this.resolveNextAction(checkoutResult);
1515
- }
1516
- let latestCheckoutResult = checkoutResult;
1517
- let authorizationType = normalizeAuthorizationType(checkoutResult.authorization_type);
1518
- let paymentReference = checkoutResult.payment_reference;
1519
- if (this.isSuccessfulStatus(checkoutResult.payment_status)) {
1520
- return this.finalizeSuccess(checkoutResult);
1521
- }
1522
- if (checkoutResult.client_secret && checkoutResult.public_key) {
1523
- const provider = normalizeCardProvider(checkoutResult.provider);
1524
- this.emit("awaiting_authorization", {
1525
- display_text: "Complete payment in the card authorization popup.",
1526
- order_id: checkoutResult.order_id,
1527
- order_number: checkoutResult.order_number
1528
- });
1529
- if (!this.allowPopups) {
1530
- return this.fail(
1531
- "PROVIDER_UNAVAILABLE",
1532
- "Card payment popup is unavailable in this environment.",
1533
- false
1534
- );
1535
- }
1536
- const popupResult = await openCardPopup(
1537
- provider,
1538
- checkoutResult,
1539
- this.checkoutData.customer.email || "customer@cimplify.io",
1540
- this.getOrderCurrency(checkoutResult),
1541
- this.signal
1542
- );
1543
- if (!popupResult.success) {
1544
- const popupError = normalizeCardPopupError(popupResult.error);
1545
- if (popupError === "POPUP_BLOCKED") {
1546
- return this.fail(
1547
- "POPUP_BLOCKED",
1548
- "Unable to open card payment popup. Please allow popups and try again.",
1549
- true
1550
- );
1551
- }
1552
- if (popupError === "PROVIDER_UNAVAILABLE") {
1553
- return this.fail(
1554
- "PROVIDER_UNAVAILABLE",
1555
- "Card payment provider is unavailable.",
1556
- false
1557
- );
1558
- }
1559
- return this.fail(
1560
- "PAYMENT_CANCELLED",
1561
- "Card payment was cancelled before completion.",
1562
- true
1563
- );
1564
- }
1565
- paymentReference = popupResult.reference || paymentReference;
1566
- }
1567
- if (checkoutResult.authorization_url) {
1568
- if (typeof window !== "undefined" && this.returnUrl) {
1569
- window.location.assign(checkoutResult.authorization_url);
1570
- return this.fail(
1571
- "REDIRECT_REQUIRED",
1572
- "Redirecting to complete payment authorization.",
1573
- true
1574
- );
1575
- }
1576
- if (typeof window !== "undefined") {
1577
- const popup = window.open(
1578
- checkoutResult.authorization_url,
1579
- "cimplify-auth",
1580
- "width=520,height=760,noopener,noreferrer"
1581
- );
1582
- if (!popup) {
1583
- return this.fail(
1584
- "POPUP_BLOCKED",
1585
- "Authorization popup was blocked. Please allow popups and retry.",
1586
- true
1587
- );
1588
- }
1589
- }
1590
- }
1591
- if (checkoutResult.requires_authorization || isPaymentStatusRequiresAction(checkoutResult.payment_status)) {
1592
- const authorization = await this.handleAuthorization({
1593
- authorizationType,
1594
- paymentReference,
1595
- displayText: checkoutResult.display_text,
1596
- provider: checkoutResult.provider
1597
- });
1598
- if (!authorization.ok) {
1599
- return authorization.result;
1600
- }
1601
- if (authorization.value) {
1602
- latestCheckoutResult = authorization.value;
1603
- paymentReference = authorization.value.payment_reference || paymentReference;
1604
- authorizationType = normalizeAuthorizationType(authorization.value.authorization_type) || authorizationType;
1605
- if (this.isSuccessfulStatus(authorization.value.payment_status)) {
1606
- return this.finalizeSuccess(authorization.value);
1607
- }
1608
- if (this.isFailureStatus(authorization.value.payment_status)) {
1609
- return this.fail(
1610
- "AUTHORIZATION_FAILED",
1611
- authorization.value.display_text || "Payment authorization failed.",
1612
- false
1613
- );
1614
- }
1615
- }
1616
- }
1617
- return this.pollUntilTerminal({
1618
- orderId: checkoutResult.order_id,
1619
- latestCheckoutResult,
1620
- paymentReference,
1621
- authorizationType
1622
- });
1623
- } catch (error) {
1624
- if (isAbortError(error)) {
1625
- return this.fail("CANCELLED", "Checkout was cancelled.", true);
1626
- }
1627
- const message = error instanceof Error ? error.message : "Checkout failed unexpectedly.";
1628
- return this.fail("CHECKOUT_FAILED", message, true);
1629
- }
1630
- }
1631
- async resolveNextAction(checkoutResult) {
1632
- const action = checkoutResult.next_action;
1633
- if (this.isSuccessfulStatus(checkoutResult.payment_status)) {
1634
- return this.finalizeSuccess(checkoutResult);
1635
- }
1636
- let latestCheckoutResult = checkoutResult;
1637
- let paymentReference = checkoutResult.payment_reference;
1638
- switch (action.type) {
1639
- case NEXT_ACTION_NONE:
1640
- return this.finalizeSuccess(checkoutResult);
1641
- case NEXT_ACTION_CARD_POPUP: {
1642
- const provider = normalizeCardProvider(action.provider);
1643
- this.emit("awaiting_authorization", {
1644
- display_text: "Complete payment in the card authorization popup.",
1645
- order_id: checkoutResult.order_id,
1646
- order_number: checkoutResult.order_number
1647
- });
1648
- if (!this.allowPopups) {
1649
- return this.fail(
1650
- "PROVIDER_UNAVAILABLE",
1651
- "Card payment popup is unavailable in this environment.",
1652
- false
1653
- );
1654
- }
1655
- const popupResult = await openCardPopup(
1656
- provider,
1657
- checkoutResult,
1658
- this.checkoutData.customer.email || "customer@cimplify.io",
1659
- this.getOrderCurrency(checkoutResult),
1660
- this.signal
1661
- );
1662
- if (!popupResult.success) {
1663
- const popupError = normalizeCardPopupError(popupResult.error);
1664
- if (popupError === "POPUP_BLOCKED") {
1665
- return this.fail(
1666
- "POPUP_BLOCKED",
1667
- "Unable to open card payment popup. Please allow popups and try again.",
1668
- true
1669
- );
1670
- }
1671
- if (popupError === "PROVIDER_UNAVAILABLE") {
1672
- return this.fail("PROVIDER_UNAVAILABLE", "Card payment provider is unavailable.", false);
1673
- }
1674
- return this.fail("PAYMENT_CANCELLED", "Card payment was cancelled before completion.", true);
1675
- }
1676
- paymentReference = popupResult.reference || paymentReference;
1677
- break;
1678
- }
1679
- case NEXT_ACTION_REDIRECT: {
1680
- if (typeof window !== "undefined" && this.returnUrl) {
1681
- window.location.assign(action.authorization_url);
1682
- return this.fail("REDIRECT_REQUIRED", "Redirecting to complete payment authorization.", true);
1683
- }
1684
- if (typeof window !== "undefined") {
1685
- const popup = window.open(
1686
- action.authorization_url,
1687
- "cimplify-auth",
1688
- "width=520,height=760,noopener,noreferrer"
1689
- );
1690
- if (!popup) {
1691
- return this.fail(
1692
- "POPUP_BLOCKED",
1693
- "Authorization popup was blocked. Please allow popups and retry.",
1694
- true
1695
- );
1696
- }
1697
- }
1698
- break;
1699
- }
1700
- case NEXT_ACTION_AUTHORIZATION: {
1701
- const authType = normalizeAuthorizationType(action.authorization_type);
1702
- const authorization = await this.handleAuthorization({
1703
- authorizationType: authType,
1704
- paymentReference,
1705
- displayText: action.display_text,
1706
- provider: checkoutResult.provider
1707
- });
1708
- if (!authorization.ok) {
1709
- return authorization.result;
1710
- }
1711
- if (authorization.value) {
1712
- latestCheckoutResult = authorization.value;
1713
- paymentReference = authorization.value.payment_reference || paymentReference;
1714
- if (this.isSuccessfulStatus(authorization.value.payment_status)) {
1715
- return this.finalizeSuccess(authorization.value);
1716
- }
1717
- if (this.isFailureStatus(authorization.value.payment_status)) {
1718
- return this.fail(
1719
- "AUTHORIZATION_FAILED",
1720
- authorization.value.display_text || "Payment authorization failed.",
1721
- false
1722
- );
1723
- }
1724
- }
1725
- break;
1726
- }
1727
- }
1728
- return this.pollUntilTerminal({
1729
- orderId: checkoutResult.order_id,
1730
- latestCheckoutResult,
1731
- paymentReference,
1732
- authorizationType: normalizeAuthorizationType(checkoutResult.authorization_type)
1733
- });
1734
- }
1735
- async pollUntilTerminal(input) {
1736
- let consecutiveErrors = 0;
1737
- let latestCheckoutResult = input.latestCheckoutResult;
1738
- let paymentReference = input.paymentReference;
1739
- let authorizationType = input.authorizationType;
1740
- for (let attempt = 0; attempt < this.maxPollAttempts; attempt++) {
1741
- this.ensureNotAborted();
1742
- this.emit("polling", {
1743
- poll_attempt: attempt,
1744
- max_poll_attempts: this.maxPollAttempts,
1745
- order_id: input.orderId,
1746
- order_number: latestCheckoutResult.order_number
1747
- });
1748
- const statusResult = await this.client.checkout.pollPaymentStatus(input.orderId);
1749
- if (!statusResult.ok) {
1750
- consecutiveErrors += 1;
1751
- if (consecutiveErrors >= MAX_CONSECUTIVE_NETWORK_ERRORS) {
1752
- return this.fail(
1753
- "NETWORK_ERROR",
1754
- "Unable to confirm payment due to repeated network errors.",
1755
- true
1756
- );
1757
- }
1758
- await this.wait(this.pollIntervalMs);
1759
- continue;
1760
- }
1761
- consecutiveErrors = 0;
1762
- if (statusResult.value.reference) {
1763
- paymentReference = statusResult.value.reference;
1764
- }
1765
- const normalized = normalizeStatusResponse(statusResult.value);
1766
- if (normalized.paid || isPaymentStatusSuccess(normalized.status)) {
1767
- return this.finalizeSuccess(latestCheckoutResult);
1768
- }
1769
- if (isPaymentStatusFailure(normalized.status)) {
1770
- return this.fail(
1771
- normalized.status ? normalized.status.toUpperCase() : "PAYMENT_FAILED",
1772
- normalized.message || "Payment failed during confirmation.",
1773
- false
1774
- );
1775
- }
1776
- if (isPaymentStatusRequiresAction(normalized.status)) {
1777
- const authorization = await this.handleAuthorization({
1778
- authorizationType,
1779
- paymentReference,
1780
- displayText: normalized.message || latestCheckoutResult.display_text,
1781
- provider: latestCheckoutResult.provider
1782
- });
1783
- if (!authorization.ok) {
1784
- return authorization.result;
1785
- }
1786
- if (authorization.value) {
1787
- latestCheckoutResult = authorization.value;
1788
- paymentReference = authorization.value.payment_reference || paymentReference;
1789
- authorizationType = normalizeAuthorizationType(authorization.value.authorization_type) || authorizationType;
1790
- if (this.isSuccessfulStatus(authorization.value.payment_status)) {
1791
- return this.finalizeSuccess(authorization.value);
1792
- }
1793
- if (this.isFailureStatus(authorization.value.payment_status)) {
1794
- return this.fail(
1795
- "AUTHORIZATION_FAILED",
1796
- authorization.value.display_text || "Payment authorization failed.",
1797
- false
1798
- );
1799
- }
1800
- }
1801
- }
1802
- await this.wait(this.pollIntervalMs);
1803
- }
1804
- try {
1805
- const finalResult = await this.client.checkout.pollPaymentStatus(input.orderId);
1806
- if (finalResult.ok) {
1807
- const normalized = normalizeStatusResponse(finalResult.value);
1808
- if (normalized.paid || isPaymentStatusSuccess(normalized.status)) {
1809
- return this.finalizeSuccess(latestCheckoutResult);
1810
- }
1811
- }
1812
- } catch {
1813
- }
1814
- return this.fail(
1815
- "PAYMENT_TIMEOUT",
1816
- "Payment confirmation timed out. Please retry checkout.",
1817
- true
1818
- );
1819
- }
1820
- async handleAuthorization(input) {
1821
- const authorizationType = input.authorizationType;
1822
- const paymentReference = input.paymentReference;
1823
- if (!authorizationType || !paymentReference) {
1824
- return { ok: true };
1825
- }
1826
- this.emit("awaiting_authorization", {
1827
- authorization_type: authorizationType,
1828
- display_text: input.displayText,
1829
- provider: input.provider
1830
- });
1831
- let authorizationResult;
1832
- const submit = async (code) => {
1833
- this.ensureNotAborted();
1834
- const trimmedCode = code.trim();
1835
- if (!trimmedCode) {
1836
- throw new Error("Authorization code is required.");
1837
- }
1838
- const submitResult = await this.client.checkout.submitAuthorization({
1839
- reference: paymentReference,
1840
- auth_type: authorizationType,
1841
- value: trimmedCode
1842
- });
1843
- if (!submitResult.ok) {
1844
- throw new Error(submitResult.error.message || "Authorization failed.");
1845
- }
1846
- authorizationResult = submitResult.value;
1847
- };
1848
- try {
1849
- if (this.onAuthorizationRequired) {
1850
- await this.onAuthorizationRequired(authorizationType, submit);
1851
- } else {
1852
- return {
1853
- ok: false,
1854
- result: this.fail(
1855
- "AUTHORIZATION_REQUIRED",
1856
- "Authorization callback is required in headless checkout mode.",
1857
- false
1858
- )
1859
- };
1860
- }
1861
- } catch (error) {
1862
- if (isAbortError(error)) {
1863
- return {
1864
- ok: false,
1865
- result: this.fail("CANCELLED", "Checkout was cancelled.", true)
1866
- };
1867
- }
1868
- const message = error instanceof Error ? error.message : "Payment authorization failed.";
1869
- return {
1870
- ok: false,
1871
- result: this.fail("AUTHORIZATION_FAILED", message, true)
1872
- };
1873
- }
1874
- return {
1875
- ok: true,
1876
- value: authorizationResult
1877
- };
1878
- }
1879
- async finalizeSuccess(checkoutResult) {
1880
- this.emit("finalizing", {
1881
- order_id: checkoutResult.order_id,
1882
- order_number: checkoutResult.order_number
1883
- });
1884
- const enrolledInLink = await this.maybeEnrollInLink(checkoutResult.order_id);
1885
- this.emit("success", {
1886
- order_id: checkoutResult.order_id,
1887
- order_number: checkoutResult.order_number
1888
- });
1889
- return {
1890
- success: true,
1891
- order: {
1892
- id: checkoutResult.order_id,
1893
- order_number: checkoutResult.order_number || checkoutResult.order_id,
1894
- status: checkoutResult.payment_status || "paid",
1895
- total: this.getOrderTotal(checkoutResult),
1896
- currency: this.getOrderCurrency(checkoutResult)
1897
- },
1898
- enrolled_in_link: enrolledInLink
1899
- };
1900
- }
1901
- async maybeEnrollInLink(orderId) {
1902
- if (!this.enrollInLink || !orderId) {
1903
- return false;
1904
- }
1905
- let businessId = this.businessId;
1906
- if (!businessId) {
1907
- const businessResult = await this.client.business.getInfo();
1908
- if (!businessResult.ok || !businessResult.value?.id) {
1909
- return false;
1910
- }
1911
- businessId = businessResult.value.id;
1912
- }
1913
- const address = this.getEnrollmentAddress();
1914
- const mobileMoney = this.getEnrollmentMobileMoney();
1915
- try {
1916
- const enrollment = await this.client.link.enrollAndLinkOrder({
1917
- order_id: orderId,
1918
- business_id: businessId,
1919
- order_type: this.orderType || this.checkoutData.order_type,
1920
- address,
1921
- mobile_money: mobileMoney
1922
- });
1923
- return enrollment.ok && enrollment.value.success;
1924
- } catch {
1925
- return false;
1926
- }
1927
- }
1928
- getEnrollmentAddress() {
1929
- const source = this.addressData ?? this.checkoutData.address_info;
1930
- if (!source?.street_address) {
1931
- return void 0;
1932
- }
1933
- return {
1934
- label: "Default",
1935
- street_address: source.street_address,
1936
- apartment: source.apartment || void 0,
1937
- city: source.city || "",
1938
- region: source.region || "",
1939
- delivery_instructions: source.delivery_instructions || void 0,
1940
- phone_for_delivery: source.phone_for_delivery || void 0
1941
- };
1942
- }
1943
- getEnrollmentMobileMoney() {
1944
- if (this.paymentData?.type === "mobile_money" && this.paymentData.phone_number && this.paymentData.provider && isValidMobileMoneyProvider(this.paymentData.provider)) {
1945
- return {
1946
- phone_number: this.paymentData.phone_number,
1947
- provider: this.paymentData.provider,
1948
- label: this.paymentData.label || "Mobile Money"
1949
- };
1950
- }
1951
- if (this.checkoutData.mobile_money_details?.phone_number) {
1952
- return {
1953
- phone_number: this.checkoutData.mobile_money_details.phone_number,
1954
- provider: this.checkoutData.mobile_money_details.provider,
1955
- label: "Mobile Money"
1956
- };
1957
- }
1958
- return void 0;
1959
- }
1960
- getOrderTotal(checkoutResult) {
1961
- if (checkoutResult.fx?.pay_amount !== void 0) {
1962
- return formatMoney2(checkoutResult.fx.pay_amount);
1963
- }
1964
- if (this.cartTotal !== void 0) {
1965
- return formatMoney2(this.cartTotal);
1966
- }
1967
- return "0.00";
1968
- }
1969
- getOrderCurrency(checkoutResult) {
1970
- if (checkoutResult.fx?.pay_currency) {
1971
- return checkoutResult.fx.pay_currency;
1972
- }
1973
- if (this.cartCurrency) {
1974
- return this.cartCurrency;
1975
- }
1976
- if (this.checkoutData.pay_currency) {
1977
- return this.checkoutData.pay_currency;
1978
- }
1979
- return "GHS";
1980
- }
1981
- emit(status, context = {}) {
1982
- if (!this.onStatusChange) {
1983
- return;
1984
- }
1985
- try {
1986
- this.onStatusChange(status, context);
1987
- } catch {
1988
- }
1989
- }
1990
- fail(code, message, recoverable) {
1991
- this.emit("failed", {
1992
- display_text: message
1993
- });
1994
- return {
1995
- success: false,
1996
- error: {
1997
- code,
1998
- message,
1999
- recoverable
2000
- }
2001
- };
2002
- }
2003
- isSuccessfulStatus(status) {
2004
- const normalized = normalizeStatusResponse({ status, paid: false });
2005
- return normalized.paid || isPaymentStatusSuccess(normalized.status);
2006
- }
2007
- isFailureStatus(status) {
2008
- const normalized = normalizeStatusResponse({ status, paid: false });
2009
- return isPaymentStatusFailure(normalized.status);
2010
- }
2011
- ensureNotAborted() {
2012
- if (this.signal?.aborted) {
2013
- throw createAbortError();
2014
- }
2015
- }
2016
- wait(ms) {
2017
- this.ensureNotAborted();
2018
- return new Promise((resolve, reject) => {
2019
- const timer = setTimeout(() => {
2020
- if (this.signal) {
2021
- this.signal.removeEventListener("abort", onAbort);
2022
- }
2023
- resolve();
2024
- }, ms);
2025
- const onAbort = () => {
2026
- clearTimeout(timer);
2027
- reject(createAbortError());
2028
- };
2029
- if (this.signal) {
2030
- this.signal.addEventListener("abort", onAbort, { once: true });
2031
- }
2032
- });
2033
- }
2034
- };
2035
-
2036
- // src/checkout.ts
2037
- function toTerminalFailure(code, message, recoverable) {
2038
- return {
2039
- success: false,
2040
- error: {
2041
- code,
2042
- message,
2043
- recoverable
2044
- }
2045
- };
2046
- }
2047
- function generateIdempotencyKey() {
2048
- if (typeof crypto !== "undefined" && crypto.randomUUID) {
2049
- return `idem_${crypto.randomUUID()}`;
2050
- }
2051
- const timestamp = Date.now().toString(36);
2052
- const random = Math.random().toString(36).substring(2, 15);
2053
- return `idem_${timestamp}_${random}`;
2054
- }
2055
- var CheckoutService = class {
2056
- constructor(client) {
2057
- this.client = client;
2058
- }
2059
- orderTokenParam(orderId) {
2060
- const token = this.client.getOrderToken(orderId);
2061
- return token ? `?token=${encodeURIComponent(token)}` : "";
2062
- }
2063
- async process(data) {
2064
- const checkoutData = {
2065
- ...data,
2066
- idempotency_key: data.idempotency_key || generateIdempotencyKey()
2067
- };
2068
- const result = await safe(
2069
- this.client.post("/api/v1/checkout", {
2070
- checkout_data: checkoutData
2071
- })
2072
- );
2073
- if (result.ok && result.value.bill_token) {
2074
- this.client.setOrderToken(result.value.order_id, result.value.bill_token);
2075
- }
2076
- return result;
2077
- }
2078
- async initializePayment(_orderId, _method) {
2079
- return err(
2080
- new CimplifyError(
2081
- "NOT_IMPLEMENTED",
2082
- "initializePayment is not available in REST mode.",
2083
- false
2084
- )
2085
- );
2086
- }
2087
- async submitAuthorization(input) {
2088
- return safe(this.client.post("/api/v1/payments/authorization", input));
2089
- }
2090
- async pollPaymentStatus(orderId) {
2091
- const encodedId = encodeURIComponent(orderId);
2092
- const tokenParam = this.orderTokenParam(orderId);
2093
- return safe(this.client.get(`/api/v1/orders/${encodedId}/payment-status${tokenParam}`));
2094
- }
2095
- async updateOrderCustomer(orderId, customer) {
2096
- const encodedId = encodeURIComponent(orderId);
2097
- const tokenParam = this.orderTokenParam(orderId);
2098
- return safe(this.client.post(`/api/v1/orders/${encodedId}/customer${tokenParam}`, customer));
2099
- }
2100
- async verifyPayment(orderId) {
2101
- const encodedId = encodeURIComponent(orderId);
2102
- const tokenParam = this.orderTokenParam(orderId);
2103
- return safe(this.client.post(`/api/v1/orders/${encodedId}/verify-payment${tokenParam}`));
2104
- }
2105
- async processAndResolve(data) {
2106
- data.on_status_change?.("preparing", {});
2107
- if (!data.cart_id) {
2108
- return ok(
2109
- toTerminalFailure(
2110
- "INVALID_CART",
2111
- "A valid cart is required before checkout can start.",
2112
- false
2113
- )
2114
- );
2115
- }
2116
- const cartResult = await this.client.cart.get();
2117
- if (!cartResult.ok || !cartResult.value?.id) {
2118
- return ok(
2119
- toTerminalFailure(
2120
- "INVALID_CART",
2121
- "Unable to load cart for checkout.",
2122
- false
2123
- )
2124
- );
2125
- }
2126
- const cart = cartResult.value;
2127
- if (cart.id !== data.cart_id || cart.items.length === 0) {
2128
- return ok(
2129
- toTerminalFailure(
2130
- "INVALID_CART",
2131
- "Cart is empty or no longer valid. Please refresh and try again.",
2132
- false
2133
- )
2134
- );
2135
- }
2136
- const checkoutData = {
2137
- cart_id: data.cart_id,
2138
- location_id: data.location_id,
2139
- customer: data.customer,
2140
- order_type: data.order_type,
2141
- address_info: data.address_info,
2142
- payment_method: data.payment_method,
2143
- mobile_money_details: data.mobile_money_details,
2144
- special_instructions: data.special_instructions,
2145
- link_address_id: data.link_address_id,
2146
- link_payment_method_id: data.link_payment_method_id,
2147
- idempotency_key: data.idempotency_key || generateIdempotencyKey(),
2148
- metadata: data.metadata,
2149
- pay_currency: data.pay_currency,
2150
- fx_quote_id: data.fx_quote_id
2151
- };
2152
- const baseCurrency = currencyCode(
2153
- (cart.pricing.currency || checkoutData.pay_currency || "GHS").toUpperCase()
2154
- );
2155
- const payCurrency = data.pay_currency?.trim().toUpperCase();
2156
- const payCurrencyCode = payCurrency ? currencyCode(payCurrency) : void 0;
2157
- const cartTotalAmount = typeof cart.pricing.total_price === "number" ? cart.pricing.total_price : Number.parseFloat(cart.pricing.total_price || "0");
2158
- if (payCurrencyCode && payCurrencyCode !== baseCurrency && !checkoutData.fx_quote_id && Number.isFinite(cartTotalAmount) && cartTotalAmount > 0) {
2159
- const fxQuoteResult = await this.client.fx.lockQuote({
2160
- from: baseCurrency,
2161
- to: payCurrencyCode,
2162
- amount: cart.pricing.total_price
2163
- });
2164
- if (!fxQuoteResult.ok) {
2165
- return ok(
2166
- toTerminalFailure(
2167
- "FX_QUOTE_FAILED",
2168
- fxQuoteResult.error.message || "Unable to lock FX quote for checkout.",
2169
- true
2170
- )
2171
- );
2172
- }
2173
- checkoutData.pay_currency = payCurrencyCode;
2174
- checkoutData.fx_quote_id = fxQuoteResult.value.id;
2175
- }
2176
- data.on_status_change?.("processing", {});
2177
- const processResult = await this.process(checkoutData);
2178
- if (!processResult.ok) {
2179
- return ok(
2180
- toTerminalFailure(
2181
- processResult.error.code || "CHECKOUT_FAILED",
2182
- processResult.error.message || "Unable to process checkout.",
2183
- processResult.error.retryable ?? true
2184
- )
2185
- );
2186
- }
2187
- const resolver = new CheckoutResolver({
2188
- client: this.client,
2189
- checkoutData,
2190
- pollIntervalMs: data.poll_interval_ms,
2191
- maxPollAttempts: data.max_poll_attempts,
2192
- onStatusChange: data.on_status_change,
2193
- onAuthorizationRequired: data.on_authorization_required,
2194
- signal: data.signal,
2195
- returnUrl: data.return_url,
2196
- enrollInLink: data.enroll_in_link,
2197
- cartTotal: cart.pricing.total_price,
2198
- cartCurrency: checkoutData.pay_currency || cart.pricing.currency || "GHS",
2199
- orderType: checkoutData.order_type,
2200
- allowPopups: data.allow_popups
2201
- });
2202
- const resolved = await resolver.resolve(processResult.value);
2203
- return ok(resolved);
2204
- }
2205
- };
2206
-
2207
- // src/orders.ts
2208
- var OrderQueries = class {
2209
- constructor(client) {
2210
- this.client = client;
2211
- }
2212
- orderTokenParam(orderId) {
2213
- const token = this.client.getOrderToken(orderId);
2214
- return token ? `?token=${encodeURIComponent(token)}` : "";
2215
- }
2216
- async list(options) {
2217
- const params = new URLSearchParams();
2218
- if (options?.status) params.set("status", options.status);
2219
- if (options?.limit) params.set("limit", String(options.limit));
2220
- if (options?.offset) params.set("offset", String(options.offset));
2221
- const path = params.toString() ? `/api/v1/orders?${params.toString()}` : "/api/v1/orders";
2222
- return safe(this.client.get(path));
2223
- }
2224
- async get(orderId) {
2225
- const encodedId = encodeURIComponent(orderId);
2226
- const tokenParam = this.orderTokenParam(orderId);
2227
- return safe(this.client.get(`/api/v1/orders/${encodedId}${tokenParam}`));
2228
- }
2229
- async getRecent(limit = 5) {
2230
- return this.list({ limit });
2231
- }
2232
- async getByStatus(status) {
2233
- return this.list({ status });
2234
- }
2235
- async cancel(orderId, reason) {
2236
- const encodedId = encodeURIComponent(orderId);
2237
- const tokenParam = this.orderTokenParam(orderId);
2238
- return safe(
2239
- this.client.post(`/api/v1/orders/${encodedId}/cancel${tokenParam}`, {
2240
- reason
2241
- })
2242
- );
2243
- }
2244
- };
2245
-
2246
- // src/link.ts
2247
- function encodePathSegment(value) {
2248
- return encodeURIComponent(value);
2249
- }
2250
- function toCreateAddressPayload(input) {
2251
- return {
2252
- label: input.label,
2253
- street_address: input.address_line1,
2254
- apartment: input.address_line2,
2255
- city: input.city,
2256
- region: input.state ?? "",
2257
- postal_code: input.postal_code,
2258
- country: input.country
2259
- };
2260
- }
2261
- function toUpdateAddressPayload(input) {
2262
- return {
2263
- label: input.label,
2264
- street_address: input.address_line1,
2265
- apartment: input.address_line2,
2266
- city: input.city,
2267
- region: input.state,
2268
- postal_code: input.postal_code,
2269
- country: input.country
2270
- };
2271
- }
2272
- function toCreateMobileMoneyPayload(input) {
2273
- return {
2274
- phone_number: input.phone_number,
2275
- provider: input.provider,
2276
- label: input.account_name
2277
- };
2278
- }
2279
- var LinkService = class {
2280
- constructor(client) {
2281
- this.client = client;
2282
- }
2283
- async getProfile() {
2284
- return safe(this.client.linkGet("/v1/link/profile"));
2285
- }
2286
- async requestOtp(input) {
2287
- return safe(this.client.linkPost("/v1/link/auth/request-otp", input));
2288
- }
2289
- async verifyOtp(input) {
2290
- const result = await safe(
2291
- this.client.linkPost("/v1/link/auth/verify-otp", input)
2292
- );
2293
- if (result.ok && result.value.session_token) {
2294
- this.client.setAccessToken(result.value.session_token);
2295
- }
2296
- return result;
2297
- }
2298
- async logout() {
2299
- const result = await safe(this.client.linkPost("/v1/link/auth/logout"));
2300
- if (result.ok) {
2301
- this.client.clearSession();
2302
- }
2303
- return result;
2304
- }
2305
- async checkStatus(contact) {
2306
- return safe(this.client.linkPost("/v1/link/check-status", { contact }));
2307
- }
2308
- async getLinkData() {
2309
- return safe(this.client.linkGet("/v1/link/data"));
2310
- }
2311
- async getAddresses() {
2312
- return safe(this.client.linkGet("/v1/link/addresses"));
2313
- }
2314
- async getMobileMoney() {
2315
- return safe(this.client.linkGet("/v1/link/mobile-money"));
2316
- }
2317
- async getPreferences() {
2318
- return safe(this.client.linkGet("/v1/link/preferences"));
2319
- }
2320
- async enroll(data) {
2321
- return safe(this.client.linkPost("/v1/link/enroll", data));
2322
- }
2323
- async enrollAndLinkOrder(data) {
2324
- return safe(
2325
- this.client.linkPost("/v1/link/enroll-and-link-order", data)
2326
- );
2327
- }
2328
- async updatePreferences(preferences) {
2329
- return safe(this.client.linkPost("/v1/link/preferences", preferences));
2330
- }
2331
- async createAddress(input) {
2332
- return safe(
2333
- this.client.linkPost("/v1/link/addresses", toCreateAddressPayload(input))
2334
- );
2335
- }
2336
- async updateAddress(input) {
2337
- return safe(
2338
- this.client.linkPost(
2339
- `/v1/link/addresses/${encodePathSegment(input.address_id)}`,
2340
- toUpdateAddressPayload(input)
2341
- )
2342
- );
2343
- }
2344
- async deleteAddress(addressId) {
2345
- return safe(
2346
- this.client.linkDelete(`/v1/link/addresses/${encodePathSegment(addressId)}`)
2347
- );
2348
- }
2349
- async setDefaultAddress(addressId) {
2350
- return safe(
2351
- this.client.linkPost(
2352
- `/v1/link/addresses/${encodePathSegment(addressId)}/default`
2353
- )
2354
- );
2355
- }
2356
- async trackAddressUsage(addressId) {
2357
- return safe(
2358
- this.client.linkPost(
2359
- `/v1/link/addresses/${encodePathSegment(addressId)}/track-usage`
2360
- )
2361
- );
2362
- }
2363
- async createMobileMoney(input) {
2364
- return safe(
2365
- this.client.linkPost(
2366
- "/v1/link/mobile-money",
2367
- toCreateMobileMoneyPayload(input)
2368
- )
2369
- );
2370
- }
2371
- async deleteMobileMoney(mobileMoneyId) {
2372
- return safe(
2373
- this.client.linkDelete(
2374
- `/v1/link/mobile-money/${encodePathSegment(mobileMoneyId)}`
2375
- )
2376
- );
2377
- }
2378
- async setDefaultMobileMoney(mobileMoneyId) {
2379
- return safe(
2380
- this.client.linkPost(
2381
- `/v1/link/mobile-money/${encodePathSegment(mobileMoneyId)}/default`
2382
- )
2383
- );
2384
- }
2385
- async trackMobileMoneyUsage(mobileMoneyId) {
2386
- return safe(
2387
- this.client.linkPost(
2388
- `/v1/link/mobile-money/${encodePathSegment(mobileMoneyId)}/track-usage`
2389
- )
2390
- );
2391
- }
2392
- async verifyMobileMoney(mobileMoneyId) {
2393
- return safe(
2394
- this.client.linkPost(
2395
- `/v1/link/mobile-money/${encodePathSegment(mobileMoneyId)}/verify`
2396
- )
2397
- );
2398
- }
2399
- async getSessions() {
2400
- return safe(this.client.linkGet("/v1/link/sessions"));
2401
- }
2402
- async revokeSession(sessionId) {
2403
- return safe(this.client.linkDelete(`/v1/link/sessions/${sessionId}`));
2404
- }
2405
- async revokeAllSessions() {
2406
- return safe(this.client.linkDelete("/v1/link/sessions"));
2407
- }
2408
- };
2409
-
2410
- // src/auth.ts
2411
- var AuthService = class {
2412
- constructor(client) {
2413
- this.client = client;
2414
- }
2415
- async getStatus() {
2416
- return safe(this.client.get("/api/v1/auth/status"));
2417
- }
2418
- async getCurrentUser() {
2419
- const result = await this.getStatus();
2420
- if (!result.ok) return result;
2421
- return ok(result.value.customer || null);
2422
- }
2423
- async isAuthenticated() {
2424
- const result = await this.getStatus();
2425
- if (!result.ok) return result;
2426
- return ok(result.value.is_authenticated);
2427
- }
2428
- async requestOtp(contact, contactType) {
2429
- return safe(
2430
- this.client.post("/api/v1/auth/request-otp", {
2431
- contact,
2432
- contact_type: contactType
2433
- })
2434
- );
2435
- }
2436
- async verifyOtp(code, contact) {
2437
- return safe(
2438
- this.client.post("/api/v1/auth/verify-otp", {
2439
- otp_code: code,
2440
- contact
2441
- })
2442
- );
2443
- }
2444
- async logout() {
2445
- return safe(this.client.post("/api/v1/auth/logout"));
2446
- }
2447
- async updateProfile(input) {
2448
- return safe(this.client.post("/api/v1/auth/profile", input));
2449
- }
2450
- };
2451
-
2452
- // src/business.ts
2453
- var BusinessService = class {
2454
- constructor(client) {
2455
- this.client = client;
2456
- }
2457
- async getInfo() {
2458
- return safe(this.client.get("/api/v1/business"));
2459
- }
2460
- async getByHandle(handle) {
2461
- const encodedHandle = encodeURIComponent(handle);
2462
- return safe(this.client.get(`/api/v1/business/by-handle/${encodedHandle}`));
2463
- }
2464
- async getByDomain(domain) {
2465
- const encodedDomain = encodeURIComponent(domain);
2466
- return safe(this.client.get(`/api/v1/business/by-domain?domain=${encodedDomain}`));
2467
- }
2468
- async getSettings() {
2469
- return safe(this.client.get("/api/v1/business/settings"));
2470
- }
2471
- async getLocations() {
2472
- return safe(this.client.get("/api/v1/business/locations"));
2473
- }
2474
- async getLocation(locationId) {
2475
- const result = await this.getLocations();
2476
- if (!result.ok) return err(result.error);
2477
- const location = result.value.find((item) => item.id === locationId);
2478
- if (!location) {
2479
- return err(new CimplifyError(ErrorCode.NOT_FOUND, `Location not found: ${locationId}`, false));
2480
- }
2481
- return ok(location);
2482
- }
2483
- async getHours() {
2484
- return safe(this.client.get("/api/v1/business/hours"));
2485
- }
2486
- async getLocationHours(locationId) {
2487
- const result = await this.getHours();
2488
- if (!result.ok) return result;
2489
- return ok(result.value.filter((hour) => hour.location_id === locationId));
2490
- }
2491
- async getBootstrap() {
2492
- return safe(this.client.get("/api/v1/bootstrap"));
2493
- }
2494
- };
2495
-
2496
- // src/inventory.ts
2497
- var InventoryService = class {
2498
- constructor(client) {
2499
- this.client = client;
2500
- }
2501
- withQuery(path, params) {
2502
- const searchParams = new URLSearchParams();
2503
- for (const [key, value] of Object.entries(params)) {
2504
- if (value === void 0) continue;
2505
- searchParams.set(key, String(value));
2506
- }
2507
- const query2 = searchParams.toString();
2508
- return query2 ? `${path}?${query2}` : path;
2509
- }
2510
- async getProductStock(productId, locationId) {
2511
- const encodedId = encodeURIComponent(productId);
2512
- const path = this.withQuery(`/api/v1/inventory/products/${encodedId}/stock`, {
2513
- location_id: locationId
2514
- });
2515
- return safe(this.client.get(path));
2516
- }
2517
- async getVariantStock(variantId, locationId) {
2518
- const encodedId = encodeURIComponent(variantId);
2519
- const path = this.withQuery(`/api/v1/inventory/variants/${encodedId}/stock`, {
2520
- location_id: locationId
2521
- });
2522
- return safe(this.client.get(path));
2523
- }
2524
- async checkProductAvailability(productId, quantity, locationId) {
2525
- const encodedId = encodeURIComponent(productId);
2526
- const path = this.withQuery(`/api/v1/inventory/products/${encodedId}/availability`, {
2527
- quantity,
2528
- location_id: locationId
2529
- });
2530
- return safe(this.client.get(path));
2531
- }
2532
- async checkVariantAvailability(variantId, quantity, locationId) {
2533
- const encodedId = encodeURIComponent(variantId);
2534
- const path = this.withQuery(`/api/v1/inventory/variants/${encodedId}/availability`, {
2535
- quantity,
2536
- location_id: locationId
2537
- });
2538
- return safe(this.client.get(path));
2539
- }
2540
- async checkMultipleAvailability(items, locationId) {
2541
- const results = await Promise.all(
2542
- items.map(
2543
- (item) => item.variant_id ? this.checkVariantAvailability(item.variant_id, item.quantity, locationId) : this.checkProductAvailability(item.product_id, item.quantity, locationId)
2544
- )
2545
- );
2546
- for (const result of results) {
2547
- if (!result.ok) return result;
2548
- }
2549
- return ok(results.map((r) => r.value));
2550
- }
2551
- async isInStock(productId, locationId) {
2552
- const result = await this.checkProductAvailability(productId, 1, locationId);
2553
- if (!result.ok) return result;
2554
- return ok(result.value.is_available);
2555
- }
2556
- async getAvailableQuantity(productId, locationId) {
2557
- const result = await this.getProductStock(productId, locationId);
2558
- if (!result.ok) return result;
2559
- return ok(result.value.available_quantity);
2560
- }
2561
- };
2562
-
2563
- // src/scheduling.ts
2564
- function withQuery2(path, params) {
2565
- const searchParams = new URLSearchParams();
2566
- for (const [key, value] of Object.entries(params)) {
2567
- if (value === void 0) continue;
2568
- searchParams.set(key, String(value));
2569
- }
2570
- const query2 = searchParams.toString();
2571
- return query2 ? `${path}?${query2}` : path;
2572
- }
2573
- function firstScheduledTime(booking) {
2574
- return booking.service_items.find((item) => typeof item.scheduled_start === "string")?.scheduled_start || booking.created_at;
2575
- }
2576
- var SchedulingService = class {
2577
- constructor(client) {
2578
- this.client = client;
2579
- }
2580
- async getServices() {
2581
- return safe(this.client.get("/api/v1/scheduling/services"));
2582
- }
2583
- async getService(serviceId) {
2584
- const encodedId = encodeURIComponent(serviceId);
2585
- return safe(this.client.get(`/api/v1/scheduling/services/${encodedId}`));
2586
- }
2587
- async getAvailableSlots(input) {
2588
- const path = withQuery2("/api/v1/scheduling/slots", {
2589
- service_id: input.service_id,
2590
- date: input.date,
2591
- participant_count: input.participant_count,
2592
- duration_minutes: input.duration_minutes
2593
- });
2594
- return safe(this.client.get(path));
2595
- }
2596
- async checkSlotAvailability(input) {
2597
- const path = withQuery2("/api/v1/scheduling/slots/check", {
2598
- service_id: input.service_id,
2599
- slot_time: input.slot_time,
2600
- duration_minutes: input.duration_minutes,
2601
- participant_count: input.participant_count
2602
- });
2603
- return safe(this.client.get(path));
2604
- }
2605
- async getServiceAvailability(params) {
2606
- const path = withQuery2("/api/v1/scheduling/availability", {
2607
- service_id: params.service_id,
2608
- start_date: params.start_date,
2609
- end_date: params.end_date,
2610
- location_id: params.location_id,
2611
- participant_count: params.participant_count
2612
- });
2613
- return safe(this.client.get(path));
2614
- }
2615
- async getBooking(bookingId) {
2616
- const encodedId = encodeURIComponent(bookingId);
2617
- return safe(this.client.get(`/api/v1/scheduling/bookings/${encodedId}`));
2618
- }
2619
- async getCustomerBookings(customerId) {
2620
- const path = withQuery2("/api/v1/scheduling/bookings", {
2621
- customer_id: customerId
2622
- });
2623
- return safe(this.client.get(path));
2624
- }
2625
- async getUpcomingBookings() {
2626
- const result = await this.getCustomerBookings();
2627
- if (!result.ok) return result;
2628
- const upcoming = result.value.filter((booking) => {
2629
- const status = String(booking.status).toLowerCase();
2630
- return status !== "completed" && status !== "cancelled";
2631
- }).sort((a, b) => firstScheduledTime(a).localeCompare(firstScheduledTime(b)));
2632
- return ok(upcoming);
2633
- }
2634
- async getPastBookings(limit = 10) {
2635
- const result = await this.getCustomerBookings();
2636
- if (!result.ok) return result;
2637
- const past = result.value.filter((booking) => String(booking.status).toLowerCase() === "completed").sort((a, b) => firstScheduledTime(b).localeCompare(firstScheduledTime(a))).slice(0, Math.max(0, limit));
2638
- return ok(past);
2639
- }
2640
- async cancelBooking(input) {
2641
- const encodedId = encodeURIComponent(input.booking_id);
2642
- return safe(
2643
- this.client.post(`/api/v1/scheduling/bookings/${encodedId}/cancel`, {
2644
- reason: input.reason
2645
- })
2646
- );
2647
- }
2648
- async rescheduleBooking(input) {
2649
- return safe(
2650
- this.client.post("/api/v1/scheduling/bookings/reschedule", input)
2651
- );
2652
- }
2653
- async getNextAvailableSlot(serviceId, fromDate) {
2654
- const date = fromDate || (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
2655
- const result = await this.getAvailableSlots({
2656
- service_id: serviceId,
2657
- date
2658
- });
2659
- if (!result.ok) return result;
2660
- return ok(result.value.find((slot) => slot.is_available) || null);
2661
- }
2662
- async hasAvailabilityOn(serviceId, date) {
2663
- const result = await this.getAvailableSlots({
2664
- service_id: serviceId,
2665
- date
2666
- });
2667
- if (!result.ok) return result;
2668
- return ok(result.value.some((slot) => slot.is_available));
2669
- }
2670
- };
2671
-
2672
- // src/lite.ts
2673
- var LiteService = class {
2674
- constructor(client) {
2675
- this.client = client;
2676
- }
2677
- async getBootstrap() {
2678
- return safe(this.client.get("/api/v1/lite/bootstrap"));
2679
- }
2680
- async getTable(tableId) {
2681
- const encodedId = encodeURIComponent(tableId);
2682
- return safe(this.client.get(`/api/v1/lite/tables/${encodedId}`));
2683
- }
2684
- async getMenu() {
2685
- return safe(this.client.get("/api/v1/lite/menu"));
2686
- }
2687
- async getMenuByCategory(categoryId) {
2688
- const encodedId = encodeURIComponent(categoryId);
2689
- return safe(this.client.get(`/api/v1/lite/menu/categories/${encodedId}`));
2690
- }
2691
- };
2692
-
2693
- // src/fx.ts
2694
- var FxService = class {
2695
- constructor(client) {
2696
- this.client = client;
2697
- }
2698
- async getRate(from, to) {
2699
- const path = `/api/v1/fx/rate?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`;
2700
- return safe(this.client.get(path));
2701
- }
2702
- async lockQuote(request) {
2703
- return safe(this.client.post("/api/v1/fx/quotes", request));
2704
- }
2705
- };
2706
-
2707
- // src/activity.ts
2708
- var ActivityService = class {
2709
- constructor(client) {
2710
- this.client = client;
2711
- }
2712
- trackProductView(productId, options = {}) {
2713
- const event = {
2714
- type: "product_view",
2715
- product_id: productId,
2716
- product_name: options.productName,
2717
- category_id: options.categoryId,
2718
- price: options.price,
2719
- page_path: options.pagePath ?? currentPath()
2720
- };
2721
- this.sendEvents([event]);
2722
- }
2723
- trackCategoryView(categoryId, options = {}) {
2724
- const event = {
2725
- type: "category_view",
2726
- category_id: categoryId,
2727
- category_name: options.categoryName,
2728
- page_path: options.pagePath ?? currentPath()
2729
- };
2730
- this.sendEvents([event]);
2731
- }
2732
- sendEvents(events) {
2733
- try {
2734
- this.client.post("/api/v1/activity/events", { events }).catch(() => {
2735
- });
2736
- } catch {
2737
- }
2738
- }
2739
- };
2740
- function currentPath() {
2741
- if (typeof window !== "undefined") {
2742
- return window.location.pathname;
2743
- }
2744
- return void 0;
2745
- }
2746
-
2747
- // src/types/elements.ts
2748
- var ELEMENT_TYPES = {
2749
- AUTH: "auth",
2750
- ADDRESS: "address",
2751
- PAYMENT: "payment",
2752
- CHECKOUT: "checkout"
2753
- };
2754
- var MESSAGE_TYPES = {
2755
- INIT: "init",
2756
- SET_TOKEN: "set_token",
2757
- SET_CART: "set_cart",
2758
- GET_DATA: "get_data",
2759
- REFRESH_TOKEN: "refresh_token",
2760
- LOGOUT: "logout",
2761
- PROCESS_CHECKOUT: "process_checkout",
2762
- ABORT_CHECKOUT: "abort_checkout",
2763
- READY: "ready",
2764
- HEIGHT_CHANGE: "height_change",
2765
- AUTHENTICATED: "authenticated",
2766
- REQUIRES_OTP: "requires_otp",
2767
- ERROR: "error",
2768
- ADDRESS_CHANGED: "address_changed",
2769
- ADDRESS_SELECTED: "address_selected",
2770
- PAYMENT_METHOD_SELECTED: "payment_method_selected",
2771
- TOKEN_REFRESHED: "token_refreshed",
2772
- LOGOUT_COMPLETE: "logout_complete",
2773
- CONTACT_PROVIDED: "contact_provided",
2774
- CHECKOUT_STATUS: "checkout_status",
2775
- CHECKOUT_COMPLETE: "checkout_complete",
2776
- ORDER_TYPE_CHANGED: "order_type_changed",
2777
- REQUEST_SUBMIT: "request_submit"
2778
- };
2779
- var EVENT_TYPES = {
2780
- READY: "ready",
2781
- AUTHENTICATED: "authenticated",
2782
- REQUIRES_OTP: "requires_otp",
2783
- ERROR: "error",
2784
- CHANGE: "change",
2785
- BLUR: "blur",
2786
- FOCUS: "focus",
2787
- ORDER_TYPE_CHANGED: "order_type_changed",
2788
- REQUEST_SUBMIT: "request_submit"
2789
- };
2790
-
2791
- // src/elements.ts
2792
- function toCheckoutError(code, message, recoverable) {
2793
- const hint = getErrorHint(code);
2794
- return {
2795
- success: false,
2796
- error: {
2797
- code,
2798
- message,
2799
- recoverable,
2800
- docs_url: hint?.docs_url,
2801
- suggestion: hint?.suggestion
2802
- }
2803
- };
2804
- }
2805
- var DEFAULT_LINK_URL = "https://link.cimplify.io";
2806
- function generateNonce() {
2807
- if (typeof crypto !== "undefined" && crypto.randomUUID) {
2808
- return crypto.randomUUID().replace(/-/g, "").slice(0, 16);
2809
- }
2810
- return Math.random().toString(36).slice(2) + Math.random().toString(36).slice(2);
2811
- }
2812
- function isAllowedOrigin(origin) {
2813
- try {
2814
- const url = new URL(origin);
2815
- const hostname = url.hostname;
2816
- if (hostname === "localhost" || hostname === "127.0.0.1") {
2817
- return true;
2818
- }
2819
- if (url.protocol !== "https:") {
2820
- return false;
2821
- }
2822
- return hostname === "cimplify.io" || hostname.endsWith(".cimplify.io");
2823
- } catch {
2824
- return false;
2825
- }
2826
- }
2827
- function parseIframeMessage(data) {
2828
- if (!data || typeof data !== "object") {
2829
- return null;
2830
- }
2831
- const maybeType = data.type;
2832
- if (typeof maybeType !== "string") {
2833
- return null;
2834
- }
2835
- return data;
2836
- }
2837
- var CimplifyElements = class {
2838
- constructor(client, businessId, options = {}) {
2839
- this.elements = /* @__PURE__ */ new Map();
2840
- this.accessToken = null;
2841
- this.accountId = null;
2842
- this.customerId = null;
2843
- this.customerData = null;
2844
- this.addressData = null;
2845
- this.paymentData = null;
2846
- this.checkoutInProgress = false;
2847
- this.activeCheckoutAbort = null;
2848
- this.businessIdResolvePromise = null;
2849
- this.client = client;
2850
- this.businessId = businessId ?? null;
2851
- this.linkUrl = options.linkUrl || DEFAULT_LINK_URL;
2852
- this.options = options;
2853
- this.boundHandleMessage = this.handleMessage.bind(this);
2854
- if (typeof window !== "undefined") {
2855
- window.addEventListener("message", this.boundHandleMessage);
2856
- }
2857
- }
2858
- debug(...args) {
2859
- if (this.client.isTestMode()) {
2860
- console.debug(...args);
2861
- }
2862
- }
2863
- create(type, options = {}) {
2864
- const existing = this.elements.get(type);
2865
- if (existing) return existing;
2866
- const element = new CimplifyElement(type, this.businessId, this.linkUrl, options, this);
2867
- this.elements.set(type, element);
2868
- return element;
2869
- }
2870
- getElement(type) {
2871
- return this.elements.get(type);
2872
- }
2873
- _removeElement(type, instance) {
2874
- const current = this.elements.get(type);
2875
- if (current === instance) {
2876
- this.elements.delete(type);
2877
- }
2878
- }
2879
- destroy() {
2880
- this.elements.forEach((element) => element.destroy());
2881
- this.elements.clear();
2882
- if (typeof window !== "undefined") {
2883
- window.removeEventListener("message", this.boundHandleMessage);
2884
- }
2885
- }
2886
- async submitCheckout(data) {
2887
- const result = await this.processCheckout({
2888
- cart_id: data.cart_id,
2889
- order_type: data.order_type ?? "delivery",
2890
- location_id: data.location_id,
2891
- notes: data.notes,
2892
- scheduled_time: data.scheduled_time,
2893
- tip_amount: data.tip_amount,
2894
- enroll_in_link: true
2895
- });
2896
- if (result.success) {
2897
- return {
2898
- success: true,
2899
- order: {
2900
- id: result.order?.id || "",
2901
- status: result.order?.status || "unknown",
2902
- total: result.order?.total || ""
2903
- }
2904
- };
2905
- }
2906
- return {
2907
- success: false,
2908
- error: {
2909
- code: result.error?.code || "CHECKOUT_FAILED",
2910
- message: result.error?.message || "Checkout failed"
2911
- }
2912
- };
2913
- }
2914
- processCheckout(options) {
2915
- let abortFn = null;
2916
- const task = (async () => {
2917
- this.debug("[cimplify:checkout] processCheckout called", { cart_id: options.cart_id, order_type: options.order_type, location_id: options.location_id });
2918
- if (this.checkoutInProgress) {
2919
- this.debug("[cimplify:checkout] BLOCKED: already processing");
2920
- return toCheckoutError(
2921
- "ALREADY_PROCESSING",
2922
- "Checkout is already in progress.",
2923
- false
2924
- );
2925
- }
2926
- this.checkoutInProgress = true;
2927
- if (!options.cart_id) {
2928
- this.debug("[cimplify:checkout] BLOCKED: no cart_id");
2929
- this.checkoutInProgress = false;
2930
- return toCheckoutError(
2931
- "INVALID_CART",
2932
- "A valid cart is required before checkout can start.",
2933
- false
2934
- );
2935
- }
2936
- if (!options.order_type) {
2937
- this.debug("[cimplify:checkout] BLOCKED: no order_type");
2938
- this.checkoutInProgress = false;
2939
- return toCheckoutError(
2940
- "ORDER_TYPE_REQUIRED",
2941
- "Order type is required before checkout can start.",
2942
- false
2943
- );
2944
- }
2945
- const checkoutElement = this.elements.get(ELEMENT_TYPES.CHECKOUT) || this.elements.get(ELEMENT_TYPES.PAYMENT);
2946
- if (!checkoutElement) {
2947
- this.debug("[cimplify:checkout] BLOCKED: no checkout element");
2948
- this.checkoutInProgress = false;
2949
- return toCheckoutError(
2950
- "NO_PAYMENT_ELEMENT",
2951
- "Checkout element must be mounted before checkout.",
2952
- false
2953
- );
2954
- }
2955
- if (!checkoutElement.isMounted()) {
2956
- this.debug("[cimplify:checkout] BLOCKED: checkout element not mounted");
2957
- this.checkoutInProgress = false;
2958
- return toCheckoutError(
2959
- "PAYMENT_NOT_MOUNTED",
2960
- "Checkout element must be mounted before checkout.",
2961
- false
2962
- );
2963
- }
2964
- const isUnifiedCheckout = this.elements.has(ELEMENT_TYPES.CHECKOUT);
2965
- if (!isUnifiedCheckout) {
2966
- const authElement = this.elements.get(ELEMENT_TYPES.AUTH);
2967
- if (authElement && !this.accessToken) {
2968
- this.debug("[cimplify:checkout] BLOCKED: auth incomplete");
2969
- this.checkoutInProgress = false;
2970
- return toCheckoutError(
2971
- "AUTH_INCOMPLETE",
2972
- "Authentication must complete before checkout can start.",
2973
- true
2974
- );
2975
- }
2976
- const addressElement = this.elements.get(ELEMENT_TYPES.ADDRESS);
2977
- if (addressElement) {
2978
- this.debug("[cimplify:checkout] getting address data...");
2979
- await addressElement.getData();
2980
- this.debug("[cimplify:checkout] address data resolved", this.addressData);
2981
- }
2982
- await this.hydrateCustomerData();
2983
- }
2984
- this.debug("[cimplify:checkout] customer data hydrated", { customerData: this.customerData, accountId: this.accountId, isUnifiedCheckout });
2985
- const processMessage = {
2986
- type: MESSAGE_TYPES.PROCESS_CHECKOUT,
2987
- cart_id: options.cart_id,
2988
- order_type: options.order_type,
2989
- location_id: options.location_id,
2990
- notes: options.notes,
2991
- scheduled_time: options.scheduled_time,
2992
- tip_amount: options.tip_amount,
2993
- pay_currency: options.pay_currency,
2994
- enroll_in_link: options.enroll_in_link ?? true,
2995
- address: isUnifiedCheckout ? void 0 : this.addressData ?? void 0,
2996
- customer: isUnifiedCheckout ? void 0 : this.customerData ? {
2997
- name: this.customerData.name,
2998
- email: this.customerData.email,
2999
- phone: this.customerData.phone
3000
- } : null,
3001
- account_id: this.accountId ?? void 0,
3002
- customer_id: this.customerId ?? void 0
3003
- };
3004
- const timeoutMs = options.timeout_ms ?? 18e4;
3005
- const paymentWindow = checkoutElement.getContentWindow();
3006
- return new Promise((resolve) => {
3007
- let settled = false;
3008
- const cleanup = () => {
3009
- if (typeof window !== "undefined") {
3010
- window.removeEventListener("message", handleCheckoutMessage);
3011
- }
3012
- clearTimeout(timeout);
3013
- this.checkoutInProgress = false;
3014
- this.activeCheckoutAbort = null;
3015
- };
3016
- const settle = (result) => {
3017
- if (settled) {
3018
- return;
3019
- }
3020
- settled = true;
3021
- cleanup();
3022
- resolve(result);
3023
- };
3024
- const timeout = setTimeout(() => {
3025
- settle(
3026
- toCheckoutError(
3027
- "TIMEOUT",
3028
- "Checkout timed out before receiving a terminal response.",
3029
- true
3030
- )
3031
- );
3032
- }, timeoutMs);
3033
- const handleCheckoutMessage = (event) => {
3034
- if (!isAllowedOrigin(event.origin)) {
3035
- return;
3036
- }
3037
- const message = parseIframeMessage(event.data);
3038
- if (!message) {
3039
- return;
3040
- }
3041
- if (message.type === MESSAGE_TYPES.LOGOUT_COMPLETE) {
3042
- checkoutElement.sendMessage({ type: MESSAGE_TYPES.ABORT_CHECKOUT });
3043
- settle(
3044
- toCheckoutError(
3045
- "AUTH_LOST",
3046
- "Authentication was cleared during checkout.",
3047
- true
3048
- )
3049
- );
3050
- return;
3051
- }
3052
- if (paymentWindow && event.source && event.source !== paymentWindow) {
3053
- return;
3054
- }
3055
- if (message.type === MESSAGE_TYPES.CHECKOUT_STATUS) {
3056
- options.on_status_change?.(message.status, message.context);
3057
- return;
3058
- }
3059
- if (message.type === MESSAGE_TYPES.CHECKOUT_COMPLETE) {
3060
- this.debug("[cimplify:checkout] received checkout_complete", { success: message.success, error: message.error });
3061
- settle({
3062
- success: message.success,
3063
- order: message.order,
3064
- error: message.error,
3065
- enrolled_in_link: message.enrolled_in_link
3066
- });
3067
- }
3068
- };
3069
- if (typeof window !== "undefined") {
3070
- window.addEventListener("message", handleCheckoutMessage);
3071
- }
3072
- abortFn = () => {
3073
- checkoutElement.sendMessage({ type: MESSAGE_TYPES.ABORT_CHECKOUT });
3074
- settle(
3075
- toCheckoutError(
3076
- "CANCELLED",
3077
- "Checkout was cancelled.",
3078
- true
3079
- )
3080
- );
3081
- };
3082
- this.activeCheckoutAbort = abortFn;
3083
- this.debug("[cimplify:checkout] sending process_checkout to checkout iframe", { cart_id: processMessage.cart_id, order_type: processMessage.order_type, hasCustomer: !!processMessage.customer, hasAddress: !!processMessage.address, isUnifiedCheckout });
3084
- checkoutElement.sendMessage(processMessage);
3085
- this.debug("[cimplify:checkout] postMessage sent, waiting for checkout_complete...");
3086
- });
3087
- })();
3088
- const abortable = task;
3089
- abortable.abort = () => {
3090
- if (abortFn) {
3091
- abortFn();
3092
- }
3093
- };
3094
- return abortable;
3095
- }
3096
- isAuthenticated() {
3097
- return this.accessToken !== null;
3098
- }
3099
- getAccessToken() {
3100
- return this.accessToken;
3101
- }
3102
- getPublicKey() {
3103
- return this.client.getPublicKey();
3104
- }
3105
- getBusinessId() {
3106
- return this.businessId;
3107
- }
3108
- async resolveBusinessId() {
3109
- if (this.businessId) {
3110
- return this.businessId;
3111
- }
3112
- if (this.businessIdResolvePromise) {
3113
- return this.businessIdResolvePromise;
3114
- }
3115
- this.businessIdResolvePromise = this.client.resolveBusinessId().then((resolvedBusinessId) => {
3116
- this.businessId = resolvedBusinessId;
3117
- return resolvedBusinessId;
3118
- }).catch(() => null).finally(() => {
3119
- this.businessIdResolvePromise = null;
3120
- });
3121
- return this.businessIdResolvePromise;
3122
- }
3123
- getAppearance() {
3124
- return this.options.appearance;
3125
- }
3126
- async hydrateCustomerData() {
3127
- if (!this.accessToken || this.customerData) {
3128
- return;
3129
- }
3130
- if (!this.client.getAccessToken()) {
3131
- this.client.setAccessToken(this.accessToken);
3132
- }
3133
- const linkDataResult = await this.client.link.getLinkData();
3134
- if (!linkDataResult.ok || !linkDataResult.value?.customer) {
3135
- return;
3136
- }
3137
- const customer = linkDataResult.value.customer;
3138
- this.customerData = {
3139
- name: customer.name || "",
3140
- email: customer.email || null,
3141
- phone: customer.phone || null
3142
- };
3143
- }
3144
- handleMessage(event) {
3145
- if (!isAllowedOrigin(event.origin)) {
3146
- return;
3147
- }
3148
- const message = parseIframeMessage(event.data);
3149
- if (!message) return;
3150
- switch (message.type) {
3151
- case MESSAGE_TYPES.AUTHENTICATED:
3152
- const customer = message.customer ?? {
3153
- name: "",
3154
- email: null,
3155
- phone: null
3156
- };
3157
- this.accessToken = message.token;
3158
- this.accountId = message.accountId;
3159
- this.customerId = message.customerId;
3160
- this.customerData = customer;
3161
- this.client.setAccessToken(message.token);
3162
- this.elements.forEach((element, type) => {
3163
- if (type !== ELEMENT_TYPES.AUTH && type !== ELEMENT_TYPES.CHECKOUT) {
3164
- element.sendMessage({ type: MESSAGE_TYPES.SET_TOKEN, token: message.token });
3165
- }
3166
- });
3167
- break;
3168
- case MESSAGE_TYPES.TOKEN_REFRESHED:
3169
- this.accessToken = message.token;
3170
- break;
3171
- case MESSAGE_TYPES.ADDRESS_CHANGED:
3172
- case MESSAGE_TYPES.ADDRESS_SELECTED:
3173
- this.addressData = message.address;
3174
- break;
3175
- case MESSAGE_TYPES.PAYMENT_METHOD_SELECTED:
3176
- this.paymentData = message.method;
3177
- break;
3178
- case MESSAGE_TYPES.CONTACT_PROVIDED:
3179
- if (!this.customerData) {
3180
- this.customerData = { name: "", email: null, phone: null };
3181
- }
3182
- if (message.contactType === "email") {
3183
- this.customerData.email = message.contact;
3184
- } else {
3185
- this.customerData.phone = message.contact;
3186
- }
3187
- break;
3188
- case MESSAGE_TYPES.LOGOUT_COMPLETE:
3189
- if (this.checkoutInProgress && this.activeCheckoutAbort) {
3190
- this.activeCheckoutAbort();
3191
- }
3192
- this.accessToken = null;
3193
- this.accountId = null;
3194
- this.customerId = null;
3195
- this.customerData = null;
3196
- this.addressData = null;
3197
- this.paymentData = null;
3198
- this.client.clearSession();
3199
- break;
3200
- }
3201
- }
3202
- _setAddressData(data) {
3203
- this.addressData = data;
3204
- }
3205
- _setPaymentData(data) {
3206
- this.paymentData = data;
3207
- }
3208
- _setGuestContact(contact, contactType) {
3209
- if (!this.customerData) {
3210
- this.customerData = { name: "", email: null, phone: null };
3211
- }
3212
- if (contactType === "email") {
3213
- this.customerData.email = contact;
3214
- } else {
3215
- this.customerData.phone = contact;
3216
- }
3217
- }
3218
- };
3219
- var CimplifyElement = class {
3220
- constructor(type, businessId, linkUrl, options, parent) {
3221
- this.iframe = null;
3222
- this.container = null;
3223
- this.mounted = false;
3224
- this.pendingInit = null;
3225
- this.eventHandlers = /* @__PURE__ */ new Map();
3226
- this.resolvers = /* @__PURE__ */ new Map();
3227
- this.listening = false;
3228
- this.type = type;
3229
- this.businessId = businessId;
3230
- this.linkUrl = linkUrl;
3231
- this.options = options;
3232
- this.parent = parent;
3233
- this.nonce = generateNonce();
3234
- this.boundHandleMessage = this.handleMessage.bind(this);
3235
- if (typeof window !== "undefined") {
3236
- window.addEventListener("message", this.boundHandleMessage);
3237
- this.listening = true;
3238
- }
3239
- }
3240
- mount(container) {
3241
- if (this.mounted) {
3242
- console.warn(`Element ${this.type} is already mounted`);
3243
- return;
3244
- }
3245
- const target = typeof container === "string" ? document.querySelector(container) : container;
3246
- if (!target) {
3247
- console.error(`Container not found: ${container}`);
3248
- return;
3249
- }
3250
- this.container = target;
3251
- this.mounted = true;
3252
- if (!this.listening && typeof window !== "undefined") {
3253
- window.addEventListener("message", this.boundHandleMessage);
3254
- this.listening = true;
3255
- }
3256
- void this.createIframe();
3257
- }
3258
- destroy() {
3259
- if (this.iframe) {
3260
- this.iframe.remove();
3261
- this.iframe = null;
3262
- }
3263
- this.container = null;
3264
- this.mounted = false;
3265
- this.eventHandlers.clear();
3266
- this.resolvers.forEach((entry) => clearTimeout(entry.timeoutId));
3267
- this.resolvers.clear();
3268
- if (this.listening && typeof window !== "undefined") {
3269
- window.removeEventListener("message", this.boundHandleMessage);
3270
- this.listening = false;
3271
- }
3272
- this.parent._removeElement(this.type, this);
3273
- }
3274
- on(event, handler) {
3275
- if (!this.eventHandlers.has(event)) {
3276
- this.eventHandlers.set(event, /* @__PURE__ */ new Set());
3277
- }
3278
- this.eventHandlers.get(event).add(handler);
3279
- }
3280
- off(event, handler) {
3281
- this.eventHandlers.get(event)?.delete(handler);
3282
- }
3283
- async getData() {
3284
- if (!this.isMounted()) {
3285
- return null;
3286
- }
3287
- return new Promise((resolve) => {
3288
- const id = Math.random().toString(36).slice(2);
3289
- const timeoutId = setTimeout(() => {
3290
- const entry = this.resolvers.get(id);
3291
- if (!entry) {
3292
- return;
3293
- }
3294
- this.resolvers.delete(id);
3295
- entry.resolve(null);
3296
- }, 5e3);
3297
- this.resolvers.set(id, { resolve, timeoutId });
3298
- this.sendMessage({ type: MESSAGE_TYPES.GET_DATA });
3299
- });
3300
- }
3301
- setCart(cart) {
3302
- this.sendMessage({ type: MESSAGE_TYPES.SET_CART, cart });
3303
- }
3304
- sendMessage(message) {
3305
- if (this.iframe?.contentWindow) {
3306
- this.iframe.contentWindow.postMessage(message, this.linkUrl);
3307
- } else {
3308
- console.warn("[cimplify:checkout] sendMessage DROPPED \u2014 no contentWindow", { type: message.type, hasIframe: !!this.iframe, isConnected: this.iframe?.isConnected });
3309
- }
3310
- }
3311
- getContentWindow() {
3312
- return this.iframe?.contentWindow ?? null;
3313
- }
3314
- isMounted() {
3315
- return this.mounted && Boolean(this.iframe) && this.iframe?.isConnected === true;
3316
- }
3317
- async createIframe() {
3318
- if (!this.container) return;
3319
- const resolvedBusinessId = this.businessId ?? await this.parent.resolveBusinessId();
3320
- if (!resolvedBusinessId || !this.container || !this.mounted) {
3321
- console.error("Unable to mount element without a resolved business ID");
3322
- this.emit(EVENT_TYPES.ERROR, {
3323
- code: "BUSINESS_ID_REQUIRED",
3324
- message: "Unable to initialize checkout without a business ID."
3325
- });
3326
- return;
3327
- }
3328
- this.businessId = resolvedBusinessId;
3329
- const iframe = document.createElement("iframe");
3330
- const url = new URL(`${this.linkUrl}/elements/${this.type}`);
3331
- url.searchParams.set("businessId", resolvedBusinessId);
3332
- url.searchParams.set("nonce", this.nonce);
3333
- if (this.options.prefillEmail) url.searchParams.set("email", this.options.prefillEmail);
3334
- if (this.options.mode) url.searchParams.set("mode", this.options.mode);
3335
- iframe.src = url.toString();
3336
- iframe.style.border = "none";
3337
- iframe.style.width = "100%";
3338
- iframe.style.minHeight = "200px";
3339
- iframe.style.display = "block";
3340
- iframe.style.overflow = "hidden";
3341
- iframe.style.background = "transparent";
3342
- iframe.setAttribute("allowtransparency", "true");
3343
- iframe.setAttribute("frameborder", "0");
3344
- iframe.setAttribute("allow", "geolocation");
3345
- iframe.setAttribute(
3346
- "sandbox",
3347
- "allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox"
3348
- );
3349
- this.iframe = iframe;
3350
- this.container.appendChild(iframe);
3351
- this.pendingInit = {
3352
- businessId: resolvedBusinessId,
3353
- publicKey: this.parent.getPublicKey()
3354
- };
3355
- }
3356
- handleMessage(event) {
3357
- if (!isAllowedOrigin(event.origin)) {
3358
- return;
3359
- }
3360
- const data = event.data;
3361
- if (data?.nonce) {
3362
- if (data.nonce !== this.nonce) return;
3363
- } else {
3364
- const iframeWindow = this.iframe?.contentWindow;
3365
- if (iframeWindow && event.source && event.source !== iframeWindow) {
3366
- return;
3367
- }
3368
- }
3369
- const message = parseIframeMessage(event.data);
3370
- if (!message) return;
3371
- switch (message.type) {
3372
- case MESSAGE_TYPES.READY:
3373
- if (this.iframe && message.height) this.iframe.style.height = `${message.height}px`;
3374
- if (this.pendingInit) {
3375
- const { publicKey } = this.pendingInit;
3376
- this.sendMessage({
3377
- type: MESSAGE_TYPES.INIT,
3378
- businessId: this.pendingInit.businessId,
3379
- publicKey,
3380
- demoMode: publicKey.length === 0,
3381
- prefillEmail: this.options.prefillEmail,
3382
- appearance: this.parent.getAppearance(),
3383
- orderTypes: this.options.orderTypes,
3384
- defaultOrderType: this.options.defaultOrderType,
3385
- renderSubmitButton: true,
3386
- submitLabel: this.options.submitLabel
3387
- });
3388
- const token = this.parent.getAccessToken();
3389
- if (token && this.type !== ELEMENT_TYPES.AUTH) {
3390
- this.sendMessage({ type: MESSAGE_TYPES.SET_TOKEN, token });
3391
- }
3392
- this.pendingInit = null;
3393
- }
3394
- this.emit(EVENT_TYPES.READY, { height: message.height });
3395
- break;
3396
- case MESSAGE_TYPES.HEIGHT_CHANGE:
3397
- if (this.iframe) this.iframe.style.height = `${message.height}px`;
3398
- break;
3399
- case MESSAGE_TYPES.AUTHENTICATED:
3400
- const customer = message.customer ?? {
3401
- name: "",
3402
- email: null,
3403
- phone: null
3404
- };
3405
- this.emit(EVENT_TYPES.AUTHENTICATED, {
3406
- accountId: message.accountId,
3407
- customerId: message.customerId,
3408
- token: message.token,
3409
- customer
3410
- });
3411
- break;
3412
- case MESSAGE_TYPES.REQUIRES_OTP:
3413
- this.emit(EVENT_TYPES.REQUIRES_OTP, { contactMasked: message.contactMasked });
3414
- break;
3415
- case MESSAGE_TYPES.ERROR:
3416
- this.emit(EVENT_TYPES.ERROR, { code: message.code, message: message.message });
3417
- break;
3418
- case MESSAGE_TYPES.ADDRESS_CHANGED:
3419
- case MESSAGE_TYPES.ADDRESS_SELECTED:
3420
- this.parent._setAddressData(message.address);
3421
- this.emit(EVENT_TYPES.CHANGE, { address: message.address });
3422
- this.resolveData(message.address);
3423
- break;
3424
- case MESSAGE_TYPES.PAYMENT_METHOD_SELECTED:
3425
- this.parent._setPaymentData(message.method);
3426
- this.emit(EVENT_TYPES.CHANGE, { paymentMethod: message.method });
3427
- this.resolveData(message.method);
3428
- break;
3429
- case MESSAGE_TYPES.CONTACT_PROVIDED:
3430
- this.parent._setGuestContact(message.contact, message.contactType);
3431
- break;
3432
- case MESSAGE_TYPES.ORDER_TYPE_CHANGED:
3433
- this.emit(EVENT_TYPES.ORDER_TYPE_CHANGED, { orderType: message.orderType });
3434
- break;
3435
- case MESSAGE_TYPES.REQUEST_SUBMIT:
3436
- this.emit(EVENT_TYPES.REQUEST_SUBMIT, {});
3437
- break;
3438
- }
3439
- }
3440
- emit(event, data) {
3441
- this.eventHandlers.get(event)?.forEach((handler) => handler(data));
3442
- }
3443
- resolveData(data) {
3444
- this.resolvers.forEach((entry) => {
3445
- clearTimeout(entry.timeoutId);
3446
- entry.resolve(data);
3447
- });
3448
- this.resolvers.clear();
3449
- }
3450
- };
3451
- function createElements(client, businessId, options) {
3452
- return new CimplifyElements(client, businessId, options);
3453
- }
3454
-
3455
- // src/client.ts
3456
- var ACCESS_TOKEN_STORAGE_KEY = "cimplify_access_token";
3457
- var SESSION_TOKEN_STORAGE_KEY = "cimplify_session_token";
3458
- var ORDER_TOKEN_PREFIX = "cimplify_ot_";
3459
- var SESSION_TOKEN_HEADER = "x-session-token";
3460
- var ORDER_TOKEN_TTL_MS = 24 * 60 * 60 * 1e3;
3461
- var DEFAULT_TIMEOUT_MS = 3e4;
3462
- var DEFAULT_MAX_RETRIES = 3;
3463
- var DEFAULT_RETRY_DELAY_MS = 1e3;
3464
- function sleep(ms) {
3465
- return new Promise((resolve) => setTimeout(resolve, ms));
3466
- }
3467
- function isRetryable(error) {
3468
- if (error instanceof TypeError && error.message.includes("fetch")) {
3469
- return true;
3470
- }
3471
- if (error instanceof DOMException && error.name === "AbortError") {
3472
- return true;
3473
- }
3474
- if (error instanceof CimplifyError) {
3475
- return error.retryable;
3476
- }
3477
- return false;
3478
- }
3479
- function toNetworkError(error, isTestMode) {
3480
- if (error instanceof DOMException && error.name === "AbortError") {
3481
- return enrichError(
3482
- new CimplifyError(
3483
- ErrorCode.TIMEOUT,
3484
- "Request timed out. Please check your connection and try again.",
3485
- true
3486
- ),
3487
- { isTestMode }
3488
- );
3489
- }
3490
- if (error instanceof TypeError && error.message.includes("fetch")) {
3491
- return enrichError(
3492
- new CimplifyError(
3493
- ErrorCode.NETWORK_ERROR,
3494
- "Network error. Please check your internet connection.",
3495
- true
3496
- ),
3497
- { isTestMode }
3498
- );
3499
- }
3500
- if (error instanceof CimplifyError) {
3501
- return enrichError(error, { isTestMode });
3502
- }
3503
- return enrichError(
3504
- new CimplifyError(
3505
- ErrorCode.UNKNOWN_ERROR,
3506
- error instanceof Error ? error.message : "An unknown error occurred",
3507
- false
3508
- ),
3509
- { isTestMode }
3510
- );
3511
- }
3512
- function deriveUrls() {
3513
- const hostname = typeof window !== "undefined" ? window.location.hostname : "";
3514
- if (hostname === "localhost" || hostname === "127.0.0.1") {
3515
- const protocol = window.location.protocol;
3516
- return {
3517
- baseUrl: `${protocol}//${hostname}:8082`,
3518
- linkApiUrl: `${protocol}//${hostname}:8080`
3519
- };
3520
- }
3521
- return {
3522
- baseUrl: "https://storefronts.cimplify.io",
3523
- linkApiUrl: "https://api.cimplify.io"
3524
- };
3525
- }
3526
- function normalizeUrl(url) {
3527
- const trimmed = url.trim();
3528
- if (!trimmed) return trimmed;
3529
- return trimmed.replace(/\/+$/, "");
3530
- }
3531
- function getEnvPublicKey() {
3532
- try {
3533
- const env = globalThis.process;
3534
- return env?.env.NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY || void 0;
3535
- } catch {
3536
- return void 0;
3537
- }
3538
- }
3539
- var CimplifyClient = class {
3540
- constructor(config = {}) {
3541
- this.accessToken = null;
3542
- this.sessionToken = null;
3543
- this.context = {};
3544
- this.businessId = null;
3545
- this.businessIdResolvePromise = null;
3546
- this.inflightRequests = /* @__PURE__ */ new Map();
3547
- this.publicKey = config.publicKey || getEnvPublicKey() || "";
3548
- const urls = deriveUrls();
3549
- this.baseUrl = config.baseUrl ? normalizeUrl(config.baseUrl) : urls.baseUrl;
3550
- this.linkApiUrl = config.linkApiUrl ? normalizeUrl(config.linkApiUrl) : urls.linkApiUrl;
3551
- this.credentials = config.credentials || "include";
3552
- this.timeout = config.timeout ?? DEFAULT_TIMEOUT_MS;
3553
- this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
3554
- this.retryDelay = config.retryDelay ?? DEFAULT_RETRY_DELAY_MS;
3555
- this.hooks = config.hooks ?? {};
3556
- this.accessToken = this.loadAccessToken();
3557
- this.sessionToken = this.loadSessionToken();
3558
- if (!this.publicKey && !config.suppressPublicKeyWarning) {
3559
- console.warn(
3560
- '[Cimplify] No public key found. Set NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY in your environment, or pass { publicKey: "pk_..." } to createCimplifyClient().'
3561
- );
3562
- }
3563
- }
3564
- buildUrl(base, path) {
3565
- const url = `${base}${path}`;
3566
- const locationId = this.context.location_id;
3567
- if (!locationId) return url;
3568
- const separator = url.includes("?") ? "&" : "?";
3569
- return `${url}${separator}location_id=${encodeURIComponent(locationId)}`;
3570
- }
3571
- getAccessToken() {
3572
- return this.accessToken;
3573
- }
3574
- getPublicKey() {
3575
- return this.publicKey;
3576
- }
3577
- isTestMode() {
3578
- return this.publicKey.trim().startsWith("pk_test_");
3579
- }
3580
- setAccessToken(token) {
3581
- const previous = this.accessToken;
3582
- this.accessToken = token;
3583
- this.saveAccessToken(token);
3584
- this.hooks.onSessionChange?.({
3585
- previousToken: previous,
3586
- newToken: token,
3587
- source: "manual"
3588
- });
3589
- }
3590
- clearSession() {
3591
- const previous = this.accessToken;
3592
- this.accessToken = null;
3593
- this.sessionToken = null;
3594
- this.saveAccessToken(null);
3595
- if (typeof window !== "undefined" && window.localStorage) {
3596
- localStorage.removeItem(SESSION_TOKEN_STORAGE_KEY);
3597
- }
3598
- this.hooks.onSessionChange?.({
3599
- previousToken: previous,
3600
- newToken: null,
3601
- source: "clear"
3602
- });
3603
- }
3604
- setOrderToken(orderId, token) {
3605
- if (typeof window !== "undefined" && window.localStorage) {
3606
- try {
3607
- const entry = JSON.stringify({ token, storedAt: Date.now() });
3608
- localStorage.setItem(`${ORDER_TOKEN_PREFIX}${orderId}`, entry);
3609
- } catch {
3610
- }
3611
- }
3612
- }
3613
- getOrderToken(orderId) {
3614
- if (typeof window !== "undefined" && window.localStorage) {
3615
- try {
3616
- const raw = localStorage.getItem(`${ORDER_TOKEN_PREFIX}${orderId}`);
3617
- if (!raw) return null;
3618
- const entry = JSON.parse(raw);
3619
- if (Date.now() - entry.storedAt > ORDER_TOKEN_TTL_MS) {
3620
- localStorage.removeItem(`${ORDER_TOKEN_PREFIX}${orderId}`);
3621
- return null;
3622
- }
3623
- return entry.token;
3624
- } catch {
3625
- return null;
3626
- }
3627
- }
3628
- return null;
3629
- }
3630
- clearOrderTokens() {
3631
- if (typeof window !== "undefined" && window.localStorage) {
3632
- const keysToRemove = [];
3633
- for (let i = 0; i < localStorage.length; i++) {
3634
- const key = localStorage.key(i);
3635
- if (key?.startsWith(ORDER_TOKEN_PREFIX)) {
3636
- keysToRemove.push(key);
3637
- }
3638
- }
3639
- keysToRemove.forEach((k) => localStorage.removeItem(k));
3640
- }
3641
- }
3642
- setLocationId(locationId) {
3643
- if (locationId) {
3644
- this.context.location_id = locationId;
3645
- } else {
3646
- delete this.context.location_id;
3647
- }
3648
- }
3649
- getLocationId() {
3650
- return this.context.location_id ?? null;
3651
- }
3652
- setBusinessId(businessId) {
3653
- const normalized = businessId.trim();
3654
- if (!normalized) {
3655
- return;
3656
- }
3657
- this.businessId = normalized;
3658
- }
3659
- getBusinessId() {
3660
- return this.businessId;
3661
- }
3662
- async resolveBusinessId() {
3663
- if (this.businessId) {
3664
- return this.businessId;
3665
- }
3666
- if (this.businessIdResolvePromise) {
3667
- return this.businessIdResolvePromise;
3668
- }
3669
- this.businessIdResolvePromise = (async () => {
3670
- const result = await this.business.getInfo();
3671
- if (!result.ok || !result.value?.id) {
3672
- throw new CimplifyError(
3673
- ErrorCode.NOT_FOUND,
3674
- "Unable to resolve business ID from the current public key.",
3675
- true
3676
- );
3677
- }
3678
- this.businessId = result.value.id;
3679
- return result.value.id;
3680
- })();
3681
- try {
3682
- return await this.businessIdResolvePromise;
3683
- } finally {
3684
- this.businessIdResolvePromise = null;
3685
- }
3686
- }
3687
- loadAccessToken() {
3688
- if (typeof window !== "undefined" && window.localStorage) {
3689
- return localStorage.getItem(ACCESS_TOKEN_STORAGE_KEY);
3690
- }
3691
- return null;
3692
- }
3693
- saveAccessToken(token) {
3694
- if (typeof window !== "undefined" && window.localStorage) {
3695
- try {
3696
- if (token) {
3697
- localStorage.setItem(ACCESS_TOKEN_STORAGE_KEY, token);
3698
- } else {
3699
- localStorage.removeItem(ACCESS_TOKEN_STORAGE_KEY);
3700
- }
3701
- } catch {
3702
- }
3703
- }
3704
- }
3705
- loadSessionToken() {
3706
- if (typeof window !== "undefined" && window.localStorage) {
3707
- return localStorage.getItem(SESSION_TOKEN_STORAGE_KEY);
3708
- }
3709
- return null;
3710
- }
3711
- saveSessionToken(token) {
3712
- if (typeof window !== "undefined" && window.localStorage) {
3713
- try {
3714
- localStorage.setItem(SESSION_TOKEN_STORAGE_KEY, token);
3715
- } catch {
3716
- }
3717
- }
3718
- }
3719
- captureSessionToken(response) {
3720
- const token = response.headers.get(SESSION_TOKEN_HEADER);
3721
- if (token && token !== this.sessionToken) {
3722
- this.sessionToken = token;
3723
- this.saveSessionToken(token);
3724
- }
3725
- }
3726
- getHeaders() {
3727
- const headers = {
3728
- "Content-Type": "application/json"
3729
- };
3730
- const trimmedPublicKey = this.publicKey.trim();
3731
- if (trimmedPublicKey) {
3732
- headers["X-API-Key"] = trimmedPublicKey;
3733
- }
3734
- if (this.accessToken) {
3735
- headers["Authorization"] = `Bearer ${this.accessToken}`;
3736
- }
3737
- if (this.sessionToken) {
3738
- headers[SESSION_TOKEN_HEADER] = this.sessionToken;
3739
- }
3740
- return headers;
3741
- }
3742
- async resilientFetch(url, options) {
3743
- const method = options.method || "GET";
3744
- const path = url.replace(this.baseUrl, "").replace(this.linkApiUrl, "");
3745
- const startTime = Date.now();
3746
- let retryCount = 0;
3747
- const context = {
3748
- method,
3749
- path,
3750
- url,
3751
- body: options.body ? JSON.parse(options.body) : void 0,
3752
- startTime
3753
- };
3754
- this.hooks.onRequestStart?.(context);
3755
- let lastError;
3756
- for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
3757
- try {
3758
- const controller = new AbortController();
3759
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
3760
- const response = await fetch(url, {
3761
- ...options,
3762
- signal: controller.signal
3763
- });
3764
- clearTimeout(timeoutId);
3765
- this.captureSessionToken(response);
3766
- if (response.ok) {
3767
- this.hooks.onRequestSuccess?.({
3768
- ...context,
3769
- status: response.status,
3770
- durationMs: Date.now() - startTime
3771
- });
3772
- return response;
3773
- }
3774
- if (response.status === 429 && attempt < this.maxRetries) {
3775
- retryCount++;
3776
- const retryAfter = response.headers.get("Retry-After");
3777
- const delay = retryAfter ? Math.min(parseInt(retryAfter, 10) * 1e3, 3e4) || this.retryDelay * Math.pow(2, attempt) : this.retryDelay * Math.pow(2, attempt);
3778
- this.hooks.onRetry?.({
3779
- ...context,
3780
- attempt: retryCount,
3781
- delayMs: delay,
3782
- error: new Error(`Rate limited: ${response.status}`)
3783
- });
3784
- await sleep(delay);
3785
- continue;
3786
- }
3787
- if (response.status >= 400 && response.status < 500) {
3788
- this.hooks.onRequestError?.({
3789
- ...context,
3790
- error: new CimplifyError(
3791
- `HTTP_${response.status}`,
3792
- `Request failed with status ${response.status}`,
3793
- false
3794
- ),
3795
- status: response.status,
3796
- durationMs: Date.now() - startTime,
3797
- retryCount,
3798
- retryable: false
3799
- });
3800
- return response;
3801
- }
3802
- if (response.status >= 500 && attempt < this.maxRetries) {
3803
- retryCount++;
3804
- const delay = this.retryDelay * Math.pow(2, attempt);
3805
- this.hooks.onRetry?.({
3806
- ...context,
3807
- attempt: retryCount,
3808
- delayMs: delay,
3809
- error: new Error(`Server error: ${response.status}`)
3810
- });
3811
- await sleep(delay);
3812
- continue;
3813
- }
3814
- this.hooks.onRequestError?.({
3815
- ...context,
3816
- error: new CimplifyError(
3817
- "SERVER_ERROR",
3818
- `Server error ${response.status} after ${retryCount} retries`,
3819
- false
3820
- ),
3821
- status: response.status,
3822
- durationMs: Date.now() - startTime,
3823
- retryCount,
3824
- retryable: false
3825
- });
3826
- return response;
3827
- } catch (error) {
3828
- lastError = error;
3829
- const networkError = toNetworkError(error, this.isTestMode());
3830
- const errorRetryable = isRetryable(error);
3831
- if (!errorRetryable || attempt >= this.maxRetries) {
3832
- this.hooks.onRequestError?.({
3833
- ...context,
3834
- error: networkError,
3835
- durationMs: Date.now() - startTime,
3836
- retryCount,
3837
- retryable: errorRetryable
3838
- });
3839
- throw networkError;
3840
- }
3841
- retryCount++;
3842
- const delay = this.retryDelay * Math.pow(2, attempt);
3843
- this.hooks.onRetry?.({
3844
- ...context,
3845
- attempt: retryCount,
3846
- delayMs: delay,
3847
- error: networkError
3848
- });
3849
- await sleep(delay);
3850
- }
3851
- }
3852
- const finalError = toNetworkError(lastError, this.isTestMode());
3853
- this.hooks.onRequestError?.({
3854
- ...context,
3855
- error: finalError,
3856
- durationMs: Date.now() - startTime,
3857
- retryCount,
3858
- retryable: false
3859
- });
3860
- throw finalError;
3861
- }
3862
- getDedupeKey(type, payload) {
3863
- return `${type}:${JSON.stringify(payload)}`;
3864
- }
3865
- async deduplicatedRequest(key, requestFn) {
3866
- const existing = this.inflightRequests.get(key);
3867
- if (existing) {
3868
- return existing;
3869
- }
3870
- const request = requestFn().finally(() => {
3871
- this.inflightRequests.delete(key);
3872
- });
3873
- this.inflightRequests.set(key, request);
3874
- return request;
3875
- }
3876
- async get(path) {
3877
- const key = this.getDedupeKey("get", path);
3878
- return this.deduplicatedRequest(key, async () => {
3879
- const response = await this.resilientFetch(this.buildUrl(this.baseUrl, path), {
3880
- method: "GET",
3881
- credentials: this.credentials,
3882
- headers: this.getHeaders()
3883
- });
3884
- return this.handleRestResponse(response);
3885
- });
3886
- }
3887
- async post(path, body) {
3888
- const response = await this.resilientFetch(this.buildUrl(this.baseUrl, path), {
3889
- method: "POST",
3890
- credentials: this.credentials,
3891
- headers: this.getHeaders(),
3892
- body: body ? JSON.stringify(body) : void 0
3893
- });
3894
- return this.handleRestResponse(response);
3895
- }
3896
- async patch(path, body) {
3897
- const response = await this.resilientFetch(this.buildUrl(this.baseUrl, path), {
3898
- method: "PATCH",
3899
- credentials: this.credentials,
3900
- headers: this.getHeaders(),
3901
- body: body ? JSON.stringify(body) : void 0
3902
- });
3903
- return this.handleRestResponse(response);
3904
- }
3905
- async delete(path) {
3906
- const response = await this.resilientFetch(this.buildUrl(this.baseUrl, path), {
3907
- method: "DELETE",
3908
- credentials: this.credentials,
3909
- headers: this.getHeaders()
3910
- });
3911
- return this.handleRestResponse(response);
3912
- }
3913
- async linkGet(path) {
3914
- const key = this.getDedupeKey("linkGet", path);
3915
- return this.deduplicatedRequest(key, async () => {
3916
- const response = await this.resilientFetch(`${this.linkApiUrl}${path}`, {
3917
- method: "GET",
3918
- credentials: this.credentials,
3919
- headers: this.getHeaders()
3920
- });
3921
- return this.handleRestResponse(response);
3922
- });
3923
- }
3924
- async linkPost(path, body) {
3925
- const response = await this.resilientFetch(`${this.linkApiUrl}${path}`, {
3926
- method: "POST",
3927
- credentials: this.credentials,
3928
- headers: this.getHeaders(),
3929
- body: body ? JSON.stringify(body) : void 0
3930
- });
3931
- return this.handleRestResponse(response);
3932
- }
3933
- async linkDelete(path) {
3934
- const response = await this.resilientFetch(`${this.linkApiUrl}${path}`, {
3935
- method: "DELETE",
3936
- credentials: this.credentials,
3937
- headers: this.getHeaders()
3938
- });
3939
- return this.handleRestResponse(response);
3940
- }
3941
- async handleRestResponse(response) {
3942
- const json = await response.json();
3943
- if (!response.ok) {
3944
- const errorCode = typeof json.error === "object" && json.error?.error_code || typeof json.error === "object" && json.error?.code || "API_ERROR";
3945
- const errorMessage = typeof json.error === "object" && json.error?.error_message || typeof json.error === "object" && json.error?.message || typeof json.error === "string" && json.error || typeof json.message === "string" && json.message || "An error occurred";
3946
- const retryable = typeof json.error === "object" && typeof json.error?.retryable === "boolean" ? json.error.retryable : false;
3947
- const error = enrichError(
3948
- new CimplifyError(
3949
- errorCode,
3950
- errorMessage,
3951
- retryable
3952
- ),
3953
- { isTestMode: this.isTestMode() }
3954
- );
3955
- if (response.status === 401 || error.code === ErrorCode.UNAUTHORIZED) {
3956
- console.warn(
3957
- "[Cimplify] Received 401 Unauthorized. Access token may be missing/expired. Refresh authentication and retry the request."
3958
- );
3959
- }
3960
- throw error;
3961
- }
3962
- if (json?.success === false || json?.error?.code || json?.error?.message) {
3963
- const error = enrichError(
3964
- new CimplifyError(
3965
- json.error?.code || "API_ERROR",
3966
- json.error?.message || "An error occurred",
3967
- json.error?.retryable || false
3968
- ),
3969
- { isTestMode: this.isTestMode() }
3970
- );
3971
- throw error;
3972
- }
3973
- if (json?.data !== void 0) {
3974
- return json.data;
3975
- }
3976
- return json;
3977
- }
3978
- get catalogue() {
3979
- if (!this._catalogue) {
3980
- this._catalogue = new CatalogueQueries(this);
3981
- }
3982
- return this._catalogue;
3983
- }
3984
- get cart() {
3985
- if (!this._cart) {
3986
- this._cart = new CartOperations(this);
3987
- }
3988
- return this._cart;
3989
- }
3990
- get checkout() {
3991
- if (!this._checkout) {
3992
- this._checkout = new CheckoutService(this);
3993
- }
3994
- return this._checkout;
3995
- }
3996
- get orders() {
3997
- if (!this._orders) {
3998
- this._orders = new OrderQueries(this);
3999
- }
4000
- return this._orders;
4001
- }
4002
- get link() {
4003
- if (!this._link) {
4004
- this._link = new LinkService(this);
4005
- }
4006
- return this._link;
4007
- }
4008
- get auth() {
4009
- if (!this._auth) {
4010
- this._auth = new AuthService(this);
4011
- }
4012
- return this._auth;
4013
- }
4014
- get business() {
4015
- if (!this._business) {
4016
- this._business = new BusinessService(this);
4017
- }
4018
- return this._business;
4019
- }
4020
- get inventory() {
4021
- if (!this._inventory) {
4022
- this._inventory = new InventoryService(this);
4023
- }
4024
- return this._inventory;
4025
- }
4026
- get scheduling() {
4027
- if (!this._scheduling) {
4028
- this._scheduling = new SchedulingService(this);
4029
- }
4030
- return this._scheduling;
4031
- }
4032
- get lite() {
4033
- if (!this._lite) {
4034
- this._lite = new LiteService(this);
4035
- }
4036
- return this._lite;
4037
- }
4038
- get fx() {
4039
- if (!this._fx) {
4040
- this._fx = new FxService(this);
4041
- }
4042
- return this._fx;
4043
- }
4044
- get activity() {
4045
- if (!this._activity) {
4046
- this._activity = new ActivityService(this);
4047
- }
4048
- return this._activity;
4049
- }
4050
- elements(businessId, options) {
4051
- if (businessId) {
4052
- this.setBusinessId(businessId);
4053
- }
4054
- return createElements(this, businessId ?? this.businessId ?? void 0, options);
4055
- }
4056
- };
4057
- function createCimplifyClient(config = {}) {
4058
- return new CimplifyClient(config);
4059
- }
4060
-
4061
- // src/query/builder.ts
4062
- function escapeQueryValue(value) {
4063
- return value.replace(/'/g, "\\'");
4064
- }
4065
- var QueryBuilder = class {
4066
- constructor(entity) {
4067
- this.filters = [];
4068
- this.modifiers = [];
4069
- this.pathSegments = [];
4070
- this.entity = entity;
4071
- }
4072
- path(segment) {
4073
- this.pathSegments.push(segment);
4074
- return this;
4075
- }
4076
- where(field, op, value) {
4077
- const v = typeof value === "string" ? `'${escapeQueryValue(value)}'` : value;
4078
- if (op === "contains" || op === "startsWith") {
4079
- this.filters.push(`@.${field} ${op} ${v}`);
4080
- } else {
4081
- this.filters.push(`@.${field}${op}${v}`);
4082
- }
4083
- return this;
4084
- }
4085
- and(field, op, value) {
4086
- return this.where(field, op, value);
4087
- }
4088
- sort(field, order = "asc") {
4089
- this.modifiers.push(`sort(${field},${order})`);
4090
- return this;
4091
- }
4092
- limit(n) {
4093
- this.modifiers.push(`limit(${n})`);
4094
- return this;
4095
- }
4096
- offset(n) {
4097
- this.modifiers.push(`offset(${n})`);
4098
- return this;
4099
- }
4100
- count() {
4101
- this.modifiers.push("count");
4102
- return this;
4103
- }
4104
- enriched() {
4105
- this.modifiers.push("enriched");
4106
- return this;
4107
- }
4108
- build() {
4109
- let query2 = this.entity;
4110
- if (this.pathSegments.length > 0) {
4111
- query2 += "." + this.pathSegments.join(".");
4112
- }
4113
- if (this.filters.length > 0) {
4114
- query2 += `[?(${this.filters.join(" && ")})]`;
4115
- }
4116
- for (const mod of this.modifiers) {
4117
- query2 += `#${mod}`;
4118
- }
4119
- return query2;
4120
- }
4121
- toString() {
4122
- return this.build();
4123
- }
4124
- };
4125
- function query(entity) {
4126
- return new QueryBuilder(entity);
4127
- }
4128
-
4129
- // src/utils/variant.ts
4130
- function stripProductPrefix(variantName, productName) {
4131
- if (!variantName || !productName) return variantName || productName;
4132
- const lower = variantName.toLowerCase().trim();
4133
- if (lower === "default" || lower === "standard") return productName;
4134
- if (lower.endsWith("-default") || lower.endsWith("-standard")) return productName;
4135
- if (variantName.startsWith(productName)) {
4136
- const rest = variantName.slice(productName.length);
4137
- const match = rest.match(/^\s*[-–—]\s*(.*)/);
4138
- if (match && match[1].length > 0) return match[1];
4139
- }
4140
- const lowerProduct = productName.toLowerCase().trim();
4141
- if (lower.startsWith(lowerProduct)) {
4142
- const rest = variantName.slice(productName.length);
4143
- const match = rest.match(/^\s*[-–—]\s*(.*)/);
4144
- if (match && match[1].length > 0) return match[1];
4145
- }
4146
- const lastDash = variantName.lastIndexOf("-");
4147
- if (lastDash > 0 && lastDash < variantName.length - 1) {
4148
- const prefix = variantName.slice(0, lastDash).trim();
4149
- const suffix = variantName.slice(lastDash + 1).trim();
4150
- if (suffix.length > 0 && prefix.length > suffix.length * 2) {
4151
- return suffix;
4152
- }
4153
- }
4154
- return variantName;
4155
- }
4156
- function getVariantDisplayName(variant, productName) {
4157
- if (variant.display_attributes?.length) {
4158
- return variant.display_attributes.map((a) => a.value_name).join(" / ");
4159
- }
4160
- if (variant.name) {
4161
- return productName ? stripProductPrefix(variant.name, productName) : variant.name;
4162
- }
4163
- return productName || (variant.is_default ? "Default" : "Option");
4164
- }
4165
- var ISO3_TO_COUNTRY_CODE = {
4166
- AGO: "AO",
4167
- ARE: "AE",
4168
- AUS: "AU",
4169
- BDI: "BI",
4170
- BRA: "BR",
4171
- BWA: "BW",
4172
- CAN: "CA",
4173
- CHE: "CH",
4174
- CHN: "CN",
4175
- COD: "CD",
4176
- EGY: "EG",
4177
- ETH: "ET",
4178
- GHA: "GH",
4179
- GIN: "GN",
4180
- GMB: "GM",
4181
- GBR: "GB",
4182
- HKG: "HK",
4183
- IDN: "ID",
4184
- IND: "IN",
4185
- ISR: "IL",
4186
- JPN: "JP",
4187
- KEN: "KE",
4188
- KOR: "KR",
4189
- LBR: "LR",
4190
- MUS: "MU",
4191
- MEX: "MX",
4192
- MOZ: "MZ",
4193
- MWI: "MW",
4194
- MYS: "MY",
4195
- NAM: "NA",
4196
- NGA: "NG",
4197
- PHL: "PH",
4198
- RWA: "RW",
4199
- SAU: "SA",
4200
- SGP: "SG",
4201
- SLE: "SL",
4202
- THA: "TH",
4203
- TUR: "TR",
4204
- TWN: "TW",
4205
- TZA: "TZ",
4206
- UGA: "UG",
4207
- USA: "US",
4208
- VNM: "VN",
4209
- ZAF: "ZA",
4210
- ZMB: "ZM"
4211
- };
4212
- var CURRENCY_TO_COUNTRY_CODE = {
4213
- AED: "AE",
4214
- AOA: "AO",
4215
- AUD: "AU",
4216
- BIF: "BI",
4217
- BWP: "BW",
4218
- BRL: "BR",
4219
- CAD: "CA",
4220
- CDF: "CD",
4221
- CHF: "CH",
4222
- CNY: "CN",
4223
- EGP: "EG",
4224
- ETB: "ET",
4225
- GHS: "GH",
4226
- GMD: "GM",
4227
- GNF: "GN",
4228
- GBP: "GB",
4229
- HKD: "HK",
4230
- IDR: "ID",
4231
- ILS: "IL",
4232
- INR: "IN",
4233
- JPY: "JP",
4234
- KES: "KE",
4235
- KRW: "KR",
4236
- LRD: "LR",
4237
- MUR: "MU",
4238
- MWK: "MW",
4239
- MXN: "MX",
4240
- MYR: "MY",
4241
- MZN: "MZ",
4242
- NAD: "NA",
4243
- NGN: "NG",
4244
- PHP: "PH",
4245
- RWF: "RW",
4246
- SAR: "SA",
4247
- SGD: "SG",
4248
- SLL: "SL",
4249
- THB: "TH",
4250
- TRY: "TR",
4251
- TWD: "TW",
4252
- TZS: "TZ",
4253
- UGX: "UG",
4254
- USD: "US",
4255
- VND: "VN",
4256
- ZAR: "ZA",
4257
- ZMW: "ZM"
4258
- };
4259
- function normalizeCountryCode(value) {
4260
- const normalized = value?.trim().toUpperCase();
4261
- if (!normalized) {
4262
- return void 0;
4263
- }
4264
- if (normalized.length === 2) {
4265
- return normalized;
4266
- }
4267
- return ISO3_TO_COUNTRY_CODE[normalized];
4268
- }
4269
- function parsePhoneCandidate(value, country) {
4270
- try {
4271
- return country ? libphonenumberJs.parsePhoneNumberFromString(value, country) : libphonenumberJs.parsePhoneNumberFromString(value);
4272
- } catch {
4273
- return void 0;
4274
- }
4275
- }
4276
- function resolvePhoneCountryCode(options = {}) {
4277
- const explicitCountry = normalizeCountryCode(options.country);
4278
- if (explicitCountry) {
4279
- return explicitCountry;
4280
- }
4281
- const currency = options.currency?.trim().toUpperCase();
4282
- if (!currency) {
4283
- return void 0;
4284
- }
4285
- return CURRENCY_TO_COUNTRY_CODE[currency];
4286
- }
4287
- function normalizePhoneToE164(raw, options = {}) {
4288
- const trimmed = raw.trim();
4289
- if (!trimmed) {
4290
- return null;
4291
- }
4292
- const country = resolvePhoneCountryCode(options);
4293
- const digits = trimmed.replace(/\D/g, "");
4294
- const internationalDigits = digits.startsWith("00") ? digits.slice(2) : digits;
4295
- const attempts = [];
4296
- const seen = /* @__PURE__ */ new Set();
4297
- function addAttempt(value, nextCountry) {
4298
- const key = `${nextCountry || ""}:${value}`;
4299
- if (seen.has(key)) {
4300
- return;
4301
- }
4302
- seen.add(key);
4303
- attempts.push({ value, country: nextCountry });
4304
- }
4305
- if (country) {
4306
- addAttempt(trimmed, country);
4307
- }
4308
- addAttempt(trimmed);
4309
- if (country && digits) {
4310
- addAttempt(digits, country);
4311
- }
4312
- if (internationalDigits) {
4313
- addAttempt(`+${internationalDigits}`);
4314
- }
4315
- for (const attempt of attempts) {
4316
- const parsed = parsePhoneCandidate(attempt.value, attempt.country);
4317
- if (parsed?.isValid()) {
4318
- return parsed.format("E.164");
4319
- }
4320
- }
4321
- return null;
4322
- }
4323
- function isValidPhoneForContext(raw, options = {}) {
4324
- return normalizePhoneToE164(raw, options) !== null;
4325
- }
4326
-
4327
- exports.AUTHORIZATION_TYPE = AUTHORIZATION_TYPE;
4328
- exports.AUTH_MUTATION = AUTH_MUTATION;
4329
- exports.ActivityService = ActivityService;
4330
- exports.AuthService = AuthService;
4331
- exports.BusinessService = BusinessService;
4332
- exports.CHECKOUT_MODE = CHECKOUT_MODE;
4333
- exports.CHECKOUT_MUTATION = CHECKOUT_MUTATION;
4334
- exports.CHECKOUT_STEP = CHECKOUT_STEP;
4335
- exports.CONTACT_TYPE = CONTACT_TYPE;
4336
- exports.CURRENCY_SYMBOLS = CURRENCY_SYMBOLS;
4337
- exports.CartOperations = CartOperations;
4338
- exports.CatalogueQueries = CatalogueQueries;
4339
- exports.CheckoutOperations = CheckoutService;
4340
- exports.CheckoutService = CheckoutService;
4341
- exports.CimplifyClient = CimplifyClient;
4342
- exports.CimplifyElement = CimplifyElement;
4343
- exports.CimplifyElements = CimplifyElements;
4344
- exports.CimplifyError = CimplifyError;
4345
- exports.DEFAULT_COUNTRY = DEFAULT_COUNTRY;
4346
- exports.DEFAULT_CURRENCY = DEFAULT_CURRENCY;
4347
- exports.DEVICE_TYPE = DEVICE_TYPE;
4348
- exports.ELEMENT_TYPES = ELEMENT_TYPES;
4349
- exports.ERROR_HINTS = ERROR_HINTS;
4350
- exports.EVENT_TYPES = EVENT_TYPES;
4351
- exports.ErrorCode = ErrorCode;
4352
- exports.FxService = FxService;
4353
- exports.InventoryService = InventoryService;
4354
- exports.LINK_MUTATION = LINK_MUTATION;
4355
- exports.LINK_QUERY = LINK_QUERY;
4356
- exports.LinkService = LinkService;
4357
- exports.LiteService = LiteService;
4358
- exports.MESSAGE_TYPES = MESSAGE_TYPES;
4359
- exports.MOBILE_MONEY_PROVIDER = MOBILE_MONEY_PROVIDER;
4360
- exports.MOBILE_MONEY_PROVIDERS = MOBILE_MONEY_PROVIDERS;
4361
- exports.ORDER_MUTATION = ORDER_MUTATION;
4362
- exports.ORDER_TYPE = ORDER_TYPE;
4363
- exports.OrderQueries = OrderQueries;
4364
- exports.PAYMENT_METHOD = PAYMENT_METHOD;
4365
- exports.PAYMENT_MUTATION = PAYMENT_MUTATION;
4366
- exports.PAYMENT_STATE = PAYMENT_STATE;
4367
- exports.PICKUP_TIME_TYPE = PICKUP_TIME_TYPE;
4368
- exports.QueryBuilder = QueryBuilder;
4369
- exports.SchedulingService = SchedulingService;
4370
- exports.ZERO = ZERO;
4371
- exports.categorizePaymentError = categorizePaymentError;
4372
- exports.combine = combine;
4373
- exports.combineObject = combineObject;
4374
- exports.createCimplifyClient = createCimplifyClient;
4375
- exports.createElements = createElements;
4376
- exports.currencyCode = currencyCode;
4377
- exports.detectMobileMoneyProvider = detectMobileMoneyProvider;
4378
- exports.enrichError = enrichError;
4379
- exports.err = err;
4380
- exports.flatMap = flatMap;
4381
- exports.formatMoney = formatMoney;
4382
- exports.formatNumberCompact = formatNumberCompact;
4383
- exports.formatPrice = formatPrice;
4384
- exports.formatPriceAdjustment = formatPriceAdjustment;
4385
- exports.formatPriceCompact = formatPriceCompact;
4386
- exports.formatPriceWithTax = formatPriceWithTax;
4387
- exports.formatProductPrice = formatProductPrice;
4388
- exports.fromPromise = fromPromise;
4389
- exports.generateIdempotencyKey = generateIdempotencyKey;
4390
- exports.getBasePrice = getBasePrice;
4391
- exports.getCurrencySymbol = getCurrencySymbol;
4392
- exports.getDiscountPercentage = getDiscountPercentage;
4393
- exports.getDisplayPrice = getDisplayPrice;
4394
- exports.getErrorHint = getErrorHint;
4395
- exports.getMarkupPercentage = getMarkupPercentage;
4396
- exports.getOrElse = getOrElse;
4397
- exports.getProductCurrency = getProductCurrency;
4398
- exports.getTaxAmount = getTaxAmount;
4399
- exports.getVariantDisplayName = getVariantDisplayName;
4400
- exports.hasTaxInfo = hasTaxInfo;
4401
- exports.isCimplifyError = isCimplifyError;
4402
- exports.isErr = isErr;
4403
- exports.isOk = isOk;
4404
- exports.isOnSale = isOnSale;
4405
- exports.isPaymentStatusFailure = isPaymentStatusFailure;
4406
- exports.isPaymentStatusRequiresAction = isPaymentStatusRequiresAction;
4407
- exports.isPaymentStatusSuccess = isPaymentStatusSuccess;
4408
- exports.isRetryableError = isRetryableError;
4409
- exports.isSupportedCurrency = isSupportedCurrency;
4410
- exports.isTaxInclusive = isTaxInclusive;
4411
- exports.isValidPhoneForContext = isValidPhoneForContext;
4412
- exports.mapError = mapError;
4413
- exports.mapResult = mapResult;
4414
- exports.money = money;
4415
- exports.moneyFromNumber = moneyFromNumber;
4416
- exports.normalizePaymentResponse = normalizePaymentResponse;
4417
- exports.normalizePhoneToE164 = normalizePhoneToE164;
4418
- exports.normalizeStatusResponse = normalizeStatusResponse;
4419
- exports.ok = ok;
4420
- exports.parsePrice = parsePrice;
4421
- exports.query = query;
4422
- exports.resolvePhoneCountryCode = resolvePhoneCountryCode;
4423
- exports.toNullable = toNullable;
4424
- exports.tryCatch = tryCatch;
4425
- exports.unwrap = unwrap;
11
+ Object.defineProperty(exports, "ActivityService", {
12
+ enumerable: true,
13
+ get: function () { return chunkOITG2SEN_js.ActivityService; }
14
+ });
15
+ Object.defineProperty(exports, "CimplifyClient", {
16
+ enumerable: true,
17
+ get: function () { return chunkOITG2SEN_js.CimplifyClient; }
18
+ });
19
+ Object.defineProperty(exports, "createCimplifyClient", {
20
+ enumerable: true,
21
+ get: function () { return chunkOITG2SEN_js.createCimplifyClient; }
22
+ });
23
+ Object.defineProperty(exports, "getVariantDisplayName", {
24
+ enumerable: true,
25
+ get: function () { return chunkOITG2SEN_js.getVariantDisplayName; }
26
+ });
27
+ Object.defineProperty(exports, "isValidPhoneForContext", {
28
+ enumerable: true,
29
+ get: function () { return chunkS6TU55KP_js.isValidPhoneForContext; }
30
+ });
31
+ Object.defineProperty(exports, "normalizePhoneToE164", {
32
+ enumerable: true,
33
+ get: function () { return chunkS6TU55KP_js.normalizePhoneToE164; }
34
+ });
35
+ Object.defineProperty(exports, "resolvePhoneCountryCode", {
36
+ enumerable: true,
37
+ get: function () { return chunkS6TU55KP_js.resolvePhoneCountryCode; }
38
+ });
39
+ Object.defineProperty(exports, "QueryBuilder", {
40
+ enumerable: true,
41
+ get: function () { return chunkFLPI2VVJ_js.QueryBuilder; }
42
+ });
43
+ Object.defineProperty(exports, "query", {
44
+ enumerable: true,
45
+ get: function () { return chunkFLPI2VVJ_js.query; }
46
+ });
47
+ Object.defineProperty(exports, "AUTHORIZATION_TYPE", {
48
+ enumerable: true,
49
+ get: function () { return chunkREPTMTQ4_js.AUTHORIZATION_TYPE; }
50
+ });
51
+ Object.defineProperty(exports, "AUTH_MUTATION", {
52
+ enumerable: true,
53
+ get: function () { return chunkREPTMTQ4_js.AUTH_MUTATION; }
54
+ });
55
+ Object.defineProperty(exports, "AuthService", {
56
+ enumerable: true,
57
+ get: function () { return chunkREPTMTQ4_js.AuthService; }
58
+ });
59
+ Object.defineProperty(exports, "BusinessService", {
60
+ enumerable: true,
61
+ get: function () { return chunkREPTMTQ4_js.BusinessService; }
62
+ });
63
+ Object.defineProperty(exports, "CHECKOUT_MODE", {
64
+ enumerable: true,
65
+ get: function () { return chunkREPTMTQ4_js.CHECKOUT_MODE; }
66
+ });
67
+ Object.defineProperty(exports, "CHECKOUT_MUTATION", {
68
+ enumerable: true,
69
+ get: function () { return chunkREPTMTQ4_js.CHECKOUT_MUTATION; }
70
+ });
71
+ Object.defineProperty(exports, "CHECKOUT_STEP", {
72
+ enumerable: true,
73
+ get: function () { return chunkREPTMTQ4_js.CHECKOUT_STEP; }
74
+ });
75
+ Object.defineProperty(exports, "CONTACT_TYPE", {
76
+ enumerable: true,
77
+ get: function () { return chunkREPTMTQ4_js.CONTACT_TYPE; }
78
+ });
79
+ Object.defineProperty(exports, "CartOperations", {
80
+ enumerable: true,
81
+ get: function () { return chunkREPTMTQ4_js.CartOperations; }
82
+ });
83
+ Object.defineProperty(exports, "CatalogueQueries", {
84
+ enumerable: true,
85
+ get: function () { return chunkREPTMTQ4_js.CatalogueQueries; }
86
+ });
87
+ Object.defineProperty(exports, "CheckoutOperations", {
88
+ enumerable: true,
89
+ get: function () { return chunkREPTMTQ4_js.CheckoutService; }
90
+ });
91
+ Object.defineProperty(exports, "CheckoutService", {
92
+ enumerable: true,
93
+ get: function () { return chunkREPTMTQ4_js.CheckoutService; }
94
+ });
95
+ Object.defineProperty(exports, "CimplifyElement", {
96
+ enumerable: true,
97
+ get: function () { return chunkREPTMTQ4_js.CimplifyElement; }
98
+ });
99
+ Object.defineProperty(exports, "CimplifyElements", {
100
+ enumerable: true,
101
+ get: function () { return chunkREPTMTQ4_js.CimplifyElements; }
102
+ });
103
+ Object.defineProperty(exports, "DEFAULT_COUNTRY", {
104
+ enumerable: true,
105
+ get: function () { return chunkREPTMTQ4_js.DEFAULT_COUNTRY; }
106
+ });
107
+ Object.defineProperty(exports, "DEFAULT_CURRENCY", {
108
+ enumerable: true,
109
+ get: function () { return chunkREPTMTQ4_js.DEFAULT_CURRENCY; }
110
+ });
111
+ Object.defineProperty(exports, "DEVICE_TYPE", {
112
+ enumerable: true,
113
+ get: function () { return chunkREPTMTQ4_js.DEVICE_TYPE; }
114
+ });
115
+ Object.defineProperty(exports, "ELEMENT_TYPES", {
116
+ enumerable: true,
117
+ get: function () { return chunkREPTMTQ4_js.ELEMENT_TYPES; }
118
+ });
119
+ Object.defineProperty(exports, "EVENT_TYPES", {
120
+ enumerable: true,
121
+ get: function () { return chunkREPTMTQ4_js.EVENT_TYPES; }
122
+ });
123
+ Object.defineProperty(exports, "FxService", {
124
+ enumerable: true,
125
+ get: function () { return chunkREPTMTQ4_js.FxService; }
126
+ });
127
+ Object.defineProperty(exports, "InventoryService", {
128
+ enumerable: true,
129
+ get: function () { return chunkREPTMTQ4_js.InventoryService; }
130
+ });
131
+ Object.defineProperty(exports, "LINK_MUTATION", {
132
+ enumerable: true,
133
+ get: function () { return chunkREPTMTQ4_js.LINK_MUTATION; }
134
+ });
135
+ Object.defineProperty(exports, "LINK_QUERY", {
136
+ enumerable: true,
137
+ get: function () { return chunkREPTMTQ4_js.LINK_QUERY; }
138
+ });
139
+ Object.defineProperty(exports, "LinkService", {
140
+ enumerable: true,
141
+ get: function () { return chunkREPTMTQ4_js.LinkService; }
142
+ });
143
+ Object.defineProperty(exports, "LiteService", {
144
+ enumerable: true,
145
+ get: function () { return chunkREPTMTQ4_js.LiteService; }
146
+ });
147
+ Object.defineProperty(exports, "MESSAGE_TYPES", {
148
+ enumerable: true,
149
+ get: function () { return chunkREPTMTQ4_js.MESSAGE_TYPES; }
150
+ });
151
+ Object.defineProperty(exports, "MOBILE_MONEY_PROVIDER", {
152
+ enumerable: true,
153
+ get: function () { return chunkREPTMTQ4_js.MOBILE_MONEY_PROVIDER; }
154
+ });
155
+ Object.defineProperty(exports, "ORDER_MUTATION", {
156
+ enumerable: true,
157
+ get: function () { return chunkREPTMTQ4_js.ORDER_MUTATION; }
158
+ });
159
+ Object.defineProperty(exports, "ORDER_TYPE", {
160
+ enumerable: true,
161
+ get: function () { return chunkREPTMTQ4_js.ORDER_TYPE; }
162
+ });
163
+ Object.defineProperty(exports, "OrderQueries", {
164
+ enumerable: true,
165
+ get: function () { return chunkREPTMTQ4_js.OrderQueries; }
166
+ });
167
+ Object.defineProperty(exports, "PAYMENT_METHOD", {
168
+ enumerable: true,
169
+ get: function () { return chunkREPTMTQ4_js.PAYMENT_METHOD; }
170
+ });
171
+ Object.defineProperty(exports, "PAYMENT_MUTATION", {
172
+ enumerable: true,
173
+ get: function () { return chunkREPTMTQ4_js.PAYMENT_MUTATION; }
174
+ });
175
+ Object.defineProperty(exports, "PAYMENT_STATE", {
176
+ enumerable: true,
177
+ get: function () { return chunkREPTMTQ4_js.PAYMENT_STATE; }
178
+ });
179
+ Object.defineProperty(exports, "PICKUP_TIME_TYPE", {
180
+ enumerable: true,
181
+ get: function () { return chunkREPTMTQ4_js.PICKUP_TIME_TYPE; }
182
+ });
183
+ Object.defineProperty(exports, "SchedulingService", {
184
+ enumerable: true,
185
+ get: function () { return chunkREPTMTQ4_js.SchedulingService; }
186
+ });
187
+ Object.defineProperty(exports, "combine", {
188
+ enumerable: true,
189
+ get: function () { return chunkREPTMTQ4_js.combine; }
190
+ });
191
+ Object.defineProperty(exports, "combineObject", {
192
+ enumerable: true,
193
+ get: function () { return chunkREPTMTQ4_js.combineObject; }
194
+ });
195
+ Object.defineProperty(exports, "createElements", {
196
+ enumerable: true,
197
+ get: function () { return chunkREPTMTQ4_js.createElements; }
198
+ });
199
+ Object.defineProperty(exports, "err", {
200
+ enumerable: true,
201
+ get: function () { return chunkREPTMTQ4_js.err; }
202
+ });
203
+ Object.defineProperty(exports, "flatMap", {
204
+ enumerable: true,
205
+ get: function () { return chunkREPTMTQ4_js.flatMap; }
206
+ });
207
+ Object.defineProperty(exports, "fromPromise", {
208
+ enumerable: true,
209
+ get: function () { return chunkREPTMTQ4_js.fromPromise; }
210
+ });
211
+ Object.defineProperty(exports, "generateIdempotencyKey", {
212
+ enumerable: true,
213
+ get: function () { return chunkREPTMTQ4_js.generateIdempotencyKey; }
214
+ });
215
+ Object.defineProperty(exports, "getOrElse", {
216
+ enumerable: true,
217
+ get: function () { return chunkREPTMTQ4_js.getOrElse; }
218
+ });
219
+ Object.defineProperty(exports, "isErr", {
220
+ enumerable: true,
221
+ get: function () { return chunkREPTMTQ4_js.isErr; }
222
+ });
223
+ Object.defineProperty(exports, "isOk", {
224
+ enumerable: true,
225
+ get: function () { return chunkREPTMTQ4_js.isOk; }
226
+ });
227
+ Object.defineProperty(exports, "mapError", {
228
+ enumerable: true,
229
+ get: function () { return chunkREPTMTQ4_js.mapError; }
230
+ });
231
+ Object.defineProperty(exports, "mapResult", {
232
+ enumerable: true,
233
+ get: function () { return chunkREPTMTQ4_js.mapResult; }
234
+ });
235
+ Object.defineProperty(exports, "ok", {
236
+ enumerable: true,
237
+ get: function () { return chunkREPTMTQ4_js.ok; }
238
+ });
239
+ Object.defineProperty(exports, "toNullable", {
240
+ enumerable: true,
241
+ get: function () { return chunkREPTMTQ4_js.toNullable; }
242
+ });
243
+ Object.defineProperty(exports, "tryCatch", {
244
+ enumerable: true,
245
+ get: function () { return chunkREPTMTQ4_js.tryCatch; }
246
+ });
247
+ Object.defineProperty(exports, "unwrap", {
248
+ enumerable: true,
249
+ get: function () { return chunkREPTMTQ4_js.unwrap; }
250
+ });
251
+ Object.defineProperty(exports, "CURRENCY_SYMBOLS", {
252
+ enumerable: true,
253
+ get: function () { return chunkJ65U5SED_js.CURRENCY_SYMBOLS; }
254
+ });
255
+ Object.defineProperty(exports, "CimplifyError", {
256
+ enumerable: true,
257
+ get: function () { return chunkJ65U5SED_js.CimplifyError; }
258
+ });
259
+ Object.defineProperty(exports, "ERROR_HINTS", {
260
+ enumerable: true,
261
+ get: function () { return chunkJ65U5SED_js.ERROR_HINTS; }
262
+ });
263
+ Object.defineProperty(exports, "ErrorCode", {
264
+ enumerable: true,
265
+ get: function () { return chunkJ65U5SED_js.ErrorCode; }
266
+ });
267
+ Object.defineProperty(exports, "MOBILE_MONEY_PROVIDERS", {
268
+ enumerable: true,
269
+ get: function () { return chunkJ65U5SED_js.MOBILE_MONEY_PROVIDERS; }
270
+ });
271
+ Object.defineProperty(exports, "ZERO", {
272
+ enumerable: true,
273
+ get: function () { return chunkJ65U5SED_js.ZERO; }
274
+ });
275
+ Object.defineProperty(exports, "categorizePaymentError", {
276
+ enumerable: true,
277
+ get: function () { return chunkJ65U5SED_js.categorizePaymentError; }
278
+ });
279
+ Object.defineProperty(exports, "currencyCode", {
280
+ enumerable: true,
281
+ get: function () { return chunkJ65U5SED_js.currencyCode; }
282
+ });
283
+ Object.defineProperty(exports, "detectMobileMoneyProvider", {
284
+ enumerable: true,
285
+ get: function () { return chunkJ65U5SED_js.detectMobileMoneyProvider; }
286
+ });
287
+ Object.defineProperty(exports, "enrichError", {
288
+ enumerable: true,
289
+ get: function () { return chunkJ65U5SED_js.enrichError; }
290
+ });
291
+ Object.defineProperty(exports, "formatMoney", {
292
+ enumerable: true,
293
+ get: function () { return chunkJ65U5SED_js.formatMoney; }
294
+ });
295
+ Object.defineProperty(exports, "formatNumberCompact", {
296
+ enumerable: true,
297
+ get: function () { return chunkJ65U5SED_js.formatNumberCompact; }
298
+ });
299
+ Object.defineProperty(exports, "formatPrice", {
300
+ enumerable: true,
301
+ get: function () { return chunkJ65U5SED_js.formatPrice; }
302
+ });
303
+ Object.defineProperty(exports, "formatPriceAdjustment", {
304
+ enumerable: true,
305
+ get: function () { return chunkJ65U5SED_js.formatPriceAdjustment; }
306
+ });
307
+ Object.defineProperty(exports, "formatPriceCompact", {
308
+ enumerable: true,
309
+ get: function () { return chunkJ65U5SED_js.formatPriceCompact; }
310
+ });
311
+ Object.defineProperty(exports, "formatPriceWithTax", {
312
+ enumerable: true,
313
+ get: function () { return chunkJ65U5SED_js.formatPriceWithTax; }
314
+ });
315
+ Object.defineProperty(exports, "formatProductPrice", {
316
+ enumerable: true,
317
+ get: function () { return chunkJ65U5SED_js.formatProductPrice; }
318
+ });
319
+ Object.defineProperty(exports, "getBasePrice", {
320
+ enumerable: true,
321
+ get: function () { return chunkJ65U5SED_js.getBasePrice; }
322
+ });
323
+ Object.defineProperty(exports, "getCurrencySymbol", {
324
+ enumerable: true,
325
+ get: function () { return chunkJ65U5SED_js.getCurrencySymbol; }
326
+ });
327
+ Object.defineProperty(exports, "getDiscountPercentage", {
328
+ enumerable: true,
329
+ get: function () { return chunkJ65U5SED_js.getDiscountPercentage; }
330
+ });
331
+ Object.defineProperty(exports, "getDisplayPrice", {
332
+ enumerable: true,
333
+ get: function () { return chunkJ65U5SED_js.getDisplayPrice; }
334
+ });
335
+ Object.defineProperty(exports, "getErrorHint", {
336
+ enumerable: true,
337
+ get: function () { return chunkJ65U5SED_js.getErrorHint; }
338
+ });
339
+ Object.defineProperty(exports, "getMarkupPercentage", {
340
+ enumerable: true,
341
+ get: function () { return chunkJ65U5SED_js.getMarkupPercentage; }
342
+ });
343
+ Object.defineProperty(exports, "getProductCurrency", {
344
+ enumerable: true,
345
+ get: function () { return chunkJ65U5SED_js.getProductCurrency; }
346
+ });
347
+ Object.defineProperty(exports, "getTaxAmount", {
348
+ enumerable: true,
349
+ get: function () { return chunkJ65U5SED_js.getTaxAmount; }
350
+ });
351
+ Object.defineProperty(exports, "hasTaxInfo", {
352
+ enumerable: true,
353
+ get: function () { return chunkJ65U5SED_js.hasTaxInfo; }
354
+ });
355
+ Object.defineProperty(exports, "isCimplifyError", {
356
+ enumerable: true,
357
+ get: function () { return chunkJ65U5SED_js.isCimplifyError; }
358
+ });
359
+ Object.defineProperty(exports, "isOnSale", {
360
+ enumerable: true,
361
+ get: function () { return chunkJ65U5SED_js.isOnSale; }
362
+ });
363
+ Object.defineProperty(exports, "isPaymentStatusFailure", {
364
+ enumerable: true,
365
+ get: function () { return chunkJ65U5SED_js.isPaymentStatusFailure; }
366
+ });
367
+ Object.defineProperty(exports, "isPaymentStatusRequiresAction", {
368
+ enumerable: true,
369
+ get: function () { return chunkJ65U5SED_js.isPaymentStatusRequiresAction; }
370
+ });
371
+ Object.defineProperty(exports, "isPaymentStatusSuccess", {
372
+ enumerable: true,
373
+ get: function () { return chunkJ65U5SED_js.isPaymentStatusSuccess; }
374
+ });
375
+ Object.defineProperty(exports, "isRetryableError", {
376
+ enumerable: true,
377
+ get: function () { return chunkJ65U5SED_js.isRetryableError; }
378
+ });
379
+ Object.defineProperty(exports, "isSupportedCurrency", {
380
+ enumerable: true,
381
+ get: function () { return chunkJ65U5SED_js.isSupportedCurrency; }
382
+ });
383
+ Object.defineProperty(exports, "isTaxInclusive", {
384
+ enumerable: true,
385
+ get: function () { return chunkJ65U5SED_js.isTaxInclusive; }
386
+ });
387
+ Object.defineProperty(exports, "money", {
388
+ enumerable: true,
389
+ get: function () { return chunkJ65U5SED_js.money; }
390
+ });
391
+ Object.defineProperty(exports, "moneyFromNumber", {
392
+ enumerable: true,
393
+ get: function () { return chunkJ65U5SED_js.moneyFromNumber; }
394
+ });
395
+ Object.defineProperty(exports, "normalizePaymentResponse", {
396
+ enumerable: true,
397
+ get: function () { return chunkJ65U5SED_js.normalizePaymentResponse; }
398
+ });
399
+ Object.defineProperty(exports, "normalizeStatusResponse", {
400
+ enumerable: true,
401
+ get: function () { return chunkJ65U5SED_js.normalizeStatusResponse; }
402
+ });
403
+ Object.defineProperty(exports, "parsePrice", {
404
+ enumerable: true,
405
+ get: function () { return chunkJ65U5SED_js.parsePrice; }
406
+ });