brainerce 1.0.1 → 1.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 CHANGED
@@ -179,9 +179,16 @@ var BrainerceClient = class {
179
179
  constructor(options) {
180
180
  this.customerToken = null;
181
181
  this.customerCartId = null;
182
+ // Session cart state (server-side guest carts)
183
+ this.sessionCartId = null;
184
+ this.sessionToken = null;
185
+ this._sessionCartPromise = null;
186
+ this._migrationDone = false;
187
+ /** localStorage key for session cart reference (sessionToken + cartId) */
188
+ this.SESSION_CART_KEY = "brainerce_session";
182
189
  /**
183
190
  * Virtual cart ID used for localStorage carts (guest users not logged in).
184
- * When a cart has this ID, operations use localStorage instead of server API.
191
+ * @deprecated Guest carts now use server-side sessions. Kept for backward compatibility.
185
192
  */
186
193
  this.VIRTUAL_LOCAL_CART_ID = "__local__";
187
194
  /**
@@ -213,6 +220,7 @@ var BrainerceClient = class {
213
220
  this.baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
214
221
  this.timeout = options.timeout || DEFAULT_TIMEOUT;
215
222
  this.onAuthError = options.onAuthError;
223
+ this.hydrateSessionCart();
216
224
  }
217
225
  withGuards(result, type) {
218
226
  if (!isDevGuardsEnabled()) return result;
@@ -1911,10 +1919,6 @@ var BrainerceClient = class {
1911
1919
  * ```
1912
1920
  */
1913
1921
  async createCart() {
1914
- if (this.isVibeCodedMode() && !this.isCustomerLoggedIn()) {
1915
- const localCart = this.getLocalCart();
1916
- return this.localCartToCart(localCart);
1917
- }
1918
1922
  if (this.isVibeCodedMode()) {
1919
1923
  return this.vibeCodedRequest("POST", "/cart");
1920
1924
  }
@@ -1933,6 +1937,9 @@ var BrainerceClient = class {
1933
1937
  * ```
1934
1938
  */
1935
1939
  async getCartBySession(sessionToken) {
1940
+ if (this.isVibeCodedMode()) {
1941
+ return this.vibeCodedRequest("GET", `/cart/session/${sessionToken}`);
1942
+ }
1936
1943
  if (this.storeId && !this.apiKey) {
1937
1944
  return this.storefrontRequest("GET", `/cart/session/${sessionToken}`);
1938
1945
  }
@@ -1958,6 +1965,7 @@ var BrainerceClient = class {
1958
1965
  */
1959
1966
  async getCart(cartId) {
1960
1967
  if (cartId === this.VIRTUAL_LOCAL_CART_ID) {
1968
+ console.warn('getCart("__local__") is deprecated. Use smartGetCart() instead.');
1961
1969
  return this.withGuards(this.localCartToCart(this.getLocalCart()), "cart");
1962
1970
  }
1963
1971
  if (this.isVibeCodedMode()) {
@@ -1982,38 +1990,14 @@ var BrainerceClient = class {
1982
1990
  */
1983
1991
  async addToCart(cartId, item) {
1984
1992
  if (cartId === this.VIRTUAL_LOCAL_CART_ID) {
1985
- let productName = "Unknown Product";
1986
- let productPrice = "0";
1987
- let productImage;
1988
- if (item.productInfo) {
1989
- productName = item.productInfo.name;
1990
- productPrice = item.productInfo.price;
1991
- productImage = item.productInfo.image;
1992
- } else {
1993
- try {
1994
- const product = await this.getProduct(item.productId);
1995
- productName = product.name;
1996
- productPrice = product.salePrice || product.basePrice;
1997
- productImage = product.images?.[0]?.url;
1998
- if (item.variantId && product.variants) {
1999
- const variant = product.variants.find((v) => v.id === item.variantId);
2000
- if (variant) {
2001
- productPrice = variant.salePrice || variant.price || productPrice;
2002
- if (variant.image) {
2003
- productImage = typeof variant.image === "string" ? variant.image : variant.image.url;
2004
- }
2005
- }
2006
- }
2007
- } catch {
2008
- }
2009
- }
1993
+ console.warn('addToCart("__local__", ...) is deprecated. Use smartAddToCart() instead.');
2010
1994
  this.addToLocalCart({
2011
1995
  productId: item.productId,
2012
1996
  variantId: item.variantId,
2013
1997
  quantity: item.quantity,
2014
- name: productName,
2015
- price: productPrice,
2016
- image: productImage
1998
+ name: item.productInfo?.name || "Unknown Product",
1999
+ price: item.productInfo?.price || "0",
2000
+ image: item.productInfo?.image
2017
2001
  });
2018
2002
  return this.withGuards(this.localCartToCart(this.getLocalCart()), "cart");
2019
2003
  }
@@ -2044,6 +2028,9 @@ var BrainerceClient = class {
2044
2028
  */
2045
2029
  async updateCartItem(cartId, itemId, data) {
2046
2030
  if (cartId === this.VIRTUAL_LOCAL_CART_ID) {
2031
+ console.warn(
2032
+ 'updateCartItem("__local__", ...) is deprecated. Use smartUpdateCartItem() instead.'
2033
+ );
2047
2034
  const index = parseInt(itemId.replace("local_", ""), 10);
2048
2035
  const localCart = this.getLocalCart();
2049
2036
  if (index >= 0 && index < localCart.items.length) {
@@ -2079,6 +2066,9 @@ var BrainerceClient = class {
2079
2066
  */
2080
2067
  async removeCartItem(cartId, itemId) {
2081
2068
  if (cartId === this.VIRTUAL_LOCAL_CART_ID) {
2069
+ console.warn(
2070
+ 'removeCartItem("__local__", ...) is deprecated. Use smartRemoveFromCart() instead.'
2071
+ );
2082
2072
  const index = parseInt(itemId.replace("local_", ""), 10);
2083
2073
  const localCart = this.getLocalCart();
2084
2074
  if (index >= 0 && index < localCart.items.length) {
@@ -2114,6 +2104,9 @@ var BrainerceClient = class {
2114
2104
  */
2115
2105
  async clearCart(cartId) {
2116
2106
  if (cartId === this.VIRTUAL_LOCAL_CART_ID) {
2107
+ console.warn(
2108
+ 'clearCart("__local__") is deprecated. Use onCheckoutComplete() or clearLocalCart() directly.'
2109
+ );
2117
2110
  this.clearLocalCart();
2118
2111
  return this.withGuards(this.localCartToCart(this.getLocalCart()), "cart");
2119
2112
  }
@@ -2394,6 +2387,230 @@ var BrainerceClient = class {
2394
2387
  isCustomerLoggedIn() {
2395
2388
  return !!this.customerToken;
2396
2389
  }
2390
+ // -------------------- Session Cart Helpers --------------------
2391
+ /**
2392
+ * Hydrate session cart state from localStorage on construction.
2393
+ * @internal
2394
+ */
2395
+ hydrateSessionCart() {
2396
+ if (!this.isLocalStorageAvailable()) return;
2397
+ try {
2398
+ const stored = window.localStorage.getItem(this.SESSION_CART_KEY);
2399
+ if (stored) {
2400
+ const ref = JSON.parse(stored);
2401
+ this.sessionToken = ref.sessionToken;
2402
+ this.sessionCartId = ref.cartId;
2403
+ }
2404
+ } catch {
2405
+ }
2406
+ }
2407
+ /**
2408
+ * Persist session cart reference to localStorage.
2409
+ * @internal
2410
+ */
2411
+ saveSessionCart(ref) {
2412
+ this.sessionToken = ref.sessionToken;
2413
+ this.sessionCartId = ref.cartId;
2414
+ if (!this.isLocalStorageAvailable()) return;
2415
+ window.localStorage.setItem(this.SESSION_CART_KEY, JSON.stringify(ref));
2416
+ }
2417
+ /**
2418
+ * Clear session cart reference from localStorage and memory.
2419
+ * @internal
2420
+ */
2421
+ clearSessionCart() {
2422
+ this.sessionToken = null;
2423
+ this.sessionCartId = null;
2424
+ this._sessionCartPromise = null;
2425
+ if (!this.isLocalStorageAvailable()) return;
2426
+ window.localStorage.removeItem(this.SESSION_CART_KEY);
2427
+ }
2428
+ /**
2429
+ * Update the cached item count in the session reference.
2430
+ * @internal
2431
+ */
2432
+ updateSessionCartItemCount(count) {
2433
+ if (!this.sessionToken || !this.sessionCartId) return;
2434
+ this.saveSessionCart({
2435
+ sessionToken: this.sessionToken,
2436
+ cartId: this.sessionCartId,
2437
+ itemCount: count
2438
+ });
2439
+ }
2440
+ /**
2441
+ * Return a synthetic empty Cart object for display when no server cart exists yet.
2442
+ * Avoids creating a server cart just to show "your cart is empty."
2443
+ * @internal
2444
+ */
2445
+ emptyCart() {
2446
+ return {
2447
+ id: "",
2448
+ sessionToken: null,
2449
+ customerId: null,
2450
+ status: "ACTIVE",
2451
+ currency: "USD",
2452
+ notes: null,
2453
+ subtotal: "0",
2454
+ discountAmount: "0",
2455
+ couponCode: null,
2456
+ items: [],
2457
+ itemCount: 0,
2458
+ expiresAt: null,
2459
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2460
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2461
+ };
2462
+ }
2463
+ /**
2464
+ * Create a server-side cart via API. Never falls back to localStorage.
2465
+ * @internal
2466
+ */
2467
+ async createServerCart() {
2468
+ if (this.isVibeCodedMode()) {
2469
+ return this.vibeCodedRequest("POST", "/cart");
2470
+ }
2471
+ if (this.storeId && !this.apiKey) {
2472
+ return this.storefrontRequest("POST", "/cart");
2473
+ }
2474
+ return this.adminRequest("POST", "/api/v1/cart");
2475
+ }
2476
+ /**
2477
+ * Get or create a server-side session cart for guest users.
2478
+ * Lazily creates the cart on first call (e.g., first add-to-cart).
2479
+ * Uses promise dedup lock to prevent race conditions on parallel calls.
2480
+ * @internal
2481
+ */
2482
+ async getOrCreateSessionCart() {
2483
+ if (this._sessionCartPromise) return this._sessionCartPromise;
2484
+ this._sessionCartPromise = this._getOrCreateSessionCartImpl();
2485
+ try {
2486
+ return await this._sessionCartPromise;
2487
+ } finally {
2488
+ this._sessionCartPromise = null;
2489
+ }
2490
+ }
2491
+ /** @internal */
2492
+ async _getOrCreateSessionCartImpl() {
2493
+ const migrated = await this.migrateLocalCartToSession();
2494
+ if (migrated) return migrated;
2495
+ if (this.sessionCartId && this.sessionToken) {
2496
+ try {
2497
+ const cart2 = await this.getCart(this.sessionCartId);
2498
+ if (cart2.status === "ACTIVE") {
2499
+ return cart2;
2500
+ }
2501
+ this.clearSessionCart();
2502
+ } catch {
2503
+ this.clearSessionCart();
2504
+ }
2505
+ }
2506
+ if (this.sessionToken) {
2507
+ try {
2508
+ const cart2 = await this.getCartBySession(this.sessionToken);
2509
+ if (cart2 && cart2.status === "ACTIVE") {
2510
+ this.saveSessionCart({
2511
+ sessionToken: this.sessionToken,
2512
+ cartId: cart2.id,
2513
+ itemCount: cart2.itemCount
2514
+ });
2515
+ return cart2;
2516
+ }
2517
+ } catch {
2518
+ this.clearSessionCart();
2519
+ }
2520
+ }
2521
+ const cart = await this.createServerCart();
2522
+ if (cart.sessionToken) {
2523
+ this.saveSessionCart({
2524
+ sessionToken: cart.sessionToken,
2525
+ cartId: cart.id,
2526
+ itemCount: cart.itemCount
2527
+ });
2528
+ }
2529
+ return cart;
2530
+ }
2531
+ /**
2532
+ * Migrate legacy localStorage cart to server session cart.
2533
+ * Called once, on first smart method call if migration is needed.
2534
+ * @internal
2535
+ */
2536
+ async migrateLocalCartToSession() {
2537
+ if (this._migrationDone) return null;
2538
+ this._migrationDone = true;
2539
+ if (this.sessionToken || this.sessionCartId) return null;
2540
+ const localCart = this.getLocalCart();
2541
+ if (localCart.items.length === 0) return null;
2542
+ try {
2543
+ const cart = await this.createServerCart();
2544
+ for (const item of localCart.items) {
2545
+ try {
2546
+ await this.addToCart(cart.id, {
2547
+ productId: item.productId,
2548
+ variantId: item.variantId,
2549
+ quantity: item.quantity
2550
+ });
2551
+ } catch {
2552
+ }
2553
+ }
2554
+ if (cart.sessionToken) {
2555
+ this.saveSessionCart({
2556
+ sessionToken: cart.sessionToken,
2557
+ cartId: cart.id
2558
+ });
2559
+ }
2560
+ this.clearLocalCart();
2561
+ return this.getCart(cart.id);
2562
+ } catch {
2563
+ this._migrationDone = false;
2564
+ return null;
2565
+ }
2566
+ }
2567
+ /**
2568
+ * Merge the guest session cart into the customer's cart on the server.
2569
+ * Tries linkCart first (fast, single call), falls back to mergeCarts endpoint.
2570
+ * @internal
2571
+ */
2572
+ async mergeSessionCartOnLogin() {
2573
+ if (this.sessionCartId) {
2574
+ try {
2575
+ return await this.linkCart(this.sessionCartId);
2576
+ } catch {
2577
+ }
2578
+ }
2579
+ if (this.isVibeCodedMode()) {
2580
+ return this.vibeCodedRequest("POST", "/cart/merge", {
2581
+ sessionToken: this.sessionToken
2582
+ });
2583
+ }
2584
+ if (this.storeId && !this.apiKey) {
2585
+ return this.storefrontRequest("POST", "/cart/merge", {
2586
+ sessionToken: this.sessionToken
2587
+ });
2588
+ }
2589
+ return this.adminRequest("POST", "/api/v1/cart/merge", {
2590
+ sessionToken: this.sessionToken
2591
+ });
2592
+ }
2593
+ /**
2594
+ * Get the cart item count without a full cart fetch.
2595
+ * Returns the cached count from localStorage if available, or 0.
2596
+ * For accurate counts, use smartGetCart() and read cart.itemCount.
2597
+ */
2598
+ getSmartCartItemCount() {
2599
+ if (this.isCustomerLoggedIn()) {
2600
+ return 0;
2601
+ }
2602
+ if (!this.isLocalStorageAvailable()) return 0;
2603
+ try {
2604
+ const stored = window.localStorage.getItem(this.SESSION_CART_KEY);
2605
+ if (stored) {
2606
+ const ref = JSON.parse(stored);
2607
+ return ref.itemCount ?? 0;
2608
+ }
2609
+ } catch {
2610
+ }
2611
+ return 0;
2612
+ }
2613
+ // -------------------- Customer Cart --------------------
2397
2614
  /**
2398
2615
  * Get or create a server cart for the logged-in customer
2399
2616
  * Caches the cart ID for subsequent calls
@@ -2446,10 +2663,10 @@ var BrainerceClient = class {
2446
2663
  throw new BrainerceError("fetchCustomerCart requires vibe-coded or storefront mode", 400);
2447
2664
  }
2448
2665
  /**
2449
- * Smart add to cart - automatically uses localStorage or server based on auth state
2666
+ * Smart add to cart - automatically uses the correct cart based on auth state
2450
2667
  *
2451
- * - **Guest (not logged in)**: Stores in localStorage
2452
- * - **Logged in**: Stores on server (database)
2668
+ * - **Logged in**: Uses customer's server cart
2669
+ * - **Guest**: Uses server-side session cart (creates one if needed)
2453
2670
  *
2454
2671
  * @example
2455
2672
  * ```typescript
@@ -2457,25 +2674,35 @@ var BrainerceClient = class {
2457
2674
  * await client.smartAddToCart({
2458
2675
  * productId: 'prod_123',
2459
2676
  * quantity: 2,
2460
- * name: 'Cool Product', // Optional: for localStorage display
2461
- * price: '29.99',
2462
2677
  * });
2463
2678
  * ```
2464
2679
  */
2465
2680
  async smartAddToCart(item) {
2466
2681
  if (this.isCustomerLoggedIn()) {
2467
2682
  const cart = await this.getOrCreateCustomerCart();
2468
- return this.addToCart(cart.id, {
2683
+ const updated = await this.addToCart(cart.id, {
2469
2684
  productId: item.productId,
2470
2685
  variantId: item.variantId,
2471
2686
  quantity: item.quantity
2472
2687
  });
2688
+ return updated;
2473
2689
  } else {
2474
- return this.addToLocalCart(item);
2690
+ const cart = await this.getOrCreateSessionCart();
2691
+ const updated = await this.addToCart(cart.id, {
2692
+ productId: item.productId,
2693
+ variantId: item.variantId,
2694
+ quantity: item.quantity
2695
+ });
2696
+ this.updateSessionCartItemCount(updated.items?.length ?? 0);
2697
+ return updated;
2475
2698
  }
2476
2699
  }
2477
2700
  /**
2478
- * Smart get cart - returns server cart if logged in, localStorage if guest
2701
+ * Smart get cart - returns the current cart (server-side for both guests and logged-in users)
2702
+ *
2703
+ * - **Logged in**: Returns customer's server cart
2704
+ * - **Guest with session**: Returns server-side session cart
2705
+ * - **Guest without session**: Returns empty cart (no server call, cart created lazily on add)
2479
2706
  *
2480
2707
  * @example
2481
2708
  * ```typescript
@@ -2487,7 +2714,10 @@ var BrainerceClient = class {
2487
2714
  if (this.isCustomerLoggedIn()) {
2488
2715
  return this.getOrCreateCustomerCart();
2489
2716
  } else {
2490
- return this.withGuards(this.getLocalCart(), "cart");
2717
+ if (!this.sessionToken) {
2718
+ return this.emptyCart();
2719
+ }
2720
+ return this.getOrCreateSessionCart();
2491
2721
  }
2492
2722
  }
2493
2723
  /**
@@ -2513,7 +2743,24 @@ var BrainerceClient = class {
2513
2743
  }
2514
2744
  return this.updateCartItem(cart.id, item.id, { quantity });
2515
2745
  } else {
2516
- return this.updateLocalCartItem(productId, quantity, variantId);
2746
+ if (!this.sessionToken) {
2747
+ return this.emptyCart();
2748
+ }
2749
+ const cart = await this.getOrCreateSessionCart();
2750
+ const item = cart.items.find(
2751
+ (i) => i.productId === productId && i.variantId === (variantId ?? null)
2752
+ );
2753
+ if (!item) {
2754
+ return cart;
2755
+ }
2756
+ let updated;
2757
+ if (quantity <= 0) {
2758
+ updated = await this.removeCartItem(cart.id, item.id);
2759
+ } else {
2760
+ updated = await this.updateCartItem(cart.id, item.id, { quantity });
2761
+ }
2762
+ this.updateSessionCartItemCount(updated.items?.length ?? 0);
2763
+ return updated;
2517
2764
  }
2518
2765
  }
2519
2766
  /**
@@ -2529,15 +2776,13 @@ var BrainerceClient = class {
2529
2776
  return this.smartUpdateCartItem(productId, 0, variantId);
2530
2777
  }
2531
2778
  /**
2532
- * Sync local cart to server on login
2779
+ * Sync guest cart to customer cart on login
2533
2780
  *
2534
2781
  * Call this AFTER setCustomerToken() when a customer logs in.
2535
2782
  * This will:
2536
- * 1. Get or create a server cart for the customer
2537
- * 2. Add all items from localStorage to the server cart (merging with existing)
2538
- * 3. Clear localStorage
2539
- *
2540
- * Items that fail to sync (e.g., out of stock) are silently skipped.
2783
+ * 1. If a server-side session cart exists, merge it into the customer cart (atomic, server-side)
2784
+ * 2. If only a legacy localStorage cart exists, sync items one by one (backward compat)
2785
+ * 3. Clear the session/localStorage after merge
2541
2786
  *
2542
2787
  * @example
2543
2788
  * ```typescript
@@ -2545,7 +2790,7 @@ var BrainerceClient = class {
2545
2790
  * const auth = await client.login(email, password);
2546
2791
  * client.setCustomerToken(auth.token);
2547
2792
  *
2548
- * // Sync their local cart to server
2793
+ * // Merge their guest cart into customer cart
2549
2794
  * const cart = await client.syncCartOnLogin();
2550
2795
  * console.log('Cart synced, items:', cart.items.length);
2551
2796
  * ```
@@ -2557,6 +2802,14 @@ var BrainerceClient = class {
2557
2802
  401
2558
2803
  );
2559
2804
  }
2805
+ if (this.sessionToken) {
2806
+ try {
2807
+ const merged = await this.mergeSessionCartOnLogin();
2808
+ this.clearSessionCart();
2809
+ return merged;
2810
+ } catch {
2811
+ }
2812
+ }
2560
2813
  const localCart = this.getLocalCart();
2561
2814
  const serverCart = await this.getOrCreateCustomerCart();
2562
2815
  if (localCart.items.length === 0) {
@@ -2578,15 +2831,15 @@ var BrainerceClient = class {
2578
2831
  /**
2579
2832
  * Clear cart state on logout
2580
2833
  *
2581
- * Call this when a customer logs out to clear the cached cart ID.
2582
- * The localStorage cart remains available for the next guest session.
2834
+ * Call this when a customer logs out to clear the cached customer cart ID.
2835
+ * The session cart (if any) remains available for the next guest session.
2583
2836
  *
2584
2837
  * @example
2585
2838
  * ```typescript
2586
2839
  * client.clearCustomerToken();
2587
2840
  * client.onLogout();
2588
2841
  *
2589
- * // Now back to guest mode - cart uses localStorage
2842
+ * // Now back to guest mode - cart uses server-side session
2590
2843
  * await client.smartAddToCart({ productId: 'prod_123', quantity: 1 });
2591
2844
  * ```
2592
2845
  */
@@ -2604,12 +2857,12 @@ var BrainerceClient = class {
2604
2857
  * // After payment success
2605
2858
  * if (paymentStatus === 'succeeded') {
2606
2859
  * client.onCheckoutComplete();
2607
- * client.clearLocalCart(); // Also clear localStorage for guests
2608
2860
  * }
2609
2861
  * ```
2610
2862
  */
2611
2863
  onCheckoutComplete() {
2612
2864
  this.customerCartId = null;
2865
+ this.clearSessionCart();
2613
2866
  }
2614
2867
  // -------------------- Checkout --------------------
2615
2868
  /**
@@ -2636,7 +2889,7 @@ var BrainerceClient = class {
2636
2889
  async createCheckout(data) {
2637
2890
  if (data.cartId === this.VIRTUAL_LOCAL_CART_ID) {
2638
2891
  throw new BrainerceError(
2639
- "Cannot create checkout from local cart directly. Use startGuestCheckout() for guest checkout with localStorage cart, or sync cart to server first with syncCartOnLogin().",
2892
+ 'Cannot create checkout from "__local__" cart. Use startGuestCheckout() or smartAddToCart() to create a server-side cart first.',
2640
2893
  400
2641
2894
  );
2642
2895
  }
@@ -2705,6 +2958,46 @@ var BrainerceClient = class {
2705
2958
  }
2706
2959
  return this.adminRequest("PATCH", `/api/v1/checkout/${checkoutId}/customer`, data);
2707
2960
  }
2961
+ /**
2962
+ * Get available shipping destinations for this store.
2963
+ *
2964
+ * Returns which countries and regions the store ships to,
2965
+ * so you can populate `<select>` dropdowns in your checkout form.
2966
+ *
2967
+ * @example
2968
+ * ```typescript
2969
+ * const dest = await client.getShippingDestinations();
2970
+ *
2971
+ * if (dest.worldwide) {
2972
+ * // Store ships everywhere — use a full country list
2973
+ * } else {
2974
+ * // Only show available countries
2975
+ * dest.countries.forEach(c => console.log(c.code, c.name));
2976
+ * }
2977
+ *
2978
+ * // Check region restrictions for a country
2979
+ * const usRegions = dest.regions['US'];
2980
+ * if (usRegions) {
2981
+ * // Only these US states are available
2982
+ * usRegions.forEach(r => console.log(r.code, r.name));
2983
+ * }
2984
+ * ```
2985
+ */
2986
+ async getShippingDestinations() {
2987
+ if (this.isVibeCodedMode()) {
2988
+ return this.vibeCodedRequest("GET", "/shipping/destinations");
2989
+ }
2990
+ if (this.storeId && !this.apiKey) {
2991
+ return this.storefrontRequest(
2992
+ "GET",
2993
+ "/checkouts/shipping-destinations"
2994
+ );
2995
+ }
2996
+ return this.adminRequest(
2997
+ "GET",
2998
+ "/api/v1/checkouts/shipping-destinations"
2999
+ );
3000
+ }
2708
3001
  /**
2709
3002
  * Set shipping address on checkout (includes customer email).
2710
3003
  * Returns the checkout and available shipping rates for the address.
@@ -3172,14 +3465,8 @@ var BrainerceClient = class {
3172
3465
  }
3173
3466
  }
3174
3467
  /**
3175
- * Get local cart from localStorage
3176
- * Returns empty cart if none exists
3177
- *
3178
- * @example
3179
- * ```typescript
3180
- * const cart = client.getLocalCart();
3181
- * console.log('Items in cart:', cart.items.length);
3182
- * ```
3468
+ * @deprecated Use `smartGetCart()` instead. Guest carts are now stored on the server.
3469
+ * Get local cart from localStorage. Returns empty cart if none exists.
3183
3470
  */
3184
3471
  getLocalCart() {
3185
3472
  if (!this.isLocalStorageAvailable()) {
@@ -3261,18 +3548,8 @@ var BrainerceClient = class {
3261
3548
  };
3262
3549
  }
3263
3550
  /**
3264
- * Add item to local cart (NO API call)
3265
- * If item already exists, updates quantity
3266
- *
3267
- * @example
3268
- * ```typescript
3269
- * client.addToLocalCart({
3270
- * productId: 'prod_123',
3271
- * quantity: 2,
3272
- * name: 'Cool Shirt',
3273
- * price: '29.99',
3274
- * });
3275
- * ```
3551
+ * @deprecated Use `smartAddToCart()` instead. Guest carts are now stored on the server.
3552
+ * Add item to local cart (NO API call). If item already exists, updates quantity.
3276
3553
  */
3277
3554
  addToLocalCart(item) {
3278
3555
  const cart = this.getLocalCart();
@@ -3294,14 +3571,8 @@ var BrainerceClient = class {
3294
3571
  return cart;
3295
3572
  }
3296
3573
  /**
3297
- * Update item quantity in local cart
3298
- * Set quantity to 0 to remove item
3299
- *
3300
- * @example
3301
- * ```typescript
3302
- * client.updateLocalCartItem('prod_123', 3); // Set quantity to 3
3303
- * client.updateLocalCartItem('prod_123', 0); // Remove item
3304
- * ```
3574
+ * @deprecated Use `smartUpdateCartItem()` instead. Guest carts are now stored on the server.
3575
+ * Update item quantity in local cart. Set quantity to 0 to remove item.
3305
3576
  */
3306
3577
  updateLocalCartItem(productId, quantity, variantId) {
3307
3578
  const cart = this.getLocalCart();
@@ -3319,24 +3590,13 @@ var BrainerceClient = class {
3319
3590
  return cart;
3320
3591
  }
3321
3592
  /**
3322
- * Remove item from local cart
3323
- *
3324
- * @example
3325
- * ```typescript
3326
- * client.removeFromLocalCart('prod_123');
3327
- * client.removeFromLocalCart('prod_456', 'variant_789');
3328
- * ```
3593
+ * @deprecated Use `smartRemoveFromCart()` instead. Guest carts are now stored on the server.
3329
3594
  */
3330
3595
  removeFromLocalCart(productId, variantId) {
3331
3596
  return this.updateLocalCartItem(productId, 0, variantId);
3332
3597
  }
3333
3598
  /**
3334
- * Clear all items from local cart
3335
- *
3336
- * @example
3337
- * ```typescript
3338
- * client.clearLocalCart();
3339
- * ```
3599
+ * @deprecated Use `onCheckoutComplete()` instead. Guest carts are now stored on the server.
3340
3600
  */
3341
3601
  clearLocalCart() {
3342
3602
  const cart = { items: [], updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
@@ -3344,16 +3604,8 @@ var BrainerceClient = class {
3344
3604
  return cart;
3345
3605
  }
3346
3606
  /**
3347
- * Set customer info on local cart
3348
- *
3349
- * @example
3350
- * ```typescript
3351
- * client.setLocalCartCustomer({
3352
- * email: 'john@example.com',
3353
- * firstName: 'John',
3354
- * lastName: 'Doe',
3355
- * });
3356
- * ```
3607
+ * @deprecated Customer info is now set via checkout address methods.
3608
+ * Still used by `submitGuestOrder()` for backward compatibility.
3357
3609
  */
3358
3610
  setLocalCartCustomer(customer) {
3359
3611
  const cart = this.getLocalCart();
@@ -3362,19 +3614,8 @@ var BrainerceClient = class {
3362
3614
  return cart;
3363
3615
  }
3364
3616
  /**
3365
- * Set shipping address on local cart
3366
- *
3367
- * @example
3368
- * ```typescript
3369
- * client.setLocalCartShippingAddress({
3370
- * firstName: 'John',
3371
- * lastName: 'Doe',
3372
- * line1: '123 Main St',
3373
- * city: 'Tel Aviv',
3374
- * postalCode: '6100000',
3375
- * country: 'IL',
3376
- * });
3377
- * ```
3617
+ * @deprecated Address is now set via `updateGuestCheckoutAddress()` after `startGuestCheckout()`.
3618
+ * Still used by `submitGuestOrder()` for backward compatibility.
3378
3619
  */
3379
3620
  setLocalCartShippingAddress(address) {
3380
3621
  const cart = this.getLocalCart();
@@ -3383,7 +3624,8 @@ var BrainerceClient = class {
3383
3624
  return cart;
3384
3625
  }
3385
3626
  /**
3386
- * Set billing address on local cart
3627
+ * @deprecated Address is now set via `updateGuestCheckoutAddress()` after `startGuestCheckout()`.
3628
+ * Still used by `submitGuestOrder()` for backward compatibility.
3387
3629
  */
3388
3630
  setLocalCartBillingAddress(address) {
3389
3631
  const cart = this.getLocalCart();
@@ -3392,7 +3634,7 @@ var BrainerceClient = class {
3392
3634
  return cart;
3393
3635
  }
3394
3636
  /**
3395
- * Set coupon code on local cart
3637
+ * @deprecated Coupons are now applied via `applyCoupon()` on the server cart.
3396
3638
  */
3397
3639
  setLocalCartCoupon(couponCode) {
3398
3640
  const cart = this.getLocalCart();
@@ -3401,7 +3643,7 @@ var BrainerceClient = class {
3401
3643
  return cart;
3402
3644
  }
3403
3645
  /**
3404
- * Get total items count in local cart
3646
+ * @deprecated Use `getSmartCartItemCount()` instead.
3405
3647
  */
3406
3648
  getLocalCartItemCount() {
3407
3649
  const cart = this.getLocalCart();
@@ -3431,6 +3673,46 @@ var BrainerceClient = class {
3431
3673
  * ```
3432
3674
  */
3433
3675
  async submitGuestOrder(options) {
3676
+ if (this.sessionToken) {
3677
+ const serverCart = await this.getOrCreateSessionCart();
3678
+ if (!serverCart.items || serverCart.items.length === 0) {
3679
+ throw new BrainerceError("Cart is empty", 400);
3680
+ }
3681
+ const localCart = this.getLocalCart();
3682
+ if (!localCart.customer?.email) {
3683
+ throw new BrainerceError(
3684
+ "Customer email is required. Call setLocalCartCustomer() first.",
3685
+ 400
3686
+ );
3687
+ }
3688
+ if (!localCart.shippingAddress) {
3689
+ throw new BrainerceError(
3690
+ "Shipping address is required. Call setLocalCartShippingAddress() first.",
3691
+ 400
3692
+ );
3693
+ }
3694
+ const trackingResult = await this.startGuestCheckout();
3695
+ if (!trackingResult.tracked) {
3696
+ throw new BrainerceError("Failed to create checkout from session cart", 500);
3697
+ }
3698
+ await this.updateGuestCheckoutAddress(trackingResult.checkoutId, {
3699
+ shippingAddress: {
3700
+ ...localCart.shippingAddress,
3701
+ email: localCart.customer.email
3702
+ },
3703
+ billingAddress: localCart.billingAddress
3704
+ });
3705
+ const orderResult = await this.completeGuestCheckout(trackingResult.checkoutId, {
3706
+ clearCartOnSuccess: options?.clearCartOnSuccess
3707
+ });
3708
+ return {
3709
+ orderId: orderResult.orderId,
3710
+ orderNumber: orderResult.orderNumber || orderResult.orderId,
3711
+ status: orderResult.status || "pending",
3712
+ total: orderResult.total ?? 0,
3713
+ message: orderResult.message || "Order created successfully"
3714
+ };
3715
+ }
3434
3716
  const cart = this.getLocalCart();
3435
3717
  if (cart.items.length === 0) {
3436
3718
  throw new BrainerceError("Cart is empty", 400);
@@ -3448,7 +3730,6 @@ var BrainerceClient = class {
3448
3730
  shippingAddress: {
3449
3731
  ...cart.shippingAddress,
3450
3732
  email: cart.customer.email
3451
- // Already validated above
3452
3733
  },
3453
3734
  billingAddress: cart.billingAddress
3454
3735
  });
@@ -3536,6 +3817,34 @@ var BrainerceClient = class {
3536
3817
  * ```
3537
3818
  */
3538
3819
  async startGuestCheckout(options) {
3820
+ if (this.sessionToken) {
3821
+ const serverCart = await this.getOrCreateSessionCart();
3822
+ if (!serverCart.items || serverCart.items.length === 0) {
3823
+ throw new BrainerceError("Cart is empty", 400);
3824
+ }
3825
+ let selectedItemIds;
3826
+ if (options?.selectedIndices?.length) {
3827
+ selectedItemIds = options.selectedIndices.map((i) => serverCart.items[i]?.id).filter((id) => !!id);
3828
+ if (selectedItemIds.length === 0) {
3829
+ throw new BrainerceError("No items selected for checkout", 400);
3830
+ }
3831
+ }
3832
+ const checkout = await this.createCheckout({
3833
+ cartId: serverCart.id,
3834
+ selectedItemIds
3835
+ });
3836
+ this.saveActiveCheckout({
3837
+ checkoutId: checkout.id,
3838
+ cartId: serverCart.id,
3839
+ selectedIndices: options?.selectedIndices
3840
+ });
3841
+ return {
3842
+ tracked: true,
3843
+ checkoutId: checkout.id,
3844
+ cartId: serverCart.id,
3845
+ message: "Checkout created from session cart"
3846
+ };
3847
+ }
3539
3848
  const cart = this.getLocalCart();
3540
3849
  if (cart.items.length === 0) {
3541
3850
  throw new BrainerceError("Cart is empty", 400);
@@ -3599,16 +3908,8 @@ var BrainerceClient = class {
3599
3908
  }
3600
3909
  }
3601
3910
  /**
3911
+ * @deprecated Partial checkout is now handled server-side via `selectedItemIds`.
3602
3912
  * Remove specific items from local cart by their indices.
3603
- * Use after partial checkout to remove only the purchased items.
3604
- *
3605
- * @param indices - Array of item indices to remove
3606
- *
3607
- * @example
3608
- * ```typescript
3609
- * // After partial checkout success, remove purchased items
3610
- * client.removeLocalCartItemsByIndex([0, 2]); // Removes items at index 0 and 2
3611
- * ```
3612
3913
  */
3613
3914
  removeLocalCartItemsByIndex(indices) {
3614
3915
  const cart = this.getLocalCart();
@@ -3685,6 +3986,7 @@ var BrainerceClient = class {
3685
3986
  this.removeLocalCartItemsByIndex(indices);
3686
3987
  } else {
3687
3988
  this.clearLocalCart();
3989
+ this.clearSessionCart();
3688
3990
  }
3689
3991
  this.customerCartId = null;
3690
3992
  }
@@ -3782,6 +4084,7 @@ var BrainerceClient = class {
3782
4084
  }
3783
4085
  if (isLoggedIn) {
3784
4086
  this.clearLocalCart();
4087
+ this.clearSessionCart();
3785
4088
  return {
3786
4089
  cleared: true,
3787
4090
  mode: "full",
@@ -3798,6 +4101,7 @@ var BrainerceClient = class {
3798
4101
  };
3799
4102
  }
3800
4103
  this.clearLocalCart();
4104
+ this.clearSessionCart();
3801
4105
  return {
3802
4106
  cleared: true,
3803
4107
  mode: "full",