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.mjs CHANGED
@@ -121,9 +121,16 @@ var BrainerceClient = class {
121
121
  constructor(options) {
122
122
  this.customerToken = null;
123
123
  this.customerCartId = null;
124
+ // Session cart state (server-side guest carts)
125
+ this.sessionCartId = null;
126
+ this.sessionToken = null;
127
+ this._sessionCartPromise = null;
128
+ this._migrationDone = false;
129
+ /** localStorage key for session cart reference (sessionToken + cartId) */
130
+ this.SESSION_CART_KEY = "brainerce_session";
124
131
  /**
125
132
  * Virtual cart ID used for localStorage carts (guest users not logged in).
126
- * When a cart has this ID, operations use localStorage instead of server API.
133
+ * @deprecated Guest carts now use server-side sessions. Kept for backward compatibility.
127
134
  */
128
135
  this.VIRTUAL_LOCAL_CART_ID = "__local__";
129
136
  /**
@@ -155,6 +162,7 @@ var BrainerceClient = class {
155
162
  this.baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
156
163
  this.timeout = options.timeout || DEFAULT_TIMEOUT;
157
164
  this.onAuthError = options.onAuthError;
165
+ this.hydrateSessionCart();
158
166
  }
159
167
  withGuards(result, type) {
160
168
  if (!isDevGuardsEnabled()) return result;
@@ -1853,10 +1861,6 @@ var BrainerceClient = class {
1853
1861
  * ```
1854
1862
  */
1855
1863
  async createCart() {
1856
- if (this.isVibeCodedMode() && !this.isCustomerLoggedIn()) {
1857
- const localCart = this.getLocalCart();
1858
- return this.localCartToCart(localCart);
1859
- }
1860
1864
  if (this.isVibeCodedMode()) {
1861
1865
  return this.vibeCodedRequest("POST", "/cart");
1862
1866
  }
@@ -1875,6 +1879,9 @@ var BrainerceClient = class {
1875
1879
  * ```
1876
1880
  */
1877
1881
  async getCartBySession(sessionToken) {
1882
+ if (this.isVibeCodedMode()) {
1883
+ return this.vibeCodedRequest("GET", `/cart/session/${sessionToken}`);
1884
+ }
1878
1885
  if (this.storeId && !this.apiKey) {
1879
1886
  return this.storefrontRequest("GET", `/cart/session/${sessionToken}`);
1880
1887
  }
@@ -1900,6 +1907,7 @@ var BrainerceClient = class {
1900
1907
  */
1901
1908
  async getCart(cartId) {
1902
1909
  if (cartId === this.VIRTUAL_LOCAL_CART_ID) {
1910
+ console.warn('getCart("__local__") is deprecated. Use smartGetCart() instead.');
1903
1911
  return this.withGuards(this.localCartToCart(this.getLocalCart()), "cart");
1904
1912
  }
1905
1913
  if (this.isVibeCodedMode()) {
@@ -1924,38 +1932,14 @@ var BrainerceClient = class {
1924
1932
  */
1925
1933
  async addToCart(cartId, item) {
1926
1934
  if (cartId === this.VIRTUAL_LOCAL_CART_ID) {
1927
- let productName = "Unknown Product";
1928
- let productPrice = "0";
1929
- let productImage;
1930
- if (item.productInfo) {
1931
- productName = item.productInfo.name;
1932
- productPrice = item.productInfo.price;
1933
- productImage = item.productInfo.image;
1934
- } else {
1935
- try {
1936
- const product = await this.getProduct(item.productId);
1937
- productName = product.name;
1938
- productPrice = product.salePrice || product.basePrice;
1939
- productImage = product.images?.[0]?.url;
1940
- if (item.variantId && product.variants) {
1941
- const variant = product.variants.find((v) => v.id === item.variantId);
1942
- if (variant) {
1943
- productPrice = variant.salePrice || variant.price || productPrice;
1944
- if (variant.image) {
1945
- productImage = typeof variant.image === "string" ? variant.image : variant.image.url;
1946
- }
1947
- }
1948
- }
1949
- } catch {
1950
- }
1951
- }
1935
+ console.warn('addToCart("__local__", ...) is deprecated. Use smartAddToCart() instead.');
1952
1936
  this.addToLocalCart({
1953
1937
  productId: item.productId,
1954
1938
  variantId: item.variantId,
1955
1939
  quantity: item.quantity,
1956
- name: productName,
1957
- price: productPrice,
1958
- image: productImage
1940
+ name: item.productInfo?.name || "Unknown Product",
1941
+ price: item.productInfo?.price || "0",
1942
+ image: item.productInfo?.image
1959
1943
  });
1960
1944
  return this.withGuards(this.localCartToCart(this.getLocalCart()), "cart");
1961
1945
  }
@@ -1986,6 +1970,9 @@ var BrainerceClient = class {
1986
1970
  */
1987
1971
  async updateCartItem(cartId, itemId, data) {
1988
1972
  if (cartId === this.VIRTUAL_LOCAL_CART_ID) {
1973
+ console.warn(
1974
+ 'updateCartItem("__local__", ...) is deprecated. Use smartUpdateCartItem() instead.'
1975
+ );
1989
1976
  const index = parseInt(itemId.replace("local_", ""), 10);
1990
1977
  const localCart = this.getLocalCart();
1991
1978
  if (index >= 0 && index < localCart.items.length) {
@@ -2021,6 +2008,9 @@ var BrainerceClient = class {
2021
2008
  */
2022
2009
  async removeCartItem(cartId, itemId) {
2023
2010
  if (cartId === this.VIRTUAL_LOCAL_CART_ID) {
2011
+ console.warn(
2012
+ 'removeCartItem("__local__", ...) is deprecated. Use smartRemoveFromCart() instead.'
2013
+ );
2024
2014
  const index = parseInt(itemId.replace("local_", ""), 10);
2025
2015
  const localCart = this.getLocalCart();
2026
2016
  if (index >= 0 && index < localCart.items.length) {
@@ -2056,6 +2046,9 @@ var BrainerceClient = class {
2056
2046
  */
2057
2047
  async clearCart(cartId) {
2058
2048
  if (cartId === this.VIRTUAL_LOCAL_CART_ID) {
2049
+ console.warn(
2050
+ 'clearCart("__local__") is deprecated. Use onCheckoutComplete() or clearLocalCart() directly.'
2051
+ );
2059
2052
  this.clearLocalCart();
2060
2053
  return this.withGuards(this.localCartToCart(this.getLocalCart()), "cart");
2061
2054
  }
@@ -2336,6 +2329,230 @@ var BrainerceClient = class {
2336
2329
  isCustomerLoggedIn() {
2337
2330
  return !!this.customerToken;
2338
2331
  }
2332
+ // -------------------- Session Cart Helpers --------------------
2333
+ /**
2334
+ * Hydrate session cart state from localStorage on construction.
2335
+ * @internal
2336
+ */
2337
+ hydrateSessionCart() {
2338
+ if (!this.isLocalStorageAvailable()) return;
2339
+ try {
2340
+ const stored = window.localStorage.getItem(this.SESSION_CART_KEY);
2341
+ if (stored) {
2342
+ const ref = JSON.parse(stored);
2343
+ this.sessionToken = ref.sessionToken;
2344
+ this.sessionCartId = ref.cartId;
2345
+ }
2346
+ } catch {
2347
+ }
2348
+ }
2349
+ /**
2350
+ * Persist session cart reference to localStorage.
2351
+ * @internal
2352
+ */
2353
+ saveSessionCart(ref) {
2354
+ this.sessionToken = ref.sessionToken;
2355
+ this.sessionCartId = ref.cartId;
2356
+ if (!this.isLocalStorageAvailable()) return;
2357
+ window.localStorage.setItem(this.SESSION_CART_KEY, JSON.stringify(ref));
2358
+ }
2359
+ /**
2360
+ * Clear session cart reference from localStorage and memory.
2361
+ * @internal
2362
+ */
2363
+ clearSessionCart() {
2364
+ this.sessionToken = null;
2365
+ this.sessionCartId = null;
2366
+ this._sessionCartPromise = null;
2367
+ if (!this.isLocalStorageAvailable()) return;
2368
+ window.localStorage.removeItem(this.SESSION_CART_KEY);
2369
+ }
2370
+ /**
2371
+ * Update the cached item count in the session reference.
2372
+ * @internal
2373
+ */
2374
+ updateSessionCartItemCount(count) {
2375
+ if (!this.sessionToken || !this.sessionCartId) return;
2376
+ this.saveSessionCart({
2377
+ sessionToken: this.sessionToken,
2378
+ cartId: this.sessionCartId,
2379
+ itemCount: count
2380
+ });
2381
+ }
2382
+ /**
2383
+ * Return a synthetic empty Cart object for display when no server cart exists yet.
2384
+ * Avoids creating a server cart just to show "your cart is empty."
2385
+ * @internal
2386
+ */
2387
+ emptyCart() {
2388
+ return {
2389
+ id: "",
2390
+ sessionToken: null,
2391
+ customerId: null,
2392
+ status: "ACTIVE",
2393
+ currency: "USD",
2394
+ notes: null,
2395
+ subtotal: "0",
2396
+ discountAmount: "0",
2397
+ couponCode: null,
2398
+ items: [],
2399
+ itemCount: 0,
2400
+ expiresAt: null,
2401
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2402
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2403
+ };
2404
+ }
2405
+ /**
2406
+ * Create a server-side cart via API. Never falls back to localStorage.
2407
+ * @internal
2408
+ */
2409
+ async createServerCart() {
2410
+ if (this.isVibeCodedMode()) {
2411
+ return this.vibeCodedRequest("POST", "/cart");
2412
+ }
2413
+ if (this.storeId && !this.apiKey) {
2414
+ return this.storefrontRequest("POST", "/cart");
2415
+ }
2416
+ return this.adminRequest("POST", "/api/v1/cart");
2417
+ }
2418
+ /**
2419
+ * Get or create a server-side session cart for guest users.
2420
+ * Lazily creates the cart on first call (e.g., first add-to-cart).
2421
+ * Uses promise dedup lock to prevent race conditions on parallel calls.
2422
+ * @internal
2423
+ */
2424
+ async getOrCreateSessionCart() {
2425
+ if (this._sessionCartPromise) return this._sessionCartPromise;
2426
+ this._sessionCartPromise = this._getOrCreateSessionCartImpl();
2427
+ try {
2428
+ return await this._sessionCartPromise;
2429
+ } finally {
2430
+ this._sessionCartPromise = null;
2431
+ }
2432
+ }
2433
+ /** @internal */
2434
+ async _getOrCreateSessionCartImpl() {
2435
+ const migrated = await this.migrateLocalCartToSession();
2436
+ if (migrated) return migrated;
2437
+ if (this.sessionCartId && this.sessionToken) {
2438
+ try {
2439
+ const cart2 = await this.getCart(this.sessionCartId);
2440
+ if (cart2.status === "ACTIVE") {
2441
+ return cart2;
2442
+ }
2443
+ this.clearSessionCart();
2444
+ } catch {
2445
+ this.clearSessionCart();
2446
+ }
2447
+ }
2448
+ if (this.sessionToken) {
2449
+ try {
2450
+ const cart2 = await this.getCartBySession(this.sessionToken);
2451
+ if (cart2 && cart2.status === "ACTIVE") {
2452
+ this.saveSessionCart({
2453
+ sessionToken: this.sessionToken,
2454
+ cartId: cart2.id,
2455
+ itemCount: cart2.itemCount
2456
+ });
2457
+ return cart2;
2458
+ }
2459
+ } catch {
2460
+ this.clearSessionCart();
2461
+ }
2462
+ }
2463
+ const cart = await this.createServerCart();
2464
+ if (cart.sessionToken) {
2465
+ this.saveSessionCart({
2466
+ sessionToken: cart.sessionToken,
2467
+ cartId: cart.id,
2468
+ itemCount: cart.itemCount
2469
+ });
2470
+ }
2471
+ return cart;
2472
+ }
2473
+ /**
2474
+ * Migrate legacy localStorage cart to server session cart.
2475
+ * Called once, on first smart method call if migration is needed.
2476
+ * @internal
2477
+ */
2478
+ async migrateLocalCartToSession() {
2479
+ if (this._migrationDone) return null;
2480
+ this._migrationDone = true;
2481
+ if (this.sessionToken || this.sessionCartId) return null;
2482
+ const localCart = this.getLocalCart();
2483
+ if (localCart.items.length === 0) return null;
2484
+ try {
2485
+ const cart = await this.createServerCart();
2486
+ for (const item of localCart.items) {
2487
+ try {
2488
+ await this.addToCart(cart.id, {
2489
+ productId: item.productId,
2490
+ variantId: item.variantId,
2491
+ quantity: item.quantity
2492
+ });
2493
+ } catch {
2494
+ }
2495
+ }
2496
+ if (cart.sessionToken) {
2497
+ this.saveSessionCart({
2498
+ sessionToken: cart.sessionToken,
2499
+ cartId: cart.id
2500
+ });
2501
+ }
2502
+ this.clearLocalCart();
2503
+ return this.getCart(cart.id);
2504
+ } catch {
2505
+ this._migrationDone = false;
2506
+ return null;
2507
+ }
2508
+ }
2509
+ /**
2510
+ * Merge the guest session cart into the customer's cart on the server.
2511
+ * Tries linkCart first (fast, single call), falls back to mergeCarts endpoint.
2512
+ * @internal
2513
+ */
2514
+ async mergeSessionCartOnLogin() {
2515
+ if (this.sessionCartId) {
2516
+ try {
2517
+ return await this.linkCart(this.sessionCartId);
2518
+ } catch {
2519
+ }
2520
+ }
2521
+ if (this.isVibeCodedMode()) {
2522
+ return this.vibeCodedRequest("POST", "/cart/merge", {
2523
+ sessionToken: this.sessionToken
2524
+ });
2525
+ }
2526
+ if (this.storeId && !this.apiKey) {
2527
+ return this.storefrontRequest("POST", "/cart/merge", {
2528
+ sessionToken: this.sessionToken
2529
+ });
2530
+ }
2531
+ return this.adminRequest("POST", "/api/v1/cart/merge", {
2532
+ sessionToken: this.sessionToken
2533
+ });
2534
+ }
2535
+ /**
2536
+ * Get the cart item count without a full cart fetch.
2537
+ * Returns the cached count from localStorage if available, or 0.
2538
+ * For accurate counts, use smartGetCart() and read cart.itemCount.
2539
+ */
2540
+ getSmartCartItemCount() {
2541
+ if (this.isCustomerLoggedIn()) {
2542
+ return 0;
2543
+ }
2544
+ if (!this.isLocalStorageAvailable()) return 0;
2545
+ try {
2546
+ const stored = window.localStorage.getItem(this.SESSION_CART_KEY);
2547
+ if (stored) {
2548
+ const ref = JSON.parse(stored);
2549
+ return ref.itemCount ?? 0;
2550
+ }
2551
+ } catch {
2552
+ }
2553
+ return 0;
2554
+ }
2555
+ // -------------------- Customer Cart --------------------
2339
2556
  /**
2340
2557
  * Get or create a server cart for the logged-in customer
2341
2558
  * Caches the cart ID for subsequent calls
@@ -2388,10 +2605,10 @@ var BrainerceClient = class {
2388
2605
  throw new BrainerceError("fetchCustomerCart requires vibe-coded or storefront mode", 400);
2389
2606
  }
2390
2607
  /**
2391
- * Smart add to cart - automatically uses localStorage or server based on auth state
2608
+ * Smart add to cart - automatically uses the correct cart based on auth state
2392
2609
  *
2393
- * - **Guest (not logged in)**: Stores in localStorage
2394
- * - **Logged in**: Stores on server (database)
2610
+ * - **Logged in**: Uses customer's server cart
2611
+ * - **Guest**: Uses server-side session cart (creates one if needed)
2395
2612
  *
2396
2613
  * @example
2397
2614
  * ```typescript
@@ -2399,25 +2616,35 @@ var BrainerceClient = class {
2399
2616
  * await client.smartAddToCart({
2400
2617
  * productId: 'prod_123',
2401
2618
  * quantity: 2,
2402
- * name: 'Cool Product', // Optional: for localStorage display
2403
- * price: '29.99',
2404
2619
  * });
2405
2620
  * ```
2406
2621
  */
2407
2622
  async smartAddToCart(item) {
2408
2623
  if (this.isCustomerLoggedIn()) {
2409
2624
  const cart = await this.getOrCreateCustomerCart();
2410
- return this.addToCart(cart.id, {
2625
+ const updated = await this.addToCart(cart.id, {
2411
2626
  productId: item.productId,
2412
2627
  variantId: item.variantId,
2413
2628
  quantity: item.quantity
2414
2629
  });
2630
+ return updated;
2415
2631
  } else {
2416
- return this.addToLocalCart(item);
2632
+ const cart = await this.getOrCreateSessionCart();
2633
+ const updated = await this.addToCart(cart.id, {
2634
+ productId: item.productId,
2635
+ variantId: item.variantId,
2636
+ quantity: item.quantity
2637
+ });
2638
+ this.updateSessionCartItemCount(updated.items?.length ?? 0);
2639
+ return updated;
2417
2640
  }
2418
2641
  }
2419
2642
  /**
2420
- * Smart get cart - returns server cart if logged in, localStorage if guest
2643
+ * Smart get cart - returns the current cart (server-side for both guests and logged-in users)
2644
+ *
2645
+ * - **Logged in**: Returns customer's server cart
2646
+ * - **Guest with session**: Returns server-side session cart
2647
+ * - **Guest without session**: Returns empty cart (no server call, cart created lazily on add)
2421
2648
  *
2422
2649
  * @example
2423
2650
  * ```typescript
@@ -2429,7 +2656,10 @@ var BrainerceClient = class {
2429
2656
  if (this.isCustomerLoggedIn()) {
2430
2657
  return this.getOrCreateCustomerCart();
2431
2658
  } else {
2432
- return this.withGuards(this.getLocalCart(), "cart");
2659
+ if (!this.sessionToken) {
2660
+ return this.emptyCart();
2661
+ }
2662
+ return this.getOrCreateSessionCart();
2433
2663
  }
2434
2664
  }
2435
2665
  /**
@@ -2455,7 +2685,24 @@ var BrainerceClient = class {
2455
2685
  }
2456
2686
  return this.updateCartItem(cart.id, item.id, { quantity });
2457
2687
  } else {
2458
- return this.updateLocalCartItem(productId, quantity, variantId);
2688
+ if (!this.sessionToken) {
2689
+ return this.emptyCart();
2690
+ }
2691
+ const cart = await this.getOrCreateSessionCart();
2692
+ const item = cart.items.find(
2693
+ (i) => i.productId === productId && i.variantId === (variantId ?? null)
2694
+ );
2695
+ if (!item) {
2696
+ return cart;
2697
+ }
2698
+ let updated;
2699
+ if (quantity <= 0) {
2700
+ updated = await this.removeCartItem(cart.id, item.id);
2701
+ } else {
2702
+ updated = await this.updateCartItem(cart.id, item.id, { quantity });
2703
+ }
2704
+ this.updateSessionCartItemCount(updated.items?.length ?? 0);
2705
+ return updated;
2459
2706
  }
2460
2707
  }
2461
2708
  /**
@@ -2471,15 +2718,13 @@ var BrainerceClient = class {
2471
2718
  return this.smartUpdateCartItem(productId, 0, variantId);
2472
2719
  }
2473
2720
  /**
2474
- * Sync local cart to server on login
2721
+ * Sync guest cart to customer cart on login
2475
2722
  *
2476
2723
  * Call this AFTER setCustomerToken() when a customer logs in.
2477
2724
  * This will:
2478
- * 1. Get or create a server cart for the customer
2479
- * 2. Add all items from localStorage to the server cart (merging with existing)
2480
- * 3. Clear localStorage
2481
- *
2482
- * Items that fail to sync (e.g., out of stock) are silently skipped.
2725
+ * 1. If a server-side session cart exists, merge it into the customer cart (atomic, server-side)
2726
+ * 2. If only a legacy localStorage cart exists, sync items one by one (backward compat)
2727
+ * 3. Clear the session/localStorage after merge
2483
2728
  *
2484
2729
  * @example
2485
2730
  * ```typescript
@@ -2487,7 +2732,7 @@ var BrainerceClient = class {
2487
2732
  * const auth = await client.login(email, password);
2488
2733
  * client.setCustomerToken(auth.token);
2489
2734
  *
2490
- * // Sync their local cart to server
2735
+ * // Merge their guest cart into customer cart
2491
2736
  * const cart = await client.syncCartOnLogin();
2492
2737
  * console.log('Cart synced, items:', cart.items.length);
2493
2738
  * ```
@@ -2499,6 +2744,14 @@ var BrainerceClient = class {
2499
2744
  401
2500
2745
  );
2501
2746
  }
2747
+ if (this.sessionToken) {
2748
+ try {
2749
+ const merged = await this.mergeSessionCartOnLogin();
2750
+ this.clearSessionCart();
2751
+ return merged;
2752
+ } catch {
2753
+ }
2754
+ }
2502
2755
  const localCart = this.getLocalCart();
2503
2756
  const serverCart = await this.getOrCreateCustomerCart();
2504
2757
  if (localCart.items.length === 0) {
@@ -2520,15 +2773,15 @@ var BrainerceClient = class {
2520
2773
  /**
2521
2774
  * Clear cart state on logout
2522
2775
  *
2523
- * Call this when a customer logs out to clear the cached cart ID.
2524
- * The localStorage cart remains available for the next guest session.
2776
+ * Call this when a customer logs out to clear the cached customer cart ID.
2777
+ * The session cart (if any) remains available for the next guest session.
2525
2778
  *
2526
2779
  * @example
2527
2780
  * ```typescript
2528
2781
  * client.clearCustomerToken();
2529
2782
  * client.onLogout();
2530
2783
  *
2531
- * // Now back to guest mode - cart uses localStorage
2784
+ * // Now back to guest mode - cart uses server-side session
2532
2785
  * await client.smartAddToCart({ productId: 'prod_123', quantity: 1 });
2533
2786
  * ```
2534
2787
  */
@@ -2546,12 +2799,12 @@ var BrainerceClient = class {
2546
2799
  * // After payment success
2547
2800
  * if (paymentStatus === 'succeeded') {
2548
2801
  * client.onCheckoutComplete();
2549
- * client.clearLocalCart(); // Also clear localStorage for guests
2550
2802
  * }
2551
2803
  * ```
2552
2804
  */
2553
2805
  onCheckoutComplete() {
2554
2806
  this.customerCartId = null;
2807
+ this.clearSessionCart();
2555
2808
  }
2556
2809
  // -------------------- Checkout --------------------
2557
2810
  /**
@@ -2578,7 +2831,7 @@ var BrainerceClient = class {
2578
2831
  async createCheckout(data) {
2579
2832
  if (data.cartId === this.VIRTUAL_LOCAL_CART_ID) {
2580
2833
  throw new BrainerceError(
2581
- "Cannot create checkout from local cart directly. Use startGuestCheckout() for guest checkout with localStorage cart, or sync cart to server first with syncCartOnLogin().",
2834
+ 'Cannot create checkout from "__local__" cart. Use startGuestCheckout() or smartAddToCart() to create a server-side cart first.',
2582
2835
  400
2583
2836
  );
2584
2837
  }
@@ -2647,6 +2900,46 @@ var BrainerceClient = class {
2647
2900
  }
2648
2901
  return this.adminRequest("PATCH", `/api/v1/checkout/${checkoutId}/customer`, data);
2649
2902
  }
2903
+ /**
2904
+ * Get available shipping destinations for this store.
2905
+ *
2906
+ * Returns which countries and regions the store ships to,
2907
+ * so you can populate `<select>` dropdowns in your checkout form.
2908
+ *
2909
+ * @example
2910
+ * ```typescript
2911
+ * const dest = await client.getShippingDestinations();
2912
+ *
2913
+ * if (dest.worldwide) {
2914
+ * // Store ships everywhere — use a full country list
2915
+ * } else {
2916
+ * // Only show available countries
2917
+ * dest.countries.forEach(c => console.log(c.code, c.name));
2918
+ * }
2919
+ *
2920
+ * // Check region restrictions for a country
2921
+ * const usRegions = dest.regions['US'];
2922
+ * if (usRegions) {
2923
+ * // Only these US states are available
2924
+ * usRegions.forEach(r => console.log(r.code, r.name));
2925
+ * }
2926
+ * ```
2927
+ */
2928
+ async getShippingDestinations() {
2929
+ if (this.isVibeCodedMode()) {
2930
+ return this.vibeCodedRequest("GET", "/shipping/destinations");
2931
+ }
2932
+ if (this.storeId && !this.apiKey) {
2933
+ return this.storefrontRequest(
2934
+ "GET",
2935
+ "/checkouts/shipping-destinations"
2936
+ );
2937
+ }
2938
+ return this.adminRequest(
2939
+ "GET",
2940
+ "/api/v1/checkouts/shipping-destinations"
2941
+ );
2942
+ }
2650
2943
  /**
2651
2944
  * Set shipping address on checkout (includes customer email).
2652
2945
  * Returns the checkout and available shipping rates for the address.
@@ -3114,14 +3407,8 @@ var BrainerceClient = class {
3114
3407
  }
3115
3408
  }
3116
3409
  /**
3117
- * Get local cart from localStorage
3118
- * Returns empty cart if none exists
3119
- *
3120
- * @example
3121
- * ```typescript
3122
- * const cart = client.getLocalCart();
3123
- * console.log('Items in cart:', cart.items.length);
3124
- * ```
3410
+ * @deprecated Use `smartGetCart()` instead. Guest carts are now stored on the server.
3411
+ * Get local cart from localStorage. Returns empty cart if none exists.
3125
3412
  */
3126
3413
  getLocalCart() {
3127
3414
  if (!this.isLocalStorageAvailable()) {
@@ -3203,18 +3490,8 @@ var BrainerceClient = class {
3203
3490
  };
3204
3491
  }
3205
3492
  /**
3206
- * Add item to local cart (NO API call)
3207
- * If item already exists, updates quantity
3208
- *
3209
- * @example
3210
- * ```typescript
3211
- * client.addToLocalCart({
3212
- * productId: 'prod_123',
3213
- * quantity: 2,
3214
- * name: 'Cool Shirt',
3215
- * price: '29.99',
3216
- * });
3217
- * ```
3493
+ * @deprecated Use `smartAddToCart()` instead. Guest carts are now stored on the server.
3494
+ * Add item to local cart (NO API call). If item already exists, updates quantity.
3218
3495
  */
3219
3496
  addToLocalCart(item) {
3220
3497
  const cart = this.getLocalCart();
@@ -3236,14 +3513,8 @@ var BrainerceClient = class {
3236
3513
  return cart;
3237
3514
  }
3238
3515
  /**
3239
- * Update item quantity in local cart
3240
- * Set quantity to 0 to remove item
3241
- *
3242
- * @example
3243
- * ```typescript
3244
- * client.updateLocalCartItem('prod_123', 3); // Set quantity to 3
3245
- * client.updateLocalCartItem('prod_123', 0); // Remove item
3246
- * ```
3516
+ * @deprecated Use `smartUpdateCartItem()` instead. Guest carts are now stored on the server.
3517
+ * Update item quantity in local cart. Set quantity to 0 to remove item.
3247
3518
  */
3248
3519
  updateLocalCartItem(productId, quantity, variantId) {
3249
3520
  const cart = this.getLocalCart();
@@ -3261,24 +3532,13 @@ var BrainerceClient = class {
3261
3532
  return cart;
3262
3533
  }
3263
3534
  /**
3264
- * Remove item from local cart
3265
- *
3266
- * @example
3267
- * ```typescript
3268
- * client.removeFromLocalCart('prod_123');
3269
- * client.removeFromLocalCart('prod_456', 'variant_789');
3270
- * ```
3535
+ * @deprecated Use `smartRemoveFromCart()` instead. Guest carts are now stored on the server.
3271
3536
  */
3272
3537
  removeFromLocalCart(productId, variantId) {
3273
3538
  return this.updateLocalCartItem(productId, 0, variantId);
3274
3539
  }
3275
3540
  /**
3276
- * Clear all items from local cart
3277
- *
3278
- * @example
3279
- * ```typescript
3280
- * client.clearLocalCart();
3281
- * ```
3541
+ * @deprecated Use `onCheckoutComplete()` instead. Guest carts are now stored on the server.
3282
3542
  */
3283
3543
  clearLocalCart() {
3284
3544
  const cart = { items: [], updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
@@ -3286,16 +3546,8 @@ var BrainerceClient = class {
3286
3546
  return cart;
3287
3547
  }
3288
3548
  /**
3289
- * Set customer info on local cart
3290
- *
3291
- * @example
3292
- * ```typescript
3293
- * client.setLocalCartCustomer({
3294
- * email: 'john@example.com',
3295
- * firstName: 'John',
3296
- * lastName: 'Doe',
3297
- * });
3298
- * ```
3549
+ * @deprecated Customer info is now set via checkout address methods.
3550
+ * Still used by `submitGuestOrder()` for backward compatibility.
3299
3551
  */
3300
3552
  setLocalCartCustomer(customer) {
3301
3553
  const cart = this.getLocalCart();
@@ -3304,19 +3556,8 @@ var BrainerceClient = class {
3304
3556
  return cart;
3305
3557
  }
3306
3558
  /**
3307
- * Set shipping address on local cart
3308
- *
3309
- * @example
3310
- * ```typescript
3311
- * client.setLocalCartShippingAddress({
3312
- * firstName: 'John',
3313
- * lastName: 'Doe',
3314
- * line1: '123 Main St',
3315
- * city: 'Tel Aviv',
3316
- * postalCode: '6100000',
3317
- * country: 'IL',
3318
- * });
3319
- * ```
3559
+ * @deprecated Address is now set via `updateGuestCheckoutAddress()` after `startGuestCheckout()`.
3560
+ * Still used by `submitGuestOrder()` for backward compatibility.
3320
3561
  */
3321
3562
  setLocalCartShippingAddress(address) {
3322
3563
  const cart = this.getLocalCart();
@@ -3325,7 +3566,8 @@ var BrainerceClient = class {
3325
3566
  return cart;
3326
3567
  }
3327
3568
  /**
3328
- * Set billing address on local cart
3569
+ * @deprecated Address is now set via `updateGuestCheckoutAddress()` after `startGuestCheckout()`.
3570
+ * Still used by `submitGuestOrder()` for backward compatibility.
3329
3571
  */
3330
3572
  setLocalCartBillingAddress(address) {
3331
3573
  const cart = this.getLocalCart();
@@ -3334,7 +3576,7 @@ var BrainerceClient = class {
3334
3576
  return cart;
3335
3577
  }
3336
3578
  /**
3337
- * Set coupon code on local cart
3579
+ * @deprecated Coupons are now applied via `applyCoupon()` on the server cart.
3338
3580
  */
3339
3581
  setLocalCartCoupon(couponCode) {
3340
3582
  const cart = this.getLocalCart();
@@ -3343,7 +3585,7 @@ var BrainerceClient = class {
3343
3585
  return cart;
3344
3586
  }
3345
3587
  /**
3346
- * Get total items count in local cart
3588
+ * @deprecated Use `getSmartCartItemCount()` instead.
3347
3589
  */
3348
3590
  getLocalCartItemCount() {
3349
3591
  const cart = this.getLocalCart();
@@ -3373,6 +3615,46 @@ var BrainerceClient = class {
3373
3615
  * ```
3374
3616
  */
3375
3617
  async submitGuestOrder(options) {
3618
+ if (this.sessionToken) {
3619
+ const serverCart = await this.getOrCreateSessionCart();
3620
+ if (!serverCart.items || serverCart.items.length === 0) {
3621
+ throw new BrainerceError("Cart is empty", 400);
3622
+ }
3623
+ const localCart = this.getLocalCart();
3624
+ if (!localCart.customer?.email) {
3625
+ throw new BrainerceError(
3626
+ "Customer email is required. Call setLocalCartCustomer() first.",
3627
+ 400
3628
+ );
3629
+ }
3630
+ if (!localCart.shippingAddress) {
3631
+ throw new BrainerceError(
3632
+ "Shipping address is required. Call setLocalCartShippingAddress() first.",
3633
+ 400
3634
+ );
3635
+ }
3636
+ const trackingResult = await this.startGuestCheckout();
3637
+ if (!trackingResult.tracked) {
3638
+ throw new BrainerceError("Failed to create checkout from session cart", 500);
3639
+ }
3640
+ await this.updateGuestCheckoutAddress(trackingResult.checkoutId, {
3641
+ shippingAddress: {
3642
+ ...localCart.shippingAddress,
3643
+ email: localCart.customer.email
3644
+ },
3645
+ billingAddress: localCart.billingAddress
3646
+ });
3647
+ const orderResult = await this.completeGuestCheckout(trackingResult.checkoutId, {
3648
+ clearCartOnSuccess: options?.clearCartOnSuccess
3649
+ });
3650
+ return {
3651
+ orderId: orderResult.orderId,
3652
+ orderNumber: orderResult.orderNumber || orderResult.orderId,
3653
+ status: orderResult.status || "pending",
3654
+ total: orderResult.total ?? 0,
3655
+ message: orderResult.message || "Order created successfully"
3656
+ };
3657
+ }
3376
3658
  const cart = this.getLocalCart();
3377
3659
  if (cart.items.length === 0) {
3378
3660
  throw new BrainerceError("Cart is empty", 400);
@@ -3390,7 +3672,6 @@ var BrainerceClient = class {
3390
3672
  shippingAddress: {
3391
3673
  ...cart.shippingAddress,
3392
3674
  email: cart.customer.email
3393
- // Already validated above
3394
3675
  },
3395
3676
  billingAddress: cart.billingAddress
3396
3677
  });
@@ -3478,6 +3759,34 @@ var BrainerceClient = class {
3478
3759
  * ```
3479
3760
  */
3480
3761
  async startGuestCheckout(options) {
3762
+ if (this.sessionToken) {
3763
+ const serverCart = await this.getOrCreateSessionCart();
3764
+ if (!serverCart.items || serverCart.items.length === 0) {
3765
+ throw new BrainerceError("Cart is empty", 400);
3766
+ }
3767
+ let selectedItemIds;
3768
+ if (options?.selectedIndices?.length) {
3769
+ selectedItemIds = options.selectedIndices.map((i) => serverCart.items[i]?.id).filter((id) => !!id);
3770
+ if (selectedItemIds.length === 0) {
3771
+ throw new BrainerceError("No items selected for checkout", 400);
3772
+ }
3773
+ }
3774
+ const checkout = await this.createCheckout({
3775
+ cartId: serverCart.id,
3776
+ selectedItemIds
3777
+ });
3778
+ this.saveActiveCheckout({
3779
+ checkoutId: checkout.id,
3780
+ cartId: serverCart.id,
3781
+ selectedIndices: options?.selectedIndices
3782
+ });
3783
+ return {
3784
+ tracked: true,
3785
+ checkoutId: checkout.id,
3786
+ cartId: serverCart.id,
3787
+ message: "Checkout created from session cart"
3788
+ };
3789
+ }
3481
3790
  const cart = this.getLocalCart();
3482
3791
  if (cart.items.length === 0) {
3483
3792
  throw new BrainerceError("Cart is empty", 400);
@@ -3541,16 +3850,8 @@ var BrainerceClient = class {
3541
3850
  }
3542
3851
  }
3543
3852
  /**
3853
+ * @deprecated Partial checkout is now handled server-side via `selectedItemIds`.
3544
3854
  * Remove specific items from local cart by their indices.
3545
- * Use after partial checkout to remove only the purchased items.
3546
- *
3547
- * @param indices - Array of item indices to remove
3548
- *
3549
- * @example
3550
- * ```typescript
3551
- * // After partial checkout success, remove purchased items
3552
- * client.removeLocalCartItemsByIndex([0, 2]); // Removes items at index 0 and 2
3553
- * ```
3554
3855
  */
3555
3856
  removeLocalCartItemsByIndex(indices) {
3556
3857
  const cart = this.getLocalCart();
@@ -3627,6 +3928,7 @@ var BrainerceClient = class {
3627
3928
  this.removeLocalCartItemsByIndex(indices);
3628
3929
  } else {
3629
3930
  this.clearLocalCart();
3931
+ this.clearSessionCart();
3630
3932
  }
3631
3933
  this.customerCartId = null;
3632
3934
  }
@@ -3724,6 +4026,7 @@ var BrainerceClient = class {
3724
4026
  }
3725
4027
  if (isLoggedIn) {
3726
4028
  this.clearLocalCart();
4029
+ this.clearSessionCart();
3727
4030
  return {
3728
4031
  cleared: true,
3729
4032
  mode: "full",
@@ -3740,6 +4043,7 @@ var BrainerceClient = class {
3740
4043
  };
3741
4044
  }
3742
4045
  this.clearLocalCart();
4046
+ this.clearSessionCart();
3743
4047
  return {
3744
4048
  cleared: true,
3745
4049
  mode: "full",