@cimplify/sdk 0.16.3 → 0.18.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.
Files changed (39) hide show
  1. package/dist/advanced.d.mts +2 -2
  2. package/dist/advanced.d.ts +2 -2
  3. package/dist/advanced.js +90 -2913
  4. package/dist/advanced.mjs +3 -2893
  5. package/dist/chunk-2JI47EYJ.mjs +2786 -0
  6. package/dist/chunk-DYKFSV77.js +2837 -0
  7. package/dist/chunk-FLPI2VVJ.js +72 -0
  8. package/dist/chunk-FTL2SXCG.mjs +674 -0
  9. package/dist/chunk-KTTQC5HG.mjs +687 -0
  10. package/dist/chunk-LM3CJ4L7.mjs +69 -0
  11. package/dist/chunk-MJECWMOY.js +692 -0
  12. package/dist/chunk-RYQ5IPWX.js +714 -0
  13. package/dist/chunk-S6TU55KP.js +170 -0
  14. package/dist/chunk-WDIMISRC.mjs +166 -0
  15. package/dist/{client-BaolRdB4.d.mts → client-B1UtuyOg.d.ts} +21 -12
  16. package/dist/{client-C59R79gx.d.ts → client-BFFfuzJr.d.mts} +21 -12
  17. package/dist/index.d.mts +4 -4
  18. package/dist/index.d.ts +4 -4
  19. package/dist/index.js +401 -4420
  20. package/dist/index.mjs +5 -4325
  21. package/dist/{payment-C6ULw3K-.d.mts → payment-D9FTaOse.d.mts} +66 -1
  22. package/dist/{payment-C6ULw3K-.d.ts → payment-D9FTaOse.d.ts} +66 -1
  23. package/dist/{price-CbR6DCt0.d.mts → price-9JsPuknm.d.mts} +1 -1
  24. package/dist/{price-Bd6JBV8W.d.ts → price-BD1iioLh.d.ts} +1 -1
  25. package/dist/react.d.mts +43 -11
  26. package/dist/react.d.ts +43 -11
  27. package/dist/react.js +540 -3981
  28. package/dist/react.mjs +489 -3933
  29. package/dist/styles.css +1 -1
  30. package/dist/utils.d.mts +5 -5
  31. package/dist/utils.d.ts +5 -5
  32. package/dist/utils.js +122 -721
  33. package/dist/utils.mjs +2 -695
  34. package/package.json +1 -1
  35. package/registry/add-on-selector.json +1 -1
  36. package/registry/catalogue-page.json +1 -1
  37. package/registry/checkout-page.json +1 -1
  38. package/registry/composite-selector.json +1 -1
  39. package/registry/product-grid.json +1 -1
@@ -0,0 +1,2837 @@
1
+ 'use strict';
2
+
3
+ var chunkRYQ5IPWX_js = require('./chunk-RYQ5IPWX.js');
4
+
5
+ // src/types/result.ts
6
+ function ok(value) {
7
+ return { ok: true, value };
8
+ }
9
+ function err(error) {
10
+ return { ok: false, error };
11
+ }
12
+ function isOk(result) {
13
+ return result.ok === true;
14
+ }
15
+ function isErr(result) {
16
+ return result.ok === false;
17
+ }
18
+ function mapResult(result, fn) {
19
+ return result.ok ? ok(fn(result.value)) : result;
20
+ }
21
+ function mapError(result, fn) {
22
+ return result.ok ? result : err(fn(result.error));
23
+ }
24
+ function flatMap(result, fn) {
25
+ return result.ok ? fn(result.value) : result;
26
+ }
27
+ function getOrElse(result, defaultFn) {
28
+ return result.ok ? result.value : defaultFn();
29
+ }
30
+ function unwrap(result) {
31
+ if (result.ok) {
32
+ return result.value;
33
+ }
34
+ throw result.error;
35
+ }
36
+ function toNullable(result) {
37
+ return result.ok ? result.value : void 0;
38
+ }
39
+ async function fromPromise(promise, mapError2) {
40
+ try {
41
+ const value = await promise;
42
+ return ok(value);
43
+ } catch (error) {
44
+ return err(mapError2(error));
45
+ }
46
+ }
47
+ function tryCatch(fn, mapError2) {
48
+ try {
49
+ return ok(fn());
50
+ } catch (error) {
51
+ return err(mapError2(error));
52
+ }
53
+ }
54
+ function combine(results) {
55
+ const values = [];
56
+ for (const result of results) {
57
+ if (!result.ok) {
58
+ return result;
59
+ }
60
+ values.push(result.value);
61
+ }
62
+ return ok(values);
63
+ }
64
+ function combineObject(results) {
65
+ const values = {};
66
+ for (const [key, result] of Object.entries(results)) {
67
+ if (!result.ok) {
68
+ return result;
69
+ }
70
+ values[key] = result.value;
71
+ }
72
+ return ok(values);
73
+ }
74
+
75
+ // src/internal/safe.ts
76
+ function toCimplifyError(error) {
77
+ if (error instanceof chunkRYQ5IPWX_js.CimplifyError) return chunkRYQ5IPWX_js.enrichError(error);
78
+ if (error instanceof Error) {
79
+ return chunkRYQ5IPWX_js.enrichError(new chunkRYQ5IPWX_js.CimplifyError(chunkRYQ5IPWX_js.ErrorCode.UNKNOWN_ERROR, error.message, false));
80
+ }
81
+ return chunkRYQ5IPWX_js.enrichError(new chunkRYQ5IPWX_js.CimplifyError(chunkRYQ5IPWX_js.ErrorCode.UNKNOWN_ERROR, String(error), false));
82
+ }
83
+ async function safe(promise) {
84
+ try {
85
+ return ok(await promise);
86
+ } catch (error) {
87
+ return err(toCimplifyError(error));
88
+ }
89
+ }
90
+
91
+ // src/catalogue.ts
92
+ function withQuery(path, params) {
93
+ const query = new URLSearchParams();
94
+ for (const [key, value] of Object.entries(params)) {
95
+ if (value === void 0) continue;
96
+ query.set(key, String(value));
97
+ }
98
+ const queryString = query.toString();
99
+ return queryString ? `${path}?${queryString}` : path;
100
+ }
101
+ function isRecord(value) {
102
+ return typeof value === "object" && value !== null;
103
+ }
104
+ function readFinalPrice(value) {
105
+ if (!isRecord(value)) return void 0;
106
+ const finalPrice = value.final_price;
107
+ if (typeof finalPrice === "string" || typeof finalPrice === "number") {
108
+ return finalPrice;
109
+ }
110
+ return void 0;
111
+ }
112
+ function needsDefaultPriceNormalization(value) {
113
+ return value === void 0 || value === null || value === "";
114
+ }
115
+ function optionNeedsNormalization(option) {
116
+ return isRecord(option) && needsDefaultPriceNormalization(option["default_price"]);
117
+ }
118
+ function addOnNeedsNormalization(addOn) {
119
+ if (!isRecord(addOn)) return false;
120
+ const options = addOn["options"];
121
+ return Array.isArray(options) && options.some((option) => optionNeedsNormalization(option));
122
+ }
123
+ function normalizeAddOnPayload(addOn) {
124
+ if (!isRecord(addOn)) return addOn;
125
+ const options = addOn["options"];
126
+ if (!Array.isArray(options)) return addOn;
127
+ if (!options.some((option) => optionNeedsNormalization(option))) return addOn;
128
+ const normalizedAddOn = { ...addOn };
129
+ normalizedAddOn["options"] = options.map((option) => {
130
+ if (!isRecord(option)) return option;
131
+ if (!optionNeedsNormalization(option)) return option;
132
+ const normalizedOption = { ...option };
133
+ const optionPrice = normalizedOption["default_price"];
134
+ if (needsDefaultPriceNormalization(optionPrice)) {
135
+ normalizedOption["default_price"] = readFinalPrice(normalizedOption["default_price_info"]) || readFinalPrice(normalizedOption["price_info"]) || "0";
136
+ }
137
+ return normalizedOption;
138
+ });
139
+ return normalizedAddOn;
140
+ }
141
+ function normalizeCatalogueProductPayload(product) {
142
+ const productRecord = product;
143
+ const defaultPrice = productRecord["default_price"];
144
+ const addOns = productRecord["add_ons"];
145
+ const needsPriceFix = needsDefaultPriceNormalization(defaultPrice);
146
+ const needsAddOnFix = Array.isArray(addOns) && addOns.some((addOn) => addOnNeedsNormalization(addOn));
147
+ if (!needsPriceFix && !needsAddOnFix) {
148
+ return product;
149
+ }
150
+ const normalized = { ...productRecord };
151
+ if (needsPriceFix) {
152
+ 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);
153
+ normalized["default_price"] = derivedDefaultPrice ?? "0";
154
+ }
155
+ if (needsAddOnFix && Array.isArray(addOns)) {
156
+ normalized["add_ons"] = addOns.map((addOn) => normalizeAddOnPayload(addOn));
157
+ }
158
+ return normalized;
159
+ }
160
+ function toFiniteNumber(value) {
161
+ if (typeof value === "number" && Number.isFinite(value)) {
162
+ return value;
163
+ }
164
+ if (typeof value === "string" && value.trim().length > 0) {
165
+ const parsed = Number(value);
166
+ if (Number.isFinite(parsed)) {
167
+ return parsed;
168
+ }
169
+ }
170
+ return void 0;
171
+ }
172
+ function normalizePagination(value) {
173
+ if (!isRecord(value)) {
174
+ return void 0;
175
+ }
176
+ const totalCount = toFiniteNumber(value.total_count);
177
+ const currentPage = toFiniteNumber(value.current_page);
178
+ const pageSize = toFiniteNumber(value.page_size);
179
+ const totalPages = toFiniteNumber(value.total_pages);
180
+ if (totalCount === void 0 || currentPage === void 0 || pageSize === void 0 || totalPages === void 0) {
181
+ return void 0;
182
+ }
183
+ return {
184
+ total_count: totalCount,
185
+ current_page: currentPage,
186
+ page_size: pageSize,
187
+ total_pages: totalPages,
188
+ has_more: value.has_more === true,
189
+ next_cursor: typeof value.next_cursor === "string" ? value.next_cursor : void 0
190
+ };
191
+ }
192
+ function normalizeCatalogueResult(payload) {
193
+ if (Array.isArray(payload)) {
194
+ return {
195
+ items: payload.map((product) => normalizeCatalogueProductPayload(product)),
196
+ is_complete: true
197
+ };
198
+ }
199
+ if (!isRecord(payload)) {
200
+ return {
201
+ items: [],
202
+ is_complete: true
203
+ };
204
+ }
205
+ const rawItems = Array.isArray(payload.products) ? payload.products : Array.isArray(payload.items) ? payload.items : [];
206
+ return {
207
+ items: rawItems.map((product) => normalizeCatalogueProductPayload(product)),
208
+ is_complete: typeof payload.is_complete === "boolean" ? payload.is_complete : true,
209
+ total_available: toFiniteNumber(payload.total_available),
210
+ pagination: normalizePagination(payload.pagination)
211
+ };
212
+ }
213
+ function normalizeCatalogueSnapshot(payload) {
214
+ if (Array.isArray(payload)) {
215
+ return {
216
+ categories: [],
217
+ products: payload.map((product) => normalizeCatalogueProductPayload(product)),
218
+ add_ons: [],
219
+ is_complete: true
220
+ };
221
+ }
222
+ if (!isRecord(payload)) {
223
+ return {
224
+ categories: [],
225
+ products: [],
226
+ add_ons: [],
227
+ is_complete: true
228
+ };
229
+ }
230
+ const rawProducts = Array.isArray(payload.products) ? payload.products : Array.isArray(payload.items) ? payload.items : [];
231
+ const rawCategories = Array.isArray(payload.categories) ? payload.categories : [];
232
+ const rawAddOns = Array.isArray(payload.add_ons) ? payload.add_ons : [];
233
+ return {
234
+ categories: rawCategories,
235
+ products: rawProducts.map((product) => normalizeCatalogueProductPayload(product)),
236
+ add_ons: rawAddOns.map((addOn) => normalizeAddOnPayload(addOn)),
237
+ is_complete: typeof payload.is_complete === "boolean" ? payload.is_complete : true,
238
+ total_available: toFiniteNumber(payload.total_available),
239
+ pagination: normalizePagination(payload.pagination)
240
+ };
241
+ }
242
+ var CatalogueQueries = class {
243
+ constructor(client) {
244
+ this.client = client;
245
+ }
246
+ async getCatalogue() {
247
+ const result = await safe(this.client.get("/api/v1/catalogue"));
248
+ if (!result.ok) return result;
249
+ return ok(normalizeCatalogueSnapshot(result.value));
250
+ }
251
+ async getProducts(options) {
252
+ const path = withQuery("/api/v1/catalogue/products", {
253
+ category_id: options?.category,
254
+ taxonomy_id: options?.taxonomy,
255
+ search: options?.search,
256
+ page: options?.page,
257
+ tags: options?.tags?.join(","),
258
+ featured: options?.featured,
259
+ in_stock: options?.in_stock,
260
+ min_price: options?.min_price,
261
+ max_price: options?.max_price,
262
+ sort_by: options?.sort_by,
263
+ sort_order: options?.sort_order,
264
+ limit: options?.limit,
265
+ offset: options?.offset,
266
+ cursor: options?.cursor,
267
+ properties: options?.properties ? JSON.stringify(options.properties) : void 0
268
+ });
269
+ const result = await safe(this.client.get(path));
270
+ if (!result.ok) return result;
271
+ return ok(normalizeCatalogueResult(result.value));
272
+ }
273
+ async getProduct(id) {
274
+ const encodedId = encodeURIComponent(id);
275
+ const result = await safe(this.client.get(`/api/v1/catalogue/products/${encodedId}`));
276
+ if (!result.ok) return result;
277
+ return ok(normalizeCatalogueProductPayload(result.value));
278
+ }
279
+ async getProductBySlug(slug) {
280
+ const encodedSlug = encodeURIComponent(slug);
281
+ const result = await safe(this.client.get(`/api/v1/catalogue/products/slug/${encodedSlug}`));
282
+ if (!result.ok) return result;
283
+ return ok(normalizeCatalogueProductPayload(result.value));
284
+ }
285
+ async getVariants(productId) {
286
+ const encodedId = encodeURIComponent(productId);
287
+ return safe(this.client.get(`/api/v1/catalogue/products/${encodedId}/variants`));
288
+ }
289
+ async getVariantAxes(productId) {
290
+ const encodedId = encodeURIComponent(productId);
291
+ return safe(this.client.get(`/api/v1/catalogue/products/${encodedId}/variant-axes`));
292
+ }
293
+ async getVariantByAxisSelections(productId, selections) {
294
+ const encodedId = encodeURIComponent(productId);
295
+ return safe(
296
+ this.client.post(
297
+ `/api/v1/catalogue/products/${encodedId}/variants/find`,
298
+ { axis_selections: selections }
299
+ )
300
+ );
301
+ }
302
+ async getVariantById(productId, variantId) {
303
+ const encodedProductId = encodeURIComponent(productId);
304
+ const encodedVariantId = encodeURIComponent(variantId);
305
+ return safe(
306
+ this.client.get(
307
+ `/api/v1/catalogue/products/${encodedProductId}/variants/${encodedVariantId}`
308
+ )
309
+ );
310
+ }
311
+ async getAddOns(productId) {
312
+ const encodedId = encodeURIComponent(productId);
313
+ return safe(this.client.get(`/api/v1/catalogue/products/${encodedId}/add-ons`));
314
+ }
315
+ async getCategories() {
316
+ return safe(this.client.get("/api/v1/catalogue/categories"));
317
+ }
318
+ async getCategory(id) {
319
+ const encodedId = encodeURIComponent(id);
320
+ return safe(this.client.get(`/api/v1/catalogue/categories/${encodedId}`));
321
+ }
322
+ async getCategoryBySlug(slug) {
323
+ const encodedSlug = encodeURIComponent(slug);
324
+ return safe(this.client.get(`/api/v1/catalogue/categories/slug/${encodedSlug}`));
325
+ }
326
+ async getCategoryProducts(categoryId, options) {
327
+ const encodedId = encodeURIComponent(categoryId);
328
+ const path = withQuery(`/api/v1/catalogue/categories/${encodedId}/products`, {
329
+ limit: options?.limit,
330
+ offset: options?.offset
331
+ });
332
+ return safe(this.client.get(path));
333
+ }
334
+ async getCollections() {
335
+ return safe(this.client.get("/api/v1/catalogue/collections"));
336
+ }
337
+ async getCollection(id) {
338
+ const encodedId = encodeURIComponent(id);
339
+ return safe(this.client.get(`/api/v1/catalogue/collections/${encodedId}`));
340
+ }
341
+ async getCollectionBySlug(slug) {
342
+ const encodedSlug = encodeURIComponent(slug);
343
+ return safe(this.client.get(`/api/v1/catalogue/collections/slug/${encodedSlug}`));
344
+ }
345
+ async getCollectionProducts(collectionId, options) {
346
+ const encodedId = encodeURIComponent(collectionId);
347
+ const path = withQuery(`/api/v1/catalogue/collections/${encodedId}/products`, {
348
+ limit: options?.limit,
349
+ offset: options?.offset
350
+ });
351
+ return safe(this.client.get(path));
352
+ }
353
+ async searchCollections(query, limit = 20) {
354
+ const path = withQuery("/api/v1/catalogue/collections", { search: query, limit });
355
+ return safe(this.client.get(path));
356
+ }
357
+ async getBundles() {
358
+ return safe(this.client.get("/api/v1/catalogue/bundles"));
359
+ }
360
+ async searchBundles(query, limit = 20) {
361
+ const path = withQuery("/api/v1/catalogue/bundles", { search: query, limit });
362
+ return safe(this.client.get(path));
363
+ }
364
+ async getComposites(options) {
365
+ const path = withQuery("/api/v1/catalogue/composites", { limit: options?.limit });
366
+ return safe(this.client.get(path));
367
+ }
368
+ async calculateCompositePrice(compositeId, selections, locationId) {
369
+ const encodedId = encodeURIComponent(compositeId);
370
+ return safe(
371
+ this.client.post(
372
+ `/api/v1/catalogue/composites/${encodedId}/calculate-price`,
373
+ {
374
+ selections,
375
+ location_id: locationId
376
+ }
377
+ )
378
+ );
379
+ }
380
+ async fetchQuote(input) {
381
+ return safe(this.client.post("/api/v1/catalogue/quotes", input));
382
+ }
383
+ async getQuote(quoteId) {
384
+ const encodedQuoteId = encodeURIComponent(quoteId);
385
+ return safe(this.client.get(`/api/v1/catalogue/quotes/${encodedQuoteId}`));
386
+ }
387
+ async refreshQuote(input) {
388
+ const encodedQuoteId = encodeURIComponent(input.quote_id);
389
+ return safe(
390
+ this.client.post(
391
+ `/api/v1/catalogue/quotes/${encodedQuoteId}/refresh`,
392
+ input
393
+ )
394
+ );
395
+ }
396
+ async getTaxonomies(parentId) {
397
+ const path = withQuery("/api/v1/catalogue/taxonomies", { parent_id: parentId });
398
+ return safe(this.client.get(path));
399
+ }
400
+ async getTaxonomy(id) {
401
+ const encodedId = encodeURIComponent(id);
402
+ return safe(this.client.get(`/api/v1/catalogue/taxonomies/${encodedId}`));
403
+ }
404
+ async getTaxonomyPath(id) {
405
+ const encodedId = encodeURIComponent(id);
406
+ return safe(this.client.get(`/api/v1/catalogue/taxonomies/${encodedId}/path`));
407
+ }
408
+ async searchTaxonomies(query, limit) {
409
+ const path = withQuery("/api/v1/catalogue/taxonomies/search", { q: query, limit });
410
+ return safe(this.client.get(path));
411
+ }
412
+ async getProductSchedules(productId) {
413
+ const encodedId = encodeURIComponent(productId);
414
+ return safe(this.client.get(`/api/v1/catalogue/products/${encodedId}/schedules`));
415
+ }
416
+ async checkProductAvailableNow(productId, locationId) {
417
+ const encodedId = encodeURIComponent(productId);
418
+ const path = withQuery(`/api/v1/catalogue/products/${encodedId}/available-now`, { location_id: locationId });
419
+ return safe(this.client.get(path));
420
+ }
421
+ async getDeals(locationId) {
422
+ const path = withQuery("/api/v1/catalogue/deals", { location_id: locationId });
423
+ return safe(this.client.get(path));
424
+ }
425
+ async getProductsOnSale() {
426
+ return safe(this.client.get("/api/v1/catalogue/deals/on-sale"));
427
+ }
428
+ async getProductDeals(productId) {
429
+ const encodedId = encodeURIComponent(productId);
430
+ return safe(this.client.get(`/api/v1/catalogue/products/${encodedId}/deals`));
431
+ }
432
+ async getCategoryDeals(categoryId) {
433
+ const encodedId = encodeURIComponent(categoryId);
434
+ return safe(this.client.get(`/api/v1/catalogue/categories/${encodedId}/deals`));
435
+ }
436
+ async getCollectionDeals(collectionId) {
437
+ const encodedId = encodeURIComponent(collectionId);
438
+ return safe(this.client.get(`/api/v1/catalogue/collections/${encodedId}/deals`));
439
+ }
440
+ async validateDiscountCode(code, orderSubtotal, locationId) {
441
+ return safe(
442
+ this.client.post("/api/v1/catalogue/deals/validate", {
443
+ discount_code: code,
444
+ order_subtotal: orderSubtotal,
445
+ location_id: locationId
446
+ })
447
+ );
448
+ }
449
+ async search(query, options) {
450
+ const result = await this.getProducts({
451
+ ...options,
452
+ search: query,
453
+ limit: options?.limit ?? 20
454
+ });
455
+ if (!result.ok) return result;
456
+ return ok(result.value.items);
457
+ }
458
+ async searchProducts(query, options) {
459
+ return this.search(query, options);
460
+ }
461
+ async getMenu(options) {
462
+ const path = withQuery("/api/v1/catalogue/menu", {
463
+ category_id: options?.category,
464
+ limit: options?.limit
465
+ });
466
+ return safe(this.client.get(path));
467
+ }
468
+ async getMenuCategory(categoryId) {
469
+ const encodedId = encodeURIComponent(categoryId);
470
+ return safe(this.client.get(`/api/v1/catalogue/menu/categories/${encodedId}`));
471
+ }
472
+ async getMenuItem(itemId) {
473
+ const encodedId = encodeURIComponent(itemId);
474
+ return safe(this.client.get(`/api/v1/catalogue/menu/items/${encodedId}`));
475
+ }
476
+ async getTags(options) {
477
+ const path = withQuery("/api/v1/catalogue/tags", {
478
+ tag_group: options?.tag_group,
479
+ search: options?.search,
480
+ min_usage: options?.min_usage,
481
+ limit: options?.limit,
482
+ offset: options?.offset
483
+ });
484
+ return safe(this.client.get(path));
485
+ }
486
+ async getAttributeDefinitions() {
487
+ return safe(this.client.get("/api/v1/catalogue/attributes"));
488
+ }
489
+ async getPropertyFacets(options) {
490
+ const path = withQuery("/api/v1/catalogue/properties/facets", {
491
+ category_id: options?.category_id,
492
+ product_type: options?.product_type
493
+ });
494
+ return safe(this.client.get(path));
495
+ }
496
+ async getTaxonomyAttributes(taxonomyId) {
497
+ const encodedId = encodeURIComponent(taxonomyId);
498
+ return safe(
499
+ this.client.get(
500
+ `/api/v1/catalogue/taxonomies/${encodedId}/attributes`
501
+ )
502
+ );
503
+ }
504
+ };
505
+
506
+ // src/cart.ts
507
+ function isUICartResponse(value) {
508
+ return "cart" in value;
509
+ }
510
+ function unwrapEnrichedCart(value) {
511
+ return isUICartResponse(value) ? value.cart : value;
512
+ }
513
+ var CartOperations = class {
514
+ constructor(client) {
515
+ this.client = client;
516
+ }
517
+ async get() {
518
+ const result = await safe(this.client.get("/api/v1/cart"));
519
+ if (!result.ok) return result;
520
+ return ok(unwrapEnrichedCart(result.value));
521
+ }
522
+ async getRaw() {
523
+ return safe(this.client.get("/api/v1/cart"));
524
+ }
525
+ async getItems() {
526
+ return safe(this.client.get("/api/v1/cart/items"));
527
+ }
528
+ async getCount() {
529
+ return safe(this.client.get("/api/v1/cart/count"));
530
+ }
531
+ async getTotal() {
532
+ return safe(this.client.get("/api/v1/cart/total"));
533
+ }
534
+ async getSummary() {
535
+ const cartResult = await this.get();
536
+ if (!cartResult.ok) return cartResult;
537
+ const cart = cartResult.value;
538
+ return ok({
539
+ item_count: cart.items.length,
540
+ total_items: cart.items.reduce((sum, item) => sum + item.quantity, 0),
541
+ subtotal: cart.pricing.subtotal,
542
+ discount_amount: cart.pricing.total_discounts,
543
+ tax_amount: cart.pricing.tax_amount,
544
+ total: cart.pricing.total_price,
545
+ currency: cart.pricing.currency
546
+ });
547
+ }
548
+ async addItem(input) {
549
+ return safe(this.client.post("/api/v1/cart/items", input));
550
+ }
551
+ async updateItem(cartItemId, updates) {
552
+ if (typeof updates.quantity === "number") {
553
+ return this.updateQuantity(cartItemId, updates.quantity);
554
+ }
555
+ const encodedId = encodeURIComponent(cartItemId);
556
+ return safe(this.client.patch(`/api/v1/cart/items/${encodedId}`, updates));
557
+ }
558
+ async updateQuantity(cartItemId, quantity) {
559
+ const encodedId = encodeURIComponent(cartItemId);
560
+ return safe(
561
+ this.client.patch(`/api/v1/cart/items/${encodedId}`, {
562
+ quantity
563
+ })
564
+ );
565
+ }
566
+ async removeItem(cartItemId) {
567
+ const encodedId = encodeURIComponent(cartItemId);
568
+ return safe(this.client.delete(`/api/v1/cart/items/${encodedId}`));
569
+ }
570
+ async clear() {
571
+ return safe(this.client.delete("/api/v1/cart"));
572
+ }
573
+ async applyCoupon(code) {
574
+ return safe(
575
+ this.client.post("/api/v1/cart/coupons", {
576
+ coupon_code: code
577
+ })
578
+ );
579
+ }
580
+ async removeCoupon() {
581
+ return safe(this.client.delete("/api/v1/cart/coupons/current"));
582
+ }
583
+ async isEmpty() {
584
+ const countResult = await this.getCount();
585
+ if (!countResult.ok) return countResult;
586
+ return ok(countResult.value === 0);
587
+ }
588
+ async hasItem(productId, variantId) {
589
+ const itemsResult = await this.getItems();
590
+ if (!itemsResult.ok) return itemsResult;
591
+ const found = itemsResult.value.some((item) => {
592
+ const matchesProduct = item.item_id === productId;
593
+ if (!variantId) return matchesProduct;
594
+ const config = item.configuration;
595
+ if ("variant" in config && config.variant) {
596
+ return matchesProduct && config.variant.variant_id === variantId;
597
+ }
598
+ return matchesProduct;
599
+ });
600
+ return ok(found);
601
+ }
602
+ async findItem(productId, variantId) {
603
+ const itemsResult = await this.getItems();
604
+ if (!itemsResult.ok) return itemsResult;
605
+ const found = itemsResult.value.find((item) => {
606
+ const matchesProduct = item.item_id === productId;
607
+ if (!variantId) return matchesProduct;
608
+ const config = item.configuration;
609
+ if ("variant" in config && config.variant) {
610
+ return matchesProduct && config.variant.variant_id === variantId;
611
+ }
612
+ return matchesProduct;
613
+ });
614
+ return ok(found);
615
+ }
616
+ };
617
+
618
+ // src/constants.ts
619
+ var CHECKOUT_MODE = {
620
+ LINK: "link",
621
+ GUEST: "guest"
622
+ };
623
+ var ORDER_TYPE = {
624
+ DELIVERY: "delivery",
625
+ PICKUP: "pickup",
626
+ DINE_IN: "dine-in",
627
+ WALK_IN: "walk-in"
628
+ };
629
+ var PAYMENT_METHOD = {
630
+ MOBILE_MONEY: "mobile_money",
631
+ CARD: "card"
632
+ };
633
+ var CHECKOUT_STEP = {
634
+ AUTHENTICATION: "authentication",
635
+ ORDER_DETAILS: "order_details",
636
+ PAYMENT_METHOD: "payment_method",
637
+ PAYMENT: "payment",
638
+ CONFIRMATION: "confirmation"
639
+ };
640
+ var PAYMENT_STATE = {
641
+ INITIAL: "initial",
642
+ PREPARING: "preparing",
643
+ PROCESSING: "processing",
644
+ VERIFYING: "verifying",
645
+ AWAITING_AUTHORIZATION: "awaiting_authorization",
646
+ SUCCESS: "success",
647
+ ERROR: "error",
648
+ TIMEOUT: "timeout"
649
+ };
650
+ var PICKUP_TIME_TYPE = {
651
+ ASAP: "asap",
652
+ SCHEDULED: "scheduled"
653
+ };
654
+ var MOBILE_MONEY_PROVIDER = {
655
+ MTN: "mtn",
656
+ VODAFONE: "vodafone",
657
+ AIRTEL: "airtel"
658
+ };
659
+ var AUTHORIZATION_TYPE = {
660
+ OTP: "otp",
661
+ PIN: "pin",
662
+ PHONE: "phone",
663
+ BIRTHDAY: "birthday",
664
+ ADDRESS: "address"
665
+ };
666
+ var DEVICE_TYPE = {
667
+ MOBILE: "mobile",
668
+ DESKTOP: "desktop",
669
+ TABLET: "tablet"
670
+ };
671
+ var CONTACT_TYPE = {
672
+ PHONE: "phone",
673
+ EMAIL: "email"
674
+ };
675
+ var LINK_QUERY = {
676
+ DATA: "link.data",
677
+ ADDRESSES: "link.addresses",
678
+ MOBILE_MONEY: "link.mobile_money",
679
+ PREFERENCES: "link.preferences",
680
+ SESSIONS: "link.sessions"
681
+ };
682
+ var LINK_MUTATION = {
683
+ CHECK_STATUS: "link.check_status",
684
+ ENROLL: "link.enroll",
685
+ ENROLL_AND_LINK_ORDER: "link.enroll_and_link_order",
686
+ UPDATE_PREFERENCES: "link.update_preferences",
687
+ CREATE_ADDRESS: "link.create_address",
688
+ UPDATE_ADDRESS: "link.update_address",
689
+ DELETE_ADDRESS: "link.delete_address",
690
+ SET_DEFAULT_ADDRESS: "link.set_default_address",
691
+ TRACK_ADDRESS_USAGE: "link.track_address_usage",
692
+ CREATE_MOBILE_MONEY: "link.create_mobile_money",
693
+ DELETE_MOBILE_MONEY: "link.delete_mobile_money",
694
+ SET_DEFAULT_MOBILE_MONEY: "link.set_default_mobile_money",
695
+ TRACK_MOBILE_MONEY_USAGE: "link.track_mobile_money_usage",
696
+ VERIFY_MOBILE_MONEY: "link.verify_mobile_money",
697
+ REVOKE_SESSION: "link.revoke_session",
698
+ REVOKE_ALL_SESSIONS: "link.revoke_all_sessions"
699
+ };
700
+ var AUTH_MUTATION = {
701
+ REQUEST_OTP: "auth.request_otp",
702
+ VERIFY_OTP: "auth.verify_otp"
703
+ };
704
+ var CHECKOUT_MUTATION = {
705
+ PROCESS: "checkout.process"
706
+ };
707
+ var PAYMENT_MUTATION = {
708
+ SUBMIT_AUTHORIZATION: "payment.submit_authorization",
709
+ CHECK_STATUS: "order.poll_payment_status"
710
+ };
711
+ var ORDER_MUTATION = {
712
+ UPDATE_CUSTOMER: "order.update_order_customer"
713
+ };
714
+ var DEFAULT_CURRENCY = "GHS";
715
+ var DEFAULT_COUNTRY = "GHA";
716
+
717
+ // src/utils/paystack.ts
718
+ async function openPaystackPopup(options, signal) {
719
+ if (typeof window === "undefined") {
720
+ return { success: false, error: "PROVIDER_UNAVAILABLE" };
721
+ }
722
+ let PaystackPop;
723
+ try {
724
+ const imported = await import('@paystack/inline-js');
725
+ PaystackPop = imported.default;
726
+ } catch {
727
+ return { success: false, error: "PROVIDER_UNAVAILABLE" };
728
+ }
729
+ return new Promise((resolve) => {
730
+ let settled = false;
731
+ const resolveOnce = (result) => {
732
+ if (settled) {
733
+ return;
734
+ }
735
+ settled = true;
736
+ if (signal) {
737
+ signal.removeEventListener("abort", onAbort);
738
+ }
739
+ resolve(result);
740
+ };
741
+ const onAbort = () => {
742
+ resolveOnce({ success: false, error: "CANCELLED" });
743
+ };
744
+ if (signal?.aborted) {
745
+ resolveOnce({ success: false, error: "CANCELLED" });
746
+ return;
747
+ }
748
+ if (signal) {
749
+ signal.addEventListener("abort", onAbort, { once: true });
750
+ }
751
+ try {
752
+ const popup = new PaystackPop();
753
+ popup.newTransaction({
754
+ key: options.key,
755
+ email: options.email,
756
+ amount: options.amount,
757
+ currency: options.currency,
758
+ reference: options.reference,
759
+ accessCode: options.accessCode,
760
+ onSuccess: (transaction) => {
761
+ resolveOnce({
762
+ success: true,
763
+ reference: transaction.reference ?? options.reference
764
+ });
765
+ },
766
+ onCancel: () => {
767
+ resolveOnce({ success: false, error: "PAYMENT_CANCELLED" });
768
+ },
769
+ onError: (error) => {
770
+ resolveOnce({
771
+ success: false,
772
+ error: error?.message || "PAYMENT_FAILED"
773
+ });
774
+ }
775
+ });
776
+ } catch {
777
+ resolveOnce({ success: false, error: "POPUP_BLOCKED" });
778
+ }
779
+ });
780
+ }
781
+
782
+ // src/utils/checkout-resolver.ts
783
+ var DEFAULT_POLL_INTERVAL_MS = 3e3;
784
+ var DEFAULT_MAX_POLL_ATTEMPTS = 60;
785
+ var MAX_CONSECUTIVE_NETWORK_ERRORS = 5;
786
+ var CARD_PROVIDER_PAYSTACK = "paystack";
787
+ var NEXT_ACTION_NONE = "none";
788
+ var NEXT_ACTION_CARD_POPUP = "card_popup";
789
+ var NEXT_ACTION_REDIRECT = "redirect";
790
+ var NEXT_ACTION_AUTHORIZATION = "authorization";
791
+ function normalizeCardPopupError(error) {
792
+ if (!error || error === "PAYMENT_CANCELLED" || error === "CANCELLED") {
793
+ return "PAYMENT_CANCELLED";
794
+ }
795
+ if (error === "PROVIDER_UNAVAILABLE") {
796
+ return "PROVIDER_UNAVAILABLE";
797
+ }
798
+ if (error === "POPUP_BLOCKED") {
799
+ return "POPUP_BLOCKED";
800
+ }
801
+ return "PAYMENT_FAILED";
802
+ }
803
+ function normalizeCardProvider(value) {
804
+ const normalized = value?.trim().toLowerCase();
805
+ return normalized && normalized.length > 0 ? normalized : CARD_PROVIDER_PAYSTACK;
806
+ }
807
+ async function openCardPopup(provider, checkoutResult, email, currency, signal) {
808
+ if (typeof window === "undefined") {
809
+ return { success: false, error: "PROVIDER_UNAVAILABLE" };
810
+ }
811
+ if (provider === CARD_PROVIDER_PAYSTACK) {
812
+ return openPaystackPopup(
813
+ {
814
+ key: checkoutResult.public_key || "",
815
+ email,
816
+ accessCode: checkoutResult.client_secret,
817
+ reference: checkoutResult.payment_reference || checkoutResult.client_secret,
818
+ currency
819
+ },
820
+ signal
821
+ );
822
+ }
823
+ return { success: false, error: "PROVIDER_UNAVAILABLE" };
824
+ }
825
+ var VALID_MOBILE_MONEY_PROVIDERS = new Set(Object.values(MOBILE_MONEY_PROVIDER));
826
+ function isValidMobileMoneyProvider(value) {
827
+ return VALID_MOBILE_MONEY_PROVIDERS.has(value);
828
+ }
829
+ function normalizeAuthorizationType(value) {
830
+ if (value && typeof value === "object" && "address" in value) {
831
+ return "address";
832
+ }
833
+ if (typeof value !== "string") return void 0;
834
+ const normalized = value.trim().toLowerCase().replace(/[\s-]+/g, "_");
835
+ if (normalized === "otp" || normalized === "pin") return normalized;
836
+ if (normalized === "phone" || normalized === "birthday" || normalized === "address") {
837
+ return normalized;
838
+ }
839
+ return void 0;
840
+ }
841
+ function formatMoney(value) {
842
+ if (typeof value === "number" && Number.isFinite(value)) {
843
+ return value.toFixed(2);
844
+ }
845
+ if (typeof value === "string" && value.trim().length > 0) {
846
+ return value;
847
+ }
848
+ return "0.00";
849
+ }
850
+ function createAbortError() {
851
+ const error = new Error("CANCELLED");
852
+ error.name = "AbortError";
853
+ return error;
854
+ }
855
+ function isAbortError(error) {
856
+ if (error instanceof DOMException && error.name === "AbortError") {
857
+ return true;
858
+ }
859
+ return error instanceof Error && (error.name === "AbortError" || error.message === "CANCELLED");
860
+ }
861
+ var CheckoutResolver = class {
862
+ constructor(options) {
863
+ this.client = options.client;
864
+ this.checkoutData = options.checkoutData;
865
+ this.pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
866
+ this.maxPollAttempts = options.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS;
867
+ this.onStatusChange = options.onStatusChange;
868
+ this.onAuthorizationRequired = options.onAuthorizationRequired;
869
+ this.signal = options.signal;
870
+ this.returnUrl = options.returnUrl;
871
+ this.enrollInLink = options.enrollInLink !== false;
872
+ this.businessId = options.businessId;
873
+ this.addressData = options.addressData;
874
+ this.paymentData = options.paymentData;
875
+ this.orderType = options.orderType;
876
+ this.cartTotal = options.cartTotal;
877
+ this.cartCurrency = options.cartCurrency;
878
+ this.allowPopups = options.allowPopups ?? typeof window !== "undefined";
879
+ }
880
+ async resolve(checkoutResult) {
881
+ try {
882
+ this.ensureNotAborted();
883
+ if (!checkoutResult.order_id) {
884
+ return this.fail("CHECKOUT_FAILED", "Checkout did not return an order ID.", false);
885
+ }
886
+ if (checkoutResult.next_action) {
887
+ return this.resolveNextAction(checkoutResult);
888
+ }
889
+ let latestCheckoutResult = checkoutResult;
890
+ let authorizationType = normalizeAuthorizationType(checkoutResult.authorization_type);
891
+ let paymentReference = checkoutResult.payment_reference;
892
+ if (this.isSuccessfulStatus(checkoutResult.payment_status)) {
893
+ return this.finalizeSuccess(checkoutResult);
894
+ }
895
+ if (checkoutResult.client_secret && checkoutResult.public_key) {
896
+ const provider = normalizeCardProvider(checkoutResult.provider);
897
+ this.emit("awaiting_authorization", {
898
+ display_text: "Complete payment in the card authorization popup.",
899
+ order_id: checkoutResult.order_id,
900
+ order_number: checkoutResult.order_number
901
+ });
902
+ if (!this.allowPopups) {
903
+ return this.fail(
904
+ "PROVIDER_UNAVAILABLE",
905
+ "Card payment popup is unavailable in this environment.",
906
+ false
907
+ );
908
+ }
909
+ const popupResult = await openCardPopup(
910
+ provider,
911
+ checkoutResult,
912
+ this.checkoutData.customer.email || "customer@cimplify.io",
913
+ this.getOrderCurrency(checkoutResult),
914
+ this.signal
915
+ );
916
+ if (!popupResult.success) {
917
+ const popupError = normalizeCardPopupError(popupResult.error);
918
+ if (popupError === "POPUP_BLOCKED") {
919
+ return this.fail(
920
+ "POPUP_BLOCKED",
921
+ "Unable to open card payment popup. Please allow popups and try again.",
922
+ true
923
+ );
924
+ }
925
+ if (popupError === "PROVIDER_UNAVAILABLE") {
926
+ return this.fail(
927
+ "PROVIDER_UNAVAILABLE",
928
+ "Card payment provider is unavailable.",
929
+ false
930
+ );
931
+ }
932
+ return this.fail(
933
+ "PAYMENT_CANCELLED",
934
+ "Card payment was cancelled before completion.",
935
+ true
936
+ );
937
+ }
938
+ paymentReference = popupResult.reference || paymentReference;
939
+ }
940
+ if (checkoutResult.authorization_url) {
941
+ if (typeof window !== "undefined" && this.returnUrl) {
942
+ window.location.assign(checkoutResult.authorization_url);
943
+ return this.fail(
944
+ "REDIRECT_REQUIRED",
945
+ "Redirecting to complete payment authorization.",
946
+ true
947
+ );
948
+ }
949
+ if (typeof window !== "undefined") {
950
+ const popup = window.open(
951
+ checkoutResult.authorization_url,
952
+ "cimplify-auth",
953
+ "width=520,height=760,noopener,noreferrer"
954
+ );
955
+ if (!popup) {
956
+ return this.fail(
957
+ "POPUP_BLOCKED",
958
+ "Authorization popup was blocked. Please allow popups and retry.",
959
+ true
960
+ );
961
+ }
962
+ }
963
+ }
964
+ if (checkoutResult.requires_authorization || chunkRYQ5IPWX_js.isPaymentStatusRequiresAction(checkoutResult.payment_status)) {
965
+ const authorization = await this.handleAuthorization({
966
+ authorizationType,
967
+ paymentReference,
968
+ displayText: checkoutResult.display_text,
969
+ provider: checkoutResult.provider
970
+ });
971
+ if (!authorization.ok) {
972
+ return authorization.result;
973
+ }
974
+ if (authorization.value) {
975
+ latestCheckoutResult = authorization.value;
976
+ paymentReference = authorization.value.payment_reference || paymentReference;
977
+ authorizationType = normalizeAuthorizationType(authorization.value.authorization_type) || authorizationType;
978
+ if (this.isSuccessfulStatus(authorization.value.payment_status)) {
979
+ return this.finalizeSuccess(authorization.value);
980
+ }
981
+ if (this.isFailureStatus(authorization.value.payment_status)) {
982
+ return this.fail(
983
+ "AUTHORIZATION_FAILED",
984
+ authorization.value.display_text || "Payment authorization failed.",
985
+ false
986
+ );
987
+ }
988
+ }
989
+ }
990
+ return this.pollUntilTerminal({
991
+ orderId: checkoutResult.order_id,
992
+ latestCheckoutResult,
993
+ paymentReference,
994
+ authorizationType
995
+ });
996
+ } catch (error) {
997
+ if (isAbortError(error)) {
998
+ return this.fail("CANCELLED", "Checkout was cancelled.", true);
999
+ }
1000
+ const message = error instanceof Error ? error.message : "Checkout failed unexpectedly.";
1001
+ return this.fail("CHECKOUT_FAILED", message, true);
1002
+ }
1003
+ }
1004
+ async resolveNextAction(checkoutResult) {
1005
+ const action = checkoutResult.next_action;
1006
+ if (this.isSuccessfulStatus(checkoutResult.payment_status)) {
1007
+ return this.finalizeSuccess(checkoutResult);
1008
+ }
1009
+ let latestCheckoutResult = checkoutResult;
1010
+ let paymentReference = checkoutResult.payment_reference;
1011
+ switch (action.type) {
1012
+ case NEXT_ACTION_NONE:
1013
+ return this.finalizeSuccess(checkoutResult);
1014
+ case NEXT_ACTION_CARD_POPUP: {
1015
+ const provider = normalizeCardProvider(action.provider);
1016
+ this.emit("awaiting_authorization", {
1017
+ display_text: "Complete payment in the card authorization popup.",
1018
+ order_id: checkoutResult.order_id,
1019
+ order_number: checkoutResult.order_number
1020
+ });
1021
+ if (!this.allowPopups) {
1022
+ return this.fail(
1023
+ "PROVIDER_UNAVAILABLE",
1024
+ "Card payment popup is unavailable in this environment.",
1025
+ false
1026
+ );
1027
+ }
1028
+ const popupResult = await openCardPopup(
1029
+ provider,
1030
+ checkoutResult,
1031
+ this.checkoutData.customer.email || "customer@cimplify.io",
1032
+ this.getOrderCurrency(checkoutResult),
1033
+ this.signal
1034
+ );
1035
+ if (!popupResult.success) {
1036
+ const popupError = normalizeCardPopupError(popupResult.error);
1037
+ if (popupError === "POPUP_BLOCKED") {
1038
+ return this.fail(
1039
+ "POPUP_BLOCKED",
1040
+ "Unable to open card payment popup. Please allow popups and try again.",
1041
+ true
1042
+ );
1043
+ }
1044
+ if (popupError === "PROVIDER_UNAVAILABLE") {
1045
+ return this.fail("PROVIDER_UNAVAILABLE", "Card payment provider is unavailable.", false);
1046
+ }
1047
+ return this.fail("PAYMENT_CANCELLED", "Card payment was cancelled before completion.", true);
1048
+ }
1049
+ paymentReference = popupResult.reference || paymentReference;
1050
+ break;
1051
+ }
1052
+ case NEXT_ACTION_REDIRECT: {
1053
+ if (typeof window !== "undefined" && this.returnUrl) {
1054
+ window.location.assign(action.authorization_url);
1055
+ return this.fail("REDIRECT_REQUIRED", "Redirecting to complete payment authorization.", true);
1056
+ }
1057
+ if (typeof window !== "undefined") {
1058
+ const popup = window.open(
1059
+ action.authorization_url,
1060
+ "cimplify-auth",
1061
+ "width=520,height=760,noopener,noreferrer"
1062
+ );
1063
+ if (!popup) {
1064
+ return this.fail(
1065
+ "POPUP_BLOCKED",
1066
+ "Authorization popup was blocked. Please allow popups and retry.",
1067
+ true
1068
+ );
1069
+ }
1070
+ }
1071
+ break;
1072
+ }
1073
+ case NEXT_ACTION_AUTHORIZATION: {
1074
+ const authType = normalizeAuthorizationType(action.authorization_type);
1075
+ const authorization = await this.handleAuthorization({
1076
+ authorizationType: authType,
1077
+ paymentReference,
1078
+ displayText: action.display_text,
1079
+ provider: checkoutResult.provider
1080
+ });
1081
+ if (!authorization.ok) {
1082
+ return authorization.result;
1083
+ }
1084
+ if (authorization.value) {
1085
+ latestCheckoutResult = authorization.value;
1086
+ paymentReference = authorization.value.payment_reference || paymentReference;
1087
+ if (this.isSuccessfulStatus(authorization.value.payment_status)) {
1088
+ return this.finalizeSuccess(authorization.value);
1089
+ }
1090
+ if (this.isFailureStatus(authorization.value.payment_status)) {
1091
+ return this.fail(
1092
+ "AUTHORIZATION_FAILED",
1093
+ authorization.value.display_text || "Payment authorization failed.",
1094
+ false
1095
+ );
1096
+ }
1097
+ }
1098
+ break;
1099
+ }
1100
+ }
1101
+ return this.pollUntilTerminal({
1102
+ orderId: checkoutResult.order_id,
1103
+ latestCheckoutResult,
1104
+ paymentReference,
1105
+ authorizationType: normalizeAuthorizationType(checkoutResult.authorization_type)
1106
+ });
1107
+ }
1108
+ async pollUntilTerminal(input) {
1109
+ let consecutiveErrors = 0;
1110
+ let latestCheckoutResult = input.latestCheckoutResult;
1111
+ let paymentReference = input.paymentReference;
1112
+ let authorizationType = input.authorizationType;
1113
+ for (let attempt = 0; attempt < this.maxPollAttempts; attempt++) {
1114
+ this.ensureNotAborted();
1115
+ this.emit("polling", {
1116
+ poll_attempt: attempt,
1117
+ max_poll_attempts: this.maxPollAttempts,
1118
+ order_id: input.orderId,
1119
+ order_number: latestCheckoutResult.order_number
1120
+ });
1121
+ const statusResult = await this.client.checkout.pollPaymentStatus(input.orderId);
1122
+ if (!statusResult.ok) {
1123
+ consecutiveErrors += 1;
1124
+ if (consecutiveErrors >= MAX_CONSECUTIVE_NETWORK_ERRORS) {
1125
+ return this.fail(
1126
+ "NETWORK_ERROR",
1127
+ "Unable to confirm payment due to repeated network errors.",
1128
+ true
1129
+ );
1130
+ }
1131
+ await this.wait(this.pollIntervalMs);
1132
+ continue;
1133
+ }
1134
+ consecutiveErrors = 0;
1135
+ if (statusResult.value.reference) {
1136
+ paymentReference = statusResult.value.reference;
1137
+ }
1138
+ const normalized = chunkRYQ5IPWX_js.normalizeStatusResponse(statusResult.value);
1139
+ if (normalized.paid || chunkRYQ5IPWX_js.isPaymentStatusSuccess(normalized.status)) {
1140
+ return this.finalizeSuccess(latestCheckoutResult);
1141
+ }
1142
+ if (chunkRYQ5IPWX_js.isPaymentStatusFailure(normalized.status)) {
1143
+ return this.fail(
1144
+ normalized.status ? normalized.status.toUpperCase() : "PAYMENT_FAILED",
1145
+ normalized.message || "Payment failed during confirmation.",
1146
+ false
1147
+ );
1148
+ }
1149
+ if (chunkRYQ5IPWX_js.isPaymentStatusRequiresAction(normalized.status)) {
1150
+ const authorization = await this.handleAuthorization({
1151
+ authorizationType,
1152
+ paymentReference,
1153
+ displayText: normalized.message || latestCheckoutResult.display_text,
1154
+ provider: latestCheckoutResult.provider
1155
+ });
1156
+ if (!authorization.ok) {
1157
+ return authorization.result;
1158
+ }
1159
+ if (authorization.value) {
1160
+ latestCheckoutResult = authorization.value;
1161
+ paymentReference = authorization.value.payment_reference || paymentReference;
1162
+ authorizationType = normalizeAuthorizationType(authorization.value.authorization_type) || authorizationType;
1163
+ if (this.isSuccessfulStatus(authorization.value.payment_status)) {
1164
+ return this.finalizeSuccess(authorization.value);
1165
+ }
1166
+ if (this.isFailureStatus(authorization.value.payment_status)) {
1167
+ return this.fail(
1168
+ "AUTHORIZATION_FAILED",
1169
+ authorization.value.display_text || "Payment authorization failed.",
1170
+ false
1171
+ );
1172
+ }
1173
+ }
1174
+ }
1175
+ await this.wait(this.pollIntervalMs);
1176
+ }
1177
+ try {
1178
+ const finalResult = await this.client.checkout.pollPaymentStatus(input.orderId);
1179
+ if (finalResult.ok) {
1180
+ const normalized = chunkRYQ5IPWX_js.normalizeStatusResponse(finalResult.value);
1181
+ if (normalized.paid || chunkRYQ5IPWX_js.isPaymentStatusSuccess(normalized.status)) {
1182
+ return this.finalizeSuccess(latestCheckoutResult);
1183
+ }
1184
+ }
1185
+ } catch {
1186
+ }
1187
+ return this.fail(
1188
+ "PAYMENT_TIMEOUT",
1189
+ "Payment confirmation timed out. Please retry checkout.",
1190
+ true
1191
+ );
1192
+ }
1193
+ async handleAuthorization(input) {
1194
+ const authorizationType = input.authorizationType;
1195
+ const paymentReference = input.paymentReference;
1196
+ if (!authorizationType || !paymentReference) {
1197
+ return { ok: true };
1198
+ }
1199
+ this.emit("awaiting_authorization", {
1200
+ authorization_type: authorizationType,
1201
+ display_text: input.displayText,
1202
+ provider: input.provider
1203
+ });
1204
+ let authorizationResult;
1205
+ const submit = async (code) => {
1206
+ this.ensureNotAborted();
1207
+ const trimmedCode = code.trim();
1208
+ if (!trimmedCode) {
1209
+ throw new Error("Authorization code is required.");
1210
+ }
1211
+ const submitResult = await this.client.checkout.submitAuthorization({
1212
+ reference: paymentReference,
1213
+ auth_type: authorizationType,
1214
+ value: trimmedCode
1215
+ });
1216
+ if (!submitResult.ok) {
1217
+ throw new Error(submitResult.error.message || "Authorization failed.");
1218
+ }
1219
+ authorizationResult = submitResult.value;
1220
+ };
1221
+ try {
1222
+ if (this.onAuthorizationRequired) {
1223
+ await this.onAuthorizationRequired(authorizationType, submit);
1224
+ } else {
1225
+ return {
1226
+ ok: false,
1227
+ result: this.fail(
1228
+ "AUTHORIZATION_REQUIRED",
1229
+ "Authorization callback is required in headless checkout mode.",
1230
+ false
1231
+ )
1232
+ };
1233
+ }
1234
+ } catch (error) {
1235
+ if (isAbortError(error)) {
1236
+ return {
1237
+ ok: false,
1238
+ result: this.fail("CANCELLED", "Checkout was cancelled.", true)
1239
+ };
1240
+ }
1241
+ const message = error instanceof Error ? error.message : "Payment authorization failed.";
1242
+ return {
1243
+ ok: false,
1244
+ result: this.fail("AUTHORIZATION_FAILED", message, true)
1245
+ };
1246
+ }
1247
+ return {
1248
+ ok: true,
1249
+ value: authorizationResult
1250
+ };
1251
+ }
1252
+ async finalizeSuccess(checkoutResult) {
1253
+ this.emit("finalizing", {
1254
+ order_id: checkoutResult.order_id,
1255
+ order_number: checkoutResult.order_number
1256
+ });
1257
+ const enrolledInLink = await this.maybeEnrollInLink(checkoutResult.order_id);
1258
+ this.emit("success", {
1259
+ order_id: checkoutResult.order_id,
1260
+ order_number: checkoutResult.order_number
1261
+ });
1262
+ return {
1263
+ success: true,
1264
+ order: {
1265
+ id: checkoutResult.order_id,
1266
+ order_number: checkoutResult.order_number || checkoutResult.order_id,
1267
+ status: checkoutResult.payment_status || "paid",
1268
+ total: this.getOrderTotal(checkoutResult),
1269
+ currency: this.getOrderCurrency(checkoutResult)
1270
+ },
1271
+ enrolled_in_link: enrolledInLink
1272
+ };
1273
+ }
1274
+ async maybeEnrollInLink(orderId) {
1275
+ if (!this.enrollInLink || !orderId) {
1276
+ return false;
1277
+ }
1278
+ let businessId = this.businessId;
1279
+ if (!businessId) {
1280
+ const businessResult = await this.client.business.getInfo();
1281
+ if (!businessResult.ok || !businessResult.value?.id) {
1282
+ return false;
1283
+ }
1284
+ businessId = businessResult.value.id;
1285
+ }
1286
+ const address = this.getEnrollmentAddress();
1287
+ const mobileMoney = this.getEnrollmentMobileMoney();
1288
+ try {
1289
+ const enrollment = await this.client.link.enrollAndLinkOrder({
1290
+ order_id: orderId,
1291
+ business_id: businessId,
1292
+ order_type: this.orderType || this.checkoutData.order_type,
1293
+ address,
1294
+ mobile_money: mobileMoney
1295
+ });
1296
+ return enrollment.ok && enrollment.value.success;
1297
+ } catch {
1298
+ return false;
1299
+ }
1300
+ }
1301
+ getEnrollmentAddress() {
1302
+ const source = this.addressData ?? this.checkoutData.address_info;
1303
+ if (!source?.street_address) {
1304
+ return void 0;
1305
+ }
1306
+ return {
1307
+ label: "Default",
1308
+ street_address: source.street_address,
1309
+ apartment: source.apartment || void 0,
1310
+ city: source.city || "",
1311
+ region: source.region || "",
1312
+ delivery_instructions: source.delivery_instructions || void 0,
1313
+ phone_for_delivery: source.phone_for_delivery || void 0
1314
+ };
1315
+ }
1316
+ getEnrollmentMobileMoney() {
1317
+ if (this.paymentData?.type === "mobile_money" && this.paymentData.phone_number && this.paymentData.provider && isValidMobileMoneyProvider(this.paymentData.provider)) {
1318
+ return {
1319
+ phone_number: this.paymentData.phone_number,
1320
+ provider: this.paymentData.provider,
1321
+ label: this.paymentData.label || "Mobile Money"
1322
+ };
1323
+ }
1324
+ if (this.checkoutData.mobile_money_details?.phone_number) {
1325
+ return {
1326
+ phone_number: this.checkoutData.mobile_money_details.phone_number,
1327
+ provider: this.checkoutData.mobile_money_details.provider,
1328
+ label: "Mobile Money"
1329
+ };
1330
+ }
1331
+ return void 0;
1332
+ }
1333
+ getOrderTotal(checkoutResult) {
1334
+ if (checkoutResult.fx?.pay_amount !== void 0) {
1335
+ return formatMoney(checkoutResult.fx.pay_amount);
1336
+ }
1337
+ if (this.cartTotal !== void 0) {
1338
+ return formatMoney(this.cartTotal);
1339
+ }
1340
+ return "0.00";
1341
+ }
1342
+ getOrderCurrency(checkoutResult) {
1343
+ if (checkoutResult.fx?.pay_currency) {
1344
+ return checkoutResult.fx.pay_currency;
1345
+ }
1346
+ if (this.cartCurrency) {
1347
+ return this.cartCurrency;
1348
+ }
1349
+ if (this.checkoutData.pay_currency) {
1350
+ return this.checkoutData.pay_currency;
1351
+ }
1352
+ return "GHS";
1353
+ }
1354
+ emit(status, context = {}) {
1355
+ if (!this.onStatusChange) {
1356
+ return;
1357
+ }
1358
+ try {
1359
+ this.onStatusChange(status, context);
1360
+ } catch {
1361
+ }
1362
+ }
1363
+ fail(code, message, recoverable) {
1364
+ this.emit("failed", {
1365
+ display_text: message
1366
+ });
1367
+ return {
1368
+ success: false,
1369
+ error: {
1370
+ code,
1371
+ message,
1372
+ recoverable
1373
+ }
1374
+ };
1375
+ }
1376
+ isSuccessfulStatus(status) {
1377
+ const normalized = chunkRYQ5IPWX_js.normalizeStatusResponse({ status, paid: false });
1378
+ return normalized.paid || chunkRYQ5IPWX_js.isPaymentStatusSuccess(normalized.status);
1379
+ }
1380
+ isFailureStatus(status) {
1381
+ const normalized = chunkRYQ5IPWX_js.normalizeStatusResponse({ status, paid: false });
1382
+ return chunkRYQ5IPWX_js.isPaymentStatusFailure(normalized.status);
1383
+ }
1384
+ ensureNotAborted() {
1385
+ if (this.signal?.aborted) {
1386
+ throw createAbortError();
1387
+ }
1388
+ }
1389
+ wait(ms) {
1390
+ this.ensureNotAborted();
1391
+ return new Promise((resolve, reject) => {
1392
+ const timer = setTimeout(() => {
1393
+ if (this.signal) {
1394
+ this.signal.removeEventListener("abort", onAbort);
1395
+ }
1396
+ resolve();
1397
+ }, ms);
1398
+ const onAbort = () => {
1399
+ clearTimeout(timer);
1400
+ reject(createAbortError());
1401
+ };
1402
+ if (this.signal) {
1403
+ this.signal.addEventListener("abort", onAbort, { once: true });
1404
+ }
1405
+ });
1406
+ }
1407
+ };
1408
+
1409
+ // src/checkout.ts
1410
+ function toTerminalFailure(code, message, recoverable) {
1411
+ return {
1412
+ success: false,
1413
+ error: {
1414
+ code,
1415
+ message,
1416
+ recoverable
1417
+ }
1418
+ };
1419
+ }
1420
+ function generateIdempotencyKey() {
1421
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
1422
+ return `idem_${crypto.randomUUID()}`;
1423
+ }
1424
+ const timestamp = Date.now().toString(36);
1425
+ const random = Math.random().toString(36).substring(2, 15);
1426
+ return `idem_${timestamp}_${random}`;
1427
+ }
1428
+ var CheckoutService = class {
1429
+ constructor(client) {
1430
+ this.client = client;
1431
+ }
1432
+ orderTokenParam(orderId) {
1433
+ const token = this.client.getOrderToken(orderId);
1434
+ return token ? `?token=${encodeURIComponent(token)}` : "";
1435
+ }
1436
+ async process(data) {
1437
+ const checkoutData = {
1438
+ ...data,
1439
+ idempotency_key: data.idempotency_key || generateIdempotencyKey()
1440
+ };
1441
+ const result = await safe(
1442
+ this.client.post("/api/v1/checkout", {
1443
+ checkout_data: checkoutData
1444
+ })
1445
+ );
1446
+ if (result.ok && result.value.bill_token) {
1447
+ this.client.setOrderToken(result.value.order_id, result.value.bill_token);
1448
+ }
1449
+ return result;
1450
+ }
1451
+ async initializePayment(_orderId, _method) {
1452
+ return err(
1453
+ new chunkRYQ5IPWX_js.CimplifyError(
1454
+ "NOT_IMPLEMENTED",
1455
+ "initializePayment is not available in REST mode.",
1456
+ false
1457
+ )
1458
+ );
1459
+ }
1460
+ async submitAuthorization(input) {
1461
+ return safe(this.client.post("/api/v1/payments/authorization", input));
1462
+ }
1463
+ async pollPaymentStatus(orderId) {
1464
+ const encodedId = encodeURIComponent(orderId);
1465
+ const tokenParam = this.orderTokenParam(orderId);
1466
+ return safe(this.client.get(`/api/v1/orders/${encodedId}/payment-status${tokenParam}`));
1467
+ }
1468
+ async updateOrderCustomer(orderId, customer) {
1469
+ const encodedId = encodeURIComponent(orderId);
1470
+ const tokenParam = this.orderTokenParam(orderId);
1471
+ return safe(this.client.post(`/api/v1/orders/${encodedId}/customer${tokenParam}`, customer));
1472
+ }
1473
+ async verifyPayment(orderId) {
1474
+ const encodedId = encodeURIComponent(orderId);
1475
+ const tokenParam = this.orderTokenParam(orderId);
1476
+ return safe(this.client.post(`/api/v1/orders/${encodedId}/verify-payment${tokenParam}`));
1477
+ }
1478
+ async processAndResolve(data) {
1479
+ data.on_status_change?.("preparing", {});
1480
+ if (!data.cart_id) {
1481
+ return ok(
1482
+ toTerminalFailure(
1483
+ "INVALID_CART",
1484
+ "A valid cart is required before checkout can start.",
1485
+ false
1486
+ )
1487
+ );
1488
+ }
1489
+ const cartResult = await this.client.cart.get();
1490
+ if (!cartResult.ok || !cartResult.value?.id) {
1491
+ return ok(
1492
+ toTerminalFailure(
1493
+ "INVALID_CART",
1494
+ "Unable to load cart for checkout.",
1495
+ false
1496
+ )
1497
+ );
1498
+ }
1499
+ const cart = cartResult.value;
1500
+ if (cart.id !== data.cart_id || cart.items.length === 0) {
1501
+ return ok(
1502
+ toTerminalFailure(
1503
+ "INVALID_CART",
1504
+ "Cart is empty or no longer valid. Please refresh and try again.",
1505
+ false
1506
+ )
1507
+ );
1508
+ }
1509
+ const checkoutData = {
1510
+ cart_id: data.cart_id,
1511
+ location_id: data.location_id,
1512
+ customer: data.customer,
1513
+ order_type: data.order_type,
1514
+ address_info: data.address_info,
1515
+ payment_method: data.payment_method,
1516
+ mobile_money_details: data.mobile_money_details,
1517
+ special_instructions: data.special_instructions,
1518
+ link_address_id: data.link_address_id,
1519
+ link_payment_method_id: data.link_payment_method_id,
1520
+ idempotency_key: data.idempotency_key || generateIdempotencyKey(),
1521
+ metadata: data.metadata,
1522
+ pay_currency: data.pay_currency,
1523
+ fx_quote_id: data.fx_quote_id
1524
+ };
1525
+ const baseCurrency = chunkRYQ5IPWX_js.currencyCode(
1526
+ (cart.pricing.currency || checkoutData.pay_currency || "GHS").toUpperCase()
1527
+ );
1528
+ const payCurrency = data.pay_currency?.trim().toUpperCase();
1529
+ const payCurrencyCode = payCurrency ? chunkRYQ5IPWX_js.currencyCode(payCurrency) : void 0;
1530
+ const cartTotalAmount = typeof cart.pricing.total_price === "number" ? cart.pricing.total_price : Number.parseFloat(cart.pricing.total_price || "0");
1531
+ if (payCurrencyCode && payCurrencyCode !== baseCurrency && !checkoutData.fx_quote_id && Number.isFinite(cartTotalAmount) && cartTotalAmount > 0) {
1532
+ const fxQuoteResult = await this.client.fx.lockQuote({
1533
+ from: baseCurrency,
1534
+ to: payCurrencyCode,
1535
+ amount: cart.pricing.total_price
1536
+ });
1537
+ if (!fxQuoteResult.ok) {
1538
+ return ok(
1539
+ toTerminalFailure(
1540
+ "FX_QUOTE_FAILED",
1541
+ fxQuoteResult.error.message || "Unable to lock FX quote for checkout.",
1542
+ true
1543
+ )
1544
+ );
1545
+ }
1546
+ checkoutData.pay_currency = payCurrencyCode;
1547
+ checkoutData.fx_quote_id = fxQuoteResult.value.id;
1548
+ }
1549
+ data.on_status_change?.("processing", {});
1550
+ const processResult = await this.process(checkoutData);
1551
+ if (!processResult.ok) {
1552
+ return ok(
1553
+ toTerminalFailure(
1554
+ processResult.error.code || "CHECKOUT_FAILED",
1555
+ processResult.error.message || "Unable to process checkout.",
1556
+ processResult.error.retryable ?? true
1557
+ )
1558
+ );
1559
+ }
1560
+ const resolver = new CheckoutResolver({
1561
+ client: this.client,
1562
+ checkoutData,
1563
+ pollIntervalMs: data.poll_interval_ms,
1564
+ maxPollAttempts: data.max_poll_attempts,
1565
+ onStatusChange: data.on_status_change,
1566
+ onAuthorizationRequired: data.on_authorization_required,
1567
+ signal: data.signal,
1568
+ returnUrl: data.return_url,
1569
+ enrollInLink: data.enroll_in_link,
1570
+ cartTotal: cart.pricing.total_price,
1571
+ cartCurrency: checkoutData.pay_currency || cart.pricing.currency || "GHS",
1572
+ orderType: checkoutData.order_type,
1573
+ allowPopups: data.allow_popups
1574
+ });
1575
+ const resolved = await resolver.resolve(processResult.value);
1576
+ return ok(resolved);
1577
+ }
1578
+ };
1579
+
1580
+ // src/orders.ts
1581
+ var OrderQueries = class {
1582
+ constructor(client) {
1583
+ this.client = client;
1584
+ }
1585
+ orderTokenParam(orderId) {
1586
+ const token = this.client.getOrderToken(orderId);
1587
+ return token ? `?token=${encodeURIComponent(token)}` : "";
1588
+ }
1589
+ async list(options) {
1590
+ const params = new URLSearchParams();
1591
+ if (options?.status) params.set("status", options.status);
1592
+ if (options?.limit) params.set("limit", String(options.limit));
1593
+ if (options?.offset) params.set("offset", String(options.offset));
1594
+ const path = params.toString() ? `/api/v1/orders?${params.toString()}` : "/api/v1/orders";
1595
+ return safe(this.client.get(path));
1596
+ }
1597
+ async get(orderId) {
1598
+ const encodedId = encodeURIComponent(orderId);
1599
+ const tokenParam = this.orderTokenParam(orderId);
1600
+ return safe(this.client.get(`/api/v1/orders/${encodedId}${tokenParam}`));
1601
+ }
1602
+ async getRecent(limit = 5) {
1603
+ return this.list({ limit });
1604
+ }
1605
+ async getByStatus(status) {
1606
+ return this.list({ status });
1607
+ }
1608
+ async cancel(orderId, reason) {
1609
+ const encodedId = encodeURIComponent(orderId);
1610
+ const tokenParam = this.orderTokenParam(orderId);
1611
+ return safe(
1612
+ this.client.post(`/api/v1/orders/${encodedId}/cancel${tokenParam}`, {
1613
+ reason
1614
+ })
1615
+ );
1616
+ }
1617
+ };
1618
+
1619
+ // src/link.ts
1620
+ function encodePathSegment(value) {
1621
+ return encodeURIComponent(value);
1622
+ }
1623
+ function toCreateAddressPayload(input) {
1624
+ return {
1625
+ label: input.label,
1626
+ street_address: input.address_line1,
1627
+ apartment: input.address_line2,
1628
+ city: input.city,
1629
+ region: input.state ?? "",
1630
+ postal_code: input.postal_code,
1631
+ country: input.country
1632
+ };
1633
+ }
1634
+ function toUpdateAddressPayload(input) {
1635
+ return {
1636
+ label: input.label,
1637
+ street_address: input.address_line1,
1638
+ apartment: input.address_line2,
1639
+ city: input.city,
1640
+ region: input.state,
1641
+ postal_code: input.postal_code,
1642
+ country: input.country
1643
+ };
1644
+ }
1645
+ function toCreateMobileMoneyPayload(input) {
1646
+ return {
1647
+ phone_number: input.phone_number,
1648
+ provider: input.provider,
1649
+ label: input.account_name
1650
+ };
1651
+ }
1652
+ var LinkService = class {
1653
+ constructor(client) {
1654
+ this.client = client;
1655
+ }
1656
+ async getProfile() {
1657
+ return safe(this.client.linkGet("/v1/link/profile"));
1658
+ }
1659
+ async requestOtp(input) {
1660
+ return safe(this.client.linkPost("/v1/link/auth/request-otp", input));
1661
+ }
1662
+ async verifyOtp(input) {
1663
+ const result = await safe(
1664
+ this.client.linkPost("/v1/link/auth/verify-otp", input)
1665
+ );
1666
+ if (result.ok && result.value.session_token) {
1667
+ this.client.setAccessToken(result.value.session_token);
1668
+ }
1669
+ return result;
1670
+ }
1671
+ async logout() {
1672
+ const result = await safe(this.client.linkPost("/v1/link/auth/logout"));
1673
+ if (result.ok) {
1674
+ this.client.clearSession();
1675
+ }
1676
+ return result;
1677
+ }
1678
+ async checkStatus(contact) {
1679
+ return safe(this.client.linkPost("/v1/link/check-status", { contact }));
1680
+ }
1681
+ async getLinkData() {
1682
+ return safe(this.client.linkGet("/v1/link/data"));
1683
+ }
1684
+ async getAddresses() {
1685
+ return safe(this.client.linkGet("/v1/link/addresses"));
1686
+ }
1687
+ async getMobileMoney() {
1688
+ return safe(this.client.linkGet("/v1/link/mobile-money"));
1689
+ }
1690
+ async getPreferences() {
1691
+ return safe(this.client.linkGet("/v1/link/preferences"));
1692
+ }
1693
+ async enroll(data) {
1694
+ return safe(this.client.linkPost("/v1/link/enroll", data));
1695
+ }
1696
+ async enrollAndLinkOrder(data) {
1697
+ return safe(
1698
+ this.client.linkPost("/v1/link/enroll-and-link-order", data)
1699
+ );
1700
+ }
1701
+ async updatePreferences(preferences) {
1702
+ return safe(this.client.linkPost("/v1/link/preferences", preferences));
1703
+ }
1704
+ async createAddress(input) {
1705
+ return safe(
1706
+ this.client.linkPost("/v1/link/addresses", toCreateAddressPayload(input))
1707
+ );
1708
+ }
1709
+ async updateAddress(input) {
1710
+ return safe(
1711
+ this.client.linkPost(
1712
+ `/v1/link/addresses/${encodePathSegment(input.address_id)}`,
1713
+ toUpdateAddressPayload(input)
1714
+ )
1715
+ );
1716
+ }
1717
+ async deleteAddress(addressId) {
1718
+ return safe(
1719
+ this.client.linkDelete(`/v1/link/addresses/${encodePathSegment(addressId)}`)
1720
+ );
1721
+ }
1722
+ async setDefaultAddress(addressId) {
1723
+ return safe(
1724
+ this.client.linkPost(
1725
+ `/v1/link/addresses/${encodePathSegment(addressId)}/default`
1726
+ )
1727
+ );
1728
+ }
1729
+ async trackAddressUsage(addressId) {
1730
+ return safe(
1731
+ this.client.linkPost(
1732
+ `/v1/link/addresses/${encodePathSegment(addressId)}/track-usage`
1733
+ )
1734
+ );
1735
+ }
1736
+ async createMobileMoney(input) {
1737
+ return safe(
1738
+ this.client.linkPost(
1739
+ "/v1/link/mobile-money",
1740
+ toCreateMobileMoneyPayload(input)
1741
+ )
1742
+ );
1743
+ }
1744
+ async deleteMobileMoney(mobileMoneyId) {
1745
+ return safe(
1746
+ this.client.linkDelete(
1747
+ `/v1/link/mobile-money/${encodePathSegment(mobileMoneyId)}`
1748
+ )
1749
+ );
1750
+ }
1751
+ async setDefaultMobileMoney(mobileMoneyId) {
1752
+ return safe(
1753
+ this.client.linkPost(
1754
+ `/v1/link/mobile-money/${encodePathSegment(mobileMoneyId)}/default`
1755
+ )
1756
+ );
1757
+ }
1758
+ async trackMobileMoneyUsage(mobileMoneyId) {
1759
+ return safe(
1760
+ this.client.linkPost(
1761
+ `/v1/link/mobile-money/${encodePathSegment(mobileMoneyId)}/track-usage`
1762
+ )
1763
+ );
1764
+ }
1765
+ async verifyMobileMoney(mobileMoneyId) {
1766
+ return safe(
1767
+ this.client.linkPost(
1768
+ `/v1/link/mobile-money/${encodePathSegment(mobileMoneyId)}/verify`
1769
+ )
1770
+ );
1771
+ }
1772
+ async getSessions() {
1773
+ return safe(this.client.linkGet("/v1/link/sessions"));
1774
+ }
1775
+ async revokeSession(sessionId) {
1776
+ return safe(this.client.linkDelete(`/v1/link/sessions/${sessionId}`));
1777
+ }
1778
+ async revokeAllSessions() {
1779
+ return safe(this.client.linkDelete("/v1/link/sessions"));
1780
+ }
1781
+ };
1782
+
1783
+ // src/auth.ts
1784
+ var AuthService = class {
1785
+ constructor(client) {
1786
+ this.client = client;
1787
+ }
1788
+ async getStatus() {
1789
+ return safe(this.client.get("/api/v1/auth/status"));
1790
+ }
1791
+ async getCurrentUser() {
1792
+ const result = await this.getStatus();
1793
+ if (!result.ok) return result;
1794
+ return ok(result.value.customer || null);
1795
+ }
1796
+ async isAuthenticated() {
1797
+ const result = await this.getStatus();
1798
+ if (!result.ok) return result;
1799
+ return ok(result.value.is_authenticated);
1800
+ }
1801
+ async requestOtp(contact, contactType) {
1802
+ return safe(
1803
+ this.client.post("/api/v1/auth/request-otp", {
1804
+ contact,
1805
+ contact_type: contactType
1806
+ })
1807
+ );
1808
+ }
1809
+ async verifyOtp(code, contact) {
1810
+ return safe(
1811
+ this.client.post("/api/v1/auth/verify-otp", {
1812
+ otp_code: code,
1813
+ contact
1814
+ })
1815
+ );
1816
+ }
1817
+ async logout() {
1818
+ return safe(this.client.post("/api/v1/auth/logout"));
1819
+ }
1820
+ async updateProfile(input) {
1821
+ return safe(this.client.post("/api/v1/auth/profile", input));
1822
+ }
1823
+ };
1824
+
1825
+ // src/business.ts
1826
+ var BusinessService = class {
1827
+ constructor(client) {
1828
+ this.client = client;
1829
+ }
1830
+ async getInfo() {
1831
+ return safe(this.client.get("/api/v1/business"));
1832
+ }
1833
+ async getByHandle(handle) {
1834
+ const encodedHandle = encodeURIComponent(handle);
1835
+ return safe(this.client.get(`/api/v1/business/by-handle/${encodedHandle}`));
1836
+ }
1837
+ async getByDomain(domain) {
1838
+ const encodedDomain = encodeURIComponent(domain);
1839
+ return safe(this.client.get(`/api/v1/business/by-domain?domain=${encodedDomain}`));
1840
+ }
1841
+ async getSettings() {
1842
+ return safe(this.client.get("/api/v1/business/settings"));
1843
+ }
1844
+ async getLocations() {
1845
+ return safe(this.client.get("/api/v1/business/locations"));
1846
+ }
1847
+ async getLocation(locationId) {
1848
+ const result = await this.getLocations();
1849
+ if (!result.ok) return err(result.error);
1850
+ const location = result.value.find((item) => item.id === locationId);
1851
+ if (!location) {
1852
+ return err(new chunkRYQ5IPWX_js.CimplifyError(chunkRYQ5IPWX_js.ErrorCode.NOT_FOUND, `Location not found: ${locationId}`, false));
1853
+ }
1854
+ return ok(location);
1855
+ }
1856
+ async getHours() {
1857
+ return safe(this.client.get("/api/v1/business/hours"));
1858
+ }
1859
+ async getLocationHours(locationId) {
1860
+ const result = await this.getHours();
1861
+ if (!result.ok) return result;
1862
+ return ok(result.value.filter((hour) => hour.location_id === locationId));
1863
+ }
1864
+ async getBootstrap() {
1865
+ return safe(this.client.get("/api/v1/bootstrap"));
1866
+ }
1867
+ };
1868
+
1869
+ // src/inventory.ts
1870
+ var InventoryService = class {
1871
+ constructor(client) {
1872
+ this.client = client;
1873
+ }
1874
+ withQuery(path, params) {
1875
+ const searchParams = new URLSearchParams();
1876
+ for (const [key, value] of Object.entries(params)) {
1877
+ if (value === void 0) continue;
1878
+ searchParams.set(key, String(value));
1879
+ }
1880
+ const query = searchParams.toString();
1881
+ return query ? `${path}?${query}` : path;
1882
+ }
1883
+ async getProductStock(productId, locationId) {
1884
+ const encodedId = encodeURIComponent(productId);
1885
+ const path = this.withQuery(`/api/v1/inventory/products/${encodedId}/stock`, {
1886
+ location_id: locationId
1887
+ });
1888
+ return safe(this.client.get(path));
1889
+ }
1890
+ async getVariantStock(variantId, locationId) {
1891
+ const encodedId = encodeURIComponent(variantId);
1892
+ const path = this.withQuery(`/api/v1/inventory/variants/${encodedId}/stock`, {
1893
+ location_id: locationId
1894
+ });
1895
+ return safe(this.client.get(path));
1896
+ }
1897
+ async checkProductAvailability(productId, quantity, locationId) {
1898
+ const encodedId = encodeURIComponent(productId);
1899
+ const path = this.withQuery(`/api/v1/inventory/products/${encodedId}/availability`, {
1900
+ quantity,
1901
+ location_id: locationId
1902
+ });
1903
+ return safe(this.client.get(path));
1904
+ }
1905
+ async checkVariantAvailability(variantId, quantity, locationId) {
1906
+ const encodedId = encodeURIComponent(variantId);
1907
+ const path = this.withQuery(`/api/v1/inventory/variants/${encodedId}/availability`, {
1908
+ quantity,
1909
+ location_id: locationId
1910
+ });
1911
+ return safe(this.client.get(path));
1912
+ }
1913
+ async checkMultipleAvailability(items, locationId) {
1914
+ const results = await Promise.all(
1915
+ items.map(
1916
+ (item) => item.variant_id ? this.checkVariantAvailability(item.variant_id, item.quantity, locationId) : this.checkProductAvailability(item.product_id, item.quantity, locationId)
1917
+ )
1918
+ );
1919
+ for (const result of results) {
1920
+ if (!result.ok) return result;
1921
+ }
1922
+ return ok(results.map((r) => r.value));
1923
+ }
1924
+ async isInStock(productId, locationId) {
1925
+ const result = await this.checkProductAvailability(productId, 1, locationId);
1926
+ if (!result.ok) return result;
1927
+ return ok(result.value.is_available);
1928
+ }
1929
+ async getAvailableQuantity(productId, locationId) {
1930
+ const result = await this.getProductStock(productId, locationId);
1931
+ if (!result.ok) return result;
1932
+ return ok(result.value.available_quantity);
1933
+ }
1934
+ };
1935
+
1936
+ // src/scheduling.ts
1937
+ function withQuery2(path, params) {
1938
+ const searchParams = new URLSearchParams();
1939
+ for (const [key, value] of Object.entries(params)) {
1940
+ if (value === void 0) continue;
1941
+ searchParams.set(key, String(value));
1942
+ }
1943
+ const query = searchParams.toString();
1944
+ return query ? `${path}?${query}` : path;
1945
+ }
1946
+ function firstScheduledTime(booking) {
1947
+ return booking.service_items.find((item) => typeof item.scheduled_start === "string")?.scheduled_start || booking.created_at;
1948
+ }
1949
+ var SchedulingService = class {
1950
+ constructor(client) {
1951
+ this.client = client;
1952
+ }
1953
+ async getServices() {
1954
+ return safe(this.client.get("/api/v1/scheduling/services"));
1955
+ }
1956
+ async getService(serviceId) {
1957
+ const encodedId = encodeURIComponent(serviceId);
1958
+ return safe(this.client.get(`/api/v1/scheduling/services/${encodedId}`));
1959
+ }
1960
+ async getAvailableSlots(input) {
1961
+ const path = withQuery2("/api/v1/scheduling/slots", {
1962
+ service_id: input.service_id,
1963
+ date: input.date,
1964
+ participant_count: input.participant_count,
1965
+ duration_minutes: input.duration_minutes
1966
+ });
1967
+ return safe(this.client.get(path));
1968
+ }
1969
+ async checkSlotAvailability(input) {
1970
+ const path = withQuery2("/api/v1/scheduling/slots/check", {
1971
+ service_id: input.service_id,
1972
+ slot_time: input.slot_time,
1973
+ duration_minutes: input.duration_minutes,
1974
+ participant_count: input.participant_count
1975
+ });
1976
+ return safe(this.client.get(path));
1977
+ }
1978
+ async getServiceAvailability(params) {
1979
+ const path = withQuery2("/api/v1/scheduling/availability", {
1980
+ service_id: params.service_id,
1981
+ start_date: params.start_date,
1982
+ end_date: params.end_date,
1983
+ location_id: params.location_id,
1984
+ participant_count: params.participant_count
1985
+ });
1986
+ return safe(this.client.get(path));
1987
+ }
1988
+ async getBooking(bookingId) {
1989
+ const encodedId = encodeURIComponent(bookingId);
1990
+ return safe(this.client.get(`/api/v1/scheduling/bookings/${encodedId}`));
1991
+ }
1992
+ async getCustomerBookings(customerId) {
1993
+ const path = withQuery2("/api/v1/scheduling/bookings", {
1994
+ customer_id: customerId
1995
+ });
1996
+ return safe(this.client.get(path));
1997
+ }
1998
+ async getUpcomingBookings() {
1999
+ const result = await this.getCustomerBookings();
2000
+ if (!result.ok) return result;
2001
+ const upcoming = result.value.filter((booking) => {
2002
+ const status = String(booking.status).toLowerCase();
2003
+ return status !== "completed" && status !== "cancelled";
2004
+ }).sort((a, b) => firstScheduledTime(a).localeCompare(firstScheduledTime(b)));
2005
+ return ok(upcoming);
2006
+ }
2007
+ async getPastBookings(limit = 10) {
2008
+ const result = await this.getCustomerBookings();
2009
+ if (!result.ok) return result;
2010
+ 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));
2011
+ return ok(past);
2012
+ }
2013
+ async cancelBooking(input) {
2014
+ const encodedId = encodeURIComponent(input.booking_id);
2015
+ return safe(
2016
+ this.client.post(`/api/v1/scheduling/bookings/${encodedId}/cancel`, {
2017
+ reason: input.reason
2018
+ })
2019
+ );
2020
+ }
2021
+ async rescheduleBooking(input) {
2022
+ return safe(
2023
+ this.client.post("/api/v1/scheduling/bookings/reschedule", input)
2024
+ );
2025
+ }
2026
+ async getNextAvailableSlot(serviceId, fromDate) {
2027
+ const date = fromDate || (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
2028
+ const result = await this.getAvailableSlots({
2029
+ service_id: serviceId,
2030
+ date
2031
+ });
2032
+ if (!result.ok) return result;
2033
+ return ok(result.value.find((slot) => slot.is_available) || null);
2034
+ }
2035
+ async hasAvailabilityOn(serviceId, date) {
2036
+ const result = await this.getAvailableSlots({
2037
+ service_id: serviceId,
2038
+ date
2039
+ });
2040
+ if (!result.ok) return result;
2041
+ return ok(result.value.some((slot) => slot.is_available));
2042
+ }
2043
+ };
2044
+
2045
+ // src/lite.ts
2046
+ var LiteService = class {
2047
+ constructor(client) {
2048
+ this.client = client;
2049
+ }
2050
+ async getBootstrap() {
2051
+ return safe(this.client.get("/api/v1/lite/bootstrap"));
2052
+ }
2053
+ async getTable(tableId) {
2054
+ const encodedId = encodeURIComponent(tableId);
2055
+ return safe(this.client.get(`/api/v1/lite/tables/${encodedId}`));
2056
+ }
2057
+ async getMenu() {
2058
+ return safe(this.client.get("/api/v1/lite/menu"));
2059
+ }
2060
+ async getMenuByCategory(categoryId) {
2061
+ const encodedId = encodeURIComponent(categoryId);
2062
+ return safe(this.client.get(`/api/v1/lite/menu/categories/${encodedId}`));
2063
+ }
2064
+ };
2065
+
2066
+ // src/fx.ts
2067
+ var FxService = class {
2068
+ constructor(client) {
2069
+ this.client = client;
2070
+ }
2071
+ async getRate(from, to) {
2072
+ const path = `/api/v1/fx/rate?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`;
2073
+ return safe(this.client.get(path));
2074
+ }
2075
+ async lockQuote(request) {
2076
+ return safe(this.client.post("/api/v1/fx/quotes", request));
2077
+ }
2078
+ };
2079
+
2080
+ // src/types/elements.ts
2081
+ var ELEMENT_TYPES = {
2082
+ AUTH: "auth",
2083
+ ADDRESS: "address",
2084
+ PAYMENT: "payment",
2085
+ CHECKOUT: "checkout"
2086
+ };
2087
+ var MESSAGE_TYPES = {
2088
+ INIT: "init",
2089
+ SET_TOKEN: "set_token",
2090
+ SET_CART: "set_cart",
2091
+ GET_DATA: "get_data",
2092
+ REFRESH_TOKEN: "refresh_token",
2093
+ LOGOUT: "logout",
2094
+ PROCESS_CHECKOUT: "process_checkout",
2095
+ ABORT_CHECKOUT: "abort_checkout",
2096
+ READY: "ready",
2097
+ HEIGHT_CHANGE: "height_change",
2098
+ AUTHENTICATED: "authenticated",
2099
+ REQUIRES_OTP: "requires_otp",
2100
+ ERROR: "error",
2101
+ ADDRESS_CHANGED: "address_changed",
2102
+ ADDRESS_SELECTED: "address_selected",
2103
+ PAYMENT_METHOD_SELECTED: "payment_method_selected",
2104
+ TOKEN_REFRESHED: "token_refreshed",
2105
+ LOGOUT_COMPLETE: "logout_complete",
2106
+ CONTACT_PROVIDED: "contact_provided",
2107
+ CHECKOUT_STATUS: "checkout_status",
2108
+ CHECKOUT_COMPLETE: "checkout_complete",
2109
+ ORDER_TYPE_CHANGED: "order_type_changed",
2110
+ REQUEST_SUBMIT: "request_submit"
2111
+ };
2112
+ var EVENT_TYPES = {
2113
+ READY: "ready",
2114
+ AUTHENTICATED: "authenticated",
2115
+ REQUIRES_OTP: "requires_otp",
2116
+ ERROR: "error",
2117
+ CHANGE: "change",
2118
+ BLUR: "blur",
2119
+ FOCUS: "focus",
2120
+ ORDER_TYPE_CHANGED: "order_type_changed",
2121
+ REQUEST_SUBMIT: "request_submit"
2122
+ };
2123
+
2124
+ // src/elements.ts
2125
+ function toCheckoutError(code, message, recoverable) {
2126
+ const hint = chunkRYQ5IPWX_js.getErrorHint(code);
2127
+ return {
2128
+ success: false,
2129
+ error: {
2130
+ code,
2131
+ message,
2132
+ recoverable,
2133
+ docs_url: hint?.docs_url,
2134
+ suggestion: hint?.suggestion
2135
+ }
2136
+ };
2137
+ }
2138
+ var DEFAULT_LINK_URL = "https://link.cimplify.io";
2139
+ function generateNonce() {
2140
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
2141
+ return crypto.randomUUID().replace(/-/g, "").slice(0, 16);
2142
+ }
2143
+ return Math.random().toString(36).slice(2) + Math.random().toString(36).slice(2);
2144
+ }
2145
+ function isAllowedOrigin(origin) {
2146
+ try {
2147
+ const url = new URL(origin);
2148
+ const hostname = url.hostname;
2149
+ if (hostname === "localhost" || hostname === "127.0.0.1") {
2150
+ return true;
2151
+ }
2152
+ if (url.protocol !== "https:") {
2153
+ return false;
2154
+ }
2155
+ return hostname === "cimplify.io" || hostname.endsWith(".cimplify.io");
2156
+ } catch {
2157
+ return false;
2158
+ }
2159
+ }
2160
+ function parseIframeMessage(data) {
2161
+ if (!data || typeof data !== "object") {
2162
+ return null;
2163
+ }
2164
+ const maybeType = data.type;
2165
+ if (typeof maybeType !== "string") {
2166
+ return null;
2167
+ }
2168
+ return data;
2169
+ }
2170
+ var CimplifyElements = class {
2171
+ constructor(client, businessId, options = {}) {
2172
+ this.elements = /* @__PURE__ */ new Map();
2173
+ this.accessToken = null;
2174
+ this.accountId = null;
2175
+ this.customerId = null;
2176
+ this.customerData = null;
2177
+ this.addressData = null;
2178
+ this.paymentData = null;
2179
+ this.checkoutInProgress = false;
2180
+ this.activeCheckoutAbort = null;
2181
+ this.businessIdResolvePromise = null;
2182
+ this.client = client;
2183
+ this.businessId = businessId ?? null;
2184
+ this.linkUrl = options.linkUrl || DEFAULT_LINK_URL;
2185
+ this.options = options;
2186
+ this.boundHandleMessage = this.handleMessage.bind(this);
2187
+ if (typeof window !== "undefined") {
2188
+ window.addEventListener("message", this.boundHandleMessage);
2189
+ }
2190
+ }
2191
+ debug(...args) {
2192
+ if (this.client.isTestMode()) {
2193
+ console.debug(...args);
2194
+ }
2195
+ }
2196
+ create(type, options = {}) {
2197
+ const existing = this.elements.get(type);
2198
+ if (existing) return existing;
2199
+ const element = new CimplifyElement(type, this.businessId, this.linkUrl, options, this);
2200
+ this.elements.set(type, element);
2201
+ return element;
2202
+ }
2203
+ getElement(type) {
2204
+ return this.elements.get(type);
2205
+ }
2206
+ _removeElement(type, instance) {
2207
+ const current = this.elements.get(type);
2208
+ if (current === instance) {
2209
+ this.elements.delete(type);
2210
+ }
2211
+ }
2212
+ destroy() {
2213
+ this.elements.forEach((element) => element.destroy());
2214
+ this.elements.clear();
2215
+ if (typeof window !== "undefined") {
2216
+ window.removeEventListener("message", this.boundHandleMessage);
2217
+ }
2218
+ }
2219
+ async submitCheckout(data) {
2220
+ const result = await this.processCheckout({
2221
+ cart_id: data.cart_id,
2222
+ order_type: data.order_type ?? "delivery",
2223
+ location_id: data.location_id,
2224
+ notes: data.notes,
2225
+ scheduled_time: data.scheduled_time,
2226
+ tip_amount: data.tip_amount,
2227
+ enroll_in_link: true
2228
+ });
2229
+ if (result.success) {
2230
+ return {
2231
+ success: true,
2232
+ order: {
2233
+ id: result.order?.id || "",
2234
+ status: result.order?.status || "unknown",
2235
+ total: result.order?.total || ""
2236
+ }
2237
+ };
2238
+ }
2239
+ return {
2240
+ success: false,
2241
+ error: {
2242
+ code: result.error?.code || "CHECKOUT_FAILED",
2243
+ message: result.error?.message || "Checkout failed"
2244
+ }
2245
+ };
2246
+ }
2247
+ processCheckout(options) {
2248
+ let abortFn = null;
2249
+ const task = (async () => {
2250
+ this.debug("[cimplify:checkout] processCheckout called", { cart_id: options.cart_id, order_type: options.order_type, location_id: options.location_id });
2251
+ if (this.checkoutInProgress) {
2252
+ this.debug("[cimplify:checkout] BLOCKED: already processing");
2253
+ return toCheckoutError(
2254
+ "ALREADY_PROCESSING",
2255
+ "Checkout is already in progress.",
2256
+ false
2257
+ );
2258
+ }
2259
+ this.checkoutInProgress = true;
2260
+ if (!options.cart_id) {
2261
+ this.debug("[cimplify:checkout] BLOCKED: no cart_id");
2262
+ this.checkoutInProgress = false;
2263
+ return toCheckoutError(
2264
+ "INVALID_CART",
2265
+ "A valid cart is required before checkout can start.",
2266
+ false
2267
+ );
2268
+ }
2269
+ if (!options.order_type) {
2270
+ this.debug("[cimplify:checkout] BLOCKED: no order_type");
2271
+ this.checkoutInProgress = false;
2272
+ return toCheckoutError(
2273
+ "ORDER_TYPE_REQUIRED",
2274
+ "Order type is required before checkout can start.",
2275
+ false
2276
+ );
2277
+ }
2278
+ const checkoutElement = this.elements.get(ELEMENT_TYPES.CHECKOUT) || this.elements.get(ELEMENT_TYPES.PAYMENT);
2279
+ if (!checkoutElement) {
2280
+ this.debug("[cimplify:checkout] BLOCKED: no checkout element");
2281
+ this.checkoutInProgress = false;
2282
+ return toCheckoutError(
2283
+ "NO_PAYMENT_ELEMENT",
2284
+ "Checkout element must be mounted before checkout.",
2285
+ false
2286
+ );
2287
+ }
2288
+ if (!checkoutElement.isMounted()) {
2289
+ this.debug("[cimplify:checkout] BLOCKED: checkout element not mounted");
2290
+ this.checkoutInProgress = false;
2291
+ return toCheckoutError(
2292
+ "PAYMENT_NOT_MOUNTED",
2293
+ "Checkout element must be mounted before checkout.",
2294
+ false
2295
+ );
2296
+ }
2297
+ const isUnifiedCheckout = this.elements.has(ELEMENT_TYPES.CHECKOUT);
2298
+ if (!isUnifiedCheckout) {
2299
+ const authElement = this.elements.get(ELEMENT_TYPES.AUTH);
2300
+ if (authElement && !this.accessToken) {
2301
+ this.debug("[cimplify:checkout] BLOCKED: auth incomplete");
2302
+ this.checkoutInProgress = false;
2303
+ return toCheckoutError(
2304
+ "AUTH_INCOMPLETE",
2305
+ "Authentication must complete before checkout can start.",
2306
+ true
2307
+ );
2308
+ }
2309
+ const addressElement = this.elements.get(ELEMENT_TYPES.ADDRESS);
2310
+ if (addressElement) {
2311
+ this.debug("[cimplify:checkout] getting address data...");
2312
+ await addressElement.getData();
2313
+ this.debug("[cimplify:checkout] address data resolved", this.addressData);
2314
+ }
2315
+ await this.hydrateCustomerData();
2316
+ }
2317
+ this.debug("[cimplify:checkout] customer data hydrated", { customerData: this.customerData, accountId: this.accountId, isUnifiedCheckout });
2318
+ const processMessage = {
2319
+ type: MESSAGE_TYPES.PROCESS_CHECKOUT,
2320
+ cart_id: options.cart_id,
2321
+ order_type: options.order_type,
2322
+ location_id: options.location_id,
2323
+ notes: options.notes,
2324
+ scheduled_time: options.scheduled_time,
2325
+ tip_amount: options.tip_amount,
2326
+ pay_currency: options.pay_currency,
2327
+ enroll_in_link: options.enroll_in_link ?? true,
2328
+ address: isUnifiedCheckout ? void 0 : this.addressData ?? void 0,
2329
+ customer: isUnifiedCheckout ? void 0 : this.customerData ? {
2330
+ name: this.customerData.name,
2331
+ email: this.customerData.email,
2332
+ phone: this.customerData.phone
2333
+ } : null,
2334
+ account_id: this.accountId ?? void 0,
2335
+ customer_id: this.customerId ?? void 0
2336
+ };
2337
+ const timeoutMs = options.timeout_ms ?? 18e4;
2338
+ const paymentWindow = checkoutElement.getContentWindow();
2339
+ return new Promise((resolve) => {
2340
+ let settled = false;
2341
+ const cleanup = () => {
2342
+ if (typeof window !== "undefined") {
2343
+ window.removeEventListener("message", handleCheckoutMessage);
2344
+ }
2345
+ clearTimeout(timeout);
2346
+ this.checkoutInProgress = false;
2347
+ this.activeCheckoutAbort = null;
2348
+ };
2349
+ const settle = (result) => {
2350
+ if (settled) {
2351
+ return;
2352
+ }
2353
+ settled = true;
2354
+ cleanup();
2355
+ resolve(result);
2356
+ };
2357
+ const timeout = setTimeout(() => {
2358
+ settle(
2359
+ toCheckoutError(
2360
+ "TIMEOUT",
2361
+ "Checkout timed out before receiving a terminal response.",
2362
+ true
2363
+ )
2364
+ );
2365
+ }, timeoutMs);
2366
+ const handleCheckoutMessage = (event) => {
2367
+ if (!isAllowedOrigin(event.origin)) {
2368
+ return;
2369
+ }
2370
+ const message = parseIframeMessage(event.data);
2371
+ if (!message) {
2372
+ return;
2373
+ }
2374
+ if (message.type === MESSAGE_TYPES.LOGOUT_COMPLETE) {
2375
+ checkoutElement.sendMessage({ type: MESSAGE_TYPES.ABORT_CHECKOUT });
2376
+ settle(
2377
+ toCheckoutError(
2378
+ "AUTH_LOST",
2379
+ "Authentication was cleared during checkout.",
2380
+ true
2381
+ )
2382
+ );
2383
+ return;
2384
+ }
2385
+ if (paymentWindow && event.source && event.source !== paymentWindow) {
2386
+ return;
2387
+ }
2388
+ if (message.type === MESSAGE_TYPES.CHECKOUT_STATUS) {
2389
+ options.on_status_change?.(message.status, message.context);
2390
+ return;
2391
+ }
2392
+ if (message.type === MESSAGE_TYPES.CHECKOUT_COMPLETE) {
2393
+ this.debug("[cimplify:checkout] received checkout_complete", { success: message.success, error: message.error });
2394
+ settle({
2395
+ success: message.success,
2396
+ order: message.order,
2397
+ error: message.error,
2398
+ enrolled_in_link: message.enrolled_in_link
2399
+ });
2400
+ }
2401
+ };
2402
+ if (typeof window !== "undefined") {
2403
+ window.addEventListener("message", handleCheckoutMessage);
2404
+ }
2405
+ abortFn = () => {
2406
+ checkoutElement.sendMessage({ type: MESSAGE_TYPES.ABORT_CHECKOUT });
2407
+ settle(
2408
+ toCheckoutError(
2409
+ "CANCELLED",
2410
+ "Checkout was cancelled.",
2411
+ true
2412
+ )
2413
+ );
2414
+ };
2415
+ this.activeCheckoutAbort = abortFn;
2416
+ 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 });
2417
+ checkoutElement.sendMessage(processMessage);
2418
+ this.debug("[cimplify:checkout] postMessage sent, waiting for checkout_complete...");
2419
+ });
2420
+ })();
2421
+ const abortable = task;
2422
+ abortable.abort = () => {
2423
+ if (abortFn) {
2424
+ abortFn();
2425
+ }
2426
+ };
2427
+ return abortable;
2428
+ }
2429
+ isAuthenticated() {
2430
+ return this.accessToken !== null;
2431
+ }
2432
+ getAccessToken() {
2433
+ return this.accessToken;
2434
+ }
2435
+ getPublicKey() {
2436
+ return this.client.getPublicKey();
2437
+ }
2438
+ getBusinessId() {
2439
+ return this.businessId;
2440
+ }
2441
+ async resolveBusinessId() {
2442
+ if (this.businessId) {
2443
+ return this.businessId;
2444
+ }
2445
+ if (this.businessIdResolvePromise) {
2446
+ return this.businessIdResolvePromise;
2447
+ }
2448
+ this.businessIdResolvePromise = this.client.resolveBusinessId().then((resolvedBusinessId) => {
2449
+ this.businessId = resolvedBusinessId;
2450
+ return resolvedBusinessId;
2451
+ }).catch(() => null).finally(() => {
2452
+ this.businessIdResolvePromise = null;
2453
+ });
2454
+ return this.businessIdResolvePromise;
2455
+ }
2456
+ getAppearance() {
2457
+ return this.options.appearance;
2458
+ }
2459
+ async hydrateCustomerData() {
2460
+ if (!this.accessToken || this.customerData) {
2461
+ return;
2462
+ }
2463
+ if (!this.client.getAccessToken()) {
2464
+ this.client.setAccessToken(this.accessToken);
2465
+ }
2466
+ const linkDataResult = await this.client.link.getLinkData();
2467
+ if (!linkDataResult.ok || !linkDataResult.value?.customer) {
2468
+ return;
2469
+ }
2470
+ const customer = linkDataResult.value.customer;
2471
+ this.customerData = {
2472
+ name: customer.name || "",
2473
+ email: customer.email || null,
2474
+ phone: customer.phone || null
2475
+ };
2476
+ }
2477
+ handleMessage(event) {
2478
+ if (!isAllowedOrigin(event.origin)) {
2479
+ return;
2480
+ }
2481
+ const message = parseIframeMessage(event.data);
2482
+ if (!message) return;
2483
+ switch (message.type) {
2484
+ case MESSAGE_TYPES.AUTHENTICATED:
2485
+ const customer = message.customer ?? {
2486
+ name: "",
2487
+ email: null,
2488
+ phone: null
2489
+ };
2490
+ this.accessToken = message.token;
2491
+ this.accountId = message.accountId;
2492
+ this.customerId = message.customerId;
2493
+ this.customerData = customer;
2494
+ this.client.setAccessToken(message.token);
2495
+ this.elements.forEach((element, type) => {
2496
+ if (type !== ELEMENT_TYPES.AUTH && type !== ELEMENT_TYPES.CHECKOUT) {
2497
+ element.sendMessage({ type: MESSAGE_TYPES.SET_TOKEN, token: message.token });
2498
+ }
2499
+ });
2500
+ break;
2501
+ case MESSAGE_TYPES.TOKEN_REFRESHED:
2502
+ this.accessToken = message.token;
2503
+ break;
2504
+ case MESSAGE_TYPES.ADDRESS_CHANGED:
2505
+ case MESSAGE_TYPES.ADDRESS_SELECTED:
2506
+ this.addressData = message.address;
2507
+ break;
2508
+ case MESSAGE_TYPES.PAYMENT_METHOD_SELECTED:
2509
+ this.paymentData = message.method;
2510
+ break;
2511
+ case MESSAGE_TYPES.CONTACT_PROVIDED:
2512
+ if (!this.customerData) {
2513
+ this.customerData = { name: "", email: null, phone: null };
2514
+ }
2515
+ if (message.contactType === "email") {
2516
+ this.customerData.email = message.contact;
2517
+ } else {
2518
+ this.customerData.phone = message.contact;
2519
+ }
2520
+ break;
2521
+ case MESSAGE_TYPES.LOGOUT_COMPLETE:
2522
+ if (this.checkoutInProgress && this.activeCheckoutAbort) {
2523
+ this.activeCheckoutAbort();
2524
+ }
2525
+ this.accessToken = null;
2526
+ this.accountId = null;
2527
+ this.customerId = null;
2528
+ this.customerData = null;
2529
+ this.addressData = null;
2530
+ this.paymentData = null;
2531
+ this.client.clearSession();
2532
+ break;
2533
+ }
2534
+ }
2535
+ _setAddressData(data) {
2536
+ this.addressData = data;
2537
+ }
2538
+ _setPaymentData(data) {
2539
+ this.paymentData = data;
2540
+ }
2541
+ _setGuestContact(contact, contactType) {
2542
+ if (!this.customerData) {
2543
+ this.customerData = { name: "", email: null, phone: null };
2544
+ }
2545
+ if (contactType === "email") {
2546
+ this.customerData.email = contact;
2547
+ } else {
2548
+ this.customerData.phone = contact;
2549
+ }
2550
+ }
2551
+ };
2552
+ var CimplifyElement = class {
2553
+ constructor(type, businessId, linkUrl, options, parent) {
2554
+ this.iframe = null;
2555
+ this.container = null;
2556
+ this.mounted = false;
2557
+ this.pendingInit = null;
2558
+ this.eventHandlers = /* @__PURE__ */ new Map();
2559
+ this.resolvers = /* @__PURE__ */ new Map();
2560
+ this.listening = false;
2561
+ this.type = type;
2562
+ this.businessId = businessId;
2563
+ this.linkUrl = linkUrl;
2564
+ this.options = options;
2565
+ this.parent = parent;
2566
+ this.nonce = generateNonce();
2567
+ this.boundHandleMessage = this.handleMessage.bind(this);
2568
+ if (typeof window !== "undefined") {
2569
+ window.addEventListener("message", this.boundHandleMessage);
2570
+ this.listening = true;
2571
+ }
2572
+ }
2573
+ mount(container) {
2574
+ if (this.mounted) {
2575
+ console.warn(`Element ${this.type} is already mounted`);
2576
+ return;
2577
+ }
2578
+ const target = typeof container === "string" ? document.querySelector(container) : container;
2579
+ if (!target) {
2580
+ console.error(`Container not found: ${container}`);
2581
+ return;
2582
+ }
2583
+ this.container = target;
2584
+ this.mounted = true;
2585
+ if (!this.listening && typeof window !== "undefined") {
2586
+ window.addEventListener("message", this.boundHandleMessage);
2587
+ this.listening = true;
2588
+ }
2589
+ void this.createIframe();
2590
+ }
2591
+ destroy() {
2592
+ if (this.iframe) {
2593
+ this.iframe.remove();
2594
+ this.iframe = null;
2595
+ }
2596
+ this.container = null;
2597
+ this.mounted = false;
2598
+ this.eventHandlers.clear();
2599
+ this.resolvers.forEach((entry) => clearTimeout(entry.timeoutId));
2600
+ this.resolvers.clear();
2601
+ if (this.listening && typeof window !== "undefined") {
2602
+ window.removeEventListener("message", this.boundHandleMessage);
2603
+ this.listening = false;
2604
+ }
2605
+ this.parent._removeElement(this.type, this);
2606
+ }
2607
+ on(event, handler) {
2608
+ if (!this.eventHandlers.has(event)) {
2609
+ this.eventHandlers.set(event, /* @__PURE__ */ new Set());
2610
+ }
2611
+ this.eventHandlers.get(event).add(handler);
2612
+ }
2613
+ off(event, handler) {
2614
+ this.eventHandlers.get(event)?.delete(handler);
2615
+ }
2616
+ async getData() {
2617
+ if (!this.isMounted()) {
2618
+ return null;
2619
+ }
2620
+ return new Promise((resolve) => {
2621
+ const id = Math.random().toString(36).slice(2);
2622
+ const timeoutId = setTimeout(() => {
2623
+ const entry = this.resolvers.get(id);
2624
+ if (!entry) {
2625
+ return;
2626
+ }
2627
+ this.resolvers.delete(id);
2628
+ entry.resolve(null);
2629
+ }, 5e3);
2630
+ this.resolvers.set(id, { resolve, timeoutId });
2631
+ this.sendMessage({ type: MESSAGE_TYPES.GET_DATA });
2632
+ });
2633
+ }
2634
+ setCart(cart) {
2635
+ this.sendMessage({ type: MESSAGE_TYPES.SET_CART, cart });
2636
+ }
2637
+ sendMessage(message) {
2638
+ if (this.iframe?.contentWindow) {
2639
+ this.iframe.contentWindow.postMessage(message, this.linkUrl);
2640
+ } else {
2641
+ console.warn("[cimplify:checkout] sendMessage DROPPED \u2014 no contentWindow", { type: message.type, hasIframe: !!this.iframe, isConnected: this.iframe?.isConnected });
2642
+ }
2643
+ }
2644
+ getContentWindow() {
2645
+ return this.iframe?.contentWindow ?? null;
2646
+ }
2647
+ isMounted() {
2648
+ return this.mounted && Boolean(this.iframe) && this.iframe?.isConnected === true;
2649
+ }
2650
+ async createIframe() {
2651
+ if (!this.container) return;
2652
+ const resolvedBusinessId = this.businessId ?? await this.parent.resolveBusinessId();
2653
+ if (!resolvedBusinessId || !this.container || !this.mounted) {
2654
+ console.error("Unable to mount element without a resolved business ID");
2655
+ this.emit(EVENT_TYPES.ERROR, {
2656
+ code: "BUSINESS_ID_REQUIRED",
2657
+ message: "Unable to initialize checkout without a business ID."
2658
+ });
2659
+ return;
2660
+ }
2661
+ this.businessId = resolvedBusinessId;
2662
+ const iframe = document.createElement("iframe");
2663
+ const url = new URL(`${this.linkUrl}/elements/${this.type}`);
2664
+ url.searchParams.set("businessId", resolvedBusinessId);
2665
+ url.searchParams.set("nonce", this.nonce);
2666
+ if (this.options.prefillEmail) url.searchParams.set("email", this.options.prefillEmail);
2667
+ if (this.options.mode) url.searchParams.set("mode", this.options.mode);
2668
+ iframe.src = url.toString();
2669
+ iframe.style.border = "none";
2670
+ iframe.style.width = "100%";
2671
+ iframe.style.minHeight = "200px";
2672
+ iframe.style.display = "block";
2673
+ iframe.style.overflow = "hidden";
2674
+ iframe.style.background = "transparent";
2675
+ iframe.setAttribute("allowtransparency", "true");
2676
+ iframe.setAttribute("frameborder", "0");
2677
+ iframe.setAttribute("allow", "geolocation");
2678
+ iframe.setAttribute(
2679
+ "sandbox",
2680
+ "allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox"
2681
+ );
2682
+ this.iframe = iframe;
2683
+ this.container.appendChild(iframe);
2684
+ this.pendingInit = {
2685
+ businessId: resolvedBusinessId,
2686
+ publicKey: this.parent.getPublicKey()
2687
+ };
2688
+ }
2689
+ handleMessage(event) {
2690
+ if (!isAllowedOrigin(event.origin)) {
2691
+ return;
2692
+ }
2693
+ const data = event.data;
2694
+ if (data?.nonce) {
2695
+ if (data.nonce !== this.nonce) return;
2696
+ } else {
2697
+ const iframeWindow = this.iframe?.contentWindow;
2698
+ if (iframeWindow && event.source && event.source !== iframeWindow) {
2699
+ return;
2700
+ }
2701
+ }
2702
+ const message = parseIframeMessage(event.data);
2703
+ if (!message) return;
2704
+ switch (message.type) {
2705
+ case MESSAGE_TYPES.READY:
2706
+ if (this.iframe && message.height) this.iframe.style.height = `${message.height}px`;
2707
+ if (this.pendingInit) {
2708
+ const { publicKey } = this.pendingInit;
2709
+ this.sendMessage({
2710
+ type: MESSAGE_TYPES.INIT,
2711
+ businessId: this.pendingInit.businessId,
2712
+ publicKey,
2713
+ demoMode: publicKey.length === 0,
2714
+ prefillEmail: this.options.prefillEmail,
2715
+ appearance: this.parent.getAppearance(),
2716
+ orderTypes: this.options.orderTypes,
2717
+ defaultOrderType: this.options.defaultOrderType,
2718
+ renderSubmitButton: true,
2719
+ submitLabel: this.options.submitLabel
2720
+ });
2721
+ const token = this.parent.getAccessToken();
2722
+ if (token && this.type !== ELEMENT_TYPES.AUTH) {
2723
+ this.sendMessage({ type: MESSAGE_TYPES.SET_TOKEN, token });
2724
+ }
2725
+ this.pendingInit = null;
2726
+ }
2727
+ this.emit(EVENT_TYPES.READY, { height: message.height });
2728
+ break;
2729
+ case MESSAGE_TYPES.HEIGHT_CHANGE:
2730
+ if (this.iframe) this.iframe.style.height = `${message.height}px`;
2731
+ break;
2732
+ case MESSAGE_TYPES.AUTHENTICATED:
2733
+ const customer = message.customer ?? {
2734
+ name: "",
2735
+ email: null,
2736
+ phone: null
2737
+ };
2738
+ this.emit(EVENT_TYPES.AUTHENTICATED, {
2739
+ accountId: message.accountId,
2740
+ customerId: message.customerId,
2741
+ token: message.token,
2742
+ customer
2743
+ });
2744
+ break;
2745
+ case MESSAGE_TYPES.REQUIRES_OTP:
2746
+ this.emit(EVENT_TYPES.REQUIRES_OTP, { contactMasked: message.contactMasked });
2747
+ break;
2748
+ case MESSAGE_TYPES.ERROR:
2749
+ this.emit(EVENT_TYPES.ERROR, { code: message.code, message: message.message });
2750
+ break;
2751
+ case MESSAGE_TYPES.ADDRESS_CHANGED:
2752
+ case MESSAGE_TYPES.ADDRESS_SELECTED:
2753
+ this.parent._setAddressData(message.address);
2754
+ this.emit(EVENT_TYPES.CHANGE, { address: message.address });
2755
+ this.resolveData(message.address);
2756
+ break;
2757
+ case MESSAGE_TYPES.PAYMENT_METHOD_SELECTED:
2758
+ this.parent._setPaymentData(message.method);
2759
+ this.emit(EVENT_TYPES.CHANGE, { paymentMethod: message.method });
2760
+ this.resolveData(message.method);
2761
+ break;
2762
+ case MESSAGE_TYPES.CONTACT_PROVIDED:
2763
+ this.parent._setGuestContact(message.contact, message.contactType);
2764
+ break;
2765
+ case MESSAGE_TYPES.ORDER_TYPE_CHANGED:
2766
+ this.emit(EVENT_TYPES.ORDER_TYPE_CHANGED, { orderType: message.orderType });
2767
+ break;
2768
+ case MESSAGE_TYPES.REQUEST_SUBMIT:
2769
+ this.emit(EVENT_TYPES.REQUEST_SUBMIT, {});
2770
+ break;
2771
+ }
2772
+ }
2773
+ emit(event, data) {
2774
+ this.eventHandlers.get(event)?.forEach((handler) => handler(data));
2775
+ }
2776
+ resolveData(data) {
2777
+ this.resolvers.forEach((entry) => {
2778
+ clearTimeout(entry.timeoutId);
2779
+ entry.resolve(data);
2780
+ });
2781
+ this.resolvers.clear();
2782
+ }
2783
+ };
2784
+ function createElements(client, businessId, options) {
2785
+ return new CimplifyElements(client, businessId, options);
2786
+ }
2787
+
2788
+ exports.AUTHORIZATION_TYPE = AUTHORIZATION_TYPE;
2789
+ exports.AUTH_MUTATION = AUTH_MUTATION;
2790
+ exports.AuthService = AuthService;
2791
+ exports.BusinessService = BusinessService;
2792
+ exports.CHECKOUT_MODE = CHECKOUT_MODE;
2793
+ exports.CHECKOUT_MUTATION = CHECKOUT_MUTATION;
2794
+ exports.CHECKOUT_STEP = CHECKOUT_STEP;
2795
+ exports.CONTACT_TYPE = CONTACT_TYPE;
2796
+ exports.CartOperations = CartOperations;
2797
+ exports.CatalogueQueries = CatalogueQueries;
2798
+ exports.CheckoutService = CheckoutService;
2799
+ exports.CimplifyElement = CimplifyElement;
2800
+ exports.CimplifyElements = CimplifyElements;
2801
+ exports.DEFAULT_COUNTRY = DEFAULT_COUNTRY;
2802
+ exports.DEFAULT_CURRENCY = DEFAULT_CURRENCY;
2803
+ exports.DEVICE_TYPE = DEVICE_TYPE;
2804
+ exports.ELEMENT_TYPES = ELEMENT_TYPES;
2805
+ exports.EVENT_TYPES = EVENT_TYPES;
2806
+ exports.FxService = FxService;
2807
+ exports.InventoryService = InventoryService;
2808
+ exports.LINK_MUTATION = LINK_MUTATION;
2809
+ exports.LINK_QUERY = LINK_QUERY;
2810
+ exports.LinkService = LinkService;
2811
+ exports.LiteService = LiteService;
2812
+ exports.MESSAGE_TYPES = MESSAGE_TYPES;
2813
+ exports.MOBILE_MONEY_PROVIDER = MOBILE_MONEY_PROVIDER;
2814
+ exports.ORDER_MUTATION = ORDER_MUTATION;
2815
+ exports.ORDER_TYPE = ORDER_TYPE;
2816
+ exports.OrderQueries = OrderQueries;
2817
+ exports.PAYMENT_METHOD = PAYMENT_METHOD;
2818
+ exports.PAYMENT_MUTATION = PAYMENT_MUTATION;
2819
+ exports.PAYMENT_STATE = PAYMENT_STATE;
2820
+ exports.PICKUP_TIME_TYPE = PICKUP_TIME_TYPE;
2821
+ exports.SchedulingService = SchedulingService;
2822
+ exports.combine = combine;
2823
+ exports.combineObject = combineObject;
2824
+ exports.createElements = createElements;
2825
+ exports.err = err;
2826
+ exports.flatMap = flatMap;
2827
+ exports.fromPromise = fromPromise;
2828
+ exports.generateIdempotencyKey = generateIdempotencyKey;
2829
+ exports.getOrElse = getOrElse;
2830
+ exports.isErr = isErr;
2831
+ exports.isOk = isOk;
2832
+ exports.mapError = mapError;
2833
+ exports.mapResult = mapResult;
2834
+ exports.ok = ok;
2835
+ exports.toNullable = toNullable;
2836
+ exports.tryCatch = tryCatch;
2837
+ exports.unwrap = unwrap;