@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/README.md +8 -1
- package/agent-kit/aiditor/add-menu.template.yaml +109 -0
- package/agent-kit/aiditor/thumbnails/wix-stores/category-list.svg +12 -0
- package/agent-kit/aiditor/thumbnails/wix-stores/category-products.svg +15 -0
- package/agent-kit/aiditor/thumbnails/wix-stores/product-page.svg +12 -0
- package/agent-kit/aiditor/thumbnails/wix-stores/product-search.svg +17 -0
- package/agent-kit/aiditor/thumbnails/wix-stores/related-products.svg +15 -0
- package/agent-kit/designer/related-products.md +123 -0
- package/dist/agent-kit/aiditor/add-menu.template.yaml +30 -8
- package/dist/agent-kit/aiditor/thumbnails/wix-stores/related-products.svg +15 -0
- package/dist/index.client.js +130 -14
- package/dist/index.d.ts +36 -10
- package/dist/index.js +394 -137
- package/package.json +17 -20
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 {
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (!
|
|
36
|
-
|
|
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
|
|
58
|
+
return result;
|
|
39
59
|
}
|
|
40
|
-
function
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
|
|
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
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
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
|
|
96
|
-
|
|
97
|
-
while (
|
|
98
|
-
result = await
|
|
99
|
-
|
|
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
|
|
111
|
-
|
|
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
|
|
122
|
-
|
|
123
|
-
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
998
|
+
const result = await getProduct(wixStores.wixClient, input.productId, {
|
|
999
|
+
includeMerchantSpecificData: true,
|
|
753
1000
|
fields: ["VARIANT_OPTION_CHOICE_NAMES"]
|
|
754
1001
|
});
|
|
755
|
-
|
|
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.
|
|
766
|
-
|
|
767
|
-
|
|
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(
|
|
893
|
-
const result = await
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
return
|
|
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(
|
|
1145
|
+
async function loadCategoryDetails(wixClient, categoryId) {
|
|
900
1146
|
try {
|
|
901
|
-
|
|
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
|
|
908
|
-
const
|
|
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.
|
|
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.
|
|
1229
|
+
activeCategory = await findCategoryBySlug$1(wixStores.wixClient, categorySlug);
|
|
980
1230
|
baseCategoryId = activeCategory?._id ?? null;
|
|
981
|
-
} else {
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
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
|
-
|
|
991
|
-
treeReference: { appNamespace: "@wix/stores" }
|
|
992
|
-
}).eq("visible", true);
|
|
1241
|
+
const categoryFilter = { visible: true };
|
|
993
1242
|
if (baseCategoryId) {
|
|
994
|
-
|
|
1243
|
+
categoryFilter["parentCategory.id"] = baseCategoryId;
|
|
995
1244
|
}
|
|
996
1245
|
const baseCategoryIds = baseCategoryId ? [baseCategoryId] : [];
|
|
997
1246
|
const [categoriesResult, productsResult] = await Promise.all([
|
|
998
|
-
|
|
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
|
|
1258
|
+
categories,
|
|
1009
1259
|
productsResult
|
|
1010
1260
|
};
|
|
1011
1261
|
}).recover((error) => {
|
|
1012
1262
|
return handleError(error);
|
|
1013
|
-
}).toPhaseOutput(({ categories
|
|
1014
|
-
const categoryInfos =
|
|
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
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
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
|
|
1527
|
+
const raw2 = product.extendedFields?.namespaces?.["_user_fields"] ?? {};
|
|
1278
1528
|
const result = {};
|
|
1279
|
-
for (const [key, value] of Object.entries(
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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?.
|
|
1609
|
-
categoryName = categoryResult.
|
|
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(
|
|
1718
|
-
const result = await
|
|
1719
|
-
|
|
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.
|
|
1979
|
+
const parentCat = await findCategoryBySlug(wixStores.wixClient, parentCategorySlug);
|
|
1727
1980
|
parentCategoryId = parentCat?._id ?? null;
|
|
1728
1981
|
}
|
|
1729
1982
|
return Pipeline.try(async () => {
|
|
1730
|
-
|
|
1731
|
-
treeReference: {
|
|
1732
|
-
appNamespace: "@wix/stores"
|
|
1733
|
-
}
|
|
1734
|
-
}).eq("visible", true);
|
|
1983
|
+
const filter = { visible: true };
|
|
1735
1984
|
if (parentCategoryId) {
|
|
1736
|
-
|
|
1985
|
+
filter["parentCategory.id"] = parentCategoryId;
|
|
1737
1986
|
}
|
|
1738
|
-
const result = await
|
|
1739
|
-
return result.
|
|
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((
|
|
1744
|
-
const categoryItems =
|
|
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
|
|
1775
|
-
if (!
|
|
2023
|
+
const raw2 = yaml.load(fileContents);
|
|
2024
|
+
if (!raw2) {
|
|
1776
2025
|
return defaults;
|
|
1777
2026
|
}
|
|
1778
|
-
const 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
|
|
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
|
-
"
|
|
1918
|
-
"
|
|
1919
|
-
"
|
|
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
|
|
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
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
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(
|
|
2259
|
-
const userFieldsSchema =
|
|
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
|
|
2381
|
-
const extendedFieldsBlock = buildExtendedFieldsSubContract(
|
|
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:
|
|
2648
|
+
extendedFieldCount: schemas.reduce(
|
|
2392
2649
|
(count, s) => count + Object.keys(s.jsonSchema?.properties ?? {}).length,
|
|
2393
2650
|
0
|
|
2394
2651
|
)
|