brainerce 1.63.0 → 2.0.2
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/README.md +665 -298
- package/dist/index.d.mts +530 -201
- package/dist/index.d.ts +530 -201
- package/dist/index.js +389 -244
- package/dist/index.mjs +389 -244
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -115,7 +115,7 @@ function isDevGuardsEnabled() {
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
// src/version.ts
|
|
118
|
-
var SDK_VERSION = "
|
|
118
|
+
var SDK_VERSION = "2.0.1";
|
|
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(
|
|
@@ -674,7 +674,7 @@ var _BrainerceClient = class _BrainerceClient {
|
|
|
674
674
|
}
|
|
675
675
|
if (!options.salesChannelId && options.connectionId) {
|
|
676
676
|
console.warn(
|
|
677
|
-
"BrainerceClient: `connectionId` is deprecated \u2014 use `salesChannelId` instead. `connectionId`
|
|
677
|
+
"BrainerceClient: `connectionId` is deprecated \u2014 use `salesChannelId` instead. `connectionId` is a permanent backward-compat alias and is not scheduled for removal."
|
|
678
678
|
);
|
|
679
679
|
}
|
|
680
680
|
if (options.apiKey && typeof window !== "undefined") {
|
|
@@ -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.
|
|
2407
|
+
* const order = await client.updateOrder('order_123', { status: 'SHIPPED' });
|
|
2403
2408
|
* ```
|
|
2404
2409
|
*/
|
|
2405
2410
|
async updateOrderStatus(orderId, status) {
|
|
2406
|
-
|
|
2407
|
-
|
|
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
|
-
*
|
|
2415
|
-
*
|
|
2416
|
-
*
|
|
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
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
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
|
-
*
|
|
2432
|
-
*
|
|
2433
|
-
*
|
|
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
|
-
|
|
2438
|
-
|
|
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
|
-
*
|
|
2446
|
-
*
|
|
2447
|
-
*
|
|
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
|
-
|
|
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)
|
|
2457
|
-
*
|
|
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
|
-
* });
|
|
2463
|
+
* Create a refund for an order.
|
|
2467
2464
|
*
|
|
2468
|
-
*
|
|
2469
|
-
*
|
|
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
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
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
|
-
*
|
|
2490
|
-
*
|
|
2491
|
-
*
|
|
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
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
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,49 @@ var _BrainerceClient = class _BrainerceClient {
|
|
|
2569
2551
|
return this.request("GET", `/api/v1/orders/${encodePathSegment(orderId)}/shipments`);
|
|
2570
2552
|
}
|
|
2571
2553
|
/**
|
|
2572
|
-
*
|
|
2573
|
-
*
|
|
2554
|
+
* Buy a return label the merchant sends to their customer to print.
|
|
2555
|
+
*
|
|
2556
|
+
* Requires admin mode (`apiKey`) with `FULFILL_ORDERS` permission — it
|
|
2557
|
+
* spends the store's carrier balance, same as {@link createShippingLabel}.
|
|
2558
|
+
*
|
|
2559
|
+
* Unlike {@link createShippingLabel}, this is **not** on the API-key `/v1`
|
|
2560
|
+
* surface — it calls the internal `/api/orders/:id/shipments/return-label`
|
|
2561
|
+
* route, which takes `storeId` explicitly rather than resolving it from the
|
|
2562
|
+
* key. There is no `rateId` in the body: a return is quoted and bought in
|
|
2563
|
+
* one call at the shipping app, because the carrier fixes a shipment as a
|
|
2564
|
+
* return when it is created and will not amend it afterwards.
|
|
2574
2565
|
*
|
|
2575
2566
|
* @example
|
|
2576
2567
|
* ```typescript
|
|
2577
|
-
* const
|
|
2578
|
-
*
|
|
2568
|
+
* const label = await client.createReturnLabel('store_abc', 'order_abc', {
|
|
2569
|
+
* reason: 'Wrong size',
|
|
2570
|
+
* returnForShipmentId: 'shp_original123',
|
|
2571
|
+
* });
|
|
2572
|
+
* console.log('Return label URL:', label.labelUrl);
|
|
2579
2573
|
* ```
|
|
2580
2574
|
*/
|
|
2575
|
+
async createReturnLabel(storeId, orderId, data) {
|
|
2576
|
+
return this.adminRequest(
|
|
2577
|
+
"POST",
|
|
2578
|
+
`/api/orders/${encodePathSegment(orderId)}/shipments/return-label`,
|
|
2579
|
+
data,
|
|
2580
|
+
{ storeId }
|
|
2581
|
+
);
|
|
2582
|
+
}
|
|
2583
|
+
/**
|
|
2584
|
+
* Cancel an order.
|
|
2585
|
+
*
|
|
2586
|
+
* **Not callable.** The API-key `/v1` surface has no cancel route, so this
|
|
2587
|
+
* throws in every mode. A status move to cancelled may be reachable through
|
|
2588
|
+
* {@link updateOrder} depending on what the order's state machine allows;
|
|
2589
|
+
* otherwise cancel from the dashboard.
|
|
2590
|
+
*/
|
|
2581
2591
|
async cancelOrder(orderId) {
|
|
2582
|
-
|
|
2592
|
+
void orderId;
|
|
2593
|
+
throw new BrainerceError(
|
|
2594
|
+
"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.",
|
|
2595
|
+
400
|
|
2596
|
+
);
|
|
2583
2597
|
}
|
|
2584
2598
|
/**
|
|
2585
2599
|
* Fulfill an order (mark as shipped), or correct the tracking of an order
|
|
@@ -2593,110 +2607,87 @@ var _BrainerceClient = class _BrainerceClient {
|
|
|
2593
2607
|
* ship date is not rewritten, and no fulfilment event fires. That is the way
|
|
2594
2608
|
* to fix a mistyped tracking number.
|
|
2595
2609
|
*
|
|
2596
|
-
*
|
|
2597
|
-
*
|
|
2598
|
-
*
|
|
2599
|
-
*
|
|
2600
|
-
*
|
|
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
|
-
* ```
|
|
2610
|
+
* **Not callable.** The API-key `/v1` surface has no fulfil route, so this
|
|
2611
|
+
* throws in every mode. To ship an order over the API today, buy a label
|
|
2612
|
+
* with {@link createShippingLabel} — the carrier's webhooks then move the
|
|
2613
|
+
* shipment through in-transit and delivered on their own. Otherwise fulfil
|
|
2614
|
+
* from the dashboard.
|
|
2611
2615
|
*/
|
|
2612
2616
|
async fulfillOrder(orderId, data) {
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
+
void orderId;
|
|
2618
|
+
void data;
|
|
2619
|
+
throw new BrainerceError(
|
|
2620
|
+
"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.",
|
|
2621
|
+
400
|
|
2617
2622
|
);
|
|
2618
2623
|
}
|
|
2619
2624
|
/**
|
|
2620
|
-
* Sync draft orders from connected platforms
|
|
2625
|
+
* Sync draft orders from connected platforms.
|
|
2621
2626
|
*
|
|
2622
|
-
*
|
|
2623
|
-
*
|
|
2624
|
-
*
|
|
2625
|
-
* console.log('Draft orders synced');
|
|
2626
|
-
* ```
|
|
2627
|
+
* **Not callable.** The API-key `/v1` surface has no draft-order routes at
|
|
2628
|
+
* all, so this throws in every mode. {@link triggerSync} covers a general
|
|
2629
|
+
* platform sync; draft orders are managed from the dashboard.
|
|
2627
2630
|
*/
|
|
2628
2631
|
async syncDraftOrders() {
|
|
2629
|
-
|
|
2632
|
+
throw new BrainerceError(
|
|
2633
|
+
"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.",
|
|
2634
|
+
400
|
|
2635
|
+
);
|
|
2630
2636
|
}
|
|
2631
2637
|
/**
|
|
2632
|
-
* Complete a draft order (convert to regular order)
|
|
2638
|
+
* Complete a draft order (convert to regular order).
|
|
2633
2639
|
*
|
|
2634
|
-
*
|
|
2635
|
-
*
|
|
2636
|
-
* const order = await client.completeDraftOrder('draft_123', {
|
|
2637
|
-
* paymentPending: false,
|
|
2638
|
-
* });
|
|
2639
|
-
* ```
|
|
2640
|
+
* **Not callable.** The API-key `/v1` surface has no draft-order routes at
|
|
2641
|
+
* all, so this throws in every mode. Complete drafts from the dashboard.
|
|
2640
2642
|
*/
|
|
2641
2643
|
async completeDraftOrder(orderId, data) {
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2644
|
+
void orderId;
|
|
2645
|
+
void data;
|
|
2646
|
+
throw new BrainerceError(
|
|
2647
|
+
"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.",
|
|
2648
|
+
400
|
|
2646
2649
|
);
|
|
2647
2650
|
}
|
|
2648
2651
|
/**
|
|
2649
|
-
* Send invoice for a draft order
|
|
2652
|
+
* Send invoice for a draft order.
|
|
2650
2653
|
*
|
|
2651
|
-
*
|
|
2652
|
-
*
|
|
2653
|
-
* await client.sendDraftInvoice('draft_123', {
|
|
2654
|
-
* to: 'customer@example.com',
|
|
2655
|
-
* subject: 'Your Invoice',
|
|
2656
|
-
* customMessage: 'Thank you for your order!',
|
|
2657
|
-
* });
|
|
2658
|
-
* ```
|
|
2654
|
+
* **Not callable.** The API-key `/v1` surface has no draft-order routes at
|
|
2655
|
+
* all, so this throws in every mode. Send the invoice from the dashboard.
|
|
2659
2656
|
*/
|
|
2660
2657
|
async sendDraftInvoice(orderId, data) {
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2658
|
+
void orderId;
|
|
2659
|
+
void data;
|
|
2660
|
+
throw new BrainerceError(
|
|
2661
|
+
"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.",
|
|
2662
|
+
400
|
|
2665
2663
|
);
|
|
2666
2664
|
}
|
|
2667
2665
|
/**
|
|
2668
|
-
* Delete a draft order
|
|
2666
|
+
* Delete a draft order.
|
|
2669
2667
|
*
|
|
2670
|
-
*
|
|
2671
|
-
*
|
|
2672
|
-
* await client.deleteDraftOrder('draft_123');
|
|
2673
|
-
* ```
|
|
2668
|
+
* **Not callable.** The API-key `/v1` surface has no draft-order routes at
|
|
2669
|
+
* all, so this throws in every mode. Delete drafts from the dashboard.
|
|
2674
2670
|
*/
|
|
2675
2671
|
async deleteDraftOrder(orderId) {
|
|
2676
|
-
|
|
2672
|
+
void orderId;
|
|
2673
|
+
throw new BrainerceError(
|
|
2674
|
+
"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.",
|
|
2675
|
+
400
|
|
2676
|
+
);
|
|
2677
2677
|
}
|
|
2678
2678
|
/**
|
|
2679
|
-
* Update a draft order
|
|
2679
|
+
* Update a draft order.
|
|
2680
2680
|
*
|
|
2681
|
-
*
|
|
2682
|
-
*
|
|
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
|
-
* ```
|
|
2681
|
+
* **Not callable.** The API-key `/v1` surface has no draft-order routes at
|
|
2682
|
+
* all, so this throws in every mode. Edit drafts from the dashboard.
|
|
2697
2683
|
*/
|
|
2698
2684
|
async updateDraftOrder(orderId, data) {
|
|
2699
|
-
|
|
2685
|
+
void orderId;
|
|
2686
|
+
void data;
|
|
2687
|
+
throw new BrainerceError(
|
|
2688
|
+
"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.",
|
|
2689
|
+
400
|
|
2690
|
+
);
|
|
2700
2691
|
}
|
|
2701
2692
|
// -------------------- Inventory --------------------
|
|
2702
2693
|
/**
|
|
@@ -2711,82 +2702,91 @@ var _BrainerceClient = class _BrainerceClient {
|
|
|
2711
2702
|
);
|
|
2712
2703
|
}
|
|
2713
2704
|
/**
|
|
2714
|
-
* Get current inventory for a product
|
|
2705
|
+
* Get current inventory for a product.
|
|
2706
|
+
*
|
|
2707
|
+
* **Admin mode only** — the API key needs the `inventory:read` scope.
|
|
2708
|
+
*
|
|
2709
|
+
* This used to request `/api/v1/inventory/:productId`, which does not
|
|
2710
|
+
* exist and 404'd silently. The live route is product-scoped:
|
|
2711
|
+
* `GET /api/v1/products/:id/inventory`. A product with no inventory row
|
|
2712
|
+
* reads back as all zeroes rather than 404ing.
|
|
2715
2713
|
*/
|
|
2716
2714
|
async getInventory(productId) {
|
|
2717
|
-
return this.
|
|
2715
|
+
return this.adminRequest(
|
|
2716
|
+
"GET",
|
|
2717
|
+
`/api/v1/products/${encodePathSegment(productId)}/inventory`
|
|
2718
|
+
);
|
|
2718
2719
|
}
|
|
2719
2720
|
/**
|
|
2720
|
-
* Edit inventory manually with reason for audit trail
|
|
2721
|
+
* Edit inventory manually with a reason for the audit trail.
|
|
2721
2722
|
*
|
|
2722
|
-
*
|
|
2723
|
-
*
|
|
2724
|
-
*
|
|
2725
|
-
*
|
|
2726
|
-
*
|
|
2727
|
-
*
|
|
2728
|
-
*
|
|
2729
|
-
*
|
|
2723
|
+
* **Not callable.** The API-key `/v1` surface carries no `inventory`
|
|
2724
|
+
* namespace, so this throws in every mode.
|
|
2725
|
+
*
|
|
2726
|
+
* {@link updateInventory} is the closest working call: it sets the same
|
|
2727
|
+
* absolute stock level over `PUT /api/v1/products/:id/inventory`, but the
|
|
2728
|
+
* reason is not yours to choose — the server records a generic
|
|
2729
|
+
* "Updated via External API" against the audit trail. If the reason text
|
|
2730
|
+
* matters, make the edit from the dashboard.
|
|
2730
2731
|
*/
|
|
2731
2732
|
async editInventory(data) {
|
|
2732
|
-
|
|
2733
|
+
void data;
|
|
2734
|
+
throw new BrainerceError(
|
|
2735
|
+
"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.",
|
|
2736
|
+
400
|
|
2737
|
+
);
|
|
2733
2738
|
}
|
|
2734
2739
|
/**
|
|
2735
|
-
* Get inventory sync status for all products in the store
|
|
2740
|
+
* Get inventory sync status for all products in the store.
|
|
2736
2741
|
*
|
|
2737
|
-
*
|
|
2738
|
-
*
|
|
2739
|
-
*
|
|
2740
|
-
* console.log(`${status.pending} products pending sync`);
|
|
2741
|
-
* console.log(`Last sync: ${status.lastSyncAt}`);
|
|
2742
|
-
* ```
|
|
2742
|
+
* **Not callable.** The API-key `/v1` surface carries no `inventory`
|
|
2743
|
+
* namespace, so this throws in every mode. Sync state is visible in the
|
|
2744
|
+
* dashboard; {@link getSyncStatus} covers platform sync jobs.
|
|
2743
2745
|
*/
|
|
2744
2746
|
async getInventorySyncStatus() {
|
|
2745
|
-
|
|
2747
|
+
throw new BrainerceError(
|
|
2748
|
+
"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.",
|
|
2749
|
+
400
|
|
2750
|
+
);
|
|
2746
2751
|
}
|
|
2747
2752
|
/**
|
|
2748
|
-
* Get inventory for multiple products at once
|
|
2753
|
+
* Get inventory for multiple products at once.
|
|
2749
2754
|
*
|
|
2750
|
-
*
|
|
2751
|
-
*
|
|
2752
|
-
*
|
|
2753
|
-
*
|
|
2754
|
-
* console.log(`${inv.productId}: ${inv.available} available`);
|
|
2755
|
-
* });
|
|
2756
|
-
* ```
|
|
2755
|
+
* **Not callable.** The API-key `/v1` surface carries no `inventory`
|
|
2756
|
+
* namespace, so this throws in every mode. There is no bulk stock read on
|
|
2757
|
+
* the API key today: fall back to {@link getInventory} per product, or read
|
|
2758
|
+
* the stock that {@link getProducts} already returns on each product.
|
|
2757
2759
|
*/
|
|
2758
2760
|
async getBulkInventory(productIds) {
|
|
2759
|
-
|
|
2761
|
+
void productIds;
|
|
2762
|
+
throw new BrainerceError(
|
|
2763
|
+
"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.",
|
|
2764
|
+
400
|
|
2765
|
+
);
|
|
2760
2766
|
}
|
|
2761
2767
|
/**
|
|
2762
|
-
* Reconcile inventory between Brainerce and connected platforms
|
|
2763
|
-
* Detects and optionally fixes discrepancies
|
|
2764
|
-
*
|
|
2765
|
-
* @example
|
|
2766
|
-
* ```typescript
|
|
2767
|
-
* // Reconcile single product (dry run)
|
|
2768
|
-
* const result = await client.reconcileInventory({ productId: 'prod_123' });
|
|
2768
|
+
* Reconcile inventory between Brainerce and connected platforms.
|
|
2769
|
+
* Detects and optionally fixes discrepancies.
|
|
2769
2770
|
*
|
|
2770
|
-
*
|
|
2771
|
-
*
|
|
2772
|
-
*
|
|
2773
|
-
* ```
|
|
2771
|
+
* **Not callable.** The API-key `/v1` surface carries no `inventory`
|
|
2772
|
+
* namespace, so this throws in every mode, `autoFix` included. Reconcile
|
|
2773
|
+
* from the dashboard.
|
|
2774
2774
|
*/
|
|
2775
2775
|
async reconcileInventory(options) {
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
"POST",
|
|
2781
|
-
"/api/v1/inventory/reconcile",
|
|
2782
|
-
void 0,
|
|
2783
|
-
queryParams
|
|
2776
|
+
void options;
|
|
2777
|
+
throw new BrainerceError(
|
|
2778
|
+
"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.",
|
|
2779
|
+
400
|
|
2784
2780
|
);
|
|
2785
2781
|
}
|
|
2786
2782
|
/**
|
|
2787
2783
|
* Check stock availability for one or more items before adding to cart or checkout
|
|
2788
2784
|
* Use this to validate stock before operations that might fail due to insufficient inventory
|
|
2789
2785
|
*
|
|
2786
|
+
* **Vibe-coded or storefront mode only.** There is no stock-check route on
|
|
2787
|
+
* the API-key `/v1` surface; in admin mode this throws. The same applies to
|
|
2788
|
+
* {@link checkCartStock}, which routes through here.
|
|
2789
|
+
*
|
|
2790
2790
|
* @example
|
|
2791
2791
|
* ```typescript
|
|
2792
2792
|
* // Check if items are available before adding to cart
|
|
@@ -2818,9 +2818,10 @@ var _BrainerceClient = class _BrainerceClient {
|
|
|
2818
2818
|
{ items }
|
|
2819
2819
|
);
|
|
2820
2820
|
}
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2821
|
+
throw new BrainerceError(
|
|
2822
|
+
"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.",
|
|
2823
|
+
400
|
|
2824
|
+
);
|
|
2824
2825
|
}
|
|
2825
2826
|
/**
|
|
2826
2827
|
* Check stock availability for cart items before checkout.
|
|
@@ -3157,49 +3158,43 @@ var _BrainerceClient = class _BrainerceClient {
|
|
|
3157
3158
|
* Request a password reset email for a customer
|
|
3158
3159
|
* Works in vibe-coded, storefront, and admin mode
|
|
3159
3160
|
*
|
|
3160
|
-
* The
|
|
3161
|
-
*
|
|
3162
|
-
*
|
|
3163
|
-
*
|
|
3164
|
-
*
|
|
3165
|
-
*
|
|
3166
|
-
*
|
|
3161
|
+
* The reset link's host is chosen by the server, not by the caller: it is
|
|
3162
|
+
* derived from the sales channel's own domain, falling back to the backend's
|
|
3163
|
+
* configured frontend URL, and the request is rejected if neither resolves.
|
|
3164
|
+
*
|
|
3165
|
+
* The SDK used to send a `resetUrl` in the request body. The backend
|
|
3166
|
+
* deliberately removed that field: any caller could submit an arbitrary URL
|
|
3167
|
+
* and have it emailed, from a Brainerce-domained sender, to the address
|
|
3168
|
+
* holder — a phishing-link injection. `ForgotPasswordDto` now declares
|
|
3169
|
+
* `email` and nothing else, and the API's global validation pipe runs with
|
|
3170
|
+
* `whitelist` + `forbidNonWhitelisted`, so a body carrying `resetUrl` fails
|
|
3171
|
+
* the whole call with `400 property resetUrl should not exist`. Only `email`
|
|
3172
|
+
* is sent.
|
|
3173
|
+
*
|
|
3174
|
+
* The endpoint always answers 200 so it cannot be used to enumerate
|
|
3175
|
+
* accounts; the mail is only sent when a matching customer exists.
|
|
3167
3176
|
*
|
|
3168
3177
|
* @param email - Customer email address
|
|
3169
|
-
* @param options -
|
|
3170
|
-
* @param options.resetUrl - Reset URL the email links should point to.
|
|
3171
|
-
* Required outside the browser; recommended inside it.
|
|
3178
|
+
* @param options - Accepted for source compatibility only. Ignored.
|
|
3172
3179
|
*/
|
|
3173
3180
|
async forgotPassword(email, options) {
|
|
3174
|
-
|
|
3175
|
-
|
|
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
|
-
}
|
|
3181
|
+
void options;
|
|
3182
|
+
const body = { email };
|
|
3187
3183
|
if (this.isVibeCodedMode()) {
|
|
3188
|
-
return this.vibeCodedRequest("POST", "/customers/forgot-password",
|
|
3189
|
-
email,
|
|
3190
|
-
resetUrl
|
|
3191
|
-
});
|
|
3184
|
+
return this.vibeCodedRequest("POST", "/customers/forgot-password", body);
|
|
3192
3185
|
}
|
|
3193
3186
|
if (this.storeId && !this.apiKey) {
|
|
3194
|
-
return this.storefrontRequest(
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3187
|
+
return this.storefrontRequest(
|
|
3188
|
+
"POST",
|
|
3189
|
+
"/customers/forgot-password",
|
|
3190
|
+
body
|
|
3191
|
+
);
|
|
3198
3192
|
}
|
|
3199
|
-
return this.adminRequest(
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3193
|
+
return this.adminRequest(
|
|
3194
|
+
"POST",
|
|
3195
|
+
"/api/v1/customers/forgot-password",
|
|
3196
|
+
body
|
|
3197
|
+
);
|
|
3203
3198
|
}
|
|
3204
3199
|
/**
|
|
3205
3200
|
* Reset customer password using a reset token received via email
|
|
@@ -10020,6 +10015,156 @@ var _BrainerceClient = class _BrainerceClient {
|
|
|
10020
10015
|
`/api/v1/oauth-providers/${encodePathSegment(provider)}`
|
|
10021
10016
|
);
|
|
10022
10017
|
}
|
|
10018
|
+
// -------------------- Translations (Admin) --------------------
|
|
10019
|
+
// These methods require Admin mode (apiKey) with a scope-bearing key —
|
|
10020
|
+
// `products:read`/`products:write` cover most entity types via
|
|
10021
|
+
// StorePermissionGuard's STORE_PERMISSION_TO_SCOPE mapping (VIEW_PRODUCTS /
|
|
10022
|
+
// EDIT_PRODUCTS). Routes: /api/stores/:storeId/translations/...
|
|
10023
|
+
//
|
|
10024
|
+
// Reads and writes the SAME `translations` JSON blob the dashboard editor
|
|
10025
|
+
// uses — this is not a separate translation system, it's API-key access to
|
|
10026
|
+
// the dashboard's own persistence path. Use it for bulk-importing
|
|
10027
|
+
// pre-translated content or automating locale coverage without a human in
|
|
10028
|
+
// the dashboard.
|
|
10029
|
+
/**
|
|
10030
|
+
* Get translation completeness across every translatable entity type, for
|
|
10031
|
+
* one or more locales. Useful as a pre-flight before a bulk import to see
|
|
10032
|
+
* which entity types/locales still need coverage.
|
|
10033
|
+
* Requires Admin mode (apiKey).
|
|
10034
|
+
*
|
|
10035
|
+
* @param storeId - Store to inspect.
|
|
10036
|
+
* @param locales - BCP-47 locale codes to check (e.g. `['he', 'fr']`). Omit
|
|
10037
|
+
* or pass an empty array to get rows with `total` populated but no
|
|
10038
|
+
* locale breakdown.
|
|
10039
|
+
*
|
|
10040
|
+
* @example
|
|
10041
|
+
* ```typescript
|
|
10042
|
+
* const status = await client.getTranslationStatus('store_123', ['he', 'fr']);
|
|
10043
|
+
* const blogHe = status.find((s) => s.entityType === 'blogPost' && s.locale === 'he');
|
|
10044
|
+
* console.log(`${blogHe?.missing} blog posts still need Hebrew`);
|
|
10045
|
+
* ```
|
|
10046
|
+
*/
|
|
10047
|
+
async getTranslationStatus(storeId, locales) {
|
|
10048
|
+
return this.adminRequest(
|
|
10049
|
+
"GET",
|
|
10050
|
+
`/api/stores/${encodePathSegment(storeId)}/translations/status`,
|
|
10051
|
+
void 0,
|
|
10052
|
+
locales && locales.length > 0 ? { locales: locales.join(",") } : void 0
|
|
10053
|
+
);
|
|
10054
|
+
}
|
|
10055
|
+
/**
|
|
10056
|
+
* Get every persisted translation for a single entity, keyed by locale.
|
|
10057
|
+
* Requires Admin mode (apiKey).
|
|
10058
|
+
*
|
|
10059
|
+
* @example
|
|
10060
|
+
* ```typescript
|
|
10061
|
+
* const translations = await client.getTranslations('store_123', 'product', 'prod_abc');
|
|
10062
|
+
* console.log(translations.he?.name); // Hebrew product name, if set
|
|
10063
|
+
* ```
|
|
10064
|
+
*/
|
|
10065
|
+
async getTranslations(storeId, entityType, entityId) {
|
|
10066
|
+
return this.adminRequest(
|
|
10067
|
+
"GET",
|
|
10068
|
+
`/api/stores/${encodePathSegment(storeId)}/translations/${encodePathSegment(entityType)}/${encodePathSegment(entityId)}`
|
|
10069
|
+
);
|
|
10070
|
+
}
|
|
10071
|
+
/**
|
|
10072
|
+
* Set/update one locale's translation for an entity. Only the fields valid
|
|
10073
|
+
* for `entityType` are persisted (e.g. `title`/`excerpt`/`content` for
|
|
10074
|
+
* `blogPost`, `name`/`description` for `category`) — fields outside that
|
|
10075
|
+
* entity's allowlist are silently ignored server-side, and omitted fields
|
|
10076
|
+
* leave any existing translation for them untouched (this is a merge, not
|
|
10077
|
+
* a replace, of the locale's fields).
|
|
10078
|
+
* Requires Admin mode (apiKey) with `products:write` (or the equivalent
|
|
10079
|
+
* scope for the target entity type).
|
|
10080
|
+
*
|
|
10081
|
+
* @example
|
|
10082
|
+
* ```typescript
|
|
10083
|
+
* // Bulk-import a pre-translated blog post
|
|
10084
|
+
* await client.setTranslation('store_123', 'blogPost', 'post_abc', 'fr', {
|
|
10085
|
+
* title: 'Le titre en français',
|
|
10086
|
+
* excerpt: "L'extrait en français",
|
|
10087
|
+
* content: '<p>Le contenu en français</p>',
|
|
10088
|
+
* });
|
|
10089
|
+
* ```
|
|
10090
|
+
*/
|
|
10091
|
+
async setTranslation(storeId, entityType, entityId, locale, fields) {
|
|
10092
|
+
return this.adminRequest(
|
|
10093
|
+
"PUT",
|
|
10094
|
+
`/api/stores/${encodePathSegment(storeId)}/translations/${encodePathSegment(entityType)}/${encodePathSegment(entityId)}/${encodePathSegment(locale)}`,
|
|
10095
|
+
fields
|
|
10096
|
+
);
|
|
10097
|
+
}
|
|
10098
|
+
/**
|
|
10099
|
+
* Delete one locale's translation for an entity. The entity's base
|
|
10100
|
+
* (default-locale) fields are unaffected.
|
|
10101
|
+
* Requires Admin mode (apiKey) with `products:write` (or the equivalent
|
|
10102
|
+
* scope for the target entity type).
|
|
10103
|
+
*/
|
|
10104
|
+
async deleteTranslation(storeId, entityType, entityId, locale) {
|
|
10105
|
+
await this.adminRequest(
|
|
10106
|
+
"DELETE",
|
|
10107
|
+
`/api/stores/${encodePathSegment(storeId)}/translations/${encodePathSegment(entityType)}/${encodePathSegment(entityId)}/${encodePathSegment(locale)}`
|
|
10108
|
+
);
|
|
10109
|
+
}
|
|
10110
|
+
/**
|
|
10111
|
+
* AI-translate a single entity into one target locale and persist the
|
|
10112
|
+
* result inline (synchronous — the response already reflects the write).
|
|
10113
|
+
* Only fields that are still empty for `targetLocale` are filled; existing
|
|
10114
|
+
* translated values are never overwritten.
|
|
10115
|
+
* Requires Admin mode (apiKey) with `products:write` (or the equivalent
|
|
10116
|
+
* scope for the target entity type).
|
|
10117
|
+
*
|
|
10118
|
+
* @param sourceFields - Optional override of the source-language text to
|
|
10119
|
+
* translate from (e.g. unsaved edits from an open editor), instead of the
|
|
10120
|
+
* entity's persisted base fields. Keys outside the entity's translatable
|
|
10121
|
+
* field set are ignored.
|
|
10122
|
+
*
|
|
10123
|
+
* @example
|
|
10124
|
+
* ```typescript
|
|
10125
|
+
* const translations = await client.aiTranslateSingle('store_123', {
|
|
10126
|
+
* entityType: 'product',
|
|
10127
|
+
* entityId: 'prod_abc',
|
|
10128
|
+
* targetLocale: 'he',
|
|
10129
|
+
* });
|
|
10130
|
+
* ```
|
|
10131
|
+
*/
|
|
10132
|
+
async aiTranslateSingle(storeId, input) {
|
|
10133
|
+
return this.adminRequest(
|
|
10134
|
+
"POST",
|
|
10135
|
+
`/api/stores/${encodePathSegment(storeId)}/translations/ai-translate-single`,
|
|
10136
|
+
input
|
|
10137
|
+
);
|
|
10138
|
+
}
|
|
10139
|
+
/**
|
|
10140
|
+
* Bulk AI-translate — enqueues a background job per entity (and, for
|
|
10141
|
+
* `entityType: 'attribute'`, one per attribute option too) rather than
|
|
10142
|
+
* translating inline. Returns the number of jobs queued, not the finished
|
|
10143
|
+
* translations; poll `getTranslationStatus` or `getTranslations` to see
|
|
10144
|
+
* results land.
|
|
10145
|
+
* Requires Admin mode (apiKey) with `products:write` (or the equivalent
|
|
10146
|
+
* scope for the target entity type).
|
|
10147
|
+
*
|
|
10148
|
+
* @param entityIds - Optional explicit ids to translate. Omit to target
|
|
10149
|
+
* every entity of `entityType` in the store that isn't already fully
|
|
10150
|
+
* translated for `targetLocale`.
|
|
10151
|
+
*
|
|
10152
|
+
* @example
|
|
10153
|
+
* ```typescript
|
|
10154
|
+
* // Translate every blog post missing French coverage
|
|
10155
|
+
* const { queued } = await client.aiTranslateBulk('store_123', {
|
|
10156
|
+
* entityType: 'blogPost',
|
|
10157
|
+
* targetLocale: 'fr',
|
|
10158
|
+
* });
|
|
10159
|
+
* ```
|
|
10160
|
+
*/
|
|
10161
|
+
async aiTranslateBulk(storeId, input) {
|
|
10162
|
+
return this.adminRequest(
|
|
10163
|
+
"POST",
|
|
10164
|
+
`/api/stores/${encodePathSegment(storeId)}/translations/ai-translate`,
|
|
10165
|
+
input
|
|
10166
|
+
);
|
|
10167
|
+
}
|
|
10023
10168
|
};
|
|
10024
10169
|
/**
|
|
10025
10170
|
* Fields present on `getAddressDetails().address` that the address endpoints
|