brainerce 1.14.0 → 1.16.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/README.md +4447 -4296
- package/dist/index.d.mts +253 -10
- package/dist/index.d.ts +253 -10
- package/dist/index.js +224 -25
- package/dist/index.mjs +223 -25
- package/package.json +76 -76
package/dist/index.js
CHANGED
|
@@ -41,6 +41,7 @@ __export(index_exports, {
|
|
|
41
41
|
getCartTotals: () => getCartTotals,
|
|
42
42
|
getDescriptionContent: () => getDescriptionContent,
|
|
43
43
|
getPriceDisplay: () => formatPrice,
|
|
44
|
+
getProductCustomizationFields: () => getProductCustomizationFields,
|
|
44
45
|
getProductMetafield: () => getProductMetafield,
|
|
45
46
|
getProductMetafieldValue: () => getProductMetafieldValue,
|
|
46
47
|
getProductMetafieldsByType: () => getProductMetafieldsByType,
|
|
@@ -241,6 +242,41 @@ var BrainerceClient = class {
|
|
|
241
242
|
this.onAuthError = options.onAuthError;
|
|
242
243
|
this.hydrateSessionCart();
|
|
243
244
|
}
|
|
245
|
+
// -------------------- Locale --------------------
|
|
246
|
+
/**
|
|
247
|
+
* Set the active locale for content translation.
|
|
248
|
+
* When set, all content endpoints (products, categories, brands) will return
|
|
249
|
+
* translated content for this locale, falling back to the store's default language.
|
|
250
|
+
*
|
|
251
|
+
* @param locale - Locale code (e.g., "he", "es", "fr") or undefined to clear
|
|
252
|
+
*/
|
|
253
|
+
setLocale(locale) {
|
|
254
|
+
this.locale = locale;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Get the currently active locale.
|
|
258
|
+
*/
|
|
259
|
+
getLocale() {
|
|
260
|
+
return this.locale;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Get the supported locales for this store.
|
|
264
|
+
* Fetches store info and returns the i18n config.
|
|
265
|
+
* Returns `[storeLanguage]` if multi-language is not enabled.
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* ```typescript
|
|
269
|
+
* const locales = await client.getSupportedLocales();
|
|
270
|
+
* // ["en", "he", "es"]
|
|
271
|
+
* ```
|
|
272
|
+
*/
|
|
273
|
+
async getSupportedLocales() {
|
|
274
|
+
const info = await this.getStoreInfo();
|
|
275
|
+
if (info.i18n?.enabled && info.i18n.supportedLocales.length > 0) {
|
|
276
|
+
return info.i18n.supportedLocales;
|
|
277
|
+
}
|
|
278
|
+
return [info.language];
|
|
279
|
+
}
|
|
244
280
|
withGuards(result, type) {
|
|
245
281
|
if (!isDevGuardsEnabled()) return result;
|
|
246
282
|
if (result && typeof result.then === "function") {
|
|
@@ -580,6 +616,7 @@ var BrainerceClient = class {
|
|
|
580
616
|
maxPrice: params?.maxPrice,
|
|
581
617
|
sortBy: params?.sortBy,
|
|
582
618
|
sortOrder: params?.sortOrder,
|
|
619
|
+
locale: params?.locale || this.locale,
|
|
583
620
|
// Admin-only params
|
|
584
621
|
type: params?.type
|
|
585
622
|
};
|
|
@@ -610,12 +647,23 @@ var BrainerceClient = class {
|
|
|
610
647
|
* Get a single product by ID
|
|
611
648
|
* Works in vibe-coded, storefront (public), and admin mode
|
|
612
649
|
*/
|
|
613
|
-
async getProduct(productId) {
|
|
650
|
+
async getProduct(productId, options) {
|
|
651
|
+
const localeParams = { locale: options?.locale || this.locale };
|
|
614
652
|
if (this.isVibeCodedMode()) {
|
|
615
|
-
return this.vibeCodedRequest(
|
|
653
|
+
return this.vibeCodedRequest(
|
|
654
|
+
"GET",
|
|
655
|
+
`/products/${productId}`,
|
|
656
|
+
void 0,
|
|
657
|
+
localeParams
|
|
658
|
+
);
|
|
616
659
|
}
|
|
617
660
|
if (this.storeId && !this.apiKey) {
|
|
618
|
-
return this.storefrontRequest(
|
|
661
|
+
return this.storefrontRequest(
|
|
662
|
+
"GET",
|
|
663
|
+
`/products/${productId}`,
|
|
664
|
+
void 0,
|
|
665
|
+
localeParams
|
|
666
|
+
);
|
|
619
667
|
}
|
|
620
668
|
return this.adminRequest("GET", `/api/v1/products/${productId}`);
|
|
621
669
|
}
|
|
@@ -629,12 +677,23 @@ var BrainerceClient = class {
|
|
|
629
677
|
* const product = await client.getProductBySlug('awesome-product-name');
|
|
630
678
|
* ```
|
|
631
679
|
*/
|
|
632
|
-
async getProductBySlug(slug) {
|
|
680
|
+
async getProductBySlug(slug, options) {
|
|
681
|
+
const localeParams = { locale: options?.locale || this.locale };
|
|
633
682
|
if (this.isVibeCodedMode()) {
|
|
634
|
-
return this.vibeCodedRequest(
|
|
683
|
+
return this.vibeCodedRequest(
|
|
684
|
+
"GET",
|
|
685
|
+
`/products/slug/${slug}`,
|
|
686
|
+
void 0,
|
|
687
|
+
localeParams
|
|
688
|
+
);
|
|
635
689
|
}
|
|
636
690
|
if (this.storeId && !this.apiKey) {
|
|
637
|
-
return this.storefrontRequest(
|
|
691
|
+
return this.storefrontRequest(
|
|
692
|
+
"GET",
|
|
693
|
+
`/products/slug/${slug}`,
|
|
694
|
+
void 0,
|
|
695
|
+
localeParams
|
|
696
|
+
);
|
|
638
697
|
}
|
|
639
698
|
return this.adminRequest("GET", `/api/v1/products/by-slug/${slug}`);
|
|
640
699
|
}
|
|
@@ -648,9 +707,10 @@ var BrainerceClient = class {
|
|
|
648
707
|
* // categories is a tree structure with children
|
|
649
708
|
* ```
|
|
650
709
|
*/
|
|
651
|
-
async getCategories() {
|
|
710
|
+
async getCategories(options) {
|
|
711
|
+
const localeParams = { locale: options?.locale || this.locale };
|
|
652
712
|
if (this.isVibeCodedMode()) {
|
|
653
|
-
return this.vibeCodedRequest("GET", "/categories");
|
|
713
|
+
return this.vibeCodedRequest("GET", "/categories", void 0, localeParams);
|
|
654
714
|
}
|
|
655
715
|
throw new BrainerceError("getCategories is only available in vibe-coded mode", 400);
|
|
656
716
|
}
|
|
@@ -664,9 +724,10 @@ var BrainerceClient = class {
|
|
|
664
724
|
* // Use brand IDs in getProducts({ brands: ['brand_id'] })
|
|
665
725
|
* ```
|
|
666
726
|
*/
|
|
667
|
-
async getBrands() {
|
|
727
|
+
async getBrands(options) {
|
|
728
|
+
const localeParams = { locale: options?.locale || this.locale };
|
|
668
729
|
if (this.isVibeCodedMode()) {
|
|
669
|
-
return this.vibeCodedRequest("GET", "/brands");
|
|
730
|
+
return this.vibeCodedRequest("GET", "/brands", void 0, localeParams);
|
|
670
731
|
}
|
|
671
732
|
throw new BrainerceError("getBrands is only available in vibe-coded mode", 400);
|
|
672
733
|
}
|
|
@@ -682,7 +743,9 @@ var BrainerceClient = class {
|
|
|
682
743
|
*/
|
|
683
744
|
async getTags() {
|
|
684
745
|
if (this.isVibeCodedMode()) {
|
|
685
|
-
return this.vibeCodedRequest("GET", "/tags"
|
|
746
|
+
return this.vibeCodedRequest("GET", "/tags", void 0, {
|
|
747
|
+
locale: this.locale
|
|
748
|
+
});
|
|
686
749
|
}
|
|
687
750
|
throw new BrainerceError("getTags is only available in vibe-coded mode", 400);
|
|
688
751
|
}
|
|
@@ -706,11 +769,27 @@ var BrainerceClient = class {
|
|
|
706
769
|
* const suggestions = await client.getSearchSuggestions('dress', 3);
|
|
707
770
|
* ```
|
|
708
771
|
*/
|
|
772
|
+
/**
|
|
773
|
+
* Get locale alternates for a product (for SEO hreflang tags).
|
|
774
|
+
* Returns the slug for each available locale.
|
|
775
|
+
*
|
|
776
|
+
* @example
|
|
777
|
+
* ```typescript
|
|
778
|
+
* const { alternates } = await client.getProductAlternates('product_id');
|
|
779
|
+
* // alternates = [{ locale: "en", slug: "running-shoes" }, { locale: "he", slug: "נעלי-ריצה" }]
|
|
780
|
+
* ```
|
|
781
|
+
*/
|
|
782
|
+
async getProductAlternates(productId) {
|
|
783
|
+
if (this.storeId && !this.apiKey) {
|
|
784
|
+
return this.storefrontRequest("GET", `/products/${productId}/alternates`);
|
|
785
|
+
}
|
|
786
|
+
throw new BrainerceError("getProductAlternates is only available in storefront mode", 400);
|
|
787
|
+
}
|
|
709
788
|
async getSearchSuggestions(query, limit) {
|
|
710
789
|
if (!query || query.trim().length === 0) {
|
|
711
790
|
return { products: [], categories: [] };
|
|
712
791
|
}
|
|
713
|
-
const queryParams = { q: query, limit };
|
|
792
|
+
const queryParams = { q: query, limit, locale: this.locale };
|
|
714
793
|
if (this.isVibeCodedMode()) {
|
|
715
794
|
return this.vibeCodedRequest(
|
|
716
795
|
"GET",
|
|
@@ -2492,14 +2571,16 @@ var BrainerceClient = class {
|
|
|
2492
2571
|
*
|
|
2493
2572
|
* @param cartId - Cart ID
|
|
2494
2573
|
* @param bumpConfigId - Order bump config ID
|
|
2574
|
+
* @param variantId - Optional variant ID (required when bump product has variants and no admin-locked variant)
|
|
2495
2575
|
* @returns Updated cart
|
|
2496
2576
|
*/
|
|
2497
|
-
async addOrderBump(cartId, bumpConfigId) {
|
|
2577
|
+
async addOrderBump(cartId, bumpConfigId, variantId) {
|
|
2578
|
+
const body = { bumpConfigId, ...variantId && { variantId } };
|
|
2498
2579
|
if (this.isVibeCodedMode()) {
|
|
2499
|
-
return this.vibeCodedRequest("POST", `/cart/${cartId}/bump`,
|
|
2580
|
+
return this.vibeCodedRequest("POST", `/cart/${cartId}/bump`, body);
|
|
2500
2581
|
}
|
|
2501
2582
|
if (this.storeId && !this.apiKey) {
|
|
2502
|
-
return this.storefrontRequest("POST", `/cart/${cartId}/bump`,
|
|
2583
|
+
return this.storefrontRequest("POST", `/cart/${cartId}/bump`, body);
|
|
2503
2584
|
}
|
|
2504
2585
|
throw new BrainerceError("addOrderBump() requires vibe-coded or storefront mode", 400);
|
|
2505
2586
|
}
|
|
@@ -2524,20 +2605,25 @@ var BrainerceClient = class {
|
|
|
2524
2605
|
*
|
|
2525
2606
|
* @param cartId - Cart ID
|
|
2526
2607
|
* @param bundleOfferId - Bundle offer ID
|
|
2608
|
+
* @param variantId - Optional variant ID (required when bundle product has variants and no admin-locked variant)
|
|
2527
2609
|
* @returns Updated cart
|
|
2528
2610
|
*
|
|
2529
2611
|
* @example
|
|
2530
2612
|
* ```typescript
|
|
2531
2613
|
* const { bundles } = await client.getCartBundles('cart_123');
|
|
2614
|
+
* // Simple product or locked variant:
|
|
2532
2615
|
* const cart = await client.addBundleToCart('cart_123', bundles[0].id);
|
|
2616
|
+
* // Product with variants (customer selects):
|
|
2617
|
+
* const cart = await client.addBundleToCart('cart_123', bundles[0].id, selectedVariantId);
|
|
2533
2618
|
* ```
|
|
2534
2619
|
*/
|
|
2535
|
-
async addBundleToCart(cartId, bundleOfferId) {
|
|
2620
|
+
async addBundleToCart(cartId, bundleOfferId, variantId) {
|
|
2621
|
+
const body = { bundleOfferId, ...variantId && { variantId } };
|
|
2536
2622
|
if (this.isVibeCodedMode()) {
|
|
2537
|
-
return this.vibeCodedRequest("POST", `/cart/${cartId}/bundle`,
|
|
2623
|
+
return this.vibeCodedRequest("POST", `/cart/${cartId}/bundle`, body);
|
|
2538
2624
|
}
|
|
2539
2625
|
if (this.storeId && !this.apiKey) {
|
|
2540
|
-
return this.storefrontRequest("POST", `/cart/${cartId}/bundle`,
|
|
2626
|
+
return this.storefrontRequest("POST", `/cart/${cartId}/bundle`, body);
|
|
2541
2627
|
}
|
|
2542
2628
|
throw new BrainerceError("addBundleToCart() requires vibe-coded or storefront mode", 400);
|
|
2543
2629
|
}
|
|
@@ -3459,6 +3545,67 @@ var BrainerceClient = class {
|
|
|
3459
3545
|
this.clearActiveCheckoutStorage();
|
|
3460
3546
|
return result;
|
|
3461
3547
|
}
|
|
3548
|
+
// -------------------- Checkout Custom Fields --------------------
|
|
3549
|
+
/**
|
|
3550
|
+
* Get applicable custom field definitions for a checkout.
|
|
3551
|
+
* Returns fields filtered by visibility conditions (delivery type, products in cart).
|
|
3552
|
+
* Use these to render dynamic input fields in the checkout flow.
|
|
3553
|
+
*/
|
|
3554
|
+
async getCheckoutCustomFields(checkoutId) {
|
|
3555
|
+
if (this.isVibeCodedMode()) {
|
|
3556
|
+
return this.vibeCodedRequest(
|
|
3557
|
+
"GET",
|
|
3558
|
+
`/checkout/${checkoutId}/custom-fields`
|
|
3559
|
+
);
|
|
3560
|
+
}
|
|
3561
|
+
if (this.storeId && !this.apiKey) {
|
|
3562
|
+
return this.storefrontRequest(
|
|
3563
|
+
"GET",
|
|
3564
|
+
`/checkout/${checkoutId}/custom-fields`
|
|
3565
|
+
);
|
|
3566
|
+
}
|
|
3567
|
+
return this.adminRequest(
|
|
3568
|
+
"GET",
|
|
3569
|
+
`/api/v1/checkouts/${checkoutId}/custom-fields`
|
|
3570
|
+
);
|
|
3571
|
+
}
|
|
3572
|
+
/**
|
|
3573
|
+
* Set checkout custom field values and recalculate surcharges.
|
|
3574
|
+
* The checkout total is automatically updated to include surcharges.
|
|
3575
|
+
*
|
|
3576
|
+
* @example
|
|
3577
|
+
* ```typescript
|
|
3578
|
+
* const checkout = await client.setCheckoutCustomFields(checkoutId, {
|
|
3579
|
+
* gift_wrapping: 'premium', // SELECT field
|
|
3580
|
+
* floor_number: 5, // NUMBER field
|
|
3581
|
+
* installation: true, // BOOLEAN field
|
|
3582
|
+
* });
|
|
3583
|
+
* // checkout.surchargeAmount reflects the new surcharges
|
|
3584
|
+
* // checkout.total is recalculated
|
|
3585
|
+
* ```
|
|
3586
|
+
*/
|
|
3587
|
+
async setCheckoutCustomFields(checkoutId, fields) {
|
|
3588
|
+
const data = { fields };
|
|
3589
|
+
if (this.isVibeCodedMode()) {
|
|
3590
|
+
return this.vibeCodedRequest(
|
|
3591
|
+
"PATCH",
|
|
3592
|
+
`/checkout/${checkoutId}/custom-fields`,
|
|
3593
|
+
data
|
|
3594
|
+
);
|
|
3595
|
+
}
|
|
3596
|
+
if (this.storeId && !this.apiKey) {
|
|
3597
|
+
return this.storefrontRequest(
|
|
3598
|
+
"PATCH",
|
|
3599
|
+
`/checkout/${checkoutId}/custom-fields`,
|
|
3600
|
+
data
|
|
3601
|
+
);
|
|
3602
|
+
}
|
|
3603
|
+
return this.adminRequest(
|
|
3604
|
+
"PATCH",
|
|
3605
|
+
`/api/v1/checkouts/${checkoutId}/custom-fields`,
|
|
3606
|
+
data
|
|
3607
|
+
);
|
|
3608
|
+
}
|
|
3462
3609
|
/**
|
|
3463
3610
|
* Delete a checkout session. Releases inventory reservations and removes
|
|
3464
3611
|
* payment records not yet linked to an order.
|
|
@@ -5502,6 +5649,53 @@ var BrainerceClient = class {
|
|
|
5502
5649
|
`/api/v1/products/${productId}/metafields/${definitionId}`
|
|
5503
5650
|
);
|
|
5504
5651
|
}
|
|
5652
|
+
// -------------------- Product Customization Fields (Admin) --------------------
|
|
5653
|
+
/**
|
|
5654
|
+
* Get customization fields assigned to a product.
|
|
5655
|
+
* Requires Admin mode (apiKey).
|
|
5656
|
+
*/
|
|
5657
|
+
async getProductCustomizationFields(productId) {
|
|
5658
|
+
return this.adminRequest(
|
|
5659
|
+
"GET",
|
|
5660
|
+
`/api/v1/metafield-definitions/products/${productId}/customization-fields`
|
|
5661
|
+
);
|
|
5662
|
+
}
|
|
5663
|
+
/**
|
|
5664
|
+
* Set customization fields for a product (replaces all existing assignments).
|
|
5665
|
+
* Only definitions marked as `isCustomerInput: true` can be assigned.
|
|
5666
|
+
* Requires Admin mode (apiKey).
|
|
5667
|
+
*/
|
|
5668
|
+
async setProductCustomizationFields(productId, definitionIds) {
|
|
5669
|
+
return this.adminRequest(
|
|
5670
|
+
"PATCH",
|
|
5671
|
+
`/api/v1/metafield-definitions/products/${productId}/customization-fields`,
|
|
5672
|
+
{ definitionIds }
|
|
5673
|
+
);
|
|
5674
|
+
}
|
|
5675
|
+
/**
|
|
5676
|
+
* Upload a file for product customization (e.g., customer logo for printing).
|
|
5677
|
+
* Available in storefront and vibe-coded modes.
|
|
5678
|
+
* Returns the uploaded file URL and key.
|
|
5679
|
+
*/
|
|
5680
|
+
async uploadCustomizationFile(file) {
|
|
5681
|
+
const formData = new FormData();
|
|
5682
|
+
formData.append("file", file);
|
|
5683
|
+
if (this.isVibeCodedMode()) {
|
|
5684
|
+
return this.vibeCodedRequest(
|
|
5685
|
+
"POST",
|
|
5686
|
+
"/customization-upload",
|
|
5687
|
+
formData
|
|
5688
|
+
);
|
|
5689
|
+
}
|
|
5690
|
+
if (this.storeId && !this.apiKey) {
|
|
5691
|
+
return this.storefrontRequest(
|
|
5692
|
+
"POST",
|
|
5693
|
+
"/customization-upload",
|
|
5694
|
+
formData
|
|
5695
|
+
);
|
|
5696
|
+
}
|
|
5697
|
+
throw new Error("uploadCustomizationFile requires storefront or vibe-coded mode");
|
|
5698
|
+
}
|
|
5505
5699
|
// -------------------- Team Management (Admin) - DEPRECATED --------------------
|
|
5506
5700
|
// These account-level methods are deprecated. Use Store Team Management methods instead.
|
|
5507
5701
|
/**
|
|
@@ -6065,14 +6259,15 @@ function getVariantOptions(variant) {
|
|
|
6065
6259
|
if (!variant?.attributes) return [];
|
|
6066
6260
|
const internalKeys = /* @__PURE__ */ new Set([
|
|
6067
6261
|
"id",
|
|
6068
|
-
"
|
|
6069
|
-
"
|
|
6070
|
-
"
|
|
6071
|
-
"
|
|
6072
|
-
"metaVariantId",
|
|
6073
|
-
"externalId"
|
|
6262
|
+
"externalId",
|
|
6263
|
+
"externalVariantId",
|
|
6264
|
+
"externalInventoryItemId",
|
|
6265
|
+
"platformVariantId"
|
|
6074
6266
|
]);
|
|
6075
|
-
|
|
6267
|
+
const isPlatformKey = (key) => /^(shopify|woocommerce|tiktok|meta)[A-Z_]/.test(key) || key.includes("VariantId") || key.includes("InventoryItemId");
|
|
6268
|
+
return Object.entries(variant.attributes).filter(
|
|
6269
|
+
([key, value]) => typeof value === "string" && !internalKeys.has(key) && !isPlatformKey(key)
|
|
6270
|
+
).map(([name, value]) => ({ name, value }));
|
|
6076
6271
|
}
|
|
6077
6272
|
function getProductSwatches(product) {
|
|
6078
6273
|
if (!product?.productAttributeOptions) return [];
|
|
@@ -6122,6 +6317,9 @@ function getProductMetafieldValue(product, key) {
|
|
|
6122
6317
|
function getProductMetafieldsByType(product, type) {
|
|
6123
6318
|
return product.metafields?.filter((m) => m.type === type) || [];
|
|
6124
6319
|
}
|
|
6320
|
+
function getProductCustomizationFields(product) {
|
|
6321
|
+
return product.customizationFields ?? [];
|
|
6322
|
+
}
|
|
6125
6323
|
function isCouponApplicableToProduct(coupon, productId) {
|
|
6126
6324
|
const getIds = (refs) => refs?.map((ref) => ref.id) ?? [];
|
|
6127
6325
|
const applicableProductIds = getIds(coupon.applicableProducts);
|
|
@@ -6143,6 +6341,7 @@ function isCouponApplicableToProduct(coupon, productId) {
|
|
|
6143
6341
|
getCartTotals,
|
|
6144
6342
|
getDescriptionContent,
|
|
6145
6343
|
getPriceDisplay,
|
|
6344
|
+
getProductCustomizationFields,
|
|
6146
6345
|
getProductMetafield,
|
|
6147
6346
|
getProductMetafieldValue,
|
|
6148
6347
|
getProductMetafieldsByType,
|