@bacano/sdk 1.2.5 → 1.2.6

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 CHANGED
@@ -288,10 +288,12 @@ await client.init();
288
288
 
289
289
  ### 3. Browse Products (No Auth Required)
290
290
 
291
- `catalog.getProducts()` only returns products that are active, enabled for the
292
- website branch, have a valid `CLIENT` price and have available
293
- inventory in one of the inventory sources configured for the website. Websites
294
- without custom sources continue using the branch's default warehouse.
291
+ `catalog.getProducts()` returns products that are active, published for the
292
+ website, enabled for its branch and have a valid `CLIENT` price. By default it
293
+ excludes sold-out products, but a website may show them globally or override
294
+ that choice per published product. The SDK applies this rule; a visible
295
+ sold-out product remains unavailable for purchase. Websites without custom
296
+ inventory sources continue using the branch's default warehouse.
295
297
 
296
298
  ```typescript
297
299
  // List products
@@ -317,7 +319,7 @@ const affordable = await client.catalog.getProducts({
317
319
  maxPrice: 50,
318
320
  });
319
321
 
320
- // In-stock only. This is already the website default, kept for UI clarity.
322
+ // Strictly in-stock, even if this website displays sold-out products.
321
323
  const available = await client.catalog.getProducts({ inStock: true });
322
324
 
323
325
  // Filter by color
@@ -353,7 +355,7 @@ const filtered = await client.catalog.getProducts({
353
355
  // Single product
354
356
  const product = await client.catalog.getProduct("product-uuid");
355
357
 
356
- // Static builds: fetch the complete sellable catalog and its first renderable
358
+ // Static builds: fetch the complete visible catalog and its first renderable
357
359
  // catalog page. This is the canonical source for initial HTML, routes,
358
360
  // metadata, sitemap and product page data.
359
361
  const bootstrap = await client.catalog.getStaticCatalogBootstrap({
@@ -369,7 +371,8 @@ const productByRoute = new Map(
369
371
  bootstrap.products.map((item) => [item.slug || item.id, item]),
370
372
  );
371
373
 
372
- // Cards and filters use product.variants. Detail selectors use the official
374
+ // Cards and filters use product.variants. These can include sold-out variants
375
+ // if the website permits their display. Detail selectors use the official
373
376
  // helper so sold-out sizes remain visible and older snapshots stay compatible.
374
377
  const detailVariants = getProductDetailVariants(product!);
375
378
 
@@ -49,9 +49,11 @@ if this contract fails; they must not silently publish an empty catalog.
49
49
 
50
50
  The static bootstrap deliberately exposes two projections on each product:
51
51
 
52
- - `product.variants` contains only variants that were saleable when Bacano
53
- generated the catalog page. Cards, price ranges, filters and listing
54
- visibility must use this projection.
52
+ - `product.variants` contains variants eligible for this website's listings.
53
+ It can include sold-out variants when the website setting or this product's
54
+ per-website exception allows them to remain visible. Cards, price ranges,
55
+ filters and listing visibility must use this projection; visibility is not
56
+ permission to purchase.
55
57
  - `product.detailVariants` also contains enabled, published variants with a
56
58
  public price that are currently sold out. Product detail selectors must use
57
59
  this projection so a customer can see unavailable sizes instead of assuming
@@ -71,8 +73,13 @@ const liveState = await client.catalog.getProductLiveState(
71
73
  `getProduct()` and `getProductBySlug()` expose the complete detail projection
72
74
  through `variants` as well. A sold-out variant returns `inStock: false` and
73
75
  `maxPurchasableQuantity: 0` from live state. Never use `detailVariants` to
74
- calculate a card's minimum price or to make a completely sold-out product
75
- appear in listings.
76
+ calculate a card's minimum price or independently decide whether a completely
77
+ sold-out product belongs in listings. The SDK applies the website rule and the
78
+ product's per-website exception to listings, static routes, search suggestions
79
+ and recommendations. `getProducts({ inStock: true })` remains strictly
80
+ in-stock. The public SDK reads these rules; their administration belongs in
81
+ Bacano. Changing them requires rebuilding static routes and catalog HTML;
82
+ live-state refresh cannot add a route missing from the build.
76
83
 
77
84
  ## Live price and availability
78
85
 
package/graphql.cjs CHANGED
@@ -122,6 +122,12 @@ var GET_PRODUCTS = (
122
122
  id
123
123
  name
124
124
  description
125
+ product_website_publications(
126
+ where: { website_id: { _eq: $websiteId }, is_visible: { _eq: true } }
127
+ limit: 1
128
+ ) {
129
+ show_when_out_of_stock
130
+ }
125
131
  long_description
126
132
  slug
127
133
  seo_title
@@ -357,6 +363,12 @@ var GET_PRODUCT_BY_PK = (
357
363
  limit: 1
358
364
  ) {
359
365
  id
366
+ product_website_publications(
367
+ where: { website_id: { _eq: $websiteId }, is_visible: { _eq: true } }
368
+ limit: 1
369
+ ) {
370
+ show_when_out_of_stock
371
+ }
360
372
  product_option_group_members(limit: 1) {
361
373
  group {
362
374
  id
@@ -606,6 +618,12 @@ var GET_PRODUCT_SEO_ENTRIES = (
606
618
  id
607
619
  name
608
620
  slug
621
+ product_website_publications(
622
+ where: { website_id: { _eq: $websiteId }, is_visible: { _eq: true } }
623
+ limit: 1
624
+ ) {
625
+ show_when_out_of_stock
626
+ }
609
627
  seo_title
610
628
  seo_description
611
629
  seo_image_file_id
@@ -2108,6 +2126,7 @@ var GET_PRODUCT_FILTERS = (
2108
2126
  query GetProductFilters(
2109
2127
  $companyId: uuid!
2110
2128
  $chainId: uuid!
2129
+ $websiteId: uuid!
2111
2130
  $where: products_bool_exp = {}
2112
2131
  $attributeListKey: String!
2113
2132
  ) {
@@ -2115,6 +2134,12 @@ var GET_PRODUCT_FILTERS = (
2115
2134
  where: {
2116
2135
  _and: [
2117
2136
  { company_id: { _eq: $companyId } }
2137
+ {
2138
+ product_website_publications: {
2139
+ website_id: { _eq: $websiteId }
2140
+ is_visible: { _eq: true }
2141
+ }
2142
+ }
2118
2143
  {
2119
2144
  chain_products: {
2120
2145
  chain_id: { _eq: $chainId }
@@ -2127,6 +2152,12 @@ var GET_PRODUCT_FILTERS = (
2127
2152
  }
2128
2153
  ) {
2129
2154
  id
2155
+ product_website_publications(
2156
+ where: { website_id: { _eq: $websiteId }, is_visible: { _eq: true } }
2157
+ limit: 1
2158
+ ) {
2159
+ show_when_out_of_stock
2160
+ }
2130
2161
  category
2131
2162
  subcategory
2132
2163
  color
@@ -2234,6 +2265,7 @@ var GET_SEARCH_SUGGESTIONS = (
2234
2265
  query GetSearchSuggestions(
2235
2266
  $companyId: uuid!
2236
2267
  $chainId: uuid!
2268
+ $websiteId: uuid!
2237
2269
  $term: String!
2238
2270
  $productLimit: Int = 5
2239
2271
  $brandLimit: Int = 3
@@ -2241,6 +2273,10 @@ var GET_SEARCH_SUGGESTIONS = (
2241
2273
  products(
2242
2274
  where: {
2243
2275
  company_id: { _eq: $companyId }
2276
+ product_website_publications: {
2277
+ website_id: { _eq: $websiteId }
2278
+ is_visible: { _eq: true }
2279
+ }
2244
2280
  chain_products: {
2245
2281
  chain_id: { _eq: $chainId }
2246
2282
  is_enabled: { _eq: true }
@@ -2253,6 +2289,29 @@ var GET_SEARCH_SUGGESTIONS = (
2253
2289
  ) {
2254
2290
  id
2255
2291
  name
2292
+ product_website_publications(
2293
+ where: { website_id: { _eq: $websiteId }, is_visible: { _eq: true } }
2294
+ limit: 1
2295
+ ) {
2296
+ show_when_out_of_stock
2297
+ }
2298
+ product_variants(where: { is_disabled: { _eq: false } }) {
2299
+ id
2300
+ product_variant_prices(
2301
+ where: {
2302
+ price_type: { _eq: CLIENT }
2303
+ _or: [
2304
+ { chain_id: { _eq: $chainId } }
2305
+ { chain_id: { _is_null: true } }
2306
+ ]
2307
+ }
2308
+ ) {
2309
+ id
2310
+ price
2311
+ price_type
2312
+ chain_id
2313
+ }
2314
+ }
2256
2315
  }
2257
2316
  brands(
2258
2317
  where: {
package/graphql.js CHANGED
@@ -62,6 +62,12 @@ var GET_PRODUCTS = (
62
62
  id
63
63
  name
64
64
  description
65
+ product_website_publications(
66
+ where: { website_id: { _eq: $websiteId }, is_visible: { _eq: true } }
67
+ limit: 1
68
+ ) {
69
+ show_when_out_of_stock
70
+ }
65
71
  long_description
66
72
  slug
67
73
  seo_title
@@ -297,6 +303,12 @@ var GET_PRODUCT_BY_PK = (
297
303
  limit: 1
298
304
  ) {
299
305
  id
306
+ product_website_publications(
307
+ where: { website_id: { _eq: $websiteId }, is_visible: { _eq: true } }
308
+ limit: 1
309
+ ) {
310
+ show_when_out_of_stock
311
+ }
300
312
  product_option_group_members(limit: 1) {
301
313
  group {
302
314
  id
@@ -546,6 +558,12 @@ var GET_PRODUCT_SEO_ENTRIES = (
546
558
  id
547
559
  name
548
560
  slug
561
+ product_website_publications(
562
+ where: { website_id: { _eq: $websiteId }, is_visible: { _eq: true } }
563
+ limit: 1
564
+ ) {
565
+ show_when_out_of_stock
566
+ }
549
567
  seo_title
550
568
  seo_description
551
569
  seo_image_file_id
@@ -2048,6 +2066,7 @@ var GET_PRODUCT_FILTERS = (
2048
2066
  query GetProductFilters(
2049
2067
  $companyId: uuid!
2050
2068
  $chainId: uuid!
2069
+ $websiteId: uuid!
2051
2070
  $where: products_bool_exp = {}
2052
2071
  $attributeListKey: String!
2053
2072
  ) {
@@ -2055,6 +2074,12 @@ var GET_PRODUCT_FILTERS = (
2055
2074
  where: {
2056
2075
  _and: [
2057
2076
  { company_id: { _eq: $companyId } }
2077
+ {
2078
+ product_website_publications: {
2079
+ website_id: { _eq: $websiteId }
2080
+ is_visible: { _eq: true }
2081
+ }
2082
+ }
2058
2083
  {
2059
2084
  chain_products: {
2060
2085
  chain_id: { _eq: $chainId }
@@ -2067,6 +2092,12 @@ var GET_PRODUCT_FILTERS = (
2067
2092
  }
2068
2093
  ) {
2069
2094
  id
2095
+ product_website_publications(
2096
+ where: { website_id: { _eq: $websiteId }, is_visible: { _eq: true } }
2097
+ limit: 1
2098
+ ) {
2099
+ show_when_out_of_stock
2100
+ }
2070
2101
  category
2071
2102
  subcategory
2072
2103
  color
@@ -2174,6 +2205,7 @@ var GET_SEARCH_SUGGESTIONS = (
2174
2205
  query GetSearchSuggestions(
2175
2206
  $companyId: uuid!
2176
2207
  $chainId: uuid!
2208
+ $websiteId: uuid!
2177
2209
  $term: String!
2178
2210
  $productLimit: Int = 5
2179
2211
  $brandLimit: Int = 3
@@ -2181,6 +2213,10 @@ var GET_SEARCH_SUGGESTIONS = (
2181
2213
  products(
2182
2214
  where: {
2183
2215
  company_id: { _eq: $companyId }
2216
+ product_website_publications: {
2217
+ website_id: { _eq: $websiteId }
2218
+ is_visible: { _eq: true }
2219
+ }
2184
2220
  chain_products: {
2185
2221
  chain_id: { _eq: $chainId }
2186
2222
  is_enabled: { _eq: true }
@@ -2193,6 +2229,29 @@ var GET_SEARCH_SUGGESTIONS = (
2193
2229
  ) {
2194
2230
  id
2195
2231
  name
2232
+ product_website_publications(
2233
+ where: { website_id: { _eq: $websiteId }, is_visible: { _eq: true } }
2234
+ limit: 1
2235
+ ) {
2236
+ show_when_out_of_stock
2237
+ }
2238
+ product_variants(where: { is_disabled: { _eq: false } }) {
2239
+ id
2240
+ product_variant_prices(
2241
+ where: {
2242
+ price_type: { _eq: CLIENT }
2243
+ _or: [
2244
+ { chain_id: { _eq: $chainId } }
2245
+ { chain_id: { _is_null: true } }
2246
+ ]
2247
+ }
2248
+ ) {
2249
+ id
2250
+ price
2251
+ price_type
2252
+ chain_id
2253
+ }
2254
+ }
2196
2255
  }
2197
2256
  brands(
2198
2257
  where: {
package/index.cjs CHANGED
@@ -551,6 +551,12 @@ var GET_PRODUCTS = (
551
551
  id
552
552
  name
553
553
  description
554
+ product_website_publications(
555
+ where: { website_id: { _eq: $websiteId }, is_visible: { _eq: true } }
556
+ limit: 1
557
+ ) {
558
+ show_when_out_of_stock
559
+ }
554
560
  long_description
555
561
  slug
556
562
  seo_title
@@ -786,6 +792,12 @@ var GET_PRODUCT_BY_PK = (
786
792
  limit: 1
787
793
  ) {
788
794
  id
795
+ product_website_publications(
796
+ where: { website_id: { _eq: $websiteId }, is_visible: { _eq: true } }
797
+ limit: 1
798
+ ) {
799
+ show_when_out_of_stock
800
+ }
789
801
  product_option_group_members(limit: 1) {
790
802
  group {
791
803
  id
@@ -1035,6 +1047,12 @@ var GET_PRODUCT_SEO_ENTRIES = (
1035
1047
  id
1036
1048
  name
1037
1049
  slug
1050
+ product_website_publications(
1051
+ where: { website_id: { _eq: $websiteId }, is_visible: { _eq: true } }
1052
+ limit: 1
1053
+ ) {
1054
+ show_when_out_of_stock
1055
+ }
1038
1056
  seo_title
1039
1057
  seo_description
1040
1058
  seo_image_file_id
@@ -2668,6 +2686,7 @@ var GET_PRODUCT_FILTERS = (
2668
2686
  query GetProductFilters(
2669
2687
  $companyId: uuid!
2670
2688
  $chainId: uuid!
2689
+ $websiteId: uuid!
2671
2690
  $where: products_bool_exp = {}
2672
2691
  $attributeListKey: String!
2673
2692
  ) {
@@ -2675,6 +2694,12 @@ var GET_PRODUCT_FILTERS = (
2675
2694
  where: {
2676
2695
  _and: [
2677
2696
  { company_id: { _eq: $companyId } }
2697
+ {
2698
+ product_website_publications: {
2699
+ website_id: { _eq: $websiteId }
2700
+ is_visible: { _eq: true }
2701
+ }
2702
+ }
2678
2703
  {
2679
2704
  chain_products: {
2680
2705
  chain_id: { _eq: $chainId }
@@ -2687,6 +2712,12 @@ var GET_PRODUCT_FILTERS = (
2687
2712
  }
2688
2713
  ) {
2689
2714
  id
2715
+ product_website_publications(
2716
+ where: { website_id: { _eq: $websiteId }, is_visible: { _eq: true } }
2717
+ limit: 1
2718
+ ) {
2719
+ show_when_out_of_stock
2720
+ }
2690
2721
  category
2691
2722
  subcategory
2692
2723
  color
@@ -2794,6 +2825,7 @@ var GET_SEARCH_SUGGESTIONS = (
2794
2825
  query GetSearchSuggestions(
2795
2826
  $companyId: uuid!
2796
2827
  $chainId: uuid!
2828
+ $websiteId: uuid!
2797
2829
  $term: String!
2798
2830
  $productLimit: Int = 5
2799
2831
  $brandLimit: Int = 3
@@ -2801,6 +2833,10 @@ var GET_SEARCH_SUGGESTIONS = (
2801
2833
  products(
2802
2834
  where: {
2803
2835
  company_id: { _eq: $companyId }
2836
+ product_website_publications: {
2837
+ website_id: { _eq: $websiteId }
2838
+ is_visible: { _eq: true }
2839
+ }
2804
2840
  chain_products: {
2805
2841
  chain_id: { _eq: $chainId }
2806
2842
  is_enabled: { _eq: true }
@@ -2813,6 +2849,29 @@ var GET_SEARCH_SUGGESTIONS = (
2813
2849
  ) {
2814
2850
  id
2815
2851
  name
2852
+ product_website_publications(
2853
+ where: { website_id: { _eq: $websiteId }, is_visible: { _eq: true } }
2854
+ limit: 1
2855
+ ) {
2856
+ show_when_out_of_stock
2857
+ }
2858
+ product_variants(where: { is_disabled: { _eq: false } }) {
2859
+ id
2860
+ product_variant_prices(
2861
+ where: {
2862
+ price_type: { _eq: CLIENT }
2863
+ _or: [
2864
+ { chain_id: { _eq: $chainId } }
2865
+ { chain_id: { _is_null: true } }
2866
+ ]
2867
+ }
2868
+ ) {
2869
+ id
2870
+ price
2871
+ price_type
2872
+ chain_id
2873
+ }
2874
+ }
2816
2875
  }
2817
2876
  brands(
2818
2877
  where: {
@@ -3972,6 +4031,7 @@ function mapProduct(raw, storageUrl, labels, chainId) {
3972
4031
  createdAt: raw.created_at,
3973
4032
  updatedAt: raw.updated_at ?? raw.created_at,
3974
4033
  variants,
4034
+ outOfStockVisibilityOverride: raw.product_website_publications?.[0]?.show_when_out_of_stock ?? null,
3975
4035
  detailVariants,
3976
4036
  media: raw.product_media.map((m) => mapMedia(m, storageUrl)),
3977
4037
  attributes: raw.product_attributes.map(
@@ -4333,7 +4393,7 @@ async function getWebsiteAvailabilityByVariantId(graphqlUrl, getHeaders, variant
4333
4393
  }
4334
4394
  return availabilityByVariantId;
4335
4395
  }
4336
- async function filterProductsForWebsiteStock(graphqlUrl, getHeaders, products, chainId, websiteId) {
4396
+ async function filterProductsForWebsiteStock(graphqlUrl, getHeaders, products, chainId, websiteId, showOutOfStockByDefault = false, onlyInStock = false) {
4337
4397
  const variantIds = products.flatMap(
4338
4398
  (product) => product.variants.map((variant) => variant.id)
4339
4399
  );
@@ -4359,11 +4419,11 @@ async function filterProductsForWebsiteStock(graphqlUrl, getHeaders, products, c
4359
4419
  pricing: resolveProductPricing(prices)
4360
4420
  };
4361
4421
  }).filter(
4362
- (variant) => inStockVariantIds.has(variant.id) && variant.pricing.currentPrice != null
4422
+ (variant) => (inStockVariantIds.has(variant.id) || !onlyInStock && (product.outOfStockVisibilityOverride ?? showOutOfStockByDefault)) && variant.pricing.currentPrice != null
4363
4423
  )
4364
4424
  })).filter((product) => product.variants.length > 0);
4365
4425
  }
4366
- async function filterSeoProductsForWebsiteStock(graphqlUrl, getHeaders, products, chainId, websiteId) {
4426
+ async function filterSeoProductsForWebsiteStock(graphqlUrl, getHeaders, products, chainId, websiteId, showOutOfStockByDefault = false) {
4367
4427
  const variantIds = products.flatMap(
4368
4428
  (product) => product.product_variants.map((variant) => variant.id)
4369
4429
  );
@@ -4385,7 +4445,7 @@ async function filterSeoProductsForWebsiteStock(graphqlUrl, getHeaders, products
4385
4445
  const pricing = resolveProductPricing(
4386
4446
  selectPublicPrices(prices, chainId)
4387
4447
  );
4388
- return inStockVariantIds.has(variant.id) && pricing.currentPrice != null;
4448
+ return (inStockVariantIds.has(variant.id) || (product.product_website_publications?.[0]?.show_when_out_of_stock ?? showOutOfStockByDefault)) && pricing.currentPrice != null;
4389
4449
  })
4390
4450
  );
4391
4451
  }
@@ -4456,7 +4516,8 @@ function createCatalogModule(graphqlUrl, getHeaders, getContext, storageUrl) {
4456
4516
  getHeaders,
4457
4517
  [mappedProduct],
4458
4518
  ctx.chainId,
4459
- ctx.websiteId
4519
+ ctx.websiteId,
4520
+ ctx.config?.show_out_of_stock_products === true
4460
4521
  );
4461
4522
  if (!filteredProducts[0]) return null;
4462
4523
  const specifications = await loadProductSpecifications([product.id]);
@@ -4689,7 +4750,8 @@ function createCatalogModule(graphqlUrl, getHeaders, getContext, storageUrl) {
4689
4750
  getHeaders,
4690
4751
  data.products ?? [],
4691
4752
  ctx.chainId,
4692
- ctx.websiteId
4753
+ ctx.websiteId,
4754
+ ctx.config?.show_out_of_stock_products === true
4693
4755
  );
4694
4756
  const entries = availableProducts.slice(0, limit).map((product) => mapProductSeoEntry(product, storageUrl)).filter((entry) => Boolean(entry));
4695
4757
  return {
@@ -4766,7 +4828,9 @@ function createCatalogModule(graphqlUrl, getHeaders, getContext, storageUrl) {
4766
4828
  (p) => mapProduct(p, storageUrl, publicAttributeLabels, chainId)
4767
4829
  ),
4768
4830
  chainId,
4769
- ctx.websiteId
4831
+ ctx.websiteId,
4832
+ ctx.config?.show_out_of_stock_products === true,
4833
+ opts?.inStock === true
4770
4834
  );
4771
4835
  const specifications = await loadProductSpecifications(
4772
4836
  products.map((product) => product.id)
@@ -4873,6 +4937,7 @@ function createCatalogModule(graphqlUrl, getHeaders, getContext, storageUrl) {
4873
4937
  {
4874
4938
  companyId: ctx.companyId,
4875
4939
  chainId,
4940
+ websiteId: ctx.websiteId,
4876
4941
  attributeListKey: DEFAULT_FILTER_ATTRIBUTE_LIST_KEY,
4877
4942
  where: buildProductWhere(opts.filters ?? {}, chainId)
4878
4943
  },
@@ -4896,7 +4961,7 @@ function createCatalogModule(graphqlUrl, getHeaders, getContext, storageUrl) {
4896
4961
  variant.product_variant_prices.map(mapPrice),
4897
4962
  chainId
4898
4963
  );
4899
- return prices.length > 0 && (availabilityByVariantId.get(variant.id)?.inStock ?? false);
4964
+ return prices.length > 0 && ((availabilityByVariantId.get(variant.id)?.inStock ?? false) || (product.product_website_publications?.[0]?.show_when_out_of_stock ?? ctx.config?.show_out_of_stock_products === true));
4900
4965
  });
4901
4966
  if (!hasVisibleVariant) continue;
4902
4967
  applicableCategories.add(product.category);
@@ -4984,6 +5049,7 @@ function createCatalogModule(graphqlUrl, getHeaders, getContext, storageUrl) {
4984
5049
  {
4985
5050
  companyId: ctx.companyId,
4986
5051
  chainId,
5052
+ websiteId: ctx.websiteId,
4987
5053
  attributeListKey: opts?.attributeListKey ?? DEFAULT_FILTER_ATTRIBUTE_LIST_KEY,
4988
5054
  where: {
4989
5055
  ...opts?.categoryName ? { category: { _eq: opts.categoryName } } : {},
@@ -5038,7 +5104,9 @@ function createCatalogModule(graphqlUrl, getHeaders, getContext, storageUrl) {
5038
5104
  chainId
5039
5105
  ),
5040
5106
  inStock: availabilityByVariantId.get(variant.id)?.inStock ?? false
5041
- })).filter((variant) => variant.inStock && variant.prices.length > 0);
5107
+ })).filter(
5108
+ (variant) => (variant.inStock || (product.product_website_publications?.[0]?.show_when_out_of_stock ?? ctx.config?.show_out_of_stock_products === true)) && variant.prices.length > 0
5109
+ );
5042
5110
  if (visibleVariants.length === 0) continue;
5043
5111
  categoryCounts.set(
5044
5112
  product.category,
@@ -5123,6 +5191,7 @@ function createCatalogModule(graphqlUrl, getHeaders, getContext, storageUrl) {
5123
5191
  "NO_CHAIN"
5124
5192
  );
5125
5193
  }
5194
+ const chainId = ctx.chainId;
5126
5195
  const term = `%${opts.query}%`;
5127
5196
  const limit = opts.limit ?? 8;
5128
5197
  const data = await executeGraphQL(
@@ -5130,7 +5199,8 @@ function createCatalogModule(graphqlUrl, getHeaders, getContext, storageUrl) {
5130
5199
  GET_SEARCH_SUGGESTIONS,
5131
5200
  {
5132
5201
  companyId: ctx.companyId,
5133
- chainId: ctx.chainId,
5202
+ chainId,
5203
+ websiteId: ctx.websiteId,
5134
5204
  term,
5135
5205
  productLimit: Math.min(limit, 5),
5136
5206
  brandLimit: Math.max(limit - 5, 3)
@@ -5138,8 +5208,29 @@ function createCatalogModule(graphqlUrl, getHeaders, getContext, storageUrl) {
5138
5208
  getHeaders
5139
5209
  );
5140
5210
  const suggestions = [];
5211
+ const availability = await getWebsiteAvailabilityByVariantId(
5212
+ graphqlUrl,
5213
+ getHeaders,
5214
+ (data.products ?? []).flatMap(
5215
+ (product) => product.product_variants.map((variant) => variant.id)
5216
+ ),
5217
+ chainId,
5218
+ ctx.websiteId
5219
+ );
5141
5220
  for (const p of data.products ?? []) {
5142
- suggestions.push({ type: "product", text: p.name, id: p.id });
5221
+ const showWithoutStock = p.product_website_publications?.[0]?.show_when_out_of_stock ?? ctx.config?.show_out_of_stock_products === true;
5222
+ const isVisible = p.product_variants.some((variant) => {
5223
+ const hasPrice = resolveProductPricing(
5224
+ selectPublicPrices(
5225
+ variant.product_variant_prices.map(mapPrice),
5226
+ chainId
5227
+ )
5228
+ ).currentPrice != null;
5229
+ return hasPrice && (showWithoutStock || availability.get(variant.id)?.inStock === true);
5230
+ });
5231
+ if (isVisible) {
5232
+ suggestions.push({ type: "product", text: p.name, id: p.id });
5233
+ }
5143
5234
  }
5144
5235
  for (const b of data.brands ?? []) {
5145
5236
  suggestions.push({ type: "brand", text: b.name, id: b.id });