@jay-framework/wix-stores 0.20.0 → 0.21.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.js CHANGED
@@ -1,12 +1,9 @@
1
1
  import { WIX_CART_CONTEXT, WIX_CART_SERVICE, cartIndicator, cartPage, provideWixCartContext, provideWixCartService } from "@jay-framework/wix-cart";
2
2
  import { createJayService, makeJayQuery, ActionError, RenderPipeline, makeJayStackComponent, makeJayInit, makeContractGenerator } from "@jay-framework/fullstack-component";
3
- import { customizationsV3, inventoryItemsV3, productsV3 } from "@wix/stores";
4
- import { categories } from "@wix/categories";
5
3
  import { registerService, getService } from "@jay-framework/stack-server-runtime";
6
- import { schemas } from "@wix/data-extension-schema";
4
+ import { wixFetch, WIX_CLIENT_SERVICE } from "@jay-framework/wix-server-client";
7
5
  import { createJayContext } from "@jay-framework/runtime";
8
6
  import "@jay-framework/component";
9
- import { WIX_CLIENT_SERVICE } from "@jay-framework/wix-server-client";
10
7
  import * as fs from "fs";
11
8
  import * as path from "path";
12
9
  import * as yaml from "js-yaml";
@@ -25,35 +22,63 @@ var CurrentSort = /* @__PURE__ */ ((CurrentSort2) => {
25
22
  CurrentSort2[CurrentSort2["nameDesc"] = 5] = "nameDesc";
26
23
  return CurrentSort2;
27
24
  })(CurrentSort || {});
