@cimplify/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,1460 @@
1
+ // src/types/common.ts
2
+ var CimplifyError = class extends Error {
3
+ constructor(code, message, retryable = false) {
4
+ super(message);
5
+ this.code = code;
6
+ this.retryable = retryable;
7
+ this.name = "CimplifyError";
8
+ }
9
+ };
10
+
11
+ // src/catalogue.ts
12
+ var CatalogueQueries = class {
13
+ constructor(client) {
14
+ this.client = client;
15
+ }
16
+ // --------------------------------------------------------------------------
17
+ // PRODUCTS
18
+ // --------------------------------------------------------------------------
19
+ async getProducts(options) {
20
+ let query2 = "products";
21
+ const filters = [];
22
+ if (options?.category) {
23
+ filters.push(`@.category_id=='${options.category}'`);
24
+ }
25
+ if (options?.featured !== void 0) {
26
+ filters.push(`@.featured==${options.featured}`);
27
+ }
28
+ if (options?.in_stock !== void 0) {
29
+ filters.push(`@.in_stock==${options.in_stock}`);
30
+ }
31
+ if (options?.search) {
32
+ filters.push(`@.name contains '${options.search}'`);
33
+ }
34
+ if (options?.min_price !== void 0) {
35
+ filters.push(`@.price>=${options.min_price}`);
36
+ }
37
+ if (options?.max_price !== void 0) {
38
+ filters.push(`@.price<=${options.max_price}`);
39
+ }
40
+ if (filters.length > 0) {
41
+ query2 += `[?(${filters.join(" && ")})]`;
42
+ }
43
+ if (options?.sort_by) {
44
+ query2 += `#sort(${options.sort_by},${options.sort_order || "asc"})`;
45
+ }
46
+ if (options?.limit) {
47
+ query2 += `#limit(${options.limit})`;
48
+ }
49
+ if (options?.offset) {
50
+ query2 += `#offset(${options.offset})`;
51
+ }
52
+ return this.client.query(query2);
53
+ }
54
+ async getProduct(id) {
55
+ return this.client.query(`products.${id}`);
56
+ }
57
+ async getProductBySlug(slug) {
58
+ const products = await this.client.query(
59
+ `products[?(@.slug=='${slug}')]`
60
+ );
61
+ if (!products.length) {
62
+ throw new Error(`Product not found: ${slug}`);
63
+ }
64
+ return products[0];
65
+ }
66
+ // --------------------------------------------------------------------------
67
+ // VARIANTS
68
+ // --------------------------------------------------------------------------
69
+ async getVariants(productId) {
70
+ return this.client.query(`products.${productId}.variants`);
71
+ }
72
+ async getVariantAxes(productId) {
73
+ return this.client.query(`products.${productId}.variant_axes`);
74
+ }
75
+ /**
76
+ * Find a variant by axis selections (e.g., { "Size": "Large", "Color": "Red" })
77
+ * Returns the matching variant or null if no match found.
78
+ */
79
+ async getVariantByAxisSelections(productId, selections) {
80
+ return this.client.query(
81
+ `products.${productId}.variant`,
82
+ { axis_selections: selections }
83
+ );
84
+ }
85
+ /**
86
+ * Get a specific variant by its ID
87
+ */
88
+ async getVariantById(productId, variantId) {
89
+ return this.client.query(
90
+ `products.${productId}.variant.${variantId}`
91
+ );
92
+ }
93
+ // --------------------------------------------------------------------------
94
+ // ADD-ONS
95
+ // --------------------------------------------------------------------------
96
+ async getAddOns(productId) {
97
+ return this.client.query(`products.${productId}.add_ons`);
98
+ }
99
+ // --------------------------------------------------------------------------
100
+ // CATEGORIES
101
+ // --------------------------------------------------------------------------
102
+ async getCategories() {
103
+ return this.client.query("categories");
104
+ }
105
+ async getCategory(id) {
106
+ return this.client.query(`categories.${id}`);
107
+ }
108
+ async getCategoryBySlug(slug) {
109
+ const categories = await this.client.query(
110
+ `categories[?(@.slug=='${slug}')]`
111
+ );
112
+ if (!categories.length) {
113
+ throw new Error(`Category not found: ${slug}`);
114
+ }
115
+ return categories[0];
116
+ }
117
+ async getCategoryProducts(categoryId) {
118
+ return this.client.query(
119
+ `products[?(@.category_id=='${categoryId}')]`
120
+ );
121
+ }
122
+ // --------------------------------------------------------------------------
123
+ // COLLECTIONS
124
+ // --------------------------------------------------------------------------
125
+ async getCollections() {
126
+ return this.client.query("collections");
127
+ }
128
+ async getCollection(id) {
129
+ return this.client.query(`collections.${id}`);
130
+ }
131
+ async getCollectionBySlug(slug) {
132
+ const collections = await this.client.query(
133
+ `collections[?(@.slug=='${slug}')]`
134
+ );
135
+ if (!collections.length) {
136
+ throw new Error(`Collection not found: ${slug}`);
137
+ }
138
+ return collections[0];
139
+ }
140
+ async getCollectionProducts(collectionId) {
141
+ return this.client.query(`collections.${collectionId}.products`);
142
+ }
143
+ async searchCollections(query2, limit = 20) {
144
+ return this.client.query(
145
+ `collections[?(@.name contains '${query2}')]#limit(${limit})`
146
+ );
147
+ }
148
+ // --------------------------------------------------------------------------
149
+ // BUNDLES
150
+ // --------------------------------------------------------------------------
151
+ async getBundles() {
152
+ return this.client.query("bundles");
153
+ }
154
+ async getBundle(id) {
155
+ return this.client.query(`bundles.${id}`);
156
+ }
157
+ async getBundleBySlug(slug) {
158
+ const bundles = await this.client.query(
159
+ `bundles[?(@.slug=='${slug}')]`
160
+ );
161
+ if (!bundles.length) {
162
+ throw new Error(`Bundle not found: ${slug}`);
163
+ }
164
+ return bundles[0];
165
+ }
166
+ async searchBundles(query2, limit = 20) {
167
+ return this.client.query(
168
+ `bundles[?(@.name contains '${query2}')]#limit(${limit})`
169
+ );
170
+ }
171
+ // --------------------------------------------------------------------------
172
+ // COMPOSITES (Build-Your-Own)
173
+ // --------------------------------------------------------------------------
174
+ async getComposites(options) {
175
+ let query2 = "composites";
176
+ if (options?.limit) {
177
+ query2 += `#limit(${options.limit})`;
178
+ }
179
+ return this.client.query(query2);
180
+ }
181
+ async getComposite(id) {
182
+ return this.client.query(`composites.${id}`);
183
+ }
184
+ async getCompositeByProductId(productId) {
185
+ return this.client.query(
186
+ `composites.by_product.${productId}`
187
+ );
188
+ }
189
+ async calculateCompositePrice(compositeId, selections, locationId) {
190
+ return this.client.call(
191
+ "composite.calculatePrice",
192
+ {
193
+ composite_id: compositeId,
194
+ selections,
195
+ location_id: locationId
196
+ }
197
+ );
198
+ }
199
+ // --------------------------------------------------------------------------
200
+ // SEARCH
201
+ // --------------------------------------------------------------------------
202
+ async search(query2, options) {
203
+ const limit = options?.limit ?? 20;
204
+ let searchQuery = `products[?(@.name contains '${query2}')]`;
205
+ if (options?.category) {
206
+ searchQuery = `products[?(@.name contains '${query2}' && @.category_id=='${options.category}')]`;
207
+ }
208
+ searchQuery += `#limit(${limit})`;
209
+ return this.client.query(searchQuery);
210
+ }
211
+ async searchProducts(query2, options) {
212
+ return this.client.call("catalogue.search", {
213
+ query: query2,
214
+ limit: options?.limit ?? 20,
215
+ category: options?.category
216
+ });
217
+ }
218
+ // --------------------------------------------------------------------------
219
+ // MENU (Restaurant-specific)
220
+ // --------------------------------------------------------------------------
221
+ async getMenu(options) {
222
+ let query2 = "menu";
223
+ if (options?.category) {
224
+ query2 = `menu[?(@.category=='${options.category}')]`;
225
+ }
226
+ if (options?.limit) {
227
+ query2 += `#limit(${options.limit})`;
228
+ }
229
+ return this.client.query(query2);
230
+ }
231
+ async getMenuCategory(categoryId) {
232
+ return this.client.query(`menu.category.${categoryId}`);
233
+ }
234
+ async getMenuItem(itemId) {
235
+ return this.client.query(`menu.${itemId}`);
236
+ }
237
+ };
238
+
239
+ // src/cart.ts
240
+ var CartOperations = class {
241
+ constructor(client) {
242
+ this.client = client;
243
+ }
244
+ // --------------------------------------------------------------------------
245
+ // CART QUERIES
246
+ // --------------------------------------------------------------------------
247
+ /**
248
+ * Get the enriched cart with product names, images, and details.
249
+ * This is the main method for storefront display.
250
+ */
251
+ async get() {
252
+ return this.client.query("cart#enriched");
253
+ }
254
+ async getRaw() {
255
+ return this.client.query("cart");
256
+ }
257
+ async getItems() {
258
+ return this.client.query("cart_items");
259
+ }
260
+ async getCount() {
261
+ return this.client.query("cart#count");
262
+ }
263
+ async getTotal() {
264
+ return this.client.query("cart#total");
265
+ }
266
+ async getSummary() {
267
+ const cart = await this.get();
268
+ return {
269
+ item_count: cart.items.length,
270
+ total_items: cart.items.reduce((sum, item) => sum + item.quantity, 0),
271
+ subtotal: cart.pricing.subtotal,
272
+ discount_amount: cart.pricing.total_discounts,
273
+ tax_amount: cart.pricing.tax_amount,
274
+ total: cart.pricing.total_price,
275
+ currency: cart.pricing.currency
276
+ };
277
+ }
278
+ // --------------------------------------------------------------------------
279
+ // CART MUTATIONS
280
+ // --------------------------------------------------------------------------
281
+ async addItem(input) {
282
+ return this.client.call("cart.addItem", input);
283
+ }
284
+ async updateItem(cartItemId, updates) {
285
+ return this.client.call("cart.updateItem", {
286
+ cart_item_id: cartItemId,
287
+ ...updates
288
+ });
289
+ }
290
+ async updateQuantity(cartItemId, quantity) {
291
+ return this.client.call("cart.updateItemQuantity", {
292
+ cart_item_id: cartItemId,
293
+ quantity
294
+ });
295
+ }
296
+ async removeItem(cartItemId) {
297
+ return this.client.call("cart.removeItem", {
298
+ cart_item_id: cartItemId
299
+ });
300
+ }
301
+ async clear() {
302
+ return this.client.call("cart.clearCart");
303
+ }
304
+ // --------------------------------------------------------------------------
305
+ // COUPONS & DISCOUNTS
306
+ // --------------------------------------------------------------------------
307
+ async applyCoupon(code) {
308
+ return this.client.call("cart.applyCoupon", {
309
+ coupon_code: code
310
+ });
311
+ }
312
+ async removeCoupon() {
313
+ return this.client.call("cart.removeCoupon");
314
+ }
315
+ // --------------------------------------------------------------------------
316
+ // CONVENIENCE METHODS
317
+ // --------------------------------------------------------------------------
318
+ async isEmpty() {
319
+ const count = await this.getCount();
320
+ return count === 0;
321
+ }
322
+ async hasItem(productId, variantId) {
323
+ const items = await this.getItems();
324
+ return items.some((item) => {
325
+ const matchesProduct = item.item_id === productId;
326
+ if (!variantId) return matchesProduct;
327
+ const config = item.configuration;
328
+ if ("variant" in config && config.variant) {
329
+ return matchesProduct && config.variant.variant_id === variantId;
330
+ }
331
+ return matchesProduct;
332
+ });
333
+ }
334
+ async findItem(productId, variantId) {
335
+ const items = await this.getItems();
336
+ return items.find((item) => {
337
+ const matchesProduct = item.item_id === productId;
338
+ if (!variantId) return matchesProduct;
339
+ const config = item.configuration;
340
+ if ("variant" in config && config.variant) {
341
+ return matchesProduct && config.variant.variant_id === variantId;
342
+ }
343
+ return matchesProduct;
344
+ });
345
+ }
346
+ };
347
+
348
+ // src/constants.ts
349
+ var CHECKOUT_MODE = {
350
+ LINK: "link",
351
+ GUEST: "guest"
352
+ };
353
+ var ORDER_TYPE = {
354
+ DELIVERY: "delivery",
355
+ PICKUP: "pickup",
356
+ DINE_IN: "dine-in",
357
+ WALK_IN: "walk-in"
358
+ };
359
+ var PAYMENT_METHOD = {
360
+ MOBILE_MONEY: "mobile_money",
361
+ CARD: "card"
362
+ };
363
+ var CHECKOUT_STEP = {
364
+ AUTHENTICATION: "authentication",
365
+ ORDER_DETAILS: "order_details",
366
+ PAYMENT_METHOD: "payment_method",
367
+ PAYMENT: "payment",
368
+ CONFIRMATION: "confirmation"
369
+ };
370
+ var PAYMENT_STATE = {
371
+ INITIAL: "initial",
372
+ PREPARING: "preparing",
373
+ PROCESSING: "processing",
374
+ VERIFYING: "verifying",
375
+ AWAITING_AUTHORIZATION: "awaiting_authorization",
376
+ SUCCESS: "success",
377
+ ERROR: "error",
378
+ TIMEOUT: "timeout"
379
+ };
380
+ var PICKUP_TIME_TYPE = {
381
+ ASAP: "asap",
382
+ SCHEDULED: "scheduled"
383
+ };
384
+ var MOBILE_MONEY_PROVIDER = {
385
+ MTN: "mtn",
386
+ VODAFONE: "vodafone",
387
+ AIRTEL: "airtel"
388
+ };
389
+ var AUTHORIZATION_TYPE = {
390
+ OTP: "otp",
391
+ PIN: "pin",
392
+ PHONE: "phone",
393
+ BIRTHDAY: "birthday",
394
+ ADDRESS: "address"
395
+ };
396
+ var LINK_QUERY = {
397
+ DATA: "link.data",
398
+ ADDRESSES: "link.addresses",
399
+ MOBILE_MONEY: "link.mobile_money",
400
+ PREFERENCES: "link.preferences",
401
+ SESSIONS: "link.sessions"
402
+ };
403
+ var LINK_MUTATION = {
404
+ CHECK_STATUS: "link.check_status",
405
+ ENROLL: "link.enroll",
406
+ ENROLL_AND_LINK_ORDER: "link.enroll_and_link_order",
407
+ UPDATE_PREFERENCES: "link.update_preferences",
408
+ CREATE_ADDRESS: "link.create_address",
409
+ UPDATE_ADDRESS: "link.update_address",
410
+ DELETE_ADDRESS: "link.delete_address",
411
+ SET_DEFAULT_ADDRESS: "link.set_default_address",
412
+ TRACK_ADDRESS_USAGE: "link.track_address_usage",
413
+ CREATE_MOBILE_MONEY: "link.create_mobile_money",
414
+ DELETE_MOBILE_MONEY: "link.delete_mobile_money",
415
+ SET_DEFAULT_MOBILE_MONEY: "link.set_default_mobile_money",
416
+ TRACK_MOBILE_MONEY_USAGE: "link.track_mobile_money_usage",
417
+ VERIFY_MOBILE_MONEY: "link.verify_mobile_money",
418
+ REVOKE_SESSION: "link.revoke_session",
419
+ REVOKE_ALL_SESSIONS: "link.revoke_all_sessions"
420
+ };
421
+ var AUTH_MUTATION = {
422
+ REQUEST_OTP: "auth.request_otp",
423
+ VERIFY_OTP: "auth.verify_otp"
424
+ };
425
+ var CHECKOUT_MUTATION = {
426
+ PROCESS: "checkout.process"
427
+ };
428
+ var PAYMENT_MUTATION = {
429
+ SUBMIT_AUTHORIZATION: "payment.submit_authorization",
430
+ CHECK_STATUS: "order.poll_payment_status"
431
+ };
432
+ var ORDER_MUTATION = {
433
+ UPDATE_CUSTOMER: "order.update_order_customer"
434
+ };
435
+ var DEFAULT_CURRENCY = "GHS";
436
+ var DEFAULT_COUNTRY = "GHA";
437
+
438
+ // src/checkout.ts
439
+ var CheckoutService = class {
440
+ constructor(client) {
441
+ this.client = client;
442
+ }
443
+ async process(data) {
444
+ return this.client.call(CHECKOUT_MUTATION.PROCESS, {
445
+ checkout_data: data
446
+ });
447
+ }
448
+ async initializePayment(orderId, method) {
449
+ return this.client.call("order.initializePayment", {
450
+ order_id: orderId,
451
+ payment_method: method
452
+ });
453
+ }
454
+ async submitAuthorization(input) {
455
+ return this.client.call(
456
+ PAYMENT_MUTATION.SUBMIT_AUTHORIZATION,
457
+ input
458
+ );
459
+ }
460
+ async pollPaymentStatus(orderId) {
461
+ return this.client.call(
462
+ PAYMENT_MUTATION.CHECK_STATUS,
463
+ orderId
464
+ );
465
+ }
466
+ async updateOrderCustomer(orderId, customer) {
467
+ return this.client.call(ORDER_MUTATION.UPDATE_CUSTOMER, {
468
+ order_id: orderId,
469
+ ...customer
470
+ });
471
+ }
472
+ async verifyPayment(orderId) {
473
+ return this.client.call("order.verifyPayment", {
474
+ order_id: orderId
475
+ });
476
+ }
477
+ };
478
+
479
+ // src/orders.ts
480
+ var OrderQueries = class {
481
+ constructor(client) {
482
+ this.client = client;
483
+ }
484
+ async list(options) {
485
+ let query2 = "orders";
486
+ if (options?.status) {
487
+ query2 += `[?(@.status=='${options.status}')]`;
488
+ }
489
+ query2 += "#sort(created_at,desc)";
490
+ if (options?.limit) {
491
+ query2 += `#limit(${options.limit})`;
492
+ }
493
+ if (options?.offset) {
494
+ query2 += `#offset(${options.offset})`;
495
+ }
496
+ return this.client.query(query2);
497
+ }
498
+ async get(orderId) {
499
+ return this.client.query(`orders.${orderId}`);
500
+ }
501
+ async getRecent(limit = 5) {
502
+ return this.client.query(
503
+ `orders#sort(created_at,desc)#limit(${limit})`
504
+ );
505
+ }
506
+ async getByStatus(status) {
507
+ return this.client.query(`orders[?(@.status=='${status}')]`);
508
+ }
509
+ async cancel(orderId, reason) {
510
+ return this.client.call("order.cancelOrder", {
511
+ order_id: orderId,
512
+ reason
513
+ });
514
+ }
515
+ };
516
+
517
+ // src/link.ts
518
+ var LinkService = class {
519
+ constructor(client) {
520
+ this.client = client;
521
+ }
522
+ async requestOtp(input) {
523
+ return this.client.linkPost("/v1/link/auth/request-otp", input);
524
+ }
525
+ async verifyOtp(input) {
526
+ const response = await this.client.linkPost(
527
+ "/v1/link/auth/verify-otp",
528
+ input
529
+ );
530
+ if (response.session_token) {
531
+ this.client.setSessionToken(response.session_token);
532
+ }
533
+ return response;
534
+ }
535
+ async logout() {
536
+ const result = await this.client.linkPost("/v1/link/auth/logout");
537
+ this.client.clearSession();
538
+ return result;
539
+ }
540
+ async checkStatus(contact) {
541
+ return this.client.call(LINK_MUTATION.CHECK_STATUS, {
542
+ contact
543
+ });
544
+ }
545
+ async getLinkData() {
546
+ return this.client.query(LINK_QUERY.DATA);
547
+ }
548
+ async getAddresses() {
549
+ return this.client.query(LINK_QUERY.ADDRESSES);
550
+ }
551
+ async getMobileMoney() {
552
+ return this.client.query(LINK_QUERY.MOBILE_MONEY);
553
+ }
554
+ async getPreferences() {
555
+ return this.client.query(LINK_QUERY.PREFERENCES);
556
+ }
557
+ async enroll(data) {
558
+ return this.client.call(LINK_MUTATION.ENROLL, data);
559
+ }
560
+ async enrollAndLinkOrder(data) {
561
+ return this.client.call(
562
+ LINK_MUTATION.ENROLL_AND_LINK_ORDER,
563
+ data
564
+ );
565
+ }
566
+ async updatePreferences(preferences) {
567
+ return this.client.call(
568
+ LINK_MUTATION.UPDATE_PREFERENCES,
569
+ preferences
570
+ );
571
+ }
572
+ async createAddress(input) {
573
+ return this.client.call(
574
+ LINK_MUTATION.CREATE_ADDRESS,
575
+ input
576
+ );
577
+ }
578
+ async updateAddress(input) {
579
+ return this.client.call(LINK_MUTATION.UPDATE_ADDRESS, input);
580
+ }
581
+ async deleteAddress(addressId) {
582
+ return this.client.call(
583
+ LINK_MUTATION.DELETE_ADDRESS,
584
+ addressId
585
+ );
586
+ }
587
+ async setDefaultAddress(addressId) {
588
+ return this.client.call(
589
+ LINK_MUTATION.SET_DEFAULT_ADDRESS,
590
+ addressId
591
+ );
592
+ }
593
+ async trackAddressUsage(addressId) {
594
+ return this.client.call(LINK_MUTATION.TRACK_ADDRESS_USAGE, {
595
+ address_id: addressId
596
+ });
597
+ }
598
+ async createMobileMoney(input) {
599
+ return this.client.call(
600
+ LINK_MUTATION.CREATE_MOBILE_MONEY,
601
+ input
602
+ );
603
+ }
604
+ async deleteMobileMoney(mobileMoneyId) {
605
+ return this.client.call(
606
+ LINK_MUTATION.DELETE_MOBILE_MONEY,
607
+ mobileMoneyId
608
+ );
609
+ }
610
+ async setDefaultMobileMoney(mobileMoneyId) {
611
+ return this.client.call(
612
+ LINK_MUTATION.SET_DEFAULT_MOBILE_MONEY,
613
+ mobileMoneyId
614
+ );
615
+ }
616
+ async trackMobileMoneyUsage(mobileMoneyId) {
617
+ return this.client.call(LINK_MUTATION.TRACK_MOBILE_MONEY_USAGE, {
618
+ mobile_money_id: mobileMoneyId
619
+ });
620
+ }
621
+ async verifyMobileMoney(mobileMoneyId) {
622
+ return this.client.call(
623
+ LINK_MUTATION.VERIFY_MOBILE_MONEY,
624
+ mobileMoneyId
625
+ );
626
+ }
627
+ async getSessions() {
628
+ return this.client.linkGet("/v1/link/sessions");
629
+ }
630
+ async revokeSession(sessionId) {
631
+ return this.client.linkDelete(
632
+ `/v1/link/sessions/${sessionId}`
633
+ );
634
+ }
635
+ async revokeAllSessions() {
636
+ return this.client.linkDelete("/v1/link/sessions");
637
+ }
638
+ async getAddressesRest() {
639
+ return this.client.linkGet("/v1/link/addresses");
640
+ }
641
+ async createAddressRest(input) {
642
+ return this.client.linkPost("/v1/link/addresses", input);
643
+ }
644
+ async deleteAddressRest(addressId) {
645
+ return this.client.linkDelete(`/v1/link/addresses/${addressId}`);
646
+ }
647
+ async setDefaultAddressRest(addressId) {
648
+ return this.client.linkPost(
649
+ `/v1/link/addresses/${addressId}/default`
650
+ );
651
+ }
652
+ async getMobileMoneyRest() {
653
+ return this.client.linkGet("/v1/link/mobile-money");
654
+ }
655
+ async createMobileMoneyRest(input) {
656
+ return this.client.linkPost("/v1/link/mobile-money", input);
657
+ }
658
+ async deleteMobileMoneyRest(mobileMoneyId) {
659
+ return this.client.linkDelete(
660
+ `/v1/link/mobile-money/${mobileMoneyId}`
661
+ );
662
+ }
663
+ async setDefaultMobileMoneyRest(mobileMoneyId) {
664
+ return this.client.linkPost(
665
+ `/v1/link/mobile-money/${mobileMoneyId}/default`
666
+ );
667
+ }
668
+ };
669
+
670
+ // src/auth.ts
671
+ var AuthService = class {
672
+ constructor(client) {
673
+ this.client = client;
674
+ }
675
+ // --------------------------------------------------------------------------
676
+ // STATUS & USER
677
+ // --------------------------------------------------------------------------
678
+ async getStatus() {
679
+ return this.client.query("auth");
680
+ }
681
+ async getCurrentUser() {
682
+ const status = await this.getStatus();
683
+ return status.customer || null;
684
+ }
685
+ async isAuthenticated() {
686
+ const status = await this.getStatus();
687
+ return status.is_authenticated;
688
+ }
689
+ // --------------------------------------------------------------------------
690
+ // OTP AUTHENTICATION
691
+ // --------------------------------------------------------------------------
692
+ async requestOtp(contact, contactType) {
693
+ await this.client.call(AUTH_MUTATION.REQUEST_OTP, {
694
+ contact,
695
+ contact_type: contactType
696
+ });
697
+ }
698
+ async verifyOtp(code, contact) {
699
+ return this.client.call(AUTH_MUTATION.VERIFY_OTP, {
700
+ otp_code: code,
701
+ contact
702
+ });
703
+ }
704
+ // --------------------------------------------------------------------------
705
+ // SESSION MANAGEMENT
706
+ // --------------------------------------------------------------------------
707
+ async logout() {
708
+ return this.client.call("auth.logout");
709
+ }
710
+ // --------------------------------------------------------------------------
711
+ // PROFILE MANAGEMENT
712
+ // --------------------------------------------------------------------------
713
+ async updateProfile(input) {
714
+ return this.client.call("auth.update_profile", input);
715
+ }
716
+ async changePassword(input) {
717
+ return this.client.call("auth.change_password", input);
718
+ }
719
+ async resetPassword(email) {
720
+ return this.client.call("auth.reset_password", { email });
721
+ }
722
+ };
723
+
724
+ // src/business.ts
725
+ var BusinessService = class {
726
+ constructor(client) {
727
+ this.client = client;
728
+ }
729
+ // --------------------------------------------------------------------------
730
+ // BUSINESS INFO
731
+ // --------------------------------------------------------------------------
732
+ async getInfo() {
733
+ return this.client.query("business.info");
734
+ }
735
+ async getByHandle(handle) {
736
+ return this.client.query(`business.handle.${handle}`);
737
+ }
738
+ async getByDomain(domain) {
739
+ return this.client.query("business.domain", { domain });
740
+ }
741
+ async getSettings() {
742
+ return this.client.query("business.settings");
743
+ }
744
+ async getTheme() {
745
+ return this.client.query("business.theme");
746
+ }
747
+ // --------------------------------------------------------------------------
748
+ // LOCATIONS
749
+ // --------------------------------------------------------------------------
750
+ async getLocations() {
751
+ return this.client.query("business.locations");
752
+ }
753
+ async getLocation(locationId) {
754
+ return this.client.query(`business.locations.${locationId}`);
755
+ }
756
+ // --------------------------------------------------------------------------
757
+ // HOURS
758
+ // --------------------------------------------------------------------------
759
+ async getHours() {
760
+ return this.client.query("business.hours");
761
+ }
762
+ async getLocationHours(locationId) {
763
+ return this.client.query(
764
+ `business.locations.${locationId}.hours`
765
+ );
766
+ }
767
+ // --------------------------------------------------------------------------
768
+ // BOOTSTRAP (for storefront initialization)
769
+ // --------------------------------------------------------------------------
770
+ async getBootstrap() {
771
+ const [business, locations, categories] = await Promise.all([
772
+ this.getInfo(),
773
+ this.getLocations(),
774
+ this.client.query("categories#select(id,name,slug)")
775
+ ]);
776
+ const defaultLocation = locations[0];
777
+ return {
778
+ business,
779
+ location: defaultLocation,
780
+ locations,
781
+ categories,
782
+ currency: business.default_currency,
783
+ is_open: defaultLocation?.accepts_online_orders ?? false,
784
+ accepts_orders: defaultLocation?.accepts_online_orders ?? false
785
+ };
786
+ }
787
+ };
788
+
789
+ // src/inventory.ts
790
+ var InventoryService = class {
791
+ constructor(client) {
792
+ this.client = client;
793
+ }
794
+ // --------------------------------------------------------------------------
795
+ // STOCK QUERIES
796
+ // --------------------------------------------------------------------------
797
+ async getStockLevels() {
798
+ return this.client.query("inventory.stock_levels");
799
+ }
800
+ async getProductStock(productId, locationId) {
801
+ if (locationId) {
802
+ return this.client.query("inventory.product", {
803
+ product_id: productId,
804
+ location_id: locationId
805
+ });
806
+ }
807
+ return this.client.query("inventory.product", {
808
+ product_id: productId
809
+ });
810
+ }
811
+ async getVariantStock(variantId, locationId) {
812
+ return this.client.query("inventory.variant", {
813
+ variant_id: variantId,
814
+ location_id: locationId
815
+ });
816
+ }
817
+ // --------------------------------------------------------------------------
818
+ // AVAILABILITY CHECKS
819
+ // --------------------------------------------------------------------------
820
+ async checkProductAvailability(productId, quantity, locationId) {
821
+ return this.client.query("inventory.check_availability", {
822
+ product_id: productId,
823
+ quantity,
824
+ location_id: locationId
825
+ });
826
+ }
827
+ async checkVariantAvailability(variantId, quantity, locationId) {
828
+ return this.client.query("inventory.check_availability", {
829
+ variant_id: variantId,
830
+ quantity,
831
+ location_id: locationId
832
+ });
833
+ }
834
+ async checkMultipleAvailability(items, locationId) {
835
+ const results = await Promise.all(
836
+ items.map(
837
+ (item) => item.variant_id ? this.checkVariantAvailability(item.variant_id, item.quantity, locationId) : this.checkProductAvailability(item.product_id, item.quantity, locationId)
838
+ )
839
+ );
840
+ return results;
841
+ }
842
+ // --------------------------------------------------------------------------
843
+ // SUMMARY
844
+ // --------------------------------------------------------------------------
845
+ async getSummary() {
846
+ return this.client.query("inventory.summary");
847
+ }
848
+ // --------------------------------------------------------------------------
849
+ // CONVENIENCE METHODS
850
+ // --------------------------------------------------------------------------
851
+ async isInStock(productId, locationId) {
852
+ const result = await this.checkProductAvailability(productId, 1, locationId);
853
+ return result.is_available;
854
+ }
855
+ async getAvailableQuantity(productId, locationId) {
856
+ const stock = await this.getProductStock(productId, locationId);
857
+ return stock.available_quantity;
858
+ }
859
+ };
860
+
861
+ // src/scheduling.ts
862
+ var SchedulingService = class {
863
+ constructor(client) {
864
+ this.client = client;
865
+ }
866
+ // --------------------------------------------------------------------------
867
+ // SERVICES
868
+ // --------------------------------------------------------------------------
869
+ async getServices() {
870
+ return this.client.query("scheduling.services");
871
+ }
872
+ async getService(serviceId) {
873
+ return this.client.query(`scheduling.services.${serviceId}`);
874
+ }
875
+ // --------------------------------------------------------------------------
876
+ // AVAILABILITY
877
+ // --------------------------------------------------------------------------
878
+ async getAvailableSlots(input) {
879
+ return this.client.query(
880
+ "scheduling.available_slots",
881
+ input
882
+ );
883
+ }
884
+ async checkSlotAvailability(input) {
885
+ return this.client.query(
886
+ "scheduling.check_slot",
887
+ input
888
+ );
889
+ }
890
+ async getServiceAvailability(params) {
891
+ return this.client.query(
892
+ "scheduling.service_availability",
893
+ params
894
+ );
895
+ }
896
+ // --------------------------------------------------------------------------
897
+ // BOOKINGS
898
+ // --------------------------------------------------------------------------
899
+ async getBooking(bookingId) {
900
+ return this.client.query(`scheduling.bookings.${bookingId}`);
901
+ }
902
+ async getCustomerBookings() {
903
+ return this.client.query("scheduling.customer_bookings");
904
+ }
905
+ async getUpcomingBookings() {
906
+ return this.client.query(
907
+ "scheduling.customer_bookings[?(@.status!='completed' && @.status!='cancelled')]#sort(start_time,asc)"
908
+ );
909
+ }
910
+ async getPastBookings(limit = 10) {
911
+ return this.client.query(
912
+ `scheduling.customer_bookings[?(@.status=='completed')]#sort(start_time,desc)#limit(${limit})`
913
+ );
914
+ }
915
+ // --------------------------------------------------------------------------
916
+ // BOOKING MANAGEMENT
917
+ // --------------------------------------------------------------------------
918
+ async cancelBooking(input) {
919
+ return this.client.call("scheduling.cancel_booking", input);
920
+ }
921
+ async rescheduleBooking(input) {
922
+ return this.client.call("scheduling.reschedule_booking", input);
923
+ }
924
+ // --------------------------------------------------------------------------
925
+ // CONVENIENCE METHODS
926
+ // --------------------------------------------------------------------------
927
+ async getNextAvailableSlot(serviceId, fromDate) {
928
+ const date = fromDate || (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
929
+ const slots = await this.getAvailableSlots({
930
+ service_id: serviceId,
931
+ date
932
+ });
933
+ return slots.find((slot) => slot.is_available) || null;
934
+ }
935
+ async hasAvailabilityOn(serviceId, date) {
936
+ const slots = await this.getAvailableSlots({
937
+ service_id: serviceId,
938
+ date
939
+ });
940
+ return slots.some((slot) => slot.is_available);
941
+ }
942
+ };
943
+
944
+ // src/lite.ts
945
+ var LiteService = class {
946
+ constructor(client) {
947
+ this.client = client;
948
+ }
949
+ // --------------------------------------------------------------------------
950
+ // BOOTSTRAP
951
+ // --------------------------------------------------------------------------
952
+ async getBootstrap() {
953
+ return this.client.query("lite.bootstrap");
954
+ }
955
+ // --------------------------------------------------------------------------
956
+ // TABLE MANAGEMENT
957
+ // --------------------------------------------------------------------------
958
+ async getTable(tableId) {
959
+ return this.client.query(`lite.table.${tableId}`);
960
+ }
961
+ async getTableByNumber(tableNumber, locationId) {
962
+ return this.client.query("lite.table_by_number", {
963
+ table_number: tableNumber,
964
+ location_id: locationId
965
+ });
966
+ }
967
+ // --------------------------------------------------------------------------
968
+ // KITCHEN ORDERS
969
+ // --------------------------------------------------------------------------
970
+ async sendToKitchen(tableId, items) {
971
+ return this.client.call("lite.send_to_kitchen", {
972
+ table_id: tableId,
973
+ items
974
+ });
975
+ }
976
+ async callWaiter(tableId, reason) {
977
+ return this.client.call("lite.call_waiter", {
978
+ table_id: tableId,
979
+ reason
980
+ });
981
+ }
982
+ async requestBill(tableId) {
983
+ return this.client.call(
984
+ "lite.request_bill",
985
+ { table_id: tableId }
986
+ );
987
+ }
988
+ // --------------------------------------------------------------------------
989
+ // MENU (optimized for lite/QR experience)
990
+ // --------------------------------------------------------------------------
991
+ async getMenu() {
992
+ return this.client.query("lite.menu");
993
+ }
994
+ async getMenuByCategory(categoryId) {
995
+ return this.client.query(`lite.menu.category.${categoryId}`);
996
+ }
997
+ };
998
+
999
+ // src/client.ts
1000
+ var SESSION_TOKEN_HEADER = "x-session-token";
1001
+ var SESSION_STORAGE_KEY = "cimplify_session_token";
1002
+ function deriveUrls() {
1003
+ const hostname = typeof window !== "undefined" ? window.location.hostname : "";
1004
+ if (hostname === "localhost" || hostname === "127.0.0.1") {
1005
+ const protocol = window.location.protocol;
1006
+ return {
1007
+ baseUrl: `${protocol}//${hostname}:8082`,
1008
+ linkApiUrl: `${protocol}//${hostname}:8080`
1009
+ };
1010
+ }
1011
+ return {
1012
+ baseUrl: "https://storefronts.cimplify.io",
1013
+ linkApiUrl: "https://api.cimplify.io"
1014
+ };
1015
+ }
1016
+ var CimplifyClient = class {
1017
+ constructor(config = {}) {
1018
+ this.sessionToken = null;
1019
+ this.publicKey = config.publicKey || "";
1020
+ const urls = deriveUrls();
1021
+ this.baseUrl = urls.baseUrl;
1022
+ this.linkApiUrl = urls.linkApiUrl;
1023
+ this.credentials = config.credentials || "include";
1024
+ this.sessionToken = this.loadSessionToken();
1025
+ }
1026
+ getSessionToken() {
1027
+ return this.sessionToken;
1028
+ }
1029
+ setSessionToken(token) {
1030
+ this.sessionToken = token;
1031
+ this.saveSessionToken(token);
1032
+ }
1033
+ clearSession() {
1034
+ this.sessionToken = null;
1035
+ this.saveSessionToken(null);
1036
+ }
1037
+ loadSessionToken() {
1038
+ if (typeof window !== "undefined" && window.localStorage) {
1039
+ return localStorage.getItem(SESSION_STORAGE_KEY);
1040
+ }
1041
+ return null;
1042
+ }
1043
+ saveSessionToken(token) {
1044
+ if (typeof window !== "undefined" && window.localStorage) {
1045
+ if (token) {
1046
+ localStorage.setItem(SESSION_STORAGE_KEY, token);
1047
+ } else {
1048
+ localStorage.removeItem(SESSION_STORAGE_KEY);
1049
+ }
1050
+ }
1051
+ }
1052
+ getHeaders() {
1053
+ const headers = {
1054
+ "Content-Type": "application/json",
1055
+ "X-API-Key": this.publicKey
1056
+ };
1057
+ if (this.sessionToken) {
1058
+ headers[SESSION_TOKEN_HEADER] = this.sessionToken;
1059
+ }
1060
+ return headers;
1061
+ }
1062
+ updateSessionFromResponse(response) {
1063
+ const newToken = response.headers.get(SESSION_TOKEN_HEADER);
1064
+ if (newToken && newToken !== this.sessionToken) {
1065
+ this.sessionToken = newToken;
1066
+ this.saveSessionToken(newToken);
1067
+ }
1068
+ }
1069
+ async query(query2, variables) {
1070
+ const body = { query: query2 };
1071
+ if (variables) {
1072
+ body.variables = variables;
1073
+ }
1074
+ const response = await fetch(`${this.baseUrl}/api/q`, {
1075
+ method: "POST",
1076
+ credentials: this.credentials,
1077
+ headers: this.getHeaders(),
1078
+ body: JSON.stringify(body)
1079
+ });
1080
+ this.updateSessionFromResponse(response);
1081
+ return this.handleResponse(response);
1082
+ }
1083
+ async call(method, args) {
1084
+ const body = {
1085
+ method,
1086
+ args: args !== void 0 ? [args] : []
1087
+ };
1088
+ const response = await fetch(`${this.baseUrl}/api/m`, {
1089
+ method: "POST",
1090
+ credentials: this.credentials,
1091
+ headers: this.getHeaders(),
1092
+ body: JSON.stringify(body)
1093
+ });
1094
+ this.updateSessionFromResponse(response);
1095
+ return this.handleResponse(response);
1096
+ }
1097
+ async get(path) {
1098
+ const response = await fetch(`${this.baseUrl}${path}`, {
1099
+ method: "GET",
1100
+ credentials: this.credentials,
1101
+ headers: this.getHeaders()
1102
+ });
1103
+ this.updateSessionFromResponse(response);
1104
+ return this.handleRestResponse(response);
1105
+ }
1106
+ async post(path, body) {
1107
+ const response = await fetch(`${this.baseUrl}${path}`, {
1108
+ method: "POST",
1109
+ credentials: this.credentials,
1110
+ headers: this.getHeaders(),
1111
+ body: body ? JSON.stringify(body) : void 0
1112
+ });
1113
+ this.updateSessionFromResponse(response);
1114
+ return this.handleRestResponse(response);
1115
+ }
1116
+ async delete(path) {
1117
+ const response = await fetch(`${this.baseUrl}${path}`, {
1118
+ method: "DELETE",
1119
+ credentials: this.credentials,
1120
+ headers: this.getHeaders()
1121
+ });
1122
+ this.updateSessionFromResponse(response);
1123
+ return this.handleRestResponse(response);
1124
+ }
1125
+ async linkGet(path) {
1126
+ const response = await fetch(`${this.linkApiUrl}${path}`, {
1127
+ method: "GET",
1128
+ credentials: this.credentials,
1129
+ headers: this.getHeaders()
1130
+ });
1131
+ this.updateSessionFromResponse(response);
1132
+ return this.handleRestResponse(response);
1133
+ }
1134
+ async linkPost(path, body) {
1135
+ const response = await fetch(`${this.linkApiUrl}${path}`, {
1136
+ method: "POST",
1137
+ credentials: this.credentials,
1138
+ headers: this.getHeaders(),
1139
+ body: body ? JSON.stringify(body) : void 0
1140
+ });
1141
+ this.updateSessionFromResponse(response);
1142
+ return this.handleRestResponse(response);
1143
+ }
1144
+ async linkDelete(path) {
1145
+ const response = await fetch(`${this.linkApiUrl}${path}`, {
1146
+ method: "DELETE",
1147
+ credentials: this.credentials,
1148
+ headers: this.getHeaders()
1149
+ });
1150
+ this.updateSessionFromResponse(response);
1151
+ return this.handleRestResponse(response);
1152
+ }
1153
+ async handleRestResponse(response) {
1154
+ const json = await response.json();
1155
+ if (!response.ok) {
1156
+ throw new CimplifyError(
1157
+ json.error?.error_code || "API_ERROR",
1158
+ json.error?.error_message || "An error occurred",
1159
+ false
1160
+ );
1161
+ }
1162
+ return json.data;
1163
+ }
1164
+ async handleResponse(response) {
1165
+ const json = await response.json();
1166
+ if (!json.success || json.error) {
1167
+ throw new CimplifyError(
1168
+ json.error?.code || "UNKNOWN_ERROR",
1169
+ json.error?.message || "An unknown error occurred",
1170
+ json.error?.retryable || false
1171
+ );
1172
+ }
1173
+ return json.data;
1174
+ }
1175
+ get catalogue() {
1176
+ if (!this._catalogue) {
1177
+ this._catalogue = new CatalogueQueries(this);
1178
+ }
1179
+ return this._catalogue;
1180
+ }
1181
+ get cart() {
1182
+ if (!this._cart) {
1183
+ this._cart = new CartOperations(this);
1184
+ }
1185
+ return this._cart;
1186
+ }
1187
+ get checkout() {
1188
+ if (!this._checkout) {
1189
+ this._checkout = new CheckoutService(this);
1190
+ }
1191
+ return this._checkout;
1192
+ }
1193
+ get orders() {
1194
+ if (!this._orders) {
1195
+ this._orders = new OrderQueries(this);
1196
+ }
1197
+ return this._orders;
1198
+ }
1199
+ get link() {
1200
+ if (!this._link) {
1201
+ this._link = new LinkService(this);
1202
+ }
1203
+ return this._link;
1204
+ }
1205
+ get auth() {
1206
+ if (!this._auth) {
1207
+ this._auth = new AuthService(this);
1208
+ }
1209
+ return this._auth;
1210
+ }
1211
+ get business() {
1212
+ if (!this._business) {
1213
+ this._business = new BusinessService(this);
1214
+ }
1215
+ return this._business;
1216
+ }
1217
+ get inventory() {
1218
+ if (!this._inventory) {
1219
+ this._inventory = new InventoryService(this);
1220
+ }
1221
+ return this._inventory;
1222
+ }
1223
+ get scheduling() {
1224
+ if (!this._scheduling) {
1225
+ this._scheduling = new SchedulingService(this);
1226
+ }
1227
+ return this._scheduling;
1228
+ }
1229
+ get lite() {
1230
+ if (!this._lite) {
1231
+ this._lite = new LiteService(this);
1232
+ }
1233
+ return this._lite;
1234
+ }
1235
+ };
1236
+ function createCimplifyClient(config) {
1237
+ return new CimplifyClient(config);
1238
+ }
1239
+
1240
+ // src/query/builder.ts
1241
+ var QueryBuilder = class {
1242
+ constructor(entity) {
1243
+ this.filters = [];
1244
+ this.modifiers = [];
1245
+ this.pathSegments = [];
1246
+ this.entity = entity;
1247
+ }
1248
+ path(segment) {
1249
+ this.pathSegments.push(segment);
1250
+ return this;
1251
+ }
1252
+ where(field, op, value) {
1253
+ const v = typeof value === "string" ? `'${value}'` : value;
1254
+ if (op === "contains" || op === "startsWith") {
1255
+ this.filters.push(`@.${field} ${op} ${v}`);
1256
+ } else {
1257
+ this.filters.push(`@.${field}${op}${v}`);
1258
+ }
1259
+ return this;
1260
+ }
1261
+ and(field, op, value) {
1262
+ return this.where(field, op, value);
1263
+ }
1264
+ sort(field, order = "asc") {
1265
+ this.modifiers.push(`sort(${field},${order})`);
1266
+ return this;
1267
+ }
1268
+ limit(n) {
1269
+ this.modifiers.push(`limit(${n})`);
1270
+ return this;
1271
+ }
1272
+ offset(n) {
1273
+ this.modifiers.push(`offset(${n})`);
1274
+ return this;
1275
+ }
1276
+ count() {
1277
+ this.modifiers.push("count");
1278
+ return this;
1279
+ }
1280
+ enriched() {
1281
+ this.modifiers.push("enriched");
1282
+ return this;
1283
+ }
1284
+ build() {
1285
+ let query2 = this.entity;
1286
+ if (this.pathSegments.length > 0) {
1287
+ query2 += "." + this.pathSegments.join(".");
1288
+ }
1289
+ if (this.filters.length > 0) {
1290
+ query2 += `[?(${this.filters.join(" && ")})]`;
1291
+ }
1292
+ for (const mod of this.modifiers) {
1293
+ query2 += `#${mod}`;
1294
+ }
1295
+ return query2;
1296
+ }
1297
+ toString() {
1298
+ return this.build();
1299
+ }
1300
+ };
1301
+ function query(entity) {
1302
+ return new QueryBuilder(entity);
1303
+ }
1304
+
1305
+ // src/utils/payment.ts
1306
+ var CURRENCY_SYMBOLS = {
1307
+ GHS: "GH\u20B5",
1308
+ USD: "$",
1309
+ EUR: "\u20AC",
1310
+ GBP: "\xA3",
1311
+ NGN: "\u20A6",
1312
+ KES: "KSh",
1313
+ ZAR: "R",
1314
+ XOF: "CFA",
1315
+ XAF: "FCFA"
1316
+ };
1317
+ function formatMoney(amount, currency = "GHS") {
1318
+ const symbol = CURRENCY_SYMBOLS[currency.toUpperCase()] || currency;
1319
+ const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
1320
+ return `${symbol}${numAmount.toFixed(2)}`;
1321
+ }
1322
+ function categorizePaymentError(error, errorCode) {
1323
+ let message = "An unexpected error occurred during payment processing. Please try again or contact support.";
1324
+ let recoverable = true;
1325
+ let code = errorCode || "PAYMENT_ERROR";
1326
+ const technical = error.stack;
1327
+ const errorMessage = error.message?.toLowerCase() || "";
1328
+ if (errorCode === "INSUFFICIENT_FUNDS" || errorMessage.includes("insufficient") || errorMessage.includes("funds")) {
1329
+ code = "INSUFFICIENT_FUNDS";
1330
+ message = "Your payment method has insufficient funds. Please try another payment method.";
1331
+ } else if (errorCode === "CARD_DECLINED" || errorMessage.includes("declined")) {
1332
+ code = "CARD_DECLINED";
1333
+ message = "Your card was declined. Please try another card or payment method.";
1334
+ } else if (errorMessage.includes("cancelled") || errorMessage.includes("canceled") || errorCode === "PAYMENT_CANCELLED") {
1335
+ code = "PAYMENT_CANCELLED";
1336
+ message = "Payment was cancelled. You can try again when ready.";
1337
+ } else if (errorMessage.includes("network") || errorMessage.includes("connection") || errorCode === "NETWORK_ERROR") {
1338
+ code = "NETWORK_ERROR";
1339
+ message = "Network connection issue. Please check your internet connection and try again.";
1340
+ } else if (errorMessage.includes("timeout") || errorCode === "TIMEOUT") {
1341
+ code = "TIMEOUT";
1342
+ message = "Payment processing timed out. Please try again.";
1343
+ } else if (errorCode === "PAYMENT_ACTION_NOT_COMPLETED") {
1344
+ code = "PAYMENT_ACTION_NOT_COMPLETED";
1345
+ message = "Payment action was not completed. Please try again.";
1346
+ } else if (errorCode === "AUTHORIZATION_FAILED") {
1347
+ code = "AUTHORIZATION_FAILED";
1348
+ message = "Authorization failed. Please check your code and try again.";
1349
+ } else if (errorCode === "INVALID_OTP") {
1350
+ code = "INVALID_OTP";
1351
+ message = "Invalid verification code. Please check and try again.";
1352
+ }
1353
+ return { code, message, recoverable, technical };
1354
+ }
1355
+ function isQuickPaymentResponse(response) {
1356
+ return response !== null && typeof response === "object" && "payment" in response && typeof response.payment === "object";
1357
+ }
1358
+ function isWebPaymentResponse(response) {
1359
+ return response !== null && typeof response === "object" && "transaction" in response && typeof response.transaction === "object";
1360
+ }
1361
+ function normalizePaymentResponse(response) {
1362
+ if (!response) {
1363
+ return {
1364
+ method: "unknown",
1365
+ provider: "unknown",
1366
+ requires_action: false,
1367
+ metadata: {}
1368
+ };
1369
+ }
1370
+ if (isQuickPaymentResponse(response)) {
1371
+ return {
1372
+ method: response.payment.type?.toLowerCase() || "unknown",
1373
+ provider: response.payment.provider?.toLowerCase() || "unknown",
1374
+ requires_action: !!response.payment.redirect_url || !!response.payment.access_code,
1375
+ public_key: response.payment.public_key,
1376
+ client_secret: response.payment.access_code,
1377
+ access_code: response.payment.access_code,
1378
+ redirect_url: response.payment.redirect_url,
1379
+ transaction_id: response.payment.reference,
1380
+ order_id: response.order_id,
1381
+ reference: response.payment.reference,
1382
+ instructions: response.payment.instructions,
1383
+ metadata: response.payment.metadata
1384
+ };
1385
+ }
1386
+ if (isWebPaymentResponse(response)) {
1387
+ const authType = response.authorization_type?.toLowerCase();
1388
+ const validAuthTypes = ["otp", "pin", "phone", "birthday", "address"];
1389
+ const safeAuthType = authType && validAuthTypes.includes(authType) ? authType : void 0;
1390
+ return {
1391
+ provider: response.transaction.provider_type?.toLowerCase() || "unknown",
1392
+ requires_action: response.requires_action || false,
1393
+ public_key: response.public_key,
1394
+ client_secret: response.client_secret,
1395
+ redirect_url: response.authorization_url,
1396
+ transaction_id: response.transaction.id,
1397
+ order_id: response.transaction.order_id,
1398
+ reference: response.transaction.provider_reference,
1399
+ metadata: response.transaction.metadata,
1400
+ method: response.transaction.payment_method?.toLowerCase() || "unknown",
1401
+ instructions: response.display_text,
1402
+ display_text: response.display_text,
1403
+ requires_authorization: response.requires_authorization,
1404
+ authorization_type: safeAuthType,
1405
+ provider_payment_id: response.provider_payment_id || response.transaction.provider_reference
1406
+ };
1407
+ }
1408
+ return {
1409
+ method: "unknown",
1410
+ provider: "unknown",
1411
+ requires_action: false,
1412
+ metadata: {}
1413
+ };
1414
+ }
1415
+ function normalizeStatusResponse(response) {
1416
+ if (!response || typeof response !== "object") {
1417
+ return {
1418
+ status: "pending",
1419
+ paid: false,
1420
+ message: "No status available"
1421
+ };
1422
+ }
1423
+ const res = response;
1424
+ const status = res.status?.toLowerCase() || "";
1425
+ let standardStatus;
1426
+ if (status === "success" || status === "completed" || res.paid === true) {
1427
+ standardStatus = "success";
1428
+ } else if (status === "failed" || status === "declined" || status === "cancelled") {
1429
+ standardStatus = "failed";
1430
+ } else if (status === "processing" || status === "pending_confirmation") {
1431
+ standardStatus = "processing";
1432
+ } else {
1433
+ standardStatus = "pending";
1434
+ }
1435
+ return {
1436
+ status: standardStatus,
1437
+ paid: res.paid || standardStatus === "success",
1438
+ amount: res.amount,
1439
+ currency: res.currency,
1440
+ reference: res.reference,
1441
+ message: res.message || ""
1442
+ };
1443
+ }
1444
+ var MOBILE_MONEY_PROVIDERS = {
1445
+ mtn: { name: "MTN Mobile Money", prefix: ["024", "054", "055", "059"] },
1446
+ vodafone: { name: "Vodafone Cash", prefix: ["020", "050"] },
1447
+ airtel: { name: "AirtelTigo Money", prefix: ["027", "057", "026", "056"] }
1448
+ };
1449
+ function detectMobileMoneyProvider(phoneNumber) {
1450
+ const cleaned = phoneNumber.replace(/\D/g, "");
1451
+ const prefix = cleaned.slice(-9, -6);
1452
+ for (const [provider, info] of Object.entries(MOBILE_MONEY_PROVIDERS)) {
1453
+ if (info.prefix.some((p) => prefix.startsWith(p.slice(1)))) {
1454
+ return provider;
1455
+ }
1456
+ }
1457
+ return null;
1458
+ }
1459
+
1460
+ export { AUTHORIZATION_TYPE, AUTH_MUTATION, AuthService, BusinessService, CHECKOUT_MODE, CHECKOUT_MUTATION, CHECKOUT_STEP, CURRENCY_SYMBOLS, CartOperations, CatalogueQueries, CheckoutService as CheckoutOperations, CheckoutService, CimplifyClient, CimplifyError, DEFAULT_COUNTRY, DEFAULT_CURRENCY, InventoryService, LINK_MUTATION, LINK_QUERY, LinkService, LiteService, MOBILE_MONEY_PROVIDER, MOBILE_MONEY_PROVIDERS, ORDER_MUTATION, ORDER_TYPE, OrderQueries, PAYMENT_METHOD, PAYMENT_MUTATION, PAYMENT_STATE, PICKUP_TIME_TYPE, QueryBuilder, SchedulingService, categorizePaymentError, createCimplifyClient, detectMobileMoneyProvider, formatMoney, normalizePaymentResponse, normalizeStatusResponse, query };