brainerce 1.63.0 → 2.0.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
@@ -115,7 +115,7 @@ function isDevGuardsEnabled() {
115
115
  }
116
116
 
117
117
  // src/version.ts
118
- var SDK_VERSION = "1.60.0";
118
+ var SDK_VERSION = "2.0.0";
119
119
 
120
120
  // src/client.ts
121
121
  var DEFAULT_BASE_URL = "https://api.brainerce.com";
@@ -561,7 +561,7 @@ var _BrainerceClient = class _BrainerceClient {
561
561
  */
562
562
  this.blog = /* @__PURE__ */ (() => {
563
563
  const publicBase = "/blog/posts";
564
- const adminBase = "/blog/posts";
564
+ const adminBase = "/api/blog/posts";
565
565
  const requireAdmin = (action) => {
566
566
  if (this.isVibeCodedMode() || this.storeId && !this.apiKey) {
567
567
  throw new BrainerceError(
@@ -2395,115 +2395,97 @@ var _BrainerceClient = class _BrainerceClient {
2395
2395
  return this.request("PATCH", `/api/v1/orders/${encodePathSegment(orderId)}`, data);
2396
2396
  }
2397
2397
  /**
2398
- * Update order status
2398
+ * Update order status.
2399
+ *
2400
+ * **Not callable — use {@link updateOrder} instead.** Status changes do work
2401
+ * over the API key, just by a different route.
2402
+ *
2403
+ * @deprecated Call `updateOrder(orderId, { status })`.
2399
2404
  *
2400
2405
  * @example
2401
2406
  * ```typescript
2402
- * const order = await client.updateOrderStatus('order_123', 'shipped');
2407
+ * const order = await client.updateOrder('order_123', { status: 'SHIPPED' });
2403
2408
  * ```
2404
2409
  */
2405
2410
  async updateOrderStatus(orderId, status) {
2406
- return this.request("PATCH", `/api/v1/orders/${encodePathSegment(orderId)}/status`, {
2407
- status
2408
- });
2411
+ void orderId;
2412
+ void status;
2413
+ throw new BrainerceError(
2414
+ "updateOrderStatus is not a route on the API-key /v1 surface. Status changes go through updateOrder instead: updateOrder(orderId, { status }) PATCHes /api/v1/orders/:id and ends up in the same service call.",
2415
+ 400
2416
+ );
2409
2417
  }
2410
2418
  /**
2411
- * Update order payment method
2412
- * Note: Only WooCommerce supports syncing payment method changes back to platform
2419
+ * Update order payment method.
2413
2420
  *
2414
- * @example
2415
- * ```typescript
2416
- * const order = await client.updatePaymentMethod('order_123', 'credit_card');
2417
- * ```
2421
+ * **Not callable.** The API-key `/v1` surface has no payment-method route,
2422
+ * so this throws in every mode. Change the payment method from the
2423
+ * dashboard until the route ships.
2418
2424
  */
2419
2425
  async updatePaymentMethod(orderId, paymentMethod) {
2420
- return this.request(
2421
- "PATCH",
2422
- `/api/v1/orders/${encodePathSegment(orderId)}/payment-method`,
2423
- {
2424
- paymentMethod
2425
- }
2426
+ void orderId;
2427
+ void paymentMethod;
2428
+ throw new BrainerceError(
2429
+ "updatePaymentMethod is not a route on the API-key /v1 surface. There is no orders/:id/payment-method endpoint to call; change the payment method from the Brainerce dashboard.",
2430
+ 400
2426
2431
  );
2427
2432
  }
2428
2433
  /**
2429
- * Update order notes
2434
+ * Update order notes.
2430
2435
  *
2431
- * @example
2432
- * ```typescript
2433
- * const order = await client.updateOrderNotes('order_123', 'Customer requested gift wrapping');
2434
- * ```
2436
+ * **Not callable.** The API-key `/v1` surface has no order-notes route, so
2437
+ * this throws in every mode. Edit notes from the dashboard until the route
2438
+ * ships.
2435
2439
  */
2436
2440
  async updateOrderNotes(orderId, notes) {
2437
- return this.request("PATCH", `/api/v1/orders/${encodePathSegment(orderId)}/notes`, {
2438
- notes
2439
- });
2441
+ void orderId;
2442
+ void notes;
2443
+ throw new BrainerceError(
2444
+ "updateOrderNotes is not a route on the API-key /v1 surface. There is no orders/:id/notes endpoint to call; edit the note from the Brainerce dashboard.",
2445
+ 400
2446
+ );
2440
2447
  }
2441
2448
  /**
2442
- * Get refunds for an order
2443
- * Returns refunds from the source platform (Shopify/WooCommerce only)
2449
+ * Get refunds for an order.
2444
2450
  *
2445
- * @example
2446
- * ```typescript
2447
- * const refunds = await client.getOrderRefunds('order_123');
2448
- * console.log('Total refunds:', refunds.length);
2449
- * ```
2451
+ * **Not callable.** The API-key `/v1` surface has no refunds route, so this
2452
+ * throws in every mode. Read refunds from the dashboard until the route
2453
+ * ships.
2450
2454
  */
2451
2455
  async getOrderRefunds(orderId) {
2452
- return this.request("GET", `/api/v1/orders/${encodePathSegment(orderId)}/refunds`);
2456
+ void orderId;
2457
+ throw new BrainerceError(
2458
+ "getOrderRefunds is not a route on the API-key /v1 surface. There is no orders/:id/refunds endpoint to call; view refunds in the Brainerce dashboard.",
2459
+ 400
2460
+ );
2453
2461
  }
2454
2462
  /**
2455
- * Create a refund for an order
2456
- * Creates refund on the source platform (Shopify/WooCommerce only)
2463
+ * Create a refund for an order.
2457
2464
  *
2458
- * @example
2459
- * ```typescript
2460
- * // Full refund
2461
- * const refund = await client.createRefund('order_123', {
2462
- * type: 'full',
2463
- * restockInventory: true,
2464
- * notifyCustomer: true,
2465
- * reason: 'Customer request',
2466
- * });
2467
- *
2468
- * // Partial refund
2469
- * const partialRefund = await client.createRefund('order_123', {
2470
- * type: 'partial',
2471
- * items: [
2472
- * { lineItemId: 'item_456', quantity: 1 },
2473
- * ],
2474
- * restockInventory: true,
2475
- * });
2476
- * ```
2465
+ * **Not callable.** The API-key `/v1` surface has no refunds route, so this
2466
+ * throws in every mode. Refund from the dashboard until the route ships.
2477
2467
  */
2478
2468
  async createRefund(orderId, data) {
2479
- return this.request(
2480
- "POST",
2481
- `/api/v1/orders/${encodePathSegment(orderId)}/refunds`,
2482
- data
2469
+ void orderId;
2470
+ void data;
2471
+ throw new BrainerceError(
2472
+ "createRefund is not a route on the API-key /v1 surface. There is no orders/:id/refunds endpoint to call, so no refund was issued; refund the order from the Brainerce dashboard.",
2473
+ 400
2483
2474
  );
2484
2475
  }
2485
2476
  /**
2486
- * Update order shipping address
2487
- * Syncs to source platform (Shopify/WooCommerce only)
2477
+ * Update order shipping address.
2488
2478
  *
2489
- * @example
2490
- * ```typescript
2491
- * const order = await client.updateOrderShipping('order_123', {
2492
- * firstName: 'John',
2493
- * lastName: 'Doe',
2494
- * line1: '456 New Address',
2495
- * city: 'Los Angeles',
2496
- * state: 'CA',
2497
- * country: 'US',
2498
- * postalCode: '90001',
2499
- * });
2500
- * ```
2479
+ * **Not callable.** The API-key `/v1` surface has no order-shipping route,
2480
+ * so this throws in every mode. Correct the address from the dashboard
2481
+ * until the route ships.
2501
2482
  */
2502
2483
  async updateOrderShipping(orderId, data) {
2503
- return this.request(
2504
- "PATCH",
2505
- `/api/v1/orders/${encodePathSegment(orderId)}/shipping`,
2506
- data
2484
+ void orderId;
2485
+ void data;
2486
+ throw new BrainerceError(
2487
+ "updateOrderShipping is not a route on the API-key /v1 surface. There is no orders/:id/shipping endpoint to call, so the address was not changed; edit it in the Brainerce dashboard.",
2488
+ 400
2507
2489
  );
2508
2490
  }
2509
2491
  /**
@@ -2569,17 +2551,19 @@ var _BrainerceClient = class _BrainerceClient {
2569
2551
  return this.request("GET", `/api/v1/orders/${encodePathSegment(orderId)}/shipments`);
2570
2552
  }
2571
2553
  /**
2572
- * Cancel an order
2573
- * Works for Shopify and WooCommerce orders that haven't been fulfilled
2554
+ * Cancel an order.
2574
2555
  *
2575
- * @example
2576
- * ```typescript
2577
- * const order = await client.cancelOrder('order_123');
2578
- * console.log('Order status:', order.status); // 'cancelled'
2579
- * ```
2556
+ * **Not callable.** The API-key `/v1` surface has no cancel route, so this
2557
+ * throws in every mode. A status move to cancelled may be reachable through
2558
+ * {@link updateOrder} depending on what the order's state machine allows;
2559
+ * otherwise cancel from the dashboard.
2580
2560
  */
2581
2561
  async cancelOrder(orderId) {
2582
- return this.request("POST", `/api/v1/orders/${encodePathSegment(orderId)}/cancel`);
2562
+ void orderId;
2563
+ throw new BrainerceError(
2564
+ "cancelOrder is not a route on the API-key /v1 surface. There is no orders/:id/cancel endpoint to call, so the order was not cancelled. Try updateOrder(orderId, { status }) for a plain status move, or cancel from the Brainerce dashboard.",
2565
+ 400
2566
+ );
2583
2567
  }
2584
2568
  /**
2585
2569
  * Fulfill an order (mark as shipped), or correct the tracking of an order
@@ -2593,110 +2577,87 @@ var _BrainerceClient = class _BrainerceClient {
2593
2577
  * ship date is not rewritten, and no fulfilment event fires. That is the way
2594
2578
  * to fix a mistyped tracking number.
2595
2579
  *
2596
- * @example
2597
- * ```typescript
2598
- * // First fulfilmentemails the shopper by default.
2599
- * await client.fulfillOrder('order_123', {
2600
- * trackingNumber: '1Z999AA10123456784',
2601
- * trackingCompany: 'UPS',
2602
- * trackingUrl: 'https://www.ups.com/track?tracknum=1Z999AA10123456784',
2603
- * notifyCustomer: true,
2604
- * });
2605
- *
2606
- * // Correction — silent unless you opt back in.
2607
- * await client.fulfillOrder('order_123', {
2608
- * trackingNumber: '1Z999AA10123456785',
2609
- * });
2610
- * ```
2580
+ * **Not callable.** The API-key `/v1` surface has no fulfil route, so this
2581
+ * throws in every mode. To ship an order over the API today, buy a label
2582
+ * with {@link createShippingLabel} — the carrier's webhooks then move the
2583
+ * shipment through in-transit and delivered on their own. Otherwise fulfil
2584
+ * from the dashboard.
2611
2585
  */
2612
2586
  async fulfillOrder(orderId, data) {
2613
- return this.request(
2614
- "POST",
2615
- `/api/v1/orders/${encodePathSegment(orderId)}/fulfill`,
2616
- data || {}
2587
+ void orderId;
2588
+ void data;
2589
+ throw new BrainerceError(
2590
+ "fulfillOrder is not a route on the API-key /v1 surface. There is no orders/:id/fulfill endpoint to call, so nothing was fulfilled and no shipped email went out. Use createShippingLabel to ship over the API, or fulfil from the Brainerce dashboard.",
2591
+ 400
2617
2592
  );
2618
2593
  }
2619
2594
  /**
2620
- * Sync draft orders from connected platforms
2595
+ * Sync draft orders from connected platforms.
2621
2596
  *
2622
- * @example
2623
- * ```typescript
2624
- * const result = await client.syncDraftOrders();
2625
- * console.log('Draft orders synced');
2626
- * ```
2597
+ * **Not callable.** The API-key `/v1` surface has no draft-order routes at
2598
+ * all, so this throws in every mode. {@link triggerSync} covers a general
2599
+ * platform sync; draft orders are managed from the dashboard.
2627
2600
  */
2628
2601
  async syncDraftOrders() {
2629
- return this.request("POST", "/api/v1/orders/sync-drafts");
2602
+ throw new BrainerceError(
2603
+ "syncDraftOrders is not a route on the API-key /v1 surface. There is no orders/sync-drafts endpoint to call, so nothing was synced. Use triggerSync for a platform sync, or work with drafts in the Brainerce dashboard.",
2604
+ 400
2605
+ );
2630
2606
  }
2631
2607
  /**
2632
- * Complete a draft order (convert to regular order)
2608
+ * Complete a draft order (convert to regular order).
2633
2609
  *
2634
- * @example
2635
- * ```typescript
2636
- * const order = await client.completeDraftOrder('draft_123', {
2637
- * paymentPending: false,
2638
- * });
2639
- * ```
2610
+ * **Not callable.** The API-key `/v1` surface has no draft-order routes at
2611
+ * all, so this throws in every mode. Complete drafts from the dashboard.
2640
2612
  */
2641
2613
  async completeDraftOrder(orderId, data) {
2642
- return this.request(
2643
- "POST",
2644
- `/api/v1/orders/${encodePathSegment(orderId)}/complete-draft`,
2645
- data || {}
2614
+ void orderId;
2615
+ void data;
2616
+ throw new BrainerceError(
2617
+ "completeDraftOrder is not a route on the API-key /v1 surface. There is no orders/:id/complete-draft endpoint to call, so the draft was not converted; complete it in the Brainerce dashboard.",
2618
+ 400
2646
2619
  );
2647
2620
  }
2648
2621
  /**
2649
- * Send invoice for a draft order
2622
+ * Send invoice for a draft order.
2650
2623
  *
2651
- * @example
2652
- * ```typescript
2653
- * await client.sendDraftInvoice('draft_123', {
2654
- * to: 'customer@example.com',
2655
- * subject: 'Your Invoice',
2656
- * customMessage: 'Thank you for your order!',
2657
- * });
2658
- * ```
2624
+ * **Not callable.** The API-key `/v1` surface has no draft-order routes at
2625
+ * all, so this throws in every mode. Send the invoice from the dashboard.
2659
2626
  */
2660
2627
  async sendDraftInvoice(orderId, data) {
2661
- return this.request(
2662
- "POST",
2663
- `/api/v1/orders/${encodePathSegment(orderId)}/send-invoice`,
2664
- data || {}
2628
+ void orderId;
2629
+ void data;
2630
+ throw new BrainerceError(
2631
+ "sendDraftInvoice is not a route on the API-key /v1 surface. There is no orders/:id/send-invoice endpoint to call, so no invoice was sent; send it from the Brainerce dashboard.",
2632
+ 400
2665
2633
  );
2666
2634
  }
2667
2635
  /**
2668
- * Delete a draft order
2636
+ * Delete a draft order.
2669
2637
  *
2670
- * @example
2671
- * ```typescript
2672
- * await client.deleteDraftOrder('draft_123');
2673
- * ```
2638
+ * **Not callable.** The API-key `/v1` surface has no draft-order routes at
2639
+ * all, so this throws in every mode. Delete drafts from the dashboard.
2674
2640
  */
2675
2641
  async deleteDraftOrder(orderId) {
2676
- await this.request("DELETE", `/api/v1/orders/${encodePathSegment(orderId)}/draft`);
2642
+ void orderId;
2643
+ throw new BrainerceError(
2644
+ "deleteDraftOrder is not a route on the API-key /v1 surface. There is no orders/:id/draft endpoint to call, so nothing was deleted; delete the draft in the Brainerce dashboard.",
2645
+ 400
2646
+ );
2677
2647
  }
2678
2648
  /**
2679
- * Update a draft order
2649
+ * Update a draft order.
2680
2650
  *
2681
- * @example
2682
- * ```typescript
2683
- * const order = await client.updateDraftOrder('draft_123', {
2684
- * note: 'Updated customer note',
2685
- * email: 'newemail@example.com',
2686
- * shippingAddress: {
2687
- * firstName: 'John',
2688
- * lastName: 'Doe',
2689
- * address1: '123 Main St',
2690
- * city: 'New York',
2691
- * province: 'NY',
2692
- * country: 'US',
2693
- * zip: '10001',
2694
- * },
2695
- * });
2696
- * ```
2651
+ * **Not callable.** The API-key `/v1` surface has no draft-order routes at
2652
+ * all, so this throws in every mode. Edit drafts from the dashboard.
2697
2653
  */
2698
2654
  async updateDraftOrder(orderId, data) {
2699
- return this.request("PATCH", `/api/v1/orders/${encodePathSegment(orderId)}/draft`, data);
2655
+ void orderId;
2656
+ void data;
2657
+ throw new BrainerceError(
2658
+ "updateDraftOrder is not a route on the API-key /v1 surface. There is no orders/:id/draft endpoint to call, so the draft was not changed; edit it in the Brainerce dashboard.",
2659
+ 400
2660
+ );
2700
2661
  }
2701
2662
  // -------------------- Inventory --------------------
2702
2663
  /**
@@ -2711,82 +2672,91 @@ var _BrainerceClient = class _BrainerceClient {
2711
2672
  );
2712
2673
  }
2713
2674
  /**
2714
- * Get current inventory for a product
2675
+ * Get current inventory for a product.
2676
+ *
2677
+ * **Admin mode only** — the API key needs the `inventory:read` scope.
2678
+ *
2679
+ * This used to request `/api/v1/inventory/:productId`, which does not
2680
+ * exist and 404'd silently. The live route is product-scoped:
2681
+ * `GET /api/v1/products/:id/inventory`. A product with no inventory row
2682
+ * reads back as all zeroes rather than 404ing.
2715
2683
  */
2716
2684
  async getInventory(productId) {
2717
- return this.request("GET", `/api/v1/inventory/${encodePathSegment(productId)}`);
2685
+ return this.adminRequest(
2686
+ "GET",
2687
+ `/api/v1/products/${encodePathSegment(productId)}/inventory`
2688
+ );
2718
2689
  }
2719
2690
  /**
2720
- * Edit inventory manually with reason for audit trail
2691
+ * Edit inventory manually with a reason for the audit trail.
2721
2692
  *
2722
- * @example
2723
- * ```typescript
2724
- * const inventory = await client.editInventory({
2725
- * productId: 'prod_123',
2726
- * newTotal: 100,
2727
- * reason: 'Restocked from warehouse',
2728
- * });
2729
- * ```
2693
+ * **Not callable.** The API-key `/v1` surface carries no `inventory`
2694
+ * namespace, so this throws in every mode.
2695
+ *
2696
+ * {@link updateInventory} is the closest working call: it sets the same
2697
+ * absolute stock level over `PUT /api/v1/products/:id/inventory`, but the
2698
+ * reason is not yours to choose — the server records a generic
2699
+ * "Updated via External API" against the audit trail. If the reason text
2700
+ * matters, make the edit from the dashboard.
2730
2701
  */
2731
2702
  async editInventory(data) {
2732
- return this.request("POST", "/api/v1/inventory/edit", data);
2703
+ void data;
2704
+ throw new BrainerceError(
2705
+ "editInventory is not a route on the API-key /v1 surface. There is no inventory/edit endpoint to call, so stock was not changed. Use updateInventory(productId, { quantity }) to set the same level, though it records a generic audit reason. Edit from the dashboard when the reason text matters.",
2706
+ 400
2707
+ );
2733
2708
  }
2734
2709
  /**
2735
- * Get inventory sync status for all products in the store
2710
+ * Get inventory sync status for all products in the store.
2736
2711
  *
2737
- * @example
2738
- * ```typescript
2739
- * const status = await client.getInventorySyncStatus();
2740
- * console.log(`${status.pending} products pending sync`);
2741
- * console.log(`Last sync: ${status.lastSyncAt}`);
2742
- * ```
2712
+ * **Not callable.** The API-key `/v1` surface carries no `inventory`
2713
+ * namespace, so this throws in every mode. Sync state is visible in the
2714
+ * dashboard; {@link getSyncStatus} covers platform sync jobs.
2743
2715
  */
2744
2716
  async getInventorySyncStatus() {
2745
- return this.request("GET", "/api/v1/inventory/sync-status");
2717
+ throw new BrainerceError(
2718
+ "getInventorySyncStatus is not a route on the API-key /v1 surface. There is no inventory/sync-status endpoint to call; check inventory sync state in the Brainerce dashboard.",
2719
+ 400
2720
+ );
2746
2721
  }
2747
2722
  /**
2748
- * Get inventory for multiple products at once
2723
+ * Get inventory for multiple products at once.
2749
2724
  *
2750
- * @example
2751
- * ```typescript
2752
- * const inventories = await client.getBulkInventory(['prod_123', 'prod_456', 'prod_789']);
2753
- * inventories.forEach(inv => {
2754
- * console.log(`${inv.productId}: ${inv.available} available`);
2755
- * });
2756
- * ```
2725
+ * **Not callable.** The API-key `/v1` surface carries no `inventory`
2726
+ * namespace, so this throws in every mode. There is no bulk stock read on
2727
+ * the API key today: fall back to {@link getInventory} per product, or read
2728
+ * the stock that {@link getProducts} already returns on each product.
2757
2729
  */
2758
2730
  async getBulkInventory(productIds) {
2759
- return this.request("POST", "/api/v1/inventory/bulk", { productIds });
2731
+ void productIds;
2732
+ throw new BrainerceError(
2733
+ "getBulkInventory is not a route on the API-key /v1 surface. There is no inventory/bulk endpoint to call; read stock per product with getInventory, or off the products returned by getProducts.",
2734
+ 400
2735
+ );
2760
2736
  }
2761
2737
  /**
2762
- * Reconcile inventory between Brainerce and connected platforms
2763
- * Detects and optionally fixes discrepancies
2738
+ * Reconcile inventory between Brainerce and connected platforms.
2739
+ * Detects and optionally fixes discrepancies.
2764
2740
  *
2765
- * @example
2766
- * ```typescript
2767
- * // Reconcile single product (dry run)
2768
- * const result = await client.reconcileInventory({ productId: 'prod_123' });
2769
- *
2770
- * // Reconcile all products with auto-fix
2771
- * const summary = await client.reconcileInventory({ autoFix: true });
2772
- * console.log(`Reconciled ${summary.reconciled} products`);
2773
- * ```
2741
+ * **Not callable.** The API-key `/v1` surface carries no `inventory`
2742
+ * namespace, so this throws in every mode, `autoFix` included. Reconcile
2743
+ * from the dashboard.
2774
2744
  */
2775
2745
  async reconcileInventory(options) {
2776
- const queryParams = {};
2777
- if (options?.productId) queryParams.productId = options.productId;
2778
- if (options?.autoFix) queryParams.autoFix = "true";
2779
- return this.request(
2780
- "POST",
2781
- "/api/v1/inventory/reconcile",
2782
- void 0,
2783
- queryParams
2746
+ void options;
2747
+ throw new BrainerceError(
2748
+ "reconcileInventory is not a route on the API-key /v1 surface. There is no inventory/reconcile endpoint to call, so nothing was reconciled or fixed; run reconciliation from the Brainerce dashboard.",
2749
+ 400
2784
2750
  );
2785
2751
  }
2786
2752
  /**
2787
2753
  * Check stock availability for one or more items before adding to cart or checkout
2788
2754
  * Use this to validate stock before operations that might fail due to insufficient inventory
2789
2755
  *
2756
+ * **Vibe-coded or storefront mode only.** There is no stock-check route on
2757
+ * the API-key `/v1` surface; in admin mode this throws. The same applies to
2758
+ * {@link checkCartStock}, which routes through here.
2759
+ *
2790
2760
  * @example
2791
2761
  * ```typescript
2792
2762
  * // Check if items are available before adding to cart
@@ -2818,9 +2788,10 @@ var _BrainerceClient = class _BrainerceClient {
2818
2788
  { items }
2819
2789
  );
2820
2790
  }
2821
- return this.request("POST", "/api/v1/inventory/check-availability", {
2822
- items
2823
- });
2791
+ throw new BrainerceError(
2792
+ "checkStockAvailability is only available in vibe-coded or storefront mode. The API-key /v1 surface has no inventory/check-availability route; read stock per product with getInventory instead.",
2793
+ 400
2794
+ );
2824
2795
  }
2825
2796
  /**
2826
2797
  * Check stock availability for cart items before checkout.
@@ -3157,49 +3128,43 @@ var _BrainerceClient = class _BrainerceClient {
3157
3128
  * Request a password reset email for a customer
3158
3129
  * Works in vibe-coded, storefront, and admin mode
3159
3130
  *
3160
- * The `resetUrl` MUST be supplied explicitly in non-browser (SSR / Node)
3161
- * contexts auto-deriving it from `window.location.origin` is impossible
3162
- * there and historically resulted in `undefined` being sent to the backend,
3163
- * which then bounced the email to a broken link. In browser contexts the
3164
- * origin is still used as a fallback but the SDK logs a one-time warning
3165
- * recommending an explicit value so server-rendered + proxied dashboards
3166
- * don't silently rely on the wrong host.
3131
+ * The reset link's host is chosen by the server, not by the caller: it is
3132
+ * derived from the sales channel's own domain, falling back to the backend's
3133
+ * configured frontend URL, and the request is rejected if neither resolves.
3134
+ *
3135
+ * The SDK used to send a `resetUrl` in the request body. The backend
3136
+ * deliberately removed that field: any caller could submit an arbitrary URL
3137
+ * and have it emailed, from a Brainerce-domained sender, to the address
3138
+ * holder — a phishing-link injection. `ForgotPasswordDto` now declares
3139
+ * `email` and nothing else, and the API's global validation pipe runs with
3140
+ * `whitelist` + `forbidNonWhitelisted`, so a body carrying `resetUrl` fails
3141
+ * the whole call with `400 property resetUrl should not exist`. Only `email`
3142
+ * is sent.
3143
+ *
3144
+ * The endpoint always answers 200 so it cannot be used to enumerate
3145
+ * accounts; the mail is only sent when a matching customer exists.
3167
3146
  *
3168
3147
  * @param email - Customer email address
3169
- * @param options - Optional settings
3170
- * @param options.resetUrl - Reset URL the email links should point to.
3171
- * Required outside the browser; recommended inside it.
3148
+ * @param options - Accepted for source compatibility only. Ignored.
3172
3149
  */
3173
3150
  async forgotPassword(email, options) {
3174
- let resetUrl = options?.resetUrl;
3175
- if (!resetUrl) {
3176
- if (typeof window === "undefined") {
3177
- throw new BrainerceError(
3178
- 'forgotPassword: `resetUrl` is required outside the browser. Pass `{ resetUrl: "https://your-site.example/reset-password" }` so the email links to the right host.',
3179
- 400
3180
- );
3181
- }
3182
- console.warn(
3183
- "BrainerceClient.forgotPassword: deriving `resetUrl` from `window.location.origin` \u2014 pass `{ resetUrl }` explicitly to avoid wrong-host links behind proxies or in SSR."
3184
- );
3185
- resetUrl = `${window.location.origin}/reset-password`;
3186
- }
3151
+ void options;
3152
+ const body = { email };
3187
3153
  if (this.isVibeCodedMode()) {
3188
- return this.vibeCodedRequest("POST", "/customers/forgot-password", {
3189
- email,
3190
- resetUrl
3191
- });
3154
+ return this.vibeCodedRequest("POST", "/customers/forgot-password", body);
3192
3155
  }
3193
3156
  if (this.storeId && !this.apiKey) {
3194
- return this.storefrontRequest("POST", "/customers/forgot-password", {
3195
- email,
3196
- resetUrl
3197
- });
3157
+ return this.storefrontRequest(
3158
+ "POST",
3159
+ "/customers/forgot-password",
3160
+ body
3161
+ );
3198
3162
  }
3199
- return this.adminRequest("POST", "/api/v1/customers/forgot-password", {
3200
- email,
3201
- resetUrl
3202
- });
3163
+ return this.adminRequest(
3164
+ "POST",
3165
+ "/api/v1/customers/forgot-password",
3166
+ body
3167
+ );
3203
3168
  }
3204
3169
  /**
3205
3170
  * Reset customer password using a reset token received via email
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brainerce",
3
- "version": "1.63.0",
3
+ "version": "2.0.0",
4
4
  "description": "Official SDK for building e-commerce storefronts with Brainerce 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",