omni-sync-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.js ADDED
@@ -0,0 +1,816 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ OmniSyncClient: () => OmniSyncClient,
24
+ OmniSyncError: () => OmniSyncError,
25
+ createWebhookHandler: () => createWebhookHandler,
26
+ isCouponApplicableToProduct: () => isCouponApplicableToProduct,
27
+ isWebhookEventType: () => isWebhookEventType,
28
+ parseWebhookEvent: () => parseWebhookEvent,
29
+ verifyWebhook: () => verifyWebhook
30
+ });
31
+ module.exports = __toCommonJS(index_exports);
32
+
33
+ // src/client.ts
34
+ var DEFAULT_BASE_URL = "https://api.omni-sync.com";
35
+ var DEFAULT_TIMEOUT = 3e4;
36
+ var OmniSyncClient = class {
37
+ constructor(options) {
38
+ if (!options.apiKey) {
39
+ throw new Error("OmniSyncClient: apiKey is required");
40
+ }
41
+ if (!options.apiKey.startsWith("omni_")) {
42
+ console.warn('OmniSyncClient: apiKey should start with "omni_"');
43
+ }
44
+ this.apiKey = options.apiKey;
45
+ this.baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
46
+ this.timeout = options.timeout || DEFAULT_TIMEOUT;
47
+ }
48
+ // -------------------- Private Methods --------------------
49
+ async request(method, path, body, queryParams) {
50
+ const url = new URL(`${this.baseUrl}${path}`);
51
+ if (queryParams) {
52
+ Object.entries(queryParams).forEach(([key, value]) => {
53
+ if (value !== void 0) {
54
+ url.searchParams.set(key, String(value));
55
+ }
56
+ });
57
+ }
58
+ const controller = new AbortController();
59
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
60
+ try {
61
+ const response = await fetch(url.toString(), {
62
+ method,
63
+ headers: {
64
+ Authorization: `Bearer ${this.apiKey}`,
65
+ "Content-Type": "application/json",
66
+ "X-SDK-Version": "0.1.0"
67
+ },
68
+ body: body ? JSON.stringify(body) : void 0,
69
+ signal: controller.signal
70
+ });
71
+ clearTimeout(timeoutId);
72
+ if (!response.ok) {
73
+ const errorData = await response.json().catch(() => ({}));
74
+ throw new OmniSyncError(
75
+ errorData.message || `Request failed with status ${response.status}`,
76
+ response.status,
77
+ errorData
78
+ );
79
+ }
80
+ const text = await response.text();
81
+ if (!text) return {};
82
+ return JSON.parse(text);
83
+ } catch (error) {
84
+ clearTimeout(timeoutId);
85
+ if (error instanceof OmniSyncError) {
86
+ throw error;
87
+ }
88
+ if (error instanceof Error) {
89
+ if (error.name === "AbortError") {
90
+ throw new OmniSyncError("Request timeout", 408);
91
+ }
92
+ throw new OmniSyncError(error.message, 0);
93
+ }
94
+ throw new OmniSyncError("Unknown error occurred", 0);
95
+ }
96
+ }
97
+ // -------------------- Products --------------------
98
+ /**
99
+ * Get a list of products with pagination
100
+ */
101
+ async getProducts(params) {
102
+ return this.request("GET", "/api/v1/products", void 0, {
103
+ page: params?.page,
104
+ limit: params?.limit,
105
+ search: params?.search,
106
+ status: params?.status,
107
+ type: params?.type,
108
+ sortBy: params?.sortBy,
109
+ sortOrder: params?.sortOrder
110
+ });
111
+ }
112
+ /**
113
+ * Get a single product by ID
114
+ */
115
+ async getProduct(productId) {
116
+ return this.request("GET", `/api/v1/products/${productId}`);
117
+ }
118
+ /**
119
+ * Create a new product
120
+ */
121
+ async createProduct(data) {
122
+ return this.request("POST", "/api/v1/products", data);
123
+ }
124
+ /**
125
+ * Update an existing product
126
+ */
127
+ async updateProduct(productId, data) {
128
+ return this.request("PATCH", `/api/v1/products/${productId}`, data);
129
+ }
130
+ /**
131
+ * Delete a product
132
+ */
133
+ async deleteProduct(productId) {
134
+ await this.request("DELETE", `/api/v1/products/${productId}`);
135
+ }
136
+ // -------------------- Orders --------------------
137
+ /**
138
+ * Get a list of orders with pagination
139
+ */
140
+ async getOrders(params) {
141
+ return this.request("GET", "/api/v1/orders", void 0, {
142
+ page: params?.page,
143
+ limit: params?.limit,
144
+ status: params?.status,
145
+ sortBy: params?.sortBy,
146
+ sortOrder: params?.sortOrder
147
+ });
148
+ }
149
+ /**
150
+ * Get a single order by ID
151
+ */
152
+ async getOrder(orderId) {
153
+ return this.request("GET", `/api/v1/orders/${orderId}`);
154
+ }
155
+ /**
156
+ * Create a new order
157
+ * This will automatically deduct inventory and sync to connected platforms
158
+ */
159
+ async createOrder(data) {
160
+ return this.request("POST", "/api/v1/orders", data);
161
+ }
162
+ /**
163
+ * Update an order (e.g., change status)
164
+ */
165
+ async updateOrder(orderId, data) {
166
+ return this.request("PATCH", `/api/v1/orders/${orderId}`, data);
167
+ }
168
+ // -------------------- Inventory --------------------
169
+ /**
170
+ * Update inventory for a product
171
+ * This will sync inventory to all connected platforms
172
+ */
173
+ async updateInventory(productId, data) {
174
+ await this.request("PUT", `/api/v1/products/${productId}/inventory`, data);
175
+ }
176
+ /**
177
+ * Get current inventory for a product
178
+ */
179
+ async getInventory(productId) {
180
+ return this.request("GET", `/api/v1/products/${productId}/inventory`);
181
+ }
182
+ // -------------------- Sync --------------------
183
+ /**
184
+ * Trigger a sync to a specific platform or all platforms
185
+ */
186
+ async triggerSync(platform) {
187
+ return this.request("POST", "/api/v1/sync", { platform });
188
+ }
189
+ /**
190
+ * Get the status of a sync job
191
+ */
192
+ async getSyncStatus(jobId) {
193
+ return this.request("GET", `/api/v1/sync/${jobId}`);
194
+ }
195
+ // -------------------- Store Info --------------------
196
+ /**
197
+ * Get information about the connected store
198
+ */
199
+ async getStoreInfo() {
200
+ return this.request("GET", "/api/v1/store");
201
+ }
202
+ // -------------------- Coupons --------------------
203
+ /**
204
+ * Get a list of coupons with pagination
205
+ */
206
+ async getCoupons(params) {
207
+ return this.request("GET", "/api/v1/coupons", void 0, {
208
+ page: params?.page,
209
+ limit: params?.limit,
210
+ search: params?.search,
211
+ status: params?.status,
212
+ type: params?.type,
213
+ platform: params?.platform,
214
+ sortBy: params?.sortBy,
215
+ sortOrder: params?.sortOrder
216
+ });
217
+ }
218
+ /**
219
+ * Get a single coupon by ID
220
+ */
221
+ async getCoupon(couponId) {
222
+ return this.request("GET", `/api/v1/coupons/${couponId}`);
223
+ }
224
+ /**
225
+ * Create a new coupon.
226
+ * Returns validation warnings if syncing to platforms that don't support certain features.
227
+ *
228
+ * @example
229
+ * ```typescript
230
+ * const coupon = await omni.createCoupon({
231
+ * code: 'SUMMER20',
232
+ * type: 'PERCENTAGE',
233
+ * value: 20,
234
+ * applicableCategories: ['cat_electronics'],
235
+ * excludedProducts: ['prod_clearance_item'],
236
+ * platforms: ['WOOCOMMERCE', 'SHOPIFY'],
237
+ * });
238
+ *
239
+ * // Check for platform limitations
240
+ * if (coupon.validationWarnings?.length) {
241
+ * console.warn('Some features not supported:', coupon.validationWarnings);
242
+ * }
243
+ * ```
244
+ */
245
+ async createCoupon(data) {
246
+ return this.request("POST", "/api/v1/coupons", data);
247
+ }
248
+ /**
249
+ * Update an existing coupon
250
+ */
251
+ async updateCoupon(couponId, data) {
252
+ return this.request("PATCH", `/api/v1/coupons/${couponId}`, data);
253
+ }
254
+ /**
255
+ * Delete a coupon
256
+ */
257
+ async deleteCoupon(couponId) {
258
+ await this.request("DELETE", `/api/v1/coupons/${couponId}`);
259
+ }
260
+ /**
261
+ * Sync a coupon to all connected platforms.
262
+ * Returns a sync job that can be tracked with getSyncStatus().
263
+ */
264
+ async syncCoupon(couponId) {
265
+ return this.request("POST", `/api/v1/coupons/${couponId}/sync`);
266
+ }
267
+ /**
268
+ * Publish a coupon to specific platforms.
269
+ * Use this for selective syncing instead of syncing to all platforms.
270
+ *
271
+ * @example
272
+ * ```typescript
273
+ * // Only sync to WooCommerce and Shopify
274
+ * await omni.publishCoupon('coupon_123', ['WOOCOMMERCE', 'SHOPIFY']);
275
+ * ```
276
+ */
277
+ async publishCoupon(couponId, platforms) {
278
+ return this.request("POST", `/api/v1/coupons/${couponId}/publish`, { platforms });
279
+ }
280
+ /**
281
+ * Get platform capabilities for coupon features.
282
+ * Use this to understand what features each platform supports.
283
+ *
284
+ * @example
285
+ * ```typescript
286
+ * const capabilities = await omni.getCouponPlatformCapabilities();
287
+ * if (!capabilities.SHOPIFY.supportsProductExclusions) {
288
+ * console.log('Shopify does not support product exclusions');
289
+ * }
290
+ * ```
291
+ */
292
+ async getCouponPlatformCapabilities() {
293
+ return this.request(
294
+ "GET",
295
+ "/api/v1/coupons/platform-capabilities"
296
+ );
297
+ }
298
+ // -------------------- Customers --------------------
299
+ /**
300
+ * Create a new customer
301
+ *
302
+ * @example
303
+ * ```typescript
304
+ * const customer = await omni.createCustomer({
305
+ * email: 'customer@example.com',
306
+ * firstName: 'John',
307
+ * lastName: 'Doe',
308
+ * acceptsMarketing: true,
309
+ * });
310
+ * ```
311
+ */
312
+ async createCustomer(data) {
313
+ return this.request("POST", "/api/v1/customers", data);
314
+ }
315
+ /**
316
+ * Get a customer by ID
317
+ */
318
+ async getCustomer(customerId) {
319
+ return this.request("GET", `/api/v1/customers/${customerId}`);
320
+ }
321
+ /**
322
+ * Update a customer
323
+ */
324
+ async updateCustomer(customerId, data) {
325
+ return this.request("PATCH", `/api/v1/customers/${customerId}`, data);
326
+ }
327
+ /**
328
+ * Get a customer by email
329
+ */
330
+ async getCustomerByEmail(email) {
331
+ return this.request("GET", "/api/v1/customers/by-email", void 0, { email });
332
+ }
333
+ /**
334
+ * Login an existing customer (returns JWT token)
335
+ *
336
+ * @example
337
+ * ```typescript
338
+ * const auth = await omni.loginCustomer('customer@example.com', 'password123');
339
+ * console.log('Customer logged in:', auth.customer.email);
340
+ * // Store auth.token for subsequent authenticated requests
341
+ * ```
342
+ */
343
+ async loginCustomer(email, password) {
344
+ return this.request("POST", "/api/v1/customers/login", {
345
+ email,
346
+ password
347
+ });
348
+ }
349
+ /**
350
+ * Register a new customer with password (creates account)
351
+ *
352
+ * @example
353
+ * ```typescript
354
+ * const auth = await omni.registerCustomer({
355
+ * email: 'newcustomer@example.com',
356
+ * password: 'securepassword123',
357
+ * firstName: 'Jane',
358
+ * lastName: 'Doe',
359
+ * });
360
+ * ```
361
+ */
362
+ async registerCustomer(data) {
363
+ return this.request("POST", "/api/v1/customers/register", data);
364
+ }
365
+ /**
366
+ * Request a password reset email for a customer
367
+ */
368
+ async forgotPassword(email) {
369
+ return this.request("POST", "/api/v1/customers/forgot-password", {
370
+ email
371
+ });
372
+ }
373
+ /**
374
+ * Get all addresses for a customer
375
+ */
376
+ async getCustomerAddresses(customerId) {
377
+ return this.request("GET", `/api/v1/customers/${customerId}/addresses`);
378
+ }
379
+ /**
380
+ * Add an address to a customer
381
+ *
382
+ * @example
383
+ * ```typescript
384
+ * const address = await omni.addCustomerAddress('cust_123', {
385
+ * firstName: 'John',
386
+ * lastName: 'Doe',
387
+ * line1: '123 Main St',
388
+ * city: 'New York',
389
+ * region: 'NY',
390
+ * postalCode: '10001',
391
+ * country: 'US',
392
+ * isDefault: true,
393
+ * });
394
+ * ```
395
+ */
396
+ async addCustomerAddress(customerId, address) {
397
+ return this.request(
398
+ "POST",
399
+ `/api/v1/customers/${customerId}/addresses`,
400
+ address
401
+ );
402
+ }
403
+ /**
404
+ * Update a customer address
405
+ */
406
+ async updateCustomerAddress(customerId, addressId, address) {
407
+ return this.request(
408
+ "PATCH",
409
+ `/api/v1/customers/${customerId}/addresses/${addressId}`,
410
+ address
411
+ );
412
+ }
413
+ /**
414
+ * Delete a customer address
415
+ */
416
+ async deleteCustomerAddress(customerId, addressId) {
417
+ await this.request("DELETE", `/api/v1/customers/${customerId}/addresses/${addressId}`);
418
+ }
419
+ /**
420
+ * Get orders for a customer
421
+ *
422
+ * @example
423
+ * ```typescript
424
+ * const orders = await omni.getCustomerOrders('cust_123', { page: 1, limit: 10 });
425
+ * console.log(`Customer has ${orders.meta.total} total orders`);
426
+ * ```
427
+ */
428
+ async getCustomerOrders(customerId, params) {
429
+ return this.request(
430
+ "GET",
431
+ `/api/v1/customers/${customerId}/orders`,
432
+ void 0,
433
+ { page: params?.page, limit: params?.limit }
434
+ );
435
+ }
436
+ // -------------------- Cart --------------------
437
+ /**
438
+ * Create a new cart for a guest user
439
+ * Returns a cart with a sessionToken that identifies this cart
440
+ *
441
+ * @example
442
+ * ```typescript
443
+ * const cart = await omni.createCart();
444
+ * console.log('Cart session:', cart.sessionToken);
445
+ * // Store sessionToken in localStorage or cookie
446
+ * ```
447
+ */
448
+ async createCart() {
449
+ return this.request("POST", "/api/v1/cart");
450
+ }
451
+ /**
452
+ * Get a cart by session token (for guest users)
453
+ *
454
+ * @example
455
+ * ```typescript
456
+ * const cart = await omni.getCartBySession('sess_abc123');
457
+ * console.log('Items in cart:', cart.itemCount);
458
+ * ```
459
+ */
460
+ async getCartBySession(sessionToken) {
461
+ return this.request("GET", `/api/v1/cart/session/${sessionToken}`);
462
+ }
463
+ /**
464
+ * Get a cart by customer ID (for authenticated users)
465
+ *
466
+ * @example
467
+ * ```typescript
468
+ * const cart = await omni.getCartByCustomer('cust_123');
469
+ * console.log('Customer cart total:', cart.subtotal);
470
+ * ```
471
+ */
472
+ async getCartByCustomer(customerId) {
473
+ return this.request("GET", `/api/v1/cart/customer/${customerId}`);
474
+ }
475
+ /**
476
+ * Get a cart by ID
477
+ */
478
+ async getCart(cartId) {
479
+ return this.request("GET", `/api/v1/cart/${cartId}`);
480
+ }
481
+ /**
482
+ * Add an item to the cart
483
+ *
484
+ * @example
485
+ * ```typescript
486
+ * const cart = await omni.addToCart('cart_123', {
487
+ * productId: 'prod_abc',
488
+ * quantity: 2,
489
+ * notes: 'Gift wrap please',
490
+ * });
491
+ * ```
492
+ */
493
+ async addToCart(cartId, item) {
494
+ return this.request("POST", `/api/v1/cart/${cartId}/items`, item);
495
+ }
496
+ /**
497
+ * Update an item quantity in the cart
498
+ *
499
+ * @example
500
+ * ```typescript
501
+ * const cart = await omni.updateCartItem('cart_123', 'item_456', { quantity: 3 });
502
+ * ```
503
+ */
504
+ async updateCartItem(cartId, itemId, data) {
505
+ return this.request("PATCH", `/api/v1/cart/${cartId}/items/${itemId}`, data);
506
+ }
507
+ /**
508
+ * Remove an item from the cart
509
+ *
510
+ * @example
511
+ * ```typescript
512
+ * const cart = await omni.removeCartItem('cart_123', 'item_456');
513
+ * ```
514
+ */
515
+ async removeCartItem(cartId, itemId) {
516
+ return this.request("DELETE", `/api/v1/cart/${cartId}/items/${itemId}`);
517
+ }
518
+ /**
519
+ * Clear all items from the cart
520
+ *
521
+ * @example
522
+ * ```typescript
523
+ * await omni.clearCart('cart_123');
524
+ * ```
525
+ */
526
+ async clearCart(cartId) {
527
+ await this.request("DELETE", `/api/v1/cart/${cartId}/items`);
528
+ }
529
+ /**
530
+ * Apply a coupon to the cart
531
+ *
532
+ * @example
533
+ * ```typescript
534
+ * const cart = await omni.applyCoupon('cart_123', 'SAVE20');
535
+ * console.log('Discount:', cart.discountAmount);
536
+ * ```
537
+ */
538
+ async applyCoupon(cartId, code) {
539
+ return this.request("POST", `/api/v1/cart/${cartId}/coupon`, { code });
540
+ }
541
+ /**
542
+ * Remove a coupon from the cart
543
+ *
544
+ * @example
545
+ * ```typescript
546
+ * const cart = await omni.removeCoupon('cart_123');
547
+ * ```
548
+ */
549
+ async removeCoupon(cartId) {
550
+ return this.request("DELETE", `/api/v1/cart/${cartId}/coupon`);
551
+ }
552
+ /**
553
+ * Merge a guest cart into a customer's cart (after login)
554
+ * The guest cart items are moved to the customer's cart
555
+ *
556
+ * @example
557
+ * ```typescript
558
+ * // After customer logs in, merge their guest cart
559
+ * const mergedCart = await omni.mergeCarts({
560
+ * sourceSessionToken: 'sess_guest_abc',
561
+ * targetCustomerId: 'cust_123',
562
+ * });
563
+ * ```
564
+ */
565
+ async mergeCarts(data) {
566
+ return this.request("POST", "/api/v1/cart/merge", data);
567
+ }
568
+ // -------------------- Checkout --------------------
569
+ /**
570
+ * Create a checkout from a cart
571
+ * Starts the checkout process and returns checkout with available options
572
+ *
573
+ * @example
574
+ * ```typescript
575
+ * const checkout = await omni.createCheckout({ cartId: 'cart_123' });
576
+ * console.log('Checkout created:', checkout.id);
577
+ * ```
578
+ */
579
+ async createCheckout(data) {
580
+ return this.request("POST", "/api/v1/checkout", data);
581
+ }
582
+ /**
583
+ * Get a checkout by ID
584
+ *
585
+ * @example
586
+ * ```typescript
587
+ * const checkout = await omni.getCheckout('checkout_123');
588
+ * console.log('Status:', checkout.status);
589
+ * ```
590
+ */
591
+ async getCheckout(checkoutId) {
592
+ return this.request("GET", `/api/v1/checkout/${checkoutId}`);
593
+ }
594
+ /**
595
+ * Set customer information on checkout
596
+ *
597
+ * @example
598
+ * ```typescript
599
+ * const checkout = await omni.setCheckoutCustomer('checkout_123', {
600
+ * email: 'customer@example.com',
601
+ * firstName: 'John',
602
+ * lastName: 'Doe',
603
+ * });
604
+ * ```
605
+ */
606
+ async setCheckoutCustomer(checkoutId, data) {
607
+ return this.request("PATCH", `/api/v1/checkout/${checkoutId}/customer`, data);
608
+ }
609
+ /**
610
+ * Set shipping address on checkout
611
+ * Returns the checkout and available shipping rates for the address
612
+ *
613
+ * @example
614
+ * ```typescript
615
+ * const { checkout, rates } = await omni.setShippingAddress('checkout_123', {
616
+ * firstName: 'John',
617
+ * lastName: 'Doe',
618
+ * line1: '123 Main St',
619
+ * city: 'New York',
620
+ * region: 'NY',
621
+ * postalCode: '10001',
622
+ * country: 'US',
623
+ * });
624
+ * console.log('Available rates:', rates);
625
+ * ```
626
+ */
627
+ async setShippingAddress(checkoutId, address) {
628
+ return this.request(
629
+ "PATCH",
630
+ `/api/v1/checkout/${checkoutId}/shipping-address`,
631
+ address
632
+ );
633
+ }
634
+ /**
635
+ * Get available shipping rates for a checkout
636
+ * Requires shipping address to be set first
637
+ *
638
+ * @example
639
+ * ```typescript
640
+ * const rates = await omni.getShippingRates('checkout_123');
641
+ * console.log('Shipping options:', rates);
642
+ * ```
643
+ */
644
+ async getShippingRates(checkoutId) {
645
+ return this.request("GET", `/api/v1/checkout/${checkoutId}/shipping-rates`);
646
+ }
647
+ /**
648
+ * Select a shipping method for checkout
649
+ *
650
+ * @example
651
+ * ```typescript
652
+ * const checkout = await omni.selectShippingMethod('checkout_123', 'rate_express');
653
+ * console.log('Shipping cost:', checkout.shippingAmount);
654
+ * ```
655
+ */
656
+ async selectShippingMethod(checkoutId, shippingRateId) {
657
+ return this.request("PATCH", `/api/v1/checkout/${checkoutId}/shipping-method`, {
658
+ shippingRateId
659
+ });
660
+ }
661
+ /**
662
+ * Set billing address on checkout
663
+ * Can optionally use shipping address as billing address
664
+ *
665
+ * @example
666
+ * ```typescript
667
+ * // Use same as shipping
668
+ * const checkout = await omni.setBillingAddress('checkout_123', {
669
+ * ...shippingAddress,
670
+ * sameAsShipping: true,
671
+ * });
672
+ *
673
+ * // Or set different billing address
674
+ * const checkout = await omni.setBillingAddress('checkout_123', {
675
+ * firstName: 'John',
676
+ * lastName: 'Doe',
677
+ * line1: '456 Business Ave',
678
+ * city: 'New York',
679
+ * region: 'NY',
680
+ * postalCode: '10002',
681
+ * country: 'US',
682
+ * });
683
+ * ```
684
+ */
685
+ async setBillingAddress(checkoutId, address) {
686
+ return this.request(
687
+ "PATCH",
688
+ `/api/v1/checkout/${checkoutId}/billing-address`,
689
+ address
690
+ );
691
+ }
692
+ /**
693
+ * Complete the checkout and create an order
694
+ * Requires customer email, shipping address, and shipping method to be set
695
+ *
696
+ * @example
697
+ * ```typescript
698
+ * const { orderId } = await omni.completeCheckout('checkout_123');
699
+ * console.log('Order created:', orderId);
700
+ * ```
701
+ */
702
+ async completeCheckout(checkoutId) {
703
+ return this.request(
704
+ "POST",
705
+ `/api/v1/checkout/${checkoutId}/complete`
706
+ );
707
+ }
708
+ };
709
+ var OmniSyncError = class extends Error {
710
+ constructor(message, statusCode, details) {
711
+ super(message);
712
+ this.name = "OmniSyncError";
713
+ this.statusCode = statusCode;
714
+ this.details = details;
715
+ }
716
+ };
717
+
718
+ // src/webhooks.ts
719
+ function verifyWebhook(payload, signature, secret) {
720
+ if (!signature || !secret) {
721
+ return false;
722
+ }
723
+ const payloadString = typeof payload === "string" ? payload : JSON.stringify(payload);
724
+ return verifyHmacSignature(payloadString, signature, secret);
725
+ }
726
+ function verifyHmacSignature(payload, signature, secret) {
727
+ try {
728
+ if (typeof globalThis.crypto === "undefined") {
729
+ const crypto2 = require("crypto");
730
+ const expectedSignature2 = crypto2.createHmac("sha256", secret).update(payload).digest("hex");
731
+ return timingSafeEqual(signature, expectedSignature2);
732
+ }
733
+ const crypto = require("crypto");
734
+ const expectedSignature = crypto.createHmac("sha256", secret).update(payload).digest("hex");
735
+ return timingSafeEqual(signature, expectedSignature);
736
+ } catch (error) {
737
+ console.error("Webhook signature verification failed:", error);
738
+ return false;
739
+ }
740
+ }
741
+ function timingSafeEqual(a, b) {
742
+ if (a.length !== b.length) {
743
+ return false;
744
+ }
745
+ let result = 0;
746
+ for (let i = 0; i < a.length; i++) {
747
+ result |= a.charCodeAt(i) ^ b.charCodeAt(i);
748
+ }
749
+ return result === 0;
750
+ }
751
+ function parseWebhookEvent(payload) {
752
+ if (typeof payload !== "object" || payload === null) {
753
+ throw new Error("Invalid webhook payload: expected object");
754
+ }
755
+ const event = payload;
756
+ if (typeof event.event !== "string") {
757
+ throw new Error("Invalid webhook payload: missing or invalid event type");
758
+ }
759
+ if (typeof event.storeId !== "string") {
760
+ throw new Error("Invalid webhook payload: missing storeId");
761
+ }
762
+ if (typeof event.entityId !== "string") {
763
+ throw new Error("Invalid webhook payload: missing entityId");
764
+ }
765
+ return {
766
+ event: event.event,
767
+ storeId: event.storeId,
768
+ entityId: event.entityId,
769
+ platform: event.platform || "CUSTOM",
770
+ data: event.data,
771
+ timestamp: event.timestamp || (/* @__PURE__ */ new Date()).toISOString()
772
+ };
773
+ }
774
+ function isWebhookEventType(event, type) {
775
+ return event.event === type;
776
+ }
777
+ function createWebhookHandler(handlers) {
778
+ return async (payload) => {
779
+ const event = parseWebhookEvent(payload);
780
+ const handler = handlers[event.event];
781
+ if (handler) {
782
+ await handler(event);
783
+ }
784
+ };
785
+ }
786
+
787
+ // src/types.ts
788
+ function isCouponApplicableToProduct(coupon, productId, productCategoryIds) {
789
+ if (coupon.excludedProducts?.includes(productId)) {
790
+ return false;
791
+ }
792
+ if (coupon.excludedCategories?.some((cat) => productCategoryIds.includes(cat))) {
793
+ return false;
794
+ }
795
+ if (coupon.applicableProducts && coupon.applicableProducts.length > 0) {
796
+ if (!coupon.applicableProducts.includes(productId)) {
797
+ return false;
798
+ }
799
+ }
800
+ if (coupon.applicableCategories && coupon.applicableCategories.length > 0) {
801
+ if (!coupon.applicableCategories.some((cat) => productCategoryIds.includes(cat))) {
802
+ return false;
803
+ }
804
+ }
805
+ return true;
806
+ }
807
+ // Annotate the CommonJS export names for ESM import in node:
808
+ 0 && (module.exports = {
809
+ OmniSyncClient,
810
+ OmniSyncError,
811
+ createWebhookHandler,
812
+ isCouponApplicableToProduct,
813
+ isWebhookEventType,
814
+ parseWebhookEvent,
815
+ verifyWebhook
816
+ });