28
- const instances = {
29
- productsV3ClientInstance: void 0,
30
- categoriesClientInstance: void 0,
31
- inventoryV3ClientInstance: void 0,
32
- customizationsV3ClientInstance: void 0
33
- };
34
- function getProductsV3Client(wixClient) {
35
- if (!instances.productsV3ClientInstance) {
36
- instances.productsV3ClientInstance = wixClient.use(productsV3);
25
+ function normalizeCategory(cat) {
26
+ if (!cat) return cat;
27
+ const normalized = { ...cat };
28
+ if (normalized.id && !normalized._id) {
29
+ normalized._id = normalized.id;
30
+ }
31
+ const parentCategory = normalized.parentCategory;
32
+ if (parentCategory?.id && !parentCategory?._id) {
33
+ normalized.parentCategory = { ...parentCategory, _id: parentCategory.id };
34
+ }
35
+ return normalized;
36
+ }
37
+ async function queryCategories(client, options) {
38
+ const result = await wixFetch(
39
+ client,
40
+ "/categories/v1/categories/query",
41
+ {
42
+ method: "POST",
43
+ body: {
44
+ query: {
45
+ filter: options?.filter,
46
+ sort: options?.sort,
47
+ cursorPaging: options?.cursorPaging || { limit: 100 }
48
+ },
49
+ treeReference: options?.treeReference || { appNamespace: "@wix/stores" }
50
+ }
51
+ }
52
+ );
53
+ if (result.categories) {
54
+ result.categories = result.categories.map(
55
+ (c) => normalizeCategory(c)
56
+ );
37
57
  }
38
- return instances.productsV3ClientInstance;
58
+ return result;
39
59
  }
40
- function getCategoriesClient(wixClient) {
41
- if (!instances.categoriesClientInstance) {
42
- instances.categoriesClientInstance = wixClient.use(categories);
43
- }
44
- return instances.categoriesClientInstance;
60
+ async function queryCustomizations(client, options) {
61
+ return wixFetch(client, "/stores/v3/customizations/query", {
62
+ method: "POST",
63
+ body: {
64
+ query: {
65
+ filter: options?.filter,
66
+ paging: options?.paging
67
+ }
68
+ }
69
+ });
45
70
  }
46
- function getInventoryClient(wixClient) {
47
- if (!instances.inventoryV3ClientInstance) {
48
- instances.inventoryV3ClientInstance = wixClient.use(inventoryItemsV3);
49
- }
50
- return instances.inventoryV3ClientInstance;
71
+ async function querySchemas(client, options) {
72
+ const namespace = options?.filter?.namespace || "";
73
+ const params = namespace ? `?fqdn=${encodeURIComponent(namespace)}` : "";
74
+ return wixFetch(client, `/schema-service/v1/schemas${params}`, {
75
+ method: "GET"
76
+ });
51
77
  }
52
- function getCustomizationsV3Client(wixClient) {
53
- if (!instances.customizationsV3ClientInstance) {
54
- instances.customizationsV3ClientInstance = wixClient.use(customizationsV3);
55
- }
56
- return instances.customizationsV3ClientInstance;
78
+ async function getAllProductsCategory(client) {
79
+ return wixFetch(client, "/stores/v3/all-products-category", {
80
+ method: "GET"
81
+ });
57
82
  }
58
83
  const WIX_STORES_SERVICE_MARKER = createJayService("Wix Store Service");
59
84
  function provideWixStoresService(wixClient, options) {
@@ -61,13 +86,8 @@ function provideWixStoresService(wixClient, options) {
61
86
  let cachedCustomizations = null;
62
87
  let cachedExtensionSchemas = null;
63
88
  let cachedAllProductsCategoryId;
64
- const categoriesClient = getCategoriesClient(wixClient);
65
- const customizationsClient = getCustomizationsV3Client(wixClient);
66
89
  const service = {
67
- products: getProductsV3Client(wixClient),
68
- categories: categoriesClient,
69
- inventory: getInventoryClient(wixClient),
70
- customizations: customizationsClient,
90
+ wixClient,
71
91
  urls: options?.urls ?? { product: "/products/{slug}", category: null },
72
92
  defaultCategory: options?.defaultCategory ?? null,
73
93
  async getCategoryTree() {
@@ -92,11 +112,16 @@ function provideWixStoresService(wixClient, options) {
92
112
  }
93
113
  }
94
114
  };
95
- let result = await categoriesClient.queryCategories({ treeReference: { appNamespace: "@wix/stores" } }).eq("visible", true).limit(100).find();
96
- processItems(result.items || []);
97
- while (result.hasNext()) {
98
- result = await result.next();
99
- processItems(result.items || []);
115
+ let cursor;
116
+ let hasMore = true;
117
+ while (hasMore) {
118
+ const result = await queryCategories(
119
+ wixClient,
120
+ cursor ? { cursorPaging: { cursor } } : { filter: { visible: true }, cursorPaging: { limit: 100 } }
121
+ );
122
+ processItems(result.categories || []);
123
+ cursor = result.pagingMetadata?.cursors?.next;
124
+ hasMore = !!cursor;
100
125
  }
101
126
  } catch (error) {
102
127
  console.error("[wix-stores] Failed to build category tree:", error);
@@ -107,8 +132,11 @@ function provideWixStoresService(wixClient, options) {
107
132
  async getCustomizations() {
108
133
  if (cachedCustomizations) return cachedCustomizations;
109
134
  try {
110
- const result = await customizationsClient.queryCustomizations().eq("customizationType", "PRODUCT_OPTION").limit(100).find();
111
- cachedCustomizations = result.items || [];
135
+ const result = await queryCustomizations(wixClient, {
136
+ filter: { customizationType: "PRODUCT_OPTION" },
137
+ paging: { limit: 100 }
138
+ });
139
+ cachedCustomizations = result.customizations || [];
112
140
  } catch (error) {
113
141
  console.error("[wix-stores] Failed to load customizations:", error);
114
142
  cachedCustomizations = [];
@@ -118,10 +146,9 @@ function provideWixStoresService(wixClient, options) {
118
146
  async getDataExtensionSchemas() {
119
147
  if (cachedExtensionSchemas) return cachedExtensionSchemas;
120
148
  try {
121
- const client = wixClient.use(schemas);
122
- const result = await client.listDataExtensionSchemas(
123
- "wix.stores.catalog.v3.product"
124
- );
149
+ const result = await querySchemas(wixClient, {
150
+ filter: { namespace: "wix.stores.catalog.v3.product" }
151
+ });
125
152
  cachedExtensionSchemas = result?.dataExtensionSchemas ?? [];
126
153
  const fieldCount = cachedExtensionSchemas.reduce(
127
154
  (n, s) => n + Object.keys(s.jsonSchema?.properties ?? {}).length,
@@ -139,7 +166,7 @@ function provideWixStoresService(wixClient, options) {
139
166
  async getAllProductsCategoryId() {
140
167
  if (cachedAllProductsCategoryId !== void 0) return cachedAllProductsCategoryId;
141
168
  try {
142
- const result = await service.products.getAllProductsCategory();
169
+ const result = await getAllProductsCategory(wixClient);
143
170
  cachedAllProductsCategoryId = result.categoryId ?? null;
144
171
  } catch (error) {
145
172
  console.error("[wix-stores] Failed to get All Products category:", error);
@@ -190,6 +217,9 @@ var ChoiceType$1 = /* @__PURE__ */ ((ChoiceType2) => {
190
217
  ChoiceType2[ChoiceType2["ONE_COLOR"] = 1] = "ONE_COLOR";
191
218
  return ChoiceType2;
192
219
  })(ChoiceType$1 || {});
220
+ function stripWixMediaResize(url) {
221
+ return url.replace(/\/v1\/(?:fit|fill|crop)\/[^/]+\/file\.\w+$/, "");
222
+ }
193
223
  function parseWixMediaUrl(url) {
194
224
  if (!url) return null;
195
225
  const match = url.match(
@@ -226,7 +256,7 @@ function formatWixMediaUrl(_id, url, resize) {
226
256
  }
227
257
  }
228
258
  if ((url == null ? void 0 : url.startsWith("http://")) || (url == null ? void 0 : url.startsWith("https://"))) {
229
- return url;
259
+ return stripWixMediaResize(url) + resizeFragment;
230
260
  }
231
261
  if (_id) {
232
262
  return `https://static.wixstatic.com/media/${_id}${resizeFragment}`;
@@ -468,6 +498,220 @@ function mapProductToCard(product, urls, tree) {
468
498
  ...mapQuickAddOptions(product)
469
499
  };
470
500
  }
501
+ function raw(value) {
502
+ return value;
503
+ }
504
+ function rawArray(value) {
505
+ return value;
506
+ }
507
+ function str(value) {
508
+ return value;
509
+ }
510
+ function normalizeProduct(product) {
511
+ if (!product) return product;
512
+ const normalized = { ...product };
513
+ if (normalized.id && !normalized._id) {
514
+ normalized._id = normalized.id;
515
+ }
516
+ const media = raw(normalized.media);
517
+ if (media?.main) {
518
+ const main = raw(media.main);
519
+ const mainImage = raw(main.image);
520
+ normalized.media = {
521
+ ...media,
522
+ main: {
523
+ _id: main.id || main._id,
524
+ url: mainImage?.url || main.url,
525
+ altText: mainImage?.altText || main.altText,
526
+ mediaType: main.mediaType,
527
+ width: mainImage?.width,
528
+ height: mainImage?.height
529
+ }
530
+ };
531
+ }
532
+ const updatedMedia = raw(normalized.media);
533
+ const itemsInfo = raw(updatedMedia?.itemsInfo);
534
+ if (itemsInfo?.items) {
535
+ itemsInfo.items = rawArray(itemsInfo.items).map((item) => {
536
+ const image = raw(item.image);
537
+ return {
538
+ _id: item.id || item._id,
539
+ url: image?.url || item.url,
540
+ altText: image?.altText || item.altText,
541
+ mediaType: item.mediaType,
542
+ width: image?.width,
543
+ height: image?.height
544
+ };
545
+ });
546
+ }
547
+ if (normalized.options) {
548
+ normalized.options = rawArray(normalized.options).map((opt) => {
549
+ const choicesSettings = raw(opt.choicesSettings);
550
+ return {
551
+ ...opt,
552
+ _id: opt.id || opt._id,
553
+ choices: choicesSettings?.choices ? rawArray(choicesSettings.choices).map((c) => {
554
+ const linkedMedia = c.linkedMedia;
555
+ const firstMedia = linkedMedia?.[0];
556
+ const firstMediaImage = firstMedia ? raw(firstMedia.image) : void 0;
557
+ return {
558
+ ...c,
559
+ _id: c.choiceId || c._id,
560
+ value: c.name || c.value,
561
+ media: firstMedia ? {
562
+ _id: firstMedia.id,
563
+ url: str(firstMediaImage?.url) || firstMedia.url,
564
+ mediaType: firstMedia.mediaType
565
+ } : void 0
566
+ };
567
+ }) : void 0
568
+ };
569
+ });
570
+ }
571
+ if (normalized.modifiers) {
572
+ normalized.modifiers = rawArray(normalized.modifiers).map((mod) => {
573
+ const choicesSettings = raw(mod.choicesSettings);
574
+ return {
575
+ ...mod,
576
+ _id: mod.id || mod._id,
577
+ choices: choicesSettings?.choices ? rawArray(choicesSettings.choices).map((c) => ({
578
+ ...c,
579
+ _id: c.choiceId || c._id,
580
+ value: c.name || c.value
581
+ })) : void 0
582
+ };
583
+ });
584
+ }
585
+ if (normalized.infoSections) {
586
+ normalized.infoSections = rawArray(normalized.infoSections).map((s) => ({
587
+ ...s,
588
+ _id: s.id || s._id
589
+ }));
590
+ }
591
+ const variantsInfo = raw(normalized.variantsInfo);
592
+ if (variantsInfo?.variants) {
593
+ variantsInfo.variants = rawArray(variantsInfo.variants).map((v) => ({
594
+ ...v,
595
+ _id: v.id || v._id
596
+ }));
597
+ }
598
+ if (normalized.ribbon) {
599
+ const ribbon = raw(normalized.ribbon);
600
+ normalized.ribbon = {
601
+ ...ribbon,
602
+ _id: ribbon.id || ribbon._id
603
+ };
604
+ }
605
+ return normalized;
606
+ }
607
+ function normalizeProducts(products) {
608
+ return products.map(normalizeProduct);
609
+ }
610
+ async function queryProducts(client, query) {
611
+ const result = await wixFetch(client, "/stores/v3/products/query", {
612
+ method: "POST",
613
+ body: {
614
+ query: {
615
+ filter: query.filter,
616
+ sort: query.sort,
617
+ paging: query.paging
618
+ },
619
+ ...query.fields ? { fields: query.fields } : {}
620
+ }
621
+ });
622
+ if (result.products) {
623
+ result.products = normalizeProducts(result.products);
624
+ }
625
+ return result;
626
+ }
627
+ async function searchProducts$1(client, search, options) {
628
+ const result = await wixFetch(client, "/stores/v3/products/search", {
629
+ method: "POST",
630
+ body: {
631
+ search,
632
+ ...options?.fields ? { fields: options.fields } : {}
633
+ }
634
+ });
635
+ if (result.products) {
636
+ result.products = normalizeProducts(result.products);
637
+ }
638
+ return result;
639
+ }
640
+ const searchProducts$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
641
+ __proto__: null,
642
+ searchProducts: searchProducts$1
643
+ }, Symbol.toStringTag, { value: "Module" }));
644
+ async function getProduct(client, productId, options) {
645
+ const params = new URLSearchParams();
646
+ {
647
+ params.set("includeMerchantSpecificData", "true");
648
+ }
649
+ if (options?.fields) {
650
+ for (const f of options.fields) {
651
+ params.append("fields", f);
652
+ }
653
+ }
654
+ const qs = params.toString();
655
+ const result = await wixFetch(
656
+ client,
657
+ `/stores/v3/products/${productId}${qs ? "?" + qs : ""}`,
658
+ {
659
+ method: "GET"
660
+ }
661
+ );
662
+ if (result.product) {
663
+ result.product = normalizeProduct(result.product);
664
+ }
665
+ return result;
666
+ }
667
+ async function getProductBySlug$1(client, slug, options) {
668
+ const params = new URLSearchParams();
669
+ if (options?.includeMerchantSpecificData) {
670
+ params.set("includeMerchantSpecificData", "true");
671
+ }
672
+ if (options?.fields) {
673
+ for (const f of options.fields) {
674
+ params.append("fields", f);
675
+ }
676
+ }
677
+ const qs = params.toString();
678
+ const result = await wixFetch(
679
+ client,
680
+ `/stores/v3/products/slug/${slug}${qs ? "?" + qs : ""}`,
681
+ {
682
+ method: "GET"
683
+ }
684
+ );
685
+ if (result.product) {
686
+ result.product = normalizeProduct(result.product);
687
+ }
688
+ return result;
689
+ }
690
+ async function getCategory(client, categoryId) {
691
+ const result = await wixFetch(
692
+ client,
693
+ `/categories/v1/categories/${categoryId}`,
694
+ {
695
+ method: "GET"
696
+ }
697
+ );
698
+ if (result.category) {
699
+ const raw2 = result.category;
700
+ if (raw2.id && !result.category._id) {
701
+ result.category._id = raw2.id;
702
+ }
703
+ if (result.category.parentCategory) {
704
+ const rawParent = result.category.parentCategory;
705
+ if (rawParent.id && !result.category.parentCategory._id) {
706
+ result.category.parentCategory = {
707
+ ...result.category.parentCategory,
708
+ _id: rawParent.id
709
+ };
710
+ }
711
+ }
712
+ }
713
+ return result;
714
+ }
471
715
  function needsCategoryInfo(wixStores) {
472
716
  const template = wixStores.urls.product;
473
717
  return template.includes("{category}") || template.includes("{prefix}");
@@ -642,7 +886,8 @@ const searchProducts = makeJayQuery("wixStores.searchProducts").withServices(WIX
642
886
  }
643
887
  }
644
888
  ];
645
- const searchResult = await wixStores.products.searchProducts(
889
+ const searchResult = await searchProducts$1(
890
+ wixStores.wixClient,
646
891
  {
647
892
  filter,
648
893
  sort: sort.length > 0 ? sort : void 0,
@@ -731,7 +976,8 @@ const getProductBySlug = makeJayQuery("wixStores.getProductBySlug").withServices
731
976
  "CURRENCY",
732
977
  ...needsCategoryInfo(wixStores) ? ["ALL_CATEGORIES_INFO"] : []
733
978
  ];
734
- const result = await wixStores.products.getProductBySlug(slug, {
979
+ const result = await getProductBySlug$1(wixStores.wixClient, slug, {
980
+ includeMerchantSpecificData: true,
735
981
  fields: [...fields]
736
982
  });
737
983
  const product = result.product;
@@ -749,10 +995,12 @@ const getProductBySlug = makeJayQuery("wixStores.getProductBySlug").withServices
749
995
  const getVariantStock = makeJayQuery("wixStores.getVariantStock").withServices(WIX_STORES_SERVICE_MARKER).withHandler(
750
996
  async (input, wixStores) => {
751
997
  try {
752
- const product = await wixStores.products.getProduct(input.productId, {
998
+ const result = await getProduct(wixStores.wixClient, input.productId, {
999
+ includeMerchantSpecificData: true,
753
1000
  fields: ["VARIANT_OPTION_CHOICE_NAMES"]
754
1001
  });
755
- return buildVariantStockMap(product);
1002
+ if (!result.product) return {};
1003
+ return buildVariantStockMap(result.product);
756
1004
  } catch (error) {
757
1005
  console.error("[wixStores.getVariantStock] Failed:", error);
758
1006
  return {};
@@ -762,12 +1010,10 @@ const getVariantStock = makeJayQuery("wixStores.getVariantStock").withServices(W
762
1010
  const getCategories = makeJayQuery("wixStores.getCategories").withServices(WIX_STORES_SERVICE_MARKER).withCaching({ maxAge: 3600 }).withHandler(
763
1011
  async (_input, wixStores) => {
764
1012
  try {
765
- const result = await wixStores.categories.queryCategories({
766
- treeReference: {
767
- appNamespace: "@wix/stores"
768
- }
769
- }).eq("visible", true).find();
770
- return (result.items || []).map((cat) => ({
1013
+ const result = await queryCategories(wixStores.wixClient, {
1014
+ filter: { visible: true }
1015
+ });
1016
+ return (result.categories || []).map((cat) => ({
771
1017
  categoryId: cat._id || "",
772
1018
  categoryName: cat.name || ""
773
1019
  }));
@@ -889,23 +1135,25 @@ const EMPTY_CATEGORY_HEADER = {
889
1135
  breadcrumbs: [],
890
1136
  seoData: { tags: [], settings: { preventAutoRedirect: false, keywords: [] } }
891
1137
  };
892
- async function findCategoryBySlug$1(categoriesClient, slug) {
893
- const result = await categoriesClient.queryCategories({ treeReference: { appNamespace: "@wix/stores" } }).eq("slug", slug).eq("visible", true).limit(1).find();
894
- const cat = result.items?.[0];
895
- if (!cat?._id)
896
- return null;
897
- return loadCategoryDetails(categoriesClient, cat._id);
1138
+ async function findCategoryBySlug$1(wixClient, slug) {
1139
+ const result = await queryCategories(wixClient, {
1140
+ filter: { slug, visible: true },
1141
+ cursorPaging: { limit: 1 }
1142
+ });
1143
+ return result.categories?.[0] ?? null;
898
1144
  }
899
- async function loadCategoryDetails(categoriesClient, categoryId) {
1145
+ async function loadCategoryDetails(wixClient, categoryId) {
900
1146
  try {
901
- return await categoriesClient.getCategory(categoryId, { appNamespace: "@wix/stores" }, { fields: ["DESCRIPTION", "BREADCRUMBS_INFO"] });
1147
+ const result = await getCategory(wixClient, categoryId);
1148
+ return result.category ?? null;
902
1149
  } catch {
903
1150
  return null;
904
1151
  }
905
1152
  }
906
1153
  async function buildCategoryHeader(wixStoreService, category, categoryUrlTemplate) {
907
- const cat = category;
908
- const imageUrl = cat.image ? formatWixMediaUrl("", cat.image) : "";
1154
+ const details = await loadCategoryDetails(wixStoreService.wixClient, category._id);
1155
+ const cat = details || category;
1156
+ const imageUrl = cat.image?.url ? formatWixMediaUrl(cat.image.id || "", cat.image.url) : "";
909
1157
  const description = cat.description || "";
910
1158
  const categoryTree = await wixStoreService.getCategoryTree();
911
1159
  const breadcrumbs = [
@@ -955,13 +1203,13 @@ async function buildCategoryHeader(wixStoreService, category, categoryUrlTemplat
955
1203
  seoData
956
1204
  };
957
1205
  if ((!description || !imageUrl) && cat.parentCategory?._id) {
958
- const parent = await loadCategoryDetails(wixStoreService.categories, cat.parentCategory._id);
1206
+ const parent = await loadCategoryDetails(wixStoreService.wixClient, cat.parentCategory._id);
959
1207
  if (parent) {
960
1208
  if (!header.description && parent.description) {
961
1209
  header = { ...header, description: parent.description };
962
1210
  }
963
1211
  if (!header.imageUrl) {
964
- const parentImage = parent.image ? formatWixMediaUrl("", parent.image) : "";
1212
+ const parentImage = parent.image?.url ? formatWixMediaUrl(parent.image.id || "", parent.image.url) : "";
965
1213
  if (parentImage) {
966
1214
  header = { ...header, imageUrl: parentImage, hasImage: true };
967
1215
  }
@@ -973,29 +1221,30 @@ async function buildCategoryHeader(wixStoreService, category, categoryUrlTemplat
973
1221
  async function renderSlowlyChanging$4(props, wixStores) {
974
1222
  const Pipeline = RenderPipeline.for();
975
1223
  const categorySlug = props.category ?? null;
1224
+ const prefixSlug = props.prefix ?? null;
1225
+ const defaultCategorySlug = wixStores.defaultCategory;
976
1226
  let activeCategory = null;
977
1227
  let baseCategoryId = null;
978
1228
  if (categorySlug) {
979
- activeCategory = await findCategoryBySlug$1(wixStores.categories, categorySlug);
1229
+ activeCategory = await findCategoryBySlug$1(wixStores.wixClient, categorySlug);
980
1230
  baseCategoryId = activeCategory?._id ?? null;
981
- } else {
982
- const allProductsCategoryId = await wixStores.getAllProductsCategoryId();
983
- if (allProductsCategoryId) {
984
- activeCategory = await loadCategoryDetails(wixStores.categories, allProductsCategoryId);
985
- }
1231
+ } else if (prefixSlug) {
1232
+ activeCategory = await findCategoryBySlug$1(wixStores.wixClient, prefixSlug);
1233
+ baseCategoryId = activeCategory?._id ?? null;
1234
+ } else if (defaultCategorySlug) {
1235
+ activeCategory = await findCategoryBySlug$1(wixStores.wixClient, defaultCategorySlug);
986
1236
  }
987
1237
  const tree = await wixStores.getCategoryTree();
988
1238
  const categoryHeader = activeCategory ? await buildCategoryHeader(wixStores, activeCategory, wixStores.urls.category) : EMPTY_CATEGORY_HEADER;
1239
+ const allProductsCategoryId = await wixStores.getAllProductsCategoryId();
989
1240
  return Pipeline.try(async () => {
990
- let query = wixStores.categories.queryCategories({
991
- treeReference: { appNamespace: "@wix/stores" }
992
- }).eq("visible", true);
1241
+ const categoryFilter = { visible: true };
993
1242
  if (baseCategoryId) {
994
- query = query.eq("parentCategory.id", baseCategoryId);
1243
+ categoryFilter["parentCategory.id"] = baseCategoryId;
995
1244
  }
996
1245
  const baseCategoryIds = baseCategoryId ? [baseCategoryId] : [];
997
1246
  const [categoriesResult, productsResult] = await Promise.all([
998
- query.find(),
1247
+ queryCategories(wixStores.wixClient, { filter: categoryFilter }),
999
1248
  searchProducts({
1000
1249
  query: "",
1001
1250
  filters: {
@@ -1004,14 +1253,15 @@ async function renderSlowlyChanging$4(props, wixStores) {
1004
1253
  pageSize: PAGE_SIZE
1005
1254
  })
1006
1255
  ]);
1256
+ const categories = (categoriesResult.categories || []).filter((cat) => cat._id !== allProductsCategoryId);
1007
1257
  return {
1008
- categories: categoriesResult.items || [],
1258
+ categories,
1009
1259
  productsResult
1010
1260
  };
1011
1261
  }).recover((error) => {
1012
1262
  return handleError(error);
1013
- }).toPhaseOutput(({ categories: categories2, productsResult }) => {
1014
- const categoryInfos = categories2.map((cat) => ({
1263
+ }).toPhaseOutput(({ categories, productsResult }) => {
1264
+ const categoryInfos = categories.map((cat) => ({
1015
1265
  categoryId: cat._id || "",
1016
1266
  categoryName: cat.name || "",
1017
1267
  categorySlug: cat.slug || "",
@@ -1176,13 +1426,13 @@ async function* loadSearchParams([wixStores]) {
1176
1426
  };
1177
1427
  const allProductsCategoryId = await wixStores.getAllProductsCategoryId();
1178
1428
  const allCategories = [];
1179
- let result = await wixStores.categories.queryCategories({
1180
- treeReference: { appNamespace: "@wix/stores" }
1181
- }).eq("visible", true).limit(100).find();
1182
- allCategories.push(...result.items || []);
1183
- while (result.hasNext()) {
1184
- result = await result.next();
1185
- allCategories.push(...result.items || []);
1429
+ let cursor;
1430
+ let hasMore = true;
1431
+ while (hasMore) {
1432
+ const result = await queryCategories(wixStores.wixClient, cursor ? { cursorPaging: { cursor } } : { filter: { visible: true }, cursorPaging: { limit: 100 } });
1433
+ allCategories.push(...result.categories || []);
1434
+ cursor = result.pagingMetadata?.cursors?.next;
1435
+ hasMore = !!cursor;
1186
1436
  }
1187
1437
  const nodeById = /* @__PURE__ */ new Map();
1188
1438
  const roots = [];
@@ -1274,9 +1524,9 @@ var MediaType = /* @__PURE__ */ ((MediaType2) => {
1274
1524
  return MediaType2;
1275
1525
  })(MediaType || {});
1276
1526
  function mapExtendedFields(product) {
1277
- const raw = product.extendedFields?.namespaces?.["_user_fields"] ?? {};
1527
+ const raw2 = product.extendedFields?.namespaces?.["_user_fields"] ?? {};
1278
1528
  const result = {};
1279
- for (const [key, value] of Object.entries(raw)) {
1529
+ for (const [key, value] of Object.entries(raw2)) {
1280
1530
  if (Array.isArray(value)) {
1281
1531
  result[key] = value.map((item, i) => typeof item === "object" && item !== null ? { ...item, _index: i } : { value: item, _index: i });
1282
1532
  } else {
@@ -1293,7 +1543,7 @@ async function* loadProductParams([wixStores]) {
1293
1543
  const fields = needsCategories ? ["ALL_CATEGORIES_INFO"] : [];
1294
1544
  try {
1295
1545
  const tree = needsCategories ? await wixStores.getCategoryTree() : null;
1296
- let result = await wixStores.products.queryProducts({ fields: [...fields] }).find();
1546
+ let result = await queryProducts(wixStores.wixClient, { fields: [...fields] });
1297
1547
  const mapProduct = (product) => {
1298
1548
  const slug = product.slug ?? "";
1299
1549
  if (!slug)
@@ -1309,11 +1559,7 @@ async function* loadProductParams([wixStores]) {
1309
1559
  }
1310
1560
  return params;
1311
1561
  };
1312
- yield result.items.map(mapProduct).filter((p) => p !== null);
1313
- while (result.hasNext()) {
1314
- result = await result.next();
1315
- yield result.items.map(mapProduct).filter((p) => p !== null);
1316
- }
1562
+ yield (result.products || []).map(mapProduct).filter((p) => p !== null);
1317
1563
  } catch (error) {
1318
1564
  console.error("Failed to load product slugs:", error);
1319
1565
  yield [];
@@ -1479,7 +1725,8 @@ async function renderSlowlyChanging$3(props, wixStores) {
1479
1725
  ...needsCategories ? ["ALL_CATEGORIES_INFO"] : []
1480
1726
  ];
1481
1727
  const [response, tree] = await Promise.all([
1482
- wixStores.products.getProductBySlug(props.slug, {
1728
+ getProductBySlug$1(wixStores.wixClient, props.slug, {
1729
+ includeMerchantSpecificData: true,
1483
1730
  fields: [...fields]
1484
1731
  }),
1485
1732
  wixStores.getCategoryTree()
@@ -1598,15 +1845,18 @@ async function renderSlowlyChanging$2(props, wixStores) {
1598
1845
  return { categoryName: "", products: [] };
1599
1846
  }
1600
1847
  const [categoryResult, searchResult] = await Promise.all([
1601
- wixStores.categories.queryCategories({ treeReference: { appNamespace: "@wix/stores" } }).eq("_id", categoryId).limit(1).find().catch(() => null),
1848
+ queryCategories(wixStores.wixClient, {
1849
+ filter: { _id: categoryId },
1850
+ cursorPaging: { limit: 1 }
1851
+ }).catch(() => null),
1602
1852
  searchProducts({
1603
1853
  query: "",
1604
1854
  filters: { categoryIds: [categoryId] },
1605
1855
  pageSize: limit + 1
1606
1856
  })
1607
1857
  ]);
1608
- if (categoryResult?.items?.[0]?.name) {
1609
- categoryName = categoryResult.items[0].name;
1858
+ if (categoryResult?.categories?.[0]?.name) {
1859
+ categoryName = categoryResult.categories[0].name;
1610
1860
  }
1611
1861
  const products = searchResult.products.filter((p) => p._id !== props.productId).slice(0, limit);
1612
1862
  return { categoryName, products };
@@ -1714,34 +1964,33 @@ async function renderFastChanging(_props, carryForward, _wixStores) {
1714
1964
  });
1715
1965
  }
1716
1966
  const productSpotlight = makeJayStackComponent().withProps().withServices(WIX_STORES_SERVICE_MARKER).withSlowlyRender(renderSlowlyChanging$1).withFastRender(renderFastChanging);
1717
- async function findCategoryBySlug(categoriesClient, slug) {
1718
- const result = await categoriesClient.queryCategories({ treeReference: { appNamespace: "@wix/stores" } }).eq("slug", slug).eq("visible", true).limit(1).find();
1719
- return result.items?.[0] ?? null;
1967
+ async function findCategoryBySlug(wixClient, slug) {
1968
+ const result = await queryCategories(wixClient, {
1969
+ filter: { slug, visible: true },
1970
+ cursorPaging: { limit: 1 }
1971
+ });
1972
+ return result.categories?.[0] ?? null;
1720
1973
  }
1721
1974
  async function renderSlowlyChanging(props, wixStores) {
1722
1975
  const Pipeline = RenderPipeline.for();
1723
1976
  const parentCategorySlug = props.parentCategory ?? wixStores.defaultCategory;
1724
1977
  let parentCategoryId = null;
1725
1978
  if (parentCategorySlug) {
1726
- const parentCat = await findCategoryBySlug(wixStores.categories, parentCategorySlug);
1979
+ const parentCat = await findCategoryBySlug(wixStores.wixClient, parentCategorySlug);
1727
1980
  parentCategoryId = parentCat?._id ?? null;
1728
1981
  }
1729
1982
  return Pipeline.try(async () => {
1730
- let query = wixStores.categories.queryCategories({
1731
- treeReference: {
1732
- appNamespace: "@wix/stores"
1733
- }
1734
- }).eq("visible", true);
1983
+ const filter = { visible: true };
1735
1984
  if (parentCategoryId) {
1736
- query = query.eq("parentCategory.id", parentCategoryId);
1985
+ filter["parentCategory.id"] = parentCategoryId;
1737
1986
  }
1738
- const result = await query.find();
1739
- return result.items || [];
1987
+ const result = await queryCategories(wixStores.wixClient, { filter });
1988
+ return result.categories || [];
1740
1989
  }).recover((error) => {
1741
1990
  console.error("Failed to load categories:", error);
1742
1991
  return Pipeline.ok([]);
1743
- }).toPhaseOutput((categories2) => {
1744
- const categoryItems = categories2.map((cat) => ({
1992
+ }).toPhaseOutput((categories) => {
1993
+ const categoryItems = categories.map((cat) => ({
1745
1994
  _id: cat._id || "",
1746
1995
  name: cat.name || "",
1747
1996
  slug: cat.slug || "",
@@ -1771,17 +2020,17 @@ function loadWixStoresConfig(projectRoot) {
1771
2020
  return defaults;
1772
2021
  }
1773
2022
  const fileContents = fs.readFileSync(configPath, "utf8");
1774
- const raw = yaml.load(fileContents);
1775
- if (!raw) {
2023
+ const raw2 = yaml.load(fileContents);
2024
+ if (!raw2) {
1776
2025
  return defaults;
1777
2026
  }
1778
- const urls = raw.urls;
2027
+ const urls = raw2.urls;
1779
2028
  return {
1780
2029
  urls: {
1781
2030
  product: typeof urls?.product === "string" ? urls.product : defaults.urls.product,
1782
2031
  category: typeof urls?.category === "string" ? urls.category : null
1783
2032
  },
1784
- defaultCategory: typeof raw.defaultCategory === "string" ? raw.defaultCategory : null
2033
+ defaultCategory: typeof raw2.defaultCategory === "string" ? raw2.defaultCategory : null
1785
2034
  };
1786
2035
  }
1787
2036
  const init = makeJayInit().withServer(async () => {
@@ -1802,6 +2051,9 @@ const init = makeJayInit().withServer(async () => {
1802
2051
  enableClientSearch: true
1803
2052
  };
1804
2053
  });
2054
+ function wixStoresStaticContractPath(contractName) {
2055
+ return `node_modules/@jay-framework/wix-stores/dist/contracts/${contractName}.jay-contract`;
2056
+ }
1805
2057
  function flattenCategoryTree(roots, parentNames = [], parentSlugs = [], rootSlug = null, rootName = null, rootHasChildren = null) {
1806
2058
  const entries = [];
1807
2059
  for (const node of roots) {
@@ -1914,9 +2166,10 @@ function buildCategoryPrompt(config, entry) {
1914
2166
  ` category-products — pass categorySlug="${node.slug}" to show products from this category; optionally pass productId to exclude a product`,
1915
2167
  "",
1916
2168
  "Contracts:",
1917
- " agent-kit/materialized-contracts/wix-stores/product-search.jay-contract",
1918
- " agent-kit/materialized-contracts/wix-stores/category-list.jay-contract",
1919
- " agent-kit/materialized-contracts/wix-stores/category-products.jay-contract",
2169
+ ` ${wixStoresStaticContractPath("product-search")}`,
2170
+ ` ${wixStoresStaticContractPath("category-list")}`,
2171
+ ` ${wixStoresStaticContractPath("category-products")}`,
2172
+ " Related products on a product page: agent-kit/designer/related-products.md",
1920
2173
  "",
1921
2174
  "Bind ViewState and refs per agent-kit/designer/INSTRUCTIONS.md."
1922
2175
  );
@@ -2047,7 +2300,8 @@ async function setupWixStores(ctx) {
2047
2300
  }
2048
2301
  const service = getService(WIX_STORES_SERVICE_MARKER);
2049
2302
  try {
2050
- await service.products.searchProducts({});
2303
+ const { searchProducts: searchProductsApi } = await Promise.resolve().then(() => searchProducts$2);
2304
+ await searchProductsApi(service.wixClient, {});
2051
2305
  } catch (e) {
2052
2306
  const msg = e.message || "";
2053
2307
  const hint = msg.includes("404") || msg.includes("not found") ? "Wix Stores may not be installed on this site" : msg.includes("403") || msg.includes("permission") ? "API key may lack Wix Stores permissions" : "This package requires the Stores Catalog V3 API — if using Catalog V1, use @jay-framework/wix-stores-v1 instead";
@@ -2082,13 +2336,16 @@ async function generateWixStoresReferences(ctx) {
2082
2336
  }
2083
2337
  fs.mkdirSync(ctx.referencesDir, { recursive: true });
2084
2338
  const allCategories = [];
2085
- let result = await storesService.categories.queryCategories({
2086
- treeReference: { appNamespace: "@wix/stores" }
2087
- }).eq("visible", true).limit(100).find();
2088
- allCategories.push(...result.items || []);
2089
- while (result.hasNext()) {
2090
- result = await result.next();
2091
- allCategories.push(...result.items || []);
2339
+ let cursor;
2340
+ let hasMore = true;
2341
+ while (hasMore) {
2342
+ const result = await queryCategories(
2343
+ storesService.wixClient,
2344
+ cursor ? { cursorPaging: { cursor } } : { filter: { visible: true }, cursorPaging: { limit: 100 } }
2345
+ );
2346
+ allCategories.push(...result.categories || []);
2347
+ cursor = result.pagingMetadata?.cursors?.next;
2348
+ hasMore = !!cursor;
2092
2349
  }
2093
2350
  const nodeMap = /* @__PURE__ */ new Map();
2094
2351
  for (const cat of allCategories) {
@@ -2255,8 +2512,8 @@ function jsonSchemaToContractTags(properties, indent = 4) {
2255
2512
  }
2256
2513
  return tags;
2257
2514
  }
2258
- function buildExtendedFieldsSubContract(schemas2, indent = 2) {
2259
- const userFieldsSchema = schemas2.find((s) => s.namespace === "_user_fields");
2515
+ function buildExtendedFieldsSubContract(schemas, indent = 2) {
2516
+ const userFieldsSchema = schemas.find((s) => s.namespace === "_user_fields");
2260
2517
  const properties = userFieldsSchema?.jsonSchema?.properties;
2261
2518
  if (!properties || Object.keys(properties).length === 0) {
2262
2519
  return null;
@@ -2377,8 +2634,8 @@ tags:
2377
2634
 
2378
2635
  # SEO data is injected into <head> via headTags (Design Log #127), not part of the contract view state.`;
2379
2636
  const generator = makeContractGenerator().withServices(WIX_STORES_SERVICE_MARKER).generateWith(async (wixStoresService) => {
2380
- const schemas2 = await wixStoresService.getDataExtensionSchemas();
2381
- const extendedFieldsBlock = buildExtendedFieldsSubContract(schemas2);
2637
+ const schemas = await wixStoresService.getDataExtensionSchemas();
2638
+ const extendedFieldsBlock = buildExtendedFieldsSubContract(schemas);
2382
2639
  let yaml2 = BASE_CONTRACT_YAML;
2383
2640
  if (extendedFieldsBlock) {
2384
2641
  yaml2 = yaml2 + "\n\n" + extendedFieldsBlock;
@@ -2388,7 +2645,7 @@ const generator = makeContractGenerator().withServices(WIX_STORES_SERVICE_MARKER
2388
2645
  yaml: yaml2,
2389
2646
  description: "Product page with data extension fields",
2390
2647
  metadata: {
2391
- extendedFieldCount: schemas2.reduce(
2648
+ extendedFieldCount: schemas.reduce(
2392
2649
  (count, s) => count + Object.keys(s.jsonSchema?.properties ?? {}).length,
2393
2650
  0
2394
2651
  )