@cimplify/sdk 0.16.3 → 0.17.0

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