omni-sync-sdk 0.20.3 → 0.21.1
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/LICENSE +0 -0
- package/README.md +133 -8
- package/dist/index.d.mts +126 -14
- package/dist/index.d.ts +126 -14
- package/dist/index.js +174 -8
- package/dist/index.mjs +174 -8
- package/package.json +9 -10
package/LICENSE
ADDED
|
File without changes
|
package/README.md
CHANGED
|
@@ -147,19 +147,32 @@ formatPrice(amount, 'USD');
|
|
|
147
147
|
formatPrice(amount, { currency: 'USD' });
|
|
148
148
|
```
|
|
149
149
|
|
|
150
|
-
### 3. Order
|
|
150
|
+
### 3. Cart/Checkout vs Order - Different Item Structures!
|
|
151
|
+
|
|
152
|
+
**IMPORTANT:** Cart and Checkout items have NESTED product data. Order items are FLAT.
|
|
151
153
|
|
|
152
154
|
```typescript
|
|
153
|
-
//
|
|
154
|
-
|
|
155
|
-
item.product.name;
|
|
155
|
+
// CartItem and CheckoutLineItem - NESTED product
|
|
156
|
+
cart.items.forEach((item) => {
|
|
157
|
+
console.log(item.product.name); // ✅ Correct for Cart/Checkout
|
|
158
|
+
console.log(item.product.sku);
|
|
159
|
+
console.log(item.product.images);
|
|
160
|
+
});
|
|
156
161
|
|
|
157
|
-
//
|
|
158
|
-
order.
|
|
159
|
-
item.name; //
|
|
160
|
-
item.
|
|
162
|
+
// OrderItem - FLAT structure
|
|
163
|
+
order.items.forEach((item) => {
|
|
164
|
+
console.log(item.name); // ✅ Correct for Orders
|
|
165
|
+
console.log(item.sku);
|
|
166
|
+
console.log(item.image); // singular, not images
|
|
167
|
+
});
|
|
161
168
|
```
|
|
162
169
|
|
|
170
|
+
| Type | Access Name | Access Image |
|
|
171
|
+
| ------------------ | ------------------- | --------------------- |
|
|
172
|
+
| `CartItem` | `item.product.name` | `item.product.images` |
|
|
173
|
+
| `CheckoutLineItem` | `item.product.name` | `item.product.images` |
|
|
174
|
+
| `OrderItem` | `item.name` | `item.image` |
|
|
175
|
+
|
|
163
176
|
### 4. Payment Status is 'succeeded', not 'completed'
|
|
164
177
|
|
|
165
178
|
```typescript
|
|
@@ -206,6 +219,118 @@ const color = variant.attributes?.['Color']; // string
|
|
|
206
219
|
const size = variant.attributes?.['Size']; // string
|
|
207
220
|
```
|
|
208
221
|
|
|
222
|
+
### 8. Address Uses `region`, NOT `state`
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
// ❌ WRONG
|
|
226
|
+
const address = {
|
|
227
|
+
state: 'NY', // This field doesn't exist!
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// ✅ CORRECT
|
|
231
|
+
const address: SetShippingAddressDto = {
|
|
232
|
+
firstName: 'John',
|
|
233
|
+
lastName: 'Doe',
|
|
234
|
+
line1: '123 Main St',
|
|
235
|
+
city: 'New York',
|
|
236
|
+
region: 'NY', // Use 'region' for state/province
|
|
237
|
+
postalCode: '10001',
|
|
238
|
+
country: 'US',
|
|
239
|
+
};
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### 9. OAuth - Use `authorizationUrl`, NOT `url`
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
// ❌ WRONG
|
|
246
|
+
const response = await omni.getOAuthAuthorizeUrl('GOOGLE', { redirectUrl });
|
|
247
|
+
window.location.href = response.url; // 'url' doesn't exist!
|
|
248
|
+
|
|
249
|
+
// ✅ CORRECT
|
|
250
|
+
const response = await omni.getOAuthAuthorizeUrl('GOOGLE', { redirectUrl });
|
|
251
|
+
window.location.href = response.authorizationUrl; // Correct property name
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### 10. OAuth Provider Type is Exported
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
// ❌ WRONG - creating your own type
|
|
258
|
+
type Provider = 'google' | 'facebook'; // lowercase won't work!
|
|
259
|
+
|
|
260
|
+
// ✅ CORRECT - import from SDK
|
|
261
|
+
import { CustomerOAuthProvider } from 'omni-sync-sdk';
|
|
262
|
+
// CustomerOAuthProvider = 'GOOGLE' | 'FACEBOOK' | 'GITHUB' (UPPERCASE)
|
|
263
|
+
|
|
264
|
+
const provider: CustomerOAuthProvider = 'GOOGLE';
|
|
265
|
+
await omni.getOAuthAuthorizeUrl(provider, { redirectUrl });
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### 11. getAvailableOAuthProviders Returns Object, Not Array
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
// ❌ WRONG - expecting array directly
|
|
272
|
+
const providers = await omni.getAvailableOAuthProviders();
|
|
273
|
+
providers.forEach(p => ...); // Error! providers is not an array
|
|
274
|
+
|
|
275
|
+
// ✅ CORRECT - access the providers property
|
|
276
|
+
const response = await omni.getAvailableOAuthProviders();
|
|
277
|
+
response.providers.forEach(p => ...); // response.providers is the array
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### 12. SDK Uses `null`, Not `undefined`
|
|
281
|
+
|
|
282
|
+
Optional fields in SDK types use `null`, not `undefined`:
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
// SDK types use:
|
|
286
|
+
slug: string | null;
|
|
287
|
+
salePrice: string | null;
|
|
288
|
+
|
|
289
|
+
// So when checking:
|
|
290
|
+
if (product.slug !== null) {
|
|
291
|
+
// ✅ Check for null
|
|
292
|
+
// ...
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### 13. Cart Has No `total` Field - Use `getCartTotals()` Helper
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
// ❌ WRONG - these fields don't exist on Cart
|
|
300
|
+
const total = cart.total; // ← 'total' doesn't exist!
|
|
301
|
+
const discount = cart.discount; // ← 'discount' doesn't exist! It's 'discountAmount'
|
|
302
|
+
|
|
303
|
+
// ✅ CORRECT - use the helper function (RECOMMENDED)
|
|
304
|
+
import { getCartTotals } from 'omni-sync-sdk';
|
|
305
|
+
const totals = getCartTotals(cart, shippingPrice);
|
|
306
|
+
// Returns: { subtotal: 59.98, discount: 10, shipping: 5.99, total: 55.97 }
|
|
307
|
+
|
|
308
|
+
// ✅ CORRECT - or calculate manually
|
|
309
|
+
const subtotal = parseFloat(cart.subtotal);
|
|
310
|
+
const discount = parseFloat(cart.discountAmount); // ← Note: 'discountAmount', NOT 'discount'
|
|
311
|
+
const total = subtotal - discount;
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
**Important Notes:**
|
|
315
|
+
|
|
316
|
+
- Cart field is `discountAmount`, NOT `discount`
|
|
317
|
+
- Cart has NO `total` field - use `getCartTotals()` or calculate
|
|
318
|
+
- Checkout DOES have a `total` field, but Cart does not
|
|
319
|
+
|
|
320
|
+
### 14. SearchSuggestions - Products Have `price`, Not `basePrice`
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
// In SearchSuggestions, ProductSuggestion has:
|
|
324
|
+
// - price: effective price (sale price if on sale, otherwise base price)
|
|
325
|
+
// - basePrice: original price
|
|
326
|
+
// - salePrice: sale price if on sale
|
|
327
|
+
|
|
328
|
+
// ✅ Use 'price' for display (it's already the correct price)
|
|
329
|
+
suggestions.products.map(p => (
|
|
330
|
+
<div>{p.name} - {formatPrice(p.price, { currency })}</div>
|
|
331
|
+
));
|
|
332
|
+
```
|
|
333
|
+
|
|
209
334
|
---
|
|
210
335
|
|
|
211
336
|
## Checkout: Guest vs Logged-In Customer
|
package/dist/index.d.mts
CHANGED
|
@@ -1692,15 +1692,27 @@ interface ShippingRate {
|
|
|
1692
1692
|
* **Note:** Order is created automatically via webhook when payment succeeds.
|
|
1693
1693
|
* No need to call `completeCheckout()` - it happens automatically.
|
|
1694
1694
|
*
|
|
1695
|
+
* **IMPORTANT: Order Summary Display**
|
|
1696
|
+
* Always use `checkout.lineItems` for displaying the Order Summary during checkout!
|
|
1697
|
+
* This is especially important for **partial checkout** (AliExpress-style) where the user
|
|
1698
|
+
* selects only some items from their cart. The `lineItems` array contains ONLY the items
|
|
1699
|
+
* being purchased in this checkout, NOT the entire cart.
|
|
1700
|
+
*
|
|
1695
1701
|
* **IMPORTANT: Price fields are strings**
|
|
1696
1702
|
* All monetary fields (subtotal, discountAmount, shippingAmount, taxAmount, total)
|
|
1697
1703
|
* are strings to preserve decimal precision. Use parseFloat() for calculations.
|
|
1698
1704
|
*
|
|
1699
1705
|
* @example
|
|
1700
1706
|
* ```typescript
|
|
1701
|
-
* // Display checkout summary
|
|
1707
|
+
* // Display checkout summary - use checkout.lineItems, NOT localCart!
|
|
1702
1708
|
* const checkout = await omni.getCheckout(checkoutId);
|
|
1703
1709
|
*
|
|
1710
|
+
* // Order Summary - ALWAYS use checkout.lineItems
|
|
1711
|
+
* checkout.lineItems.forEach(item => {
|
|
1712
|
+
* console.log(item.product.name, item.quantity, item.unitPrice);
|
|
1713
|
+
* });
|
|
1714
|
+
*
|
|
1715
|
+
* // Totals
|
|
1704
1716
|
* const subtotal = parseFloat(checkout.subtotal);
|
|
1705
1717
|
* const discount = parseFloat(checkout.discountAmount);
|
|
1706
1718
|
* const shipping = parseFloat(checkout.shippingAmount);
|
|
@@ -1712,11 +1724,6 @@ interface ShippingRate {
|
|
|
1712
1724
|
* console.log(`Shipping: $${shipping.toFixed(2)}`);
|
|
1713
1725
|
* console.log(`Tax: $${tax.toFixed(2)}`);
|
|
1714
1726
|
* console.log(`Total: $${total.toFixed(2)}`);
|
|
1715
|
-
*
|
|
1716
|
-
* // Access line items (nested structure)
|
|
1717
|
-
* checkout.lineItems.forEach(item => {
|
|
1718
|
-
* console.log(item.product.name, item.quantity);
|
|
1719
|
-
* });
|
|
1720
1727
|
* ```
|
|
1721
1728
|
*
|
|
1722
1729
|
* @see CheckoutLineItem for item structure
|
|
@@ -3057,6 +3064,11 @@ declare class OmniSyncClient {
|
|
|
3057
3064
|
* When a cart has this ID, operations use localStorage instead of server API.
|
|
3058
3065
|
*/
|
|
3059
3066
|
private readonly VIRTUAL_LOCAL_CART_ID;
|
|
3067
|
+
/**
|
|
3068
|
+
* localStorage key for persisting active checkout across page redirects.
|
|
3069
|
+
* This is needed because Stripe redirects lose in-memory state.
|
|
3070
|
+
*/
|
|
3071
|
+
private readonly ACTIVE_CHECKOUT_KEY;
|
|
3060
3072
|
private readonly onAuthError?;
|
|
3061
3073
|
constructor(options: OmniSyncClientOptions);
|
|
3062
3074
|
/**
|
|
@@ -4748,6 +4760,11 @@ declare class OmniSyncClient {
|
|
|
4748
4760
|
* Pass `selectedIndices` to checkout only specific items from the local cart.
|
|
4749
4761
|
* Use the index of each item in the cart.items array.
|
|
4750
4762
|
*
|
|
4763
|
+
* **IMPORTANT - Order Summary Display:**
|
|
4764
|
+
* After calling this function, use `getCheckout(checkoutId)` to get the checkout
|
|
4765
|
+
* and display `checkout.lineItems` in your Order Summary - NOT the local cart items!
|
|
4766
|
+
* The checkout.lineItems contains ONLY the selected items for this checkout.
|
|
4767
|
+
*
|
|
4751
4768
|
* @param options.selectedIndices - Optional array of item indices for partial checkout
|
|
4752
4769
|
* @returns Tracking result with checkoutId if enabled
|
|
4753
4770
|
*
|
|
@@ -4760,19 +4777,22 @@ declare class OmniSyncClient {
|
|
|
4760
4777
|
* const result = await omni.startGuestCheckout({ selectedIndices: [0, 2] });
|
|
4761
4778
|
*
|
|
4762
4779
|
* if (result.tracked) {
|
|
4763
|
-
* //
|
|
4764
|
-
*
|
|
4780
|
+
* // IMPORTANT: Fetch checkout and use checkout.lineItems for Order Summary!
|
|
4781
|
+
* const checkout = await omni.getCheckout(result.checkoutId);
|
|
4782
|
+
*
|
|
4783
|
+
* // Display Order Summary using checkout.lineItems (NOT localCart.items!)
|
|
4784
|
+
* // checkout.lineItems contains ONLY the selected items
|
|
4785
|
+
* checkout.lineItems.forEach(item => {
|
|
4786
|
+
* console.log(item.product.name, item.quantity, item.unitPrice);
|
|
4787
|
+
* });
|
|
4765
4788
|
*
|
|
4766
4789
|
* // Update checkout with address
|
|
4767
|
-
* await omni.
|
|
4790
|
+
* await omni.updateGuestCheckoutAddress(result.checkoutId, {
|
|
4768
4791
|
* shippingAddress: { ... },
|
|
4769
4792
|
* });
|
|
4770
4793
|
*
|
|
4771
|
-
* //
|
|
4772
|
-
*
|
|
4773
|
-
*
|
|
4774
|
-
* // For partial checkout: remove only purchased items
|
|
4775
|
-
* omni.removeLocalCartItemsByIndex([0, 2]);
|
|
4794
|
+
* // After payment success, call handlePaymentSuccess() to clear cart
|
|
4795
|
+
* omni.handlePaymentSuccess(result.checkoutId);
|
|
4776
4796
|
* } else {
|
|
4777
4797
|
* // Tracking not enabled, use regular submitGuestOrder
|
|
4778
4798
|
* const order = await omni.submitGuestOrder();
|
|
@@ -4782,6 +4802,21 @@ declare class OmniSyncClient {
|
|
|
4782
4802
|
startGuestCheckout(options?: {
|
|
4783
4803
|
selectedIndices?: number[];
|
|
4784
4804
|
}): Promise<GuestCheckoutStartResponse>;
|
|
4805
|
+
/**
|
|
4806
|
+
* Save active checkout to localStorage (persists across page redirects)
|
|
4807
|
+
* @internal
|
|
4808
|
+
*/
|
|
4809
|
+
private saveActiveCheckout;
|
|
4810
|
+
/**
|
|
4811
|
+
* Load active checkout from localStorage
|
|
4812
|
+
* @internal
|
|
4813
|
+
*/
|
|
4814
|
+
private loadActiveCheckout;
|
|
4815
|
+
/**
|
|
4816
|
+
* Clear active checkout from localStorage
|
|
4817
|
+
* @internal
|
|
4818
|
+
*/
|
|
4819
|
+
private clearActiveCheckoutStorage;
|
|
4785
4820
|
/**
|
|
4786
4821
|
* Remove specific items from local cart by their indices.
|
|
4787
4822
|
* Use after partial checkout to remove only the purchased items.
|
|
@@ -4829,6 +4864,83 @@ declare class OmniSyncClient {
|
|
|
4829
4864
|
clearCartOnSuccess?: boolean;
|
|
4830
4865
|
selectedIndices?: number[];
|
|
4831
4866
|
}): Promise<GuestOrderResponse>;
|
|
4867
|
+
/**
|
|
4868
|
+
* Get the active guest checkout session info.
|
|
4869
|
+
* Use this to check if there's an active checkout before handling payment success.
|
|
4870
|
+
*
|
|
4871
|
+
* @returns The active checkout info or null if no checkout is active
|
|
4872
|
+
*
|
|
4873
|
+
* @example
|
|
4874
|
+
* ```typescript
|
|
4875
|
+
* const activeCheckout = omni.getActiveGuestCheckout();
|
|
4876
|
+
* if (activeCheckout) {
|
|
4877
|
+
* console.log('Active checkout:', activeCheckout.checkoutId);
|
|
4878
|
+
* console.log('Partial checkout:', activeCheckout.selectedIndices?.length);
|
|
4879
|
+
* }
|
|
4880
|
+
* ```
|
|
4881
|
+
*/
|
|
4882
|
+
getActiveGuestCheckout(): {
|
|
4883
|
+
checkoutId: string;
|
|
4884
|
+
cartId: string;
|
|
4885
|
+
selectedIndices?: number[];
|
|
4886
|
+
} | null;
|
|
4887
|
+
/**
|
|
4888
|
+
* Handle payment success - automatically clears the cart (both local and server).
|
|
4889
|
+
*
|
|
4890
|
+
* Call this after Stripe payment succeeds (payment_intent.succeeded or confirmPayment success).
|
|
4891
|
+
* This handles ALL checkout scenarios:
|
|
4892
|
+
*
|
|
4893
|
+
* **For guest users (local cart):**
|
|
4894
|
+
* - Full checkout: clears entire localStorage cart
|
|
4895
|
+
* - Partial checkout: removes only the purchased items
|
|
4896
|
+
*
|
|
4897
|
+
* **For logged-in users (server cart):**
|
|
4898
|
+
* - Clears the cached cart ID so next `smartGetCart()` fetches fresh data
|
|
4899
|
+
* - The server cart is already marked as CONVERTED by the webhook
|
|
4900
|
+
*
|
|
4901
|
+
* **IMPORTANT:** Call this from your payment success handler (e.g., after stripe.confirmPayment succeeds,
|
|
4902
|
+
* or on your success page after redirect). This works for both guests AND logged-in users!
|
|
4903
|
+
*
|
|
4904
|
+
* @param checkoutId - Optional checkout ID for validation
|
|
4905
|
+
* @returns Object indicating whether cart was cleared and how
|
|
4906
|
+
*
|
|
4907
|
+
* @example
|
|
4908
|
+
* ```typescript
|
|
4909
|
+
* // After stripe.confirmPayment() succeeds (works for guests AND logged-in users)
|
|
4910
|
+
* const { error, paymentIntent } = await stripe.confirmPayment({
|
|
4911
|
+
* elements,
|
|
4912
|
+
* confirmParams: { return_url: '/checkout/success' },
|
|
4913
|
+
* redirect: 'if_required',
|
|
4914
|
+
* });
|
|
4915
|
+
*
|
|
4916
|
+
* if (!error && paymentIntent?.status === 'succeeded') {
|
|
4917
|
+
* // Clear the cart automatically - handles all scenarios!
|
|
4918
|
+
* const result = omni.handlePaymentSuccess(checkoutId);
|
|
4919
|
+
* console.log('Cart cleared:', result.cleared);
|
|
4920
|
+
* console.log('User type:', result.userType); // 'guest' or 'customer'
|
|
4921
|
+
* }
|
|
4922
|
+
* ```
|
|
4923
|
+
*
|
|
4924
|
+
* @example
|
|
4925
|
+
* ```typescript
|
|
4926
|
+
* // On success page (after redirect)
|
|
4927
|
+
* const checkoutId = new URLSearchParams(location.search).get('checkout_id');
|
|
4928
|
+
* if (checkoutId) {
|
|
4929
|
+
* omni.handlePaymentSuccess(checkoutId);
|
|
4930
|
+
* }
|
|
4931
|
+
* ```
|
|
4932
|
+
*/
|
|
4933
|
+
handlePaymentSuccess(checkoutId?: string): {
|
|
4934
|
+
cleared: boolean;
|
|
4935
|
+
mode: 'full' | 'partial' | 'none';
|
|
4936
|
+
userType: 'guest' | 'customer';
|
|
4937
|
+
itemsRemoved?: number;
|
|
4938
|
+
};
|
|
4939
|
+
/**
|
|
4940
|
+
* Clear the active guest checkout tracking without clearing the cart.
|
|
4941
|
+
* Use this if the user abandons checkout or navigates away.
|
|
4942
|
+
*/
|
|
4943
|
+
clearActiveGuestCheckout(): void;
|
|
4832
4944
|
/**
|
|
4833
4945
|
* Create order from custom data (not from local cart)
|
|
4834
4946
|
* Use this if you manage cart state yourself
|
package/dist/index.d.ts
CHANGED
|
@@ -1692,15 +1692,27 @@ interface ShippingRate {
|
|
|
1692
1692
|
* **Note:** Order is created automatically via webhook when payment succeeds.
|
|
1693
1693
|
* No need to call `completeCheckout()` - it happens automatically.
|
|
1694
1694
|
*
|
|
1695
|
+
* **IMPORTANT: Order Summary Display**
|
|
1696
|
+
* Always use `checkout.lineItems` for displaying the Order Summary during checkout!
|
|
1697
|
+
* This is especially important for **partial checkout** (AliExpress-style) where the user
|
|
1698
|
+
* selects only some items from their cart. The `lineItems` array contains ONLY the items
|
|
1699
|
+
* being purchased in this checkout, NOT the entire cart.
|
|
1700
|
+
*
|
|
1695
1701
|
* **IMPORTANT: Price fields are strings**
|
|
1696
1702
|
* All monetary fields (subtotal, discountAmount, shippingAmount, taxAmount, total)
|
|
1697
1703
|
* are strings to preserve decimal precision. Use parseFloat() for calculations.
|
|
1698
1704
|
*
|
|
1699
1705
|
* @example
|
|
1700
1706
|
* ```typescript
|
|
1701
|
-
* // Display checkout summary
|
|
1707
|
+
* // Display checkout summary - use checkout.lineItems, NOT localCart!
|
|
1702
1708
|
* const checkout = await omni.getCheckout(checkoutId);
|
|
1703
1709
|
*
|
|
1710
|
+
* // Order Summary - ALWAYS use checkout.lineItems
|
|
1711
|
+
* checkout.lineItems.forEach(item => {
|
|
1712
|
+
* console.log(item.product.name, item.quantity, item.unitPrice);
|
|
1713
|
+
* });
|
|
1714
|
+
*
|
|
1715
|
+
* // Totals
|
|
1704
1716
|
* const subtotal = parseFloat(checkout.subtotal);
|
|
1705
1717
|
* const discount = parseFloat(checkout.discountAmount);
|
|
1706
1718
|
* const shipping = parseFloat(checkout.shippingAmount);
|
|
@@ -1712,11 +1724,6 @@ interface ShippingRate {
|
|
|
1712
1724
|
* console.log(`Shipping: $${shipping.toFixed(2)}`);
|
|
1713
1725
|
* console.log(`Tax: $${tax.toFixed(2)}`);
|
|
1714
1726
|
* console.log(`Total: $${total.toFixed(2)}`);
|
|
1715
|
-
*
|
|
1716
|
-
* // Access line items (nested structure)
|
|
1717
|
-
* checkout.lineItems.forEach(item => {
|
|
1718
|
-
* console.log(item.product.name, item.quantity);
|
|
1719
|
-
* });
|
|
1720
1727
|
* ```
|
|
1721
1728
|
*
|
|
1722
1729
|
* @see CheckoutLineItem for item structure
|
|
@@ -3057,6 +3064,11 @@ declare class OmniSyncClient {
|
|
|
3057
3064
|
* When a cart has this ID, operations use localStorage instead of server API.
|
|
3058
3065
|
*/
|
|
3059
3066
|
private readonly VIRTUAL_LOCAL_CART_ID;
|
|
3067
|
+
/**
|
|
3068
|
+
* localStorage key for persisting active checkout across page redirects.
|
|
3069
|
+
* This is needed because Stripe redirects lose in-memory state.
|
|
3070
|
+
*/
|
|
3071
|
+
private readonly ACTIVE_CHECKOUT_KEY;
|
|
3060
3072
|
private readonly onAuthError?;
|
|
3061
3073
|
constructor(options: OmniSyncClientOptions);
|
|
3062
3074
|
/**
|
|
@@ -4748,6 +4760,11 @@ declare class OmniSyncClient {
|
|
|
4748
4760
|
* Pass `selectedIndices` to checkout only specific items from the local cart.
|
|
4749
4761
|
* Use the index of each item in the cart.items array.
|
|
4750
4762
|
*
|
|
4763
|
+
* **IMPORTANT - Order Summary Display:**
|
|
4764
|
+
* After calling this function, use `getCheckout(checkoutId)` to get the checkout
|
|
4765
|
+
* and display `checkout.lineItems` in your Order Summary - NOT the local cart items!
|
|
4766
|
+
* The checkout.lineItems contains ONLY the selected items for this checkout.
|
|
4767
|
+
*
|
|
4751
4768
|
* @param options.selectedIndices - Optional array of item indices for partial checkout
|
|
4752
4769
|
* @returns Tracking result with checkoutId if enabled
|
|
4753
4770
|
*
|
|
@@ -4760,19 +4777,22 @@ declare class OmniSyncClient {
|
|
|
4760
4777
|
* const result = await omni.startGuestCheckout({ selectedIndices: [0, 2] });
|
|
4761
4778
|
*
|
|
4762
4779
|
* if (result.tracked) {
|
|
4763
|
-
* //
|
|
4764
|
-
*
|
|
4780
|
+
* // IMPORTANT: Fetch checkout and use checkout.lineItems for Order Summary!
|
|
4781
|
+
* const checkout = await omni.getCheckout(result.checkoutId);
|
|
4782
|
+
*
|
|
4783
|
+
* // Display Order Summary using checkout.lineItems (NOT localCart.items!)
|
|
4784
|
+
* // checkout.lineItems contains ONLY the selected items
|
|
4785
|
+
* checkout.lineItems.forEach(item => {
|
|
4786
|
+
* console.log(item.product.name, item.quantity, item.unitPrice);
|
|
4787
|
+
* });
|
|
4765
4788
|
*
|
|
4766
4789
|
* // Update checkout with address
|
|
4767
|
-
* await omni.
|
|
4790
|
+
* await omni.updateGuestCheckoutAddress(result.checkoutId, {
|
|
4768
4791
|
* shippingAddress: { ... },
|
|
4769
4792
|
* });
|
|
4770
4793
|
*
|
|
4771
|
-
* //
|
|
4772
|
-
*
|
|
4773
|
-
*
|
|
4774
|
-
* // For partial checkout: remove only purchased items
|
|
4775
|
-
* omni.removeLocalCartItemsByIndex([0, 2]);
|
|
4794
|
+
* // After payment success, call handlePaymentSuccess() to clear cart
|
|
4795
|
+
* omni.handlePaymentSuccess(result.checkoutId);
|
|
4776
4796
|
* } else {
|
|
4777
4797
|
* // Tracking not enabled, use regular submitGuestOrder
|
|
4778
4798
|
* const order = await omni.submitGuestOrder();
|
|
@@ -4782,6 +4802,21 @@ declare class OmniSyncClient {
|
|
|
4782
4802
|
startGuestCheckout(options?: {
|
|
4783
4803
|
selectedIndices?: number[];
|
|
4784
4804
|
}): Promise<GuestCheckoutStartResponse>;
|
|
4805
|
+
/**
|
|
4806
|
+
* Save active checkout to localStorage (persists across page redirects)
|
|
4807
|
+
* @internal
|
|
4808
|
+
*/
|
|
4809
|
+
private saveActiveCheckout;
|
|
4810
|
+
/**
|
|
4811
|
+
* Load active checkout from localStorage
|
|
4812
|
+
* @internal
|
|
4813
|
+
*/
|
|
4814
|
+
private loadActiveCheckout;
|
|
4815
|
+
/**
|
|
4816
|
+
* Clear active checkout from localStorage
|
|
4817
|
+
* @internal
|
|
4818
|
+
*/
|
|
4819
|
+
private clearActiveCheckoutStorage;
|
|
4785
4820
|
/**
|
|
4786
4821
|
* Remove specific items from local cart by their indices.
|
|
4787
4822
|
* Use after partial checkout to remove only the purchased items.
|
|
@@ -4829,6 +4864,83 @@ declare class OmniSyncClient {
|
|
|
4829
4864
|
clearCartOnSuccess?: boolean;
|
|
4830
4865
|
selectedIndices?: number[];
|
|
4831
4866
|
}): Promise<GuestOrderResponse>;
|
|
4867
|
+
/**
|
|
4868
|
+
* Get the active guest checkout session info.
|
|
4869
|
+
* Use this to check if there's an active checkout before handling payment success.
|
|
4870
|
+
*
|
|
4871
|
+
* @returns The active checkout info or null if no checkout is active
|
|
4872
|
+
*
|
|
4873
|
+
* @example
|
|
4874
|
+
* ```typescript
|
|
4875
|
+
* const activeCheckout = omni.getActiveGuestCheckout();
|
|
4876
|
+
* if (activeCheckout) {
|
|
4877
|
+
* console.log('Active checkout:', activeCheckout.checkoutId);
|
|
4878
|
+
* console.log('Partial checkout:', activeCheckout.selectedIndices?.length);
|
|
4879
|
+
* }
|
|
4880
|
+
* ```
|
|
4881
|
+
*/
|
|
4882
|
+
getActiveGuestCheckout(): {
|
|
4883
|
+
checkoutId: string;
|
|
4884
|
+
cartId: string;
|
|
4885
|
+
selectedIndices?: number[];
|
|
4886
|
+
} | null;
|
|
4887
|
+
/**
|
|
4888
|
+
* Handle payment success - automatically clears the cart (both local and server).
|
|
4889
|
+
*
|
|
4890
|
+
* Call this after Stripe payment succeeds (payment_intent.succeeded or confirmPayment success).
|
|
4891
|
+
* This handles ALL checkout scenarios:
|
|
4892
|
+
*
|
|
4893
|
+
* **For guest users (local cart):**
|
|
4894
|
+
* - Full checkout: clears entire localStorage cart
|
|
4895
|
+
* - Partial checkout: removes only the purchased items
|
|
4896
|
+
*
|
|
4897
|
+
* **For logged-in users (server cart):**
|
|
4898
|
+
* - Clears the cached cart ID so next `smartGetCart()` fetches fresh data
|
|
4899
|
+
* - The server cart is already marked as CONVERTED by the webhook
|
|
4900
|
+
*
|
|
4901
|
+
* **IMPORTANT:** Call this from your payment success handler (e.g., after stripe.confirmPayment succeeds,
|
|
4902
|
+
* or on your success page after redirect). This works for both guests AND logged-in users!
|
|
4903
|
+
*
|
|
4904
|
+
* @param checkoutId - Optional checkout ID for validation
|
|
4905
|
+
* @returns Object indicating whether cart was cleared and how
|
|
4906
|
+
*
|
|
4907
|
+
* @example
|
|
4908
|
+
* ```typescript
|
|
4909
|
+
* // After stripe.confirmPayment() succeeds (works for guests AND logged-in users)
|
|
4910
|
+
* const { error, paymentIntent } = await stripe.confirmPayment({
|
|
4911
|
+
* elements,
|
|
4912
|
+
* confirmParams: { return_url: '/checkout/success' },
|
|
4913
|
+
* redirect: 'if_required',
|
|
4914
|
+
* });
|
|
4915
|
+
*
|
|
4916
|
+
* if (!error && paymentIntent?.status === 'succeeded') {
|
|
4917
|
+
* // Clear the cart automatically - handles all scenarios!
|
|
4918
|
+
* const result = omni.handlePaymentSuccess(checkoutId);
|
|
4919
|
+
* console.log('Cart cleared:', result.cleared);
|
|
4920
|
+
* console.log('User type:', result.userType); // 'guest' or 'customer'
|
|
4921
|
+
* }
|
|
4922
|
+
* ```
|
|
4923
|
+
*
|
|
4924
|
+
* @example
|
|
4925
|
+
* ```typescript
|
|
4926
|
+
* // On success page (after redirect)
|
|
4927
|
+
* const checkoutId = new URLSearchParams(location.search).get('checkout_id');
|
|
4928
|
+
* if (checkoutId) {
|
|
4929
|
+
* omni.handlePaymentSuccess(checkoutId);
|
|
4930
|
+
* }
|
|
4931
|
+
* ```
|
|
4932
|
+
*/
|
|
4933
|
+
handlePaymentSuccess(checkoutId?: string): {
|
|
4934
|
+
cleared: boolean;
|
|
4935
|
+
mode: 'full' | 'partial' | 'none';
|
|
4936
|
+
userType: 'guest' | 'customer';
|
|
4937
|
+
itemsRemoved?: number;
|
|
4938
|
+
};
|
|
4939
|
+
/**
|
|
4940
|
+
* Clear the active guest checkout tracking without clearing the cart.
|
|
4941
|
+
* Use this if the user abandons checkout or navigates away.
|
|
4942
|
+
*/
|
|
4943
|
+
clearActiveGuestCheckout(): void;
|
|
4832
4944
|
/**
|
|
4833
4945
|
* Create order from custom data (not from local cart)
|
|
4834
4946
|
* Use this if you manage cart state yourself
|
package/dist/index.js
CHANGED
|
@@ -54,6 +54,11 @@ var OmniSyncClient = class {
|
|
|
54
54
|
* When a cart has this ID, operations use localStorage instead of server API.
|
|
55
55
|
*/
|
|
56
56
|
this.VIRTUAL_LOCAL_CART_ID = "__local__";
|
|
57
|
+
/**
|
|
58
|
+
* localStorage key for persisting active checkout across page redirects.
|
|
59
|
+
* This is needed because Stripe redirects lose in-memory state.
|
|
60
|
+
*/
|
|
61
|
+
this.ACTIVE_CHECKOUT_KEY = "omni_active_checkout";
|
|
57
62
|
// -------------------- Local Cart (Client-Side for Guests) --------------------
|
|
58
63
|
// These methods store cart data in localStorage - NO API calls!
|
|
59
64
|
// Use for guest users in vibe-coded sites
|
|
@@ -2255,6 +2260,12 @@ var OmniSyncClient = class {
|
|
|
2255
2260
|
* ```
|
|
2256
2261
|
*/
|
|
2257
2262
|
async createCheckout(data) {
|
|
2263
|
+
if (data.cartId === this.VIRTUAL_LOCAL_CART_ID) {
|
|
2264
|
+
throw new OmniSyncError(
|
|
2265
|
+
"Cannot create checkout from local cart directly. Use startGuestCheckout() for guest checkout with localStorage cart, or sync cart to server first with syncCartOnLogin().",
|
|
2266
|
+
400
|
|
2267
|
+
);
|
|
2268
|
+
}
|
|
2258
2269
|
if (this.isVibeCodedMode()) {
|
|
2259
2270
|
return this.vibeCodedRequest("POST", "/checkout", data);
|
|
2260
2271
|
}
|
|
@@ -3069,6 +3080,11 @@ var OmniSyncClient = class {
|
|
|
3069
3080
|
* Pass `selectedIndices` to checkout only specific items from the local cart.
|
|
3070
3081
|
* Use the index of each item in the cart.items array.
|
|
3071
3082
|
*
|
|
3083
|
+
* **IMPORTANT - Order Summary Display:**
|
|
3084
|
+
* After calling this function, use `getCheckout(checkoutId)` to get the checkout
|
|
3085
|
+
* and display `checkout.lineItems` in your Order Summary - NOT the local cart items!
|
|
3086
|
+
* The checkout.lineItems contains ONLY the selected items for this checkout.
|
|
3087
|
+
*
|
|
3072
3088
|
* @param options.selectedIndices - Optional array of item indices for partial checkout
|
|
3073
3089
|
* @returns Tracking result with checkoutId if enabled
|
|
3074
3090
|
*
|
|
@@ -3081,19 +3097,22 @@ var OmniSyncClient = class {
|
|
|
3081
3097
|
* const result = await omni.startGuestCheckout({ selectedIndices: [0, 2] });
|
|
3082
3098
|
*
|
|
3083
3099
|
* if (result.tracked) {
|
|
3084
|
-
* //
|
|
3085
|
-
*
|
|
3100
|
+
* // IMPORTANT: Fetch checkout and use checkout.lineItems for Order Summary!
|
|
3101
|
+
* const checkout = await omni.getCheckout(result.checkoutId);
|
|
3102
|
+
*
|
|
3103
|
+
* // Display Order Summary using checkout.lineItems (NOT localCart.items!)
|
|
3104
|
+
* // checkout.lineItems contains ONLY the selected items
|
|
3105
|
+
* checkout.lineItems.forEach(item => {
|
|
3106
|
+
* console.log(item.product.name, item.quantity, item.unitPrice);
|
|
3107
|
+
* });
|
|
3086
3108
|
*
|
|
3087
3109
|
* // Update checkout with address
|
|
3088
|
-
* await omni.
|
|
3110
|
+
* await omni.updateGuestCheckoutAddress(result.checkoutId, {
|
|
3089
3111
|
* shippingAddress: { ... },
|
|
3090
3112
|
* });
|
|
3091
3113
|
*
|
|
3092
|
-
* //
|
|
3093
|
-
*
|
|
3094
|
-
*
|
|
3095
|
-
* // For partial checkout: remove only purchased items
|
|
3096
|
-
* omni.removeLocalCartItemsByIndex([0, 2]);
|
|
3114
|
+
* // After payment success, call handlePaymentSuccess() to clear cart
|
|
3115
|
+
* omni.handlePaymentSuccess(result.checkoutId);
|
|
3097
3116
|
* } else {
|
|
3098
3117
|
* // Tracking not enabled, use regular submitGuestOrder
|
|
3099
3118
|
* const order = await omni.submitGuestOrder();
|
|
@@ -3121,8 +3140,48 @@ var OmniSyncClient = class {
|
|
|
3121
3140
|
customer: cart.customer
|
|
3122
3141
|
}
|
|
3123
3142
|
);
|
|
3143
|
+
if (response.tracked && response.checkoutId && response.cartId) {
|
|
3144
|
+
this.saveActiveCheckout({
|
|
3145
|
+
checkoutId: response.checkoutId,
|
|
3146
|
+
cartId: response.cartId,
|
|
3147
|
+
selectedIndices: options?.selectedIndices
|
|
3148
|
+
});
|
|
3149
|
+
}
|
|
3124
3150
|
return response;
|
|
3125
3151
|
}
|
|
3152
|
+
/**
|
|
3153
|
+
* Save active checkout to localStorage (persists across page redirects)
|
|
3154
|
+
* @internal
|
|
3155
|
+
*/
|
|
3156
|
+
saveActiveCheckout(checkout) {
|
|
3157
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
3158
|
+
localStorage.setItem(this.ACTIVE_CHECKOUT_KEY, JSON.stringify(checkout));
|
|
3159
|
+
}
|
|
3160
|
+
}
|
|
3161
|
+
/**
|
|
3162
|
+
* Load active checkout from localStorage
|
|
3163
|
+
* @internal
|
|
3164
|
+
*/
|
|
3165
|
+
loadActiveCheckout() {
|
|
3166
|
+
if (typeof window === "undefined" || !window.localStorage) {
|
|
3167
|
+
return null;
|
|
3168
|
+
}
|
|
3169
|
+
try {
|
|
3170
|
+
const data = localStorage.getItem(this.ACTIVE_CHECKOUT_KEY);
|
|
3171
|
+
return data ? JSON.parse(data) : null;
|
|
3172
|
+
} catch {
|
|
3173
|
+
return null;
|
|
3174
|
+
}
|
|
3175
|
+
}
|
|
3176
|
+
/**
|
|
3177
|
+
* Clear active checkout from localStorage
|
|
3178
|
+
* @internal
|
|
3179
|
+
*/
|
|
3180
|
+
clearActiveCheckoutStorage() {
|
|
3181
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
3182
|
+
localStorage.removeItem(this.ACTIVE_CHECKOUT_KEY);
|
|
3183
|
+
}
|
|
3184
|
+
}
|
|
3126
3185
|
/**
|
|
3127
3186
|
* Remove specific items from local cart by their indices.
|
|
3128
3187
|
* Use after partial checkout to remove only the purchased items.
|
|
@@ -3213,6 +3272,113 @@ var OmniSyncClient = class {
|
|
|
3213
3272
|
}
|
|
3214
3273
|
return result;
|
|
3215
3274
|
}
|
|
3275
|
+
/**
|
|
3276
|
+
* Get the active guest checkout session info.
|
|
3277
|
+
* Use this to check if there's an active checkout before handling payment success.
|
|
3278
|
+
*
|
|
3279
|
+
* @returns The active checkout info or null if no checkout is active
|
|
3280
|
+
*
|
|
3281
|
+
* @example
|
|
3282
|
+
* ```typescript
|
|
3283
|
+
* const activeCheckout = omni.getActiveGuestCheckout();
|
|
3284
|
+
* if (activeCheckout) {
|
|
3285
|
+
* console.log('Active checkout:', activeCheckout.checkoutId);
|
|
3286
|
+
* console.log('Partial checkout:', activeCheckout.selectedIndices?.length);
|
|
3287
|
+
* }
|
|
3288
|
+
* ```
|
|
3289
|
+
*/
|
|
3290
|
+
getActiveGuestCheckout() {
|
|
3291
|
+
return this.loadActiveCheckout();
|
|
3292
|
+
}
|
|
3293
|
+
/**
|
|
3294
|
+
* Handle payment success - automatically clears the cart (both local and server).
|
|
3295
|
+
*
|
|
3296
|
+
* Call this after Stripe payment succeeds (payment_intent.succeeded or confirmPayment success).
|
|
3297
|
+
* This handles ALL checkout scenarios:
|
|
3298
|
+
*
|
|
3299
|
+
* **For guest users (local cart):**
|
|
3300
|
+
* - Full checkout: clears entire localStorage cart
|
|
3301
|
+
* - Partial checkout: removes only the purchased items
|
|
3302
|
+
*
|
|
3303
|
+
* **For logged-in users (server cart):**
|
|
3304
|
+
* - Clears the cached cart ID so next `smartGetCart()` fetches fresh data
|
|
3305
|
+
* - The server cart is already marked as CONVERTED by the webhook
|
|
3306
|
+
*
|
|
3307
|
+
* **IMPORTANT:** Call this from your payment success handler (e.g., after stripe.confirmPayment succeeds,
|
|
3308
|
+
* or on your success page after redirect). This works for both guests AND logged-in users!
|
|
3309
|
+
*
|
|
3310
|
+
* @param checkoutId - Optional checkout ID for validation
|
|
3311
|
+
* @returns Object indicating whether cart was cleared and how
|
|
3312
|
+
*
|
|
3313
|
+
* @example
|
|
3314
|
+
* ```typescript
|
|
3315
|
+
* // After stripe.confirmPayment() succeeds (works for guests AND logged-in users)
|
|
3316
|
+
* const { error, paymentIntent } = await stripe.confirmPayment({
|
|
3317
|
+
* elements,
|
|
3318
|
+
* confirmParams: { return_url: '/checkout/success' },
|
|
3319
|
+
* redirect: 'if_required',
|
|
3320
|
+
* });
|
|
3321
|
+
*
|
|
3322
|
+
* if (!error && paymentIntent?.status === 'succeeded') {
|
|
3323
|
+
* // Clear the cart automatically - handles all scenarios!
|
|
3324
|
+
* const result = omni.handlePaymentSuccess(checkoutId);
|
|
3325
|
+
* console.log('Cart cleared:', result.cleared);
|
|
3326
|
+
* console.log('User type:', result.userType); // 'guest' or 'customer'
|
|
3327
|
+
* }
|
|
3328
|
+
* ```
|
|
3329
|
+
*
|
|
3330
|
+
* @example
|
|
3331
|
+
* ```typescript
|
|
3332
|
+
* // On success page (after redirect)
|
|
3333
|
+
* const checkoutId = new URLSearchParams(location.search).get('checkout_id');
|
|
3334
|
+
* if (checkoutId) {
|
|
3335
|
+
* omni.handlePaymentSuccess(checkoutId);
|
|
3336
|
+
* }
|
|
3337
|
+
* ```
|
|
3338
|
+
*/
|
|
3339
|
+
handlePaymentSuccess(checkoutId) {
|
|
3340
|
+
const isLoggedIn = this.isCustomerLoggedIn();
|
|
3341
|
+
if (isLoggedIn) {
|
|
3342
|
+
this.customerCartId = null;
|
|
3343
|
+
}
|
|
3344
|
+
const activeCheckout = this.loadActiveCheckout();
|
|
3345
|
+
if (checkoutId && activeCheckout && activeCheckout.checkoutId !== checkoutId) {
|
|
3346
|
+
console.warn(
|
|
3347
|
+
`handlePaymentSuccess: checkoutId mismatch. Expected ${activeCheckout.checkoutId}, got ${checkoutId}. Proceeding with cleanup.`
|
|
3348
|
+
);
|
|
3349
|
+
}
|
|
3350
|
+
this.clearActiveCheckoutStorage();
|
|
3351
|
+
if (isLoggedIn) {
|
|
3352
|
+
this.clearLocalCart();
|
|
3353
|
+
return {
|
|
3354
|
+
cleared: true,
|
|
3355
|
+
mode: "full",
|
|
3356
|
+
userType: "customer"
|
|
3357
|
+
};
|
|
3358
|
+
}
|
|
3359
|
+
if (activeCheckout?.selectedIndices && activeCheckout.selectedIndices.length > 0) {
|
|
3360
|
+
this.removeLocalCartItemsByIndex(activeCheckout.selectedIndices);
|
|
3361
|
+
return {
|
|
3362
|
+
cleared: true,
|
|
3363
|
+
mode: "partial",
|
|
3364
|
+
userType: "guest",
|
|
3365
|
+
itemsRemoved: activeCheckout.selectedIndices.length
|
|
3366
|
+
};
|
|
3367
|
+
}
|
|
3368
|
+
this.clearLocalCart();
|
|
3369
|
+
return {
|
|
3370
|
+
cleared: true,
|
|
3371
|
+
mode: "full",
|
|
3372
|
+
userType: "guest"
|
|
3373
|
+
};
|
|
3374
|
+
}
|
|
3375
|
+
/**
|
|
3376
|
+
* Clear the active guest checkout tracking without clearing the cart.
|
|
3377
|
+
* Use this if the user abandons checkout or navigates away.
|
|
3378
|
+
*/
|
|
3379
|
+
clearActiveGuestCheckout() {
|
|
3380
|
+
this.clearActiveCheckoutStorage();
|
|
3381
|
+
}
|
|
3216
3382
|
/**
|
|
3217
3383
|
* Create order from custom data (not from local cart)
|
|
3218
3384
|
* Use this if you manage cart state yourself
|
package/dist/index.mjs
CHANGED
|
@@ -17,6 +17,11 @@ var OmniSyncClient = class {
|
|
|
17
17
|
* When a cart has this ID, operations use localStorage instead of server API.
|
|
18
18
|
*/
|
|
19
19
|
this.VIRTUAL_LOCAL_CART_ID = "__local__";
|
|
20
|
+
/**
|
|
21
|
+
* localStorage key for persisting active checkout across page redirects.
|
|
22
|
+
* This is needed because Stripe redirects lose in-memory state.
|
|
23
|
+
*/
|
|
24
|
+
this.ACTIVE_CHECKOUT_KEY = "omni_active_checkout";
|
|
20
25
|
// -------------------- Local Cart (Client-Side for Guests) --------------------
|
|
21
26
|
// These methods store cart data in localStorage - NO API calls!
|
|
22
27
|
// Use for guest users in vibe-coded sites
|
|
@@ -2218,6 +2223,12 @@ var OmniSyncClient = class {
|
|
|
2218
2223
|
* ```
|
|
2219
2224
|
*/
|
|
2220
2225
|
async createCheckout(data) {
|
|
2226
|
+
if (data.cartId === this.VIRTUAL_LOCAL_CART_ID) {
|
|
2227
|
+
throw new OmniSyncError(
|
|
2228
|
+
"Cannot create checkout from local cart directly. Use startGuestCheckout() for guest checkout with localStorage cart, or sync cart to server first with syncCartOnLogin().",
|
|
2229
|
+
400
|
|
2230
|
+
);
|
|
2231
|
+
}
|
|
2221
2232
|
if (this.isVibeCodedMode()) {
|
|
2222
2233
|
return this.vibeCodedRequest("POST", "/checkout", data);
|
|
2223
2234
|
}
|
|
@@ -3032,6 +3043,11 @@ var OmniSyncClient = class {
|
|
|
3032
3043
|
* Pass `selectedIndices` to checkout only specific items from the local cart.
|
|
3033
3044
|
* Use the index of each item in the cart.items array.
|
|
3034
3045
|
*
|
|
3046
|
+
* **IMPORTANT - Order Summary Display:**
|
|
3047
|
+
* After calling this function, use `getCheckout(checkoutId)` to get the checkout
|
|
3048
|
+
* and display `checkout.lineItems` in your Order Summary - NOT the local cart items!
|
|
3049
|
+
* The checkout.lineItems contains ONLY the selected items for this checkout.
|
|
3050
|
+
*
|
|
3035
3051
|
* @param options.selectedIndices - Optional array of item indices for partial checkout
|
|
3036
3052
|
* @returns Tracking result with checkoutId if enabled
|
|
3037
3053
|
*
|
|
@@ -3044,19 +3060,22 @@ var OmniSyncClient = class {
|
|
|
3044
3060
|
* const result = await omni.startGuestCheckout({ selectedIndices: [0, 2] });
|
|
3045
3061
|
*
|
|
3046
3062
|
* if (result.tracked) {
|
|
3047
|
-
* //
|
|
3048
|
-
*
|
|
3063
|
+
* // IMPORTANT: Fetch checkout and use checkout.lineItems for Order Summary!
|
|
3064
|
+
* const checkout = await omni.getCheckout(result.checkoutId);
|
|
3065
|
+
*
|
|
3066
|
+
* // Display Order Summary using checkout.lineItems (NOT localCart.items!)
|
|
3067
|
+
* // checkout.lineItems contains ONLY the selected items
|
|
3068
|
+
* checkout.lineItems.forEach(item => {
|
|
3069
|
+
* console.log(item.product.name, item.quantity, item.unitPrice);
|
|
3070
|
+
* });
|
|
3049
3071
|
*
|
|
3050
3072
|
* // Update checkout with address
|
|
3051
|
-
* await omni.
|
|
3073
|
+
* await omni.updateGuestCheckoutAddress(result.checkoutId, {
|
|
3052
3074
|
* shippingAddress: { ... },
|
|
3053
3075
|
* });
|
|
3054
3076
|
*
|
|
3055
|
-
* //
|
|
3056
|
-
*
|
|
3057
|
-
*
|
|
3058
|
-
* // For partial checkout: remove only purchased items
|
|
3059
|
-
* omni.removeLocalCartItemsByIndex([0, 2]);
|
|
3077
|
+
* // After payment success, call handlePaymentSuccess() to clear cart
|
|
3078
|
+
* omni.handlePaymentSuccess(result.checkoutId);
|
|
3060
3079
|
* } else {
|
|
3061
3080
|
* // Tracking not enabled, use regular submitGuestOrder
|
|
3062
3081
|
* const order = await omni.submitGuestOrder();
|
|
@@ -3084,8 +3103,48 @@ var OmniSyncClient = class {
|
|
|
3084
3103
|
customer: cart.customer
|
|
3085
3104
|
}
|
|
3086
3105
|
);
|
|
3106
|
+
if (response.tracked && response.checkoutId && response.cartId) {
|
|
3107
|
+
this.saveActiveCheckout({
|
|
3108
|
+
checkoutId: response.checkoutId,
|
|
3109
|
+
cartId: response.cartId,
|
|
3110
|
+
selectedIndices: options?.selectedIndices
|
|
3111
|
+
});
|
|
3112
|
+
}
|
|
3087
3113
|
return response;
|
|
3088
3114
|
}
|
|
3115
|
+
/**
|
|
3116
|
+
* Save active checkout to localStorage (persists across page redirects)
|
|
3117
|
+
* @internal
|
|
3118
|
+
*/
|
|
3119
|
+
saveActiveCheckout(checkout) {
|
|
3120
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
3121
|
+
localStorage.setItem(this.ACTIVE_CHECKOUT_KEY, JSON.stringify(checkout));
|
|
3122
|
+
}
|
|
3123
|
+
}
|
|
3124
|
+
/**
|
|
3125
|
+
* Load active checkout from localStorage
|
|
3126
|
+
* @internal
|
|
3127
|
+
*/
|
|
3128
|
+
loadActiveCheckout() {
|
|
3129
|
+
if (typeof window === "undefined" || !window.localStorage) {
|
|
3130
|
+
return null;
|
|
3131
|
+
}
|
|
3132
|
+
try {
|
|
3133
|
+
const data = localStorage.getItem(this.ACTIVE_CHECKOUT_KEY);
|
|
3134
|
+
return data ? JSON.parse(data) : null;
|
|
3135
|
+
} catch {
|
|
3136
|
+
return null;
|
|
3137
|
+
}
|
|
3138
|
+
}
|
|
3139
|
+
/**
|
|
3140
|
+
* Clear active checkout from localStorage
|
|
3141
|
+
* @internal
|
|
3142
|
+
*/
|
|
3143
|
+
clearActiveCheckoutStorage() {
|
|
3144
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
3145
|
+
localStorage.removeItem(this.ACTIVE_CHECKOUT_KEY);
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3089
3148
|
/**
|
|
3090
3149
|
* Remove specific items from local cart by their indices.
|
|
3091
3150
|
* Use after partial checkout to remove only the purchased items.
|
|
@@ -3176,6 +3235,113 @@ var OmniSyncClient = class {
|
|
|
3176
3235
|
}
|
|
3177
3236
|
return result;
|
|
3178
3237
|
}
|
|
3238
|
+
/**
|
|
3239
|
+
* Get the active guest checkout session info.
|
|
3240
|
+
* Use this to check if there's an active checkout before handling payment success.
|
|
3241
|
+
*
|
|
3242
|
+
* @returns The active checkout info or null if no checkout is active
|
|
3243
|
+
*
|
|
3244
|
+
* @example
|
|
3245
|
+
* ```typescript
|
|
3246
|
+
* const activeCheckout = omni.getActiveGuestCheckout();
|
|
3247
|
+
* if (activeCheckout) {
|
|
3248
|
+
* console.log('Active checkout:', activeCheckout.checkoutId);
|
|
3249
|
+
* console.log('Partial checkout:', activeCheckout.selectedIndices?.length);
|
|
3250
|
+
* }
|
|
3251
|
+
* ```
|
|
3252
|
+
*/
|
|
3253
|
+
getActiveGuestCheckout() {
|
|
3254
|
+
return this.loadActiveCheckout();
|
|
3255
|
+
}
|
|
3256
|
+
/**
|
|
3257
|
+
* Handle payment success - automatically clears the cart (both local and server).
|
|
3258
|
+
*
|
|
3259
|
+
* Call this after Stripe payment succeeds (payment_intent.succeeded or confirmPayment success).
|
|
3260
|
+
* This handles ALL checkout scenarios:
|
|
3261
|
+
*
|
|
3262
|
+
* **For guest users (local cart):**
|
|
3263
|
+
* - Full checkout: clears entire localStorage cart
|
|
3264
|
+
* - Partial checkout: removes only the purchased items
|
|
3265
|
+
*
|
|
3266
|
+
* **For logged-in users (server cart):**
|
|
3267
|
+
* - Clears the cached cart ID so next `smartGetCart()` fetches fresh data
|
|
3268
|
+
* - The server cart is already marked as CONVERTED by the webhook
|
|
3269
|
+
*
|
|
3270
|
+
* **IMPORTANT:** Call this from your payment success handler (e.g., after stripe.confirmPayment succeeds,
|
|
3271
|
+
* or on your success page after redirect). This works for both guests AND logged-in users!
|
|
3272
|
+
*
|
|
3273
|
+
* @param checkoutId - Optional checkout ID for validation
|
|
3274
|
+
* @returns Object indicating whether cart was cleared and how
|
|
3275
|
+
*
|
|
3276
|
+
* @example
|
|
3277
|
+
* ```typescript
|
|
3278
|
+
* // After stripe.confirmPayment() succeeds (works for guests AND logged-in users)
|
|
3279
|
+
* const { error, paymentIntent } = await stripe.confirmPayment({
|
|
3280
|
+
* elements,
|
|
3281
|
+
* confirmParams: { return_url: '/checkout/success' },
|
|
3282
|
+
* redirect: 'if_required',
|
|
3283
|
+
* });
|
|
3284
|
+
*
|
|
3285
|
+
* if (!error && paymentIntent?.status === 'succeeded') {
|
|
3286
|
+
* // Clear the cart automatically - handles all scenarios!
|
|
3287
|
+
* const result = omni.handlePaymentSuccess(checkoutId);
|
|
3288
|
+
* console.log('Cart cleared:', result.cleared);
|
|
3289
|
+
* console.log('User type:', result.userType); // 'guest' or 'customer'
|
|
3290
|
+
* }
|
|
3291
|
+
* ```
|
|
3292
|
+
*
|
|
3293
|
+
* @example
|
|
3294
|
+
* ```typescript
|
|
3295
|
+
* // On success page (after redirect)
|
|
3296
|
+
* const checkoutId = new URLSearchParams(location.search).get('checkout_id');
|
|
3297
|
+
* if (checkoutId) {
|
|
3298
|
+
* omni.handlePaymentSuccess(checkoutId);
|
|
3299
|
+
* }
|
|
3300
|
+
* ```
|
|
3301
|
+
*/
|
|
3302
|
+
handlePaymentSuccess(checkoutId) {
|
|
3303
|
+
const isLoggedIn = this.isCustomerLoggedIn();
|
|
3304
|
+
if (isLoggedIn) {
|
|
3305
|
+
this.customerCartId = null;
|
|
3306
|
+
}
|
|
3307
|
+
const activeCheckout = this.loadActiveCheckout();
|
|
3308
|
+
if (checkoutId && activeCheckout && activeCheckout.checkoutId !== checkoutId) {
|
|
3309
|
+
console.warn(
|
|
3310
|
+
`handlePaymentSuccess: checkoutId mismatch. Expected ${activeCheckout.checkoutId}, got ${checkoutId}. Proceeding with cleanup.`
|
|
3311
|
+
);
|
|
3312
|
+
}
|
|
3313
|
+
this.clearActiveCheckoutStorage();
|
|
3314
|
+
if (isLoggedIn) {
|
|
3315
|
+
this.clearLocalCart();
|
|
3316
|
+
return {
|
|
3317
|
+
cleared: true,
|
|
3318
|
+
mode: "full",
|
|
3319
|
+
userType: "customer"
|
|
3320
|
+
};
|
|
3321
|
+
}
|
|
3322
|
+
if (activeCheckout?.selectedIndices && activeCheckout.selectedIndices.length > 0) {
|
|
3323
|
+
this.removeLocalCartItemsByIndex(activeCheckout.selectedIndices);
|
|
3324
|
+
return {
|
|
3325
|
+
cleared: true,
|
|
3326
|
+
mode: "partial",
|
|
3327
|
+
userType: "guest",
|
|
3328
|
+
itemsRemoved: activeCheckout.selectedIndices.length
|
|
3329
|
+
};
|
|
3330
|
+
}
|
|
3331
|
+
this.clearLocalCart();
|
|
3332
|
+
return {
|
|
3333
|
+
cleared: true,
|
|
3334
|
+
mode: "full",
|
|
3335
|
+
userType: "guest"
|
|
3336
|
+
};
|
|
3337
|
+
}
|
|
3338
|
+
/**
|
|
3339
|
+
* Clear the active guest checkout tracking without clearing the cart.
|
|
3340
|
+
* Use this if the user abandons checkout or navigates away.
|
|
3341
|
+
*/
|
|
3342
|
+
clearActiveGuestCheckout() {
|
|
3343
|
+
this.clearActiveCheckoutStorage();
|
|
3344
|
+
}
|
|
3179
3345
|
/**
|
|
3180
3346
|
* Create order from custom data (not from local cart)
|
|
3181
3347
|
* Use this if you manage cart state yourself
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omni-sync-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.1",
|
|
4
4
|
"description": "Official SDK for building e-commerce storefronts with OmniSync Platform. Perfect for vibe-coded sites, AI-built stores (Cursor, Lovable, v0), and custom storefronts.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -16,14 +16,6 @@
|
|
|
16
16
|
"dist",
|
|
17
17
|
"README.md"
|
|
18
18
|
],
|
|
19
|
-
"scripts": {
|
|
20
|
-
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
21
|
-
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
22
|
-
"lint": "eslint \"src/**/*.ts\"",
|
|
23
|
-
"test": "vitest run",
|
|
24
|
-
"test:watch": "vitest",
|
|
25
|
-
"prepublishOnly": "pnpm build"
|
|
26
|
-
},
|
|
27
19
|
"keywords": [
|
|
28
20
|
"omni-sync",
|
|
29
21
|
"e-commerce",
|
|
@@ -72,5 +64,12 @@
|
|
|
72
64
|
"typescript": {
|
|
73
65
|
"optional": true
|
|
74
66
|
}
|
|
67
|
+
},
|
|
68
|
+
"scripts": {
|
|
69
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
70
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
71
|
+
"lint": "eslint \"src/**/*.ts\"",
|
|
72
|
+
"test": "vitest run",
|
|
73
|
+
"test:watch": "vitest"
|
|
75
74
|
}
|
|
76
|
-
}
|
|
75
|
+
}
|