@jay-framework/wix-stores 0.16.3 → 0.16.5
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.d.ts +52 -1
- package/dist/index.js +302 -4
- package/package.json +18 -15
- package/plugin.yaml +7 -4
package/dist/index.d.ts
CHANGED
|
@@ -420,6 +420,40 @@ declare function buildCategoryUrl(urls: UrlTemplates, tree: CategoryTree, catego
|
|
|
420
420
|
/** Variant stock map: colorChoiceId -> textChoiceId -> inStock */
|
|
421
421
|
type VariantStockMap = Record<string, Record<string, boolean>>;
|
|
422
422
|
|
|
423
|
+
/**
|
|
424
|
+
* Data Extension Schema → Contract Tag Utilities
|
|
425
|
+
*
|
|
426
|
+
* Converts Wix Data Extension JSON Schema properties to jay-contract YAML tags.
|
|
427
|
+
* Used to materialize the product-page contract with site-specific custom fields.
|
|
428
|
+
*
|
|
429
|
+
* Design Log #16
|
|
430
|
+
*/
|
|
431
|
+
/** A single property from the JSON Schema returned by listDataExtensionSchemas */
|
|
432
|
+
interface JsonSchemaProperty {
|
|
433
|
+
type: string;
|
|
434
|
+
items?: JsonSchemaProperty & {
|
|
435
|
+
properties?: Record<string, JsonSchemaProperty>;
|
|
436
|
+
};
|
|
437
|
+
properties?: Record<string, JsonSchemaProperty>;
|
|
438
|
+
maxLength?: number;
|
|
439
|
+
maxItems?: number;
|
|
440
|
+
/** Wix extension metadata — ignored for contract generation */
|
|
441
|
+
'x-wix-permissions'?: unknown;
|
|
442
|
+
'x-wix-created-date'?: string;
|
|
443
|
+
'x-wix-filterable'?: boolean;
|
|
444
|
+
}
|
|
445
|
+
/** Schema returned by listDataExtensionSchemas for a single namespace */
|
|
446
|
+
interface DataExtensionSchema {
|
|
447
|
+
fqdn?: string | null;
|
|
448
|
+
namespace?: string | null;
|
|
449
|
+
jsonSchema?: {
|
|
450
|
+
properties?: Record<string, JsonSchemaProperty>;
|
|
451
|
+
additionalProperties?: boolean;
|
|
452
|
+
} | null;
|
|
453
|
+
_id?: string | null;
|
|
454
|
+
revision?: string | null;
|
|
455
|
+
}
|
|
456
|
+
|
|
423
457
|
interface WixStoresService {
|
|
424
458
|
products: BuildDescriptors<typeof productsV3, {}>;
|
|
425
459
|
categories: BuildDescriptors<typeof categories, {}>;
|
|
@@ -433,6 +467,8 @@ interface WixStoresService {
|
|
|
433
467
|
getCategoryTree(): Promise<CategoryTree>;
|
|
434
468
|
/** Get cached product customizations (options with choices). Lazily loaded. */
|
|
435
469
|
getCustomizations(): Promise<Customization[]>;
|
|
470
|
+
/** Get cached data extension schemas for products. Lazily loaded. */
|
|
471
|
+
getDataExtensionSchemas(): Promise<DataExtensionSchema[]>;
|
|
436
472
|
}
|
|
437
473
|
/**
|
|
438
474
|
* Server service marker for Wix Stores.
|
|
@@ -982,4 +1018,19 @@ declare function setupWixStores(ctx: PluginSetupContext): Promise<PluginSetupRes
|
|
|
982
1018
|
*/
|
|
983
1019
|
declare function generateWixStoresReferences(ctx: PluginReferencesContext): Promise<PluginReferencesResult>;
|
|
984
1020
|
|
|
985
|
-
|
|
1021
|
+
/**
|
|
1022
|
+
* Product Page Contract Generator
|
|
1023
|
+
*
|
|
1024
|
+
* Materializes the product-page contract by extending the base static contract
|
|
1025
|
+
* with site-specific data extension fields from the Wix Data Extension Schema API.
|
|
1026
|
+
*
|
|
1027
|
+
* Design Log #16
|
|
1028
|
+
*/
|
|
1029
|
+
/**
|
|
1030
|
+
* Generator for the product-page contract.
|
|
1031
|
+
* Takes the base contract YAML and appends an extendedFields sub-contract
|
|
1032
|
+
* generated from the site's data extension schemas.
|
|
1033
|
+
*/
|
|
1034
|
+
declare const generator: _jay_framework_fullstack_component.DynamicContractGenerator<[WixStoresService]>;
|
|
1035
|
+
|
|
1036
|
+
export { type CategoryListParams, type CategoryTree, type GetProductBySlugInput, type ProductPageParams, type ProductSearchParams, WIX_STORES_CONTEXT, WIX_STORES_SERVICE_MARKER, type WixStoresContext, type WixStoresInitData, type WixStoresService, type WixStoresServiceOptions, buildCategoryUrl, buildProductUrl, categoryList, findCategoryImage, findRootCategoryId, findRootCategorySlug, generateWixStoresReferences, getCategories, getProductBySlug, getVariantStock, init, productPage, generator as productPageContractGenerator, productSearch, provideWixStoresService, searchProducts, setupWixStores };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { WIX_CART_CONTEXT, WIX_CART_SERVICE, cartIndicator, cartPage, provideWixCartContext, provideWixCartService } from "@jay-framework/wix-cart";
|
|
2
|
-
import { createJayService, makeJayQuery, ActionError, makeJayStackComponent, RenderPipeline, makeJayInit } from "@jay-framework/fullstack-component";
|
|
2
|
+
import { createJayService, makeJayQuery, ActionError, makeJayStackComponent, RenderPipeline, makeJayInit, makeContractGenerator } from "@jay-framework/fullstack-component";
|
|
3
3
|
import { customizationsV3, inventoryItemsV3, productsV3 } from "@wix/stores";
|
|
4
4
|
import { categories } from "@wix/categories";
|
|
5
5
|
import { registerService, getService } from "@jay-framework/stack-server-runtime";
|
|
6
|
+
import { schemas } from "@wix/data-extension-schema";
|
|
6
7
|
import { createJayContext } from "@jay-framework/runtime";
|
|
7
8
|
import "@jay-framework/component";
|
|
8
9
|
import { WIX_CLIENT_SERVICE } from "@jay-framework/wix-server-client";
|
|
@@ -57,6 +58,7 @@ const WIX_STORES_SERVICE_MARKER = createJayService("Wix Store Service");
|
|
|
57
58
|
function provideWixStoresService(wixClient, options) {
|
|
58
59
|
let cachedTree = null;
|
|
59
60
|
let cachedCustomizations = null;
|
|
61
|
+
let cachedExtensionSchemas = null;
|
|
60
62
|
const categoriesClient = getCategoriesClient(wixClient);
|
|
61
63
|
const customizationsClient = getCustomizationsV3Client(wixClient);
|
|
62
64
|
const service = {
|
|
@@ -110,6 +112,27 @@ function provideWixStoresService(wixClient, options) {
|
|
|
110
112
|
cachedCustomizations = [];
|
|
111
113
|
}
|
|
112
114
|
return cachedCustomizations;
|
|
115
|
+
},
|
|
116
|
+
async getDataExtensionSchemas() {
|
|
117
|
+
if (cachedExtensionSchemas) return cachedExtensionSchemas;
|
|
118
|
+
try {
|
|
119
|
+
const client = wixClient.use(schemas);
|
|
120
|
+
const result = await client.listDataExtensionSchemas(
|
|
121
|
+
"wix.stores.catalog.v3.product"
|
|
122
|
+
);
|
|
123
|
+
cachedExtensionSchemas = result?.dataExtensionSchemas ?? [];
|
|
124
|
+
const fieldCount = cachedExtensionSchemas.reduce(
|
|
125
|
+
(n, s) => n + Object.keys(s.jsonSchema?.properties ?? {}).length,
|
|
126
|
+
0
|
|
127
|
+
);
|
|
128
|
+
console.log(
|
|
129
|
+
`[wix-stores] Loaded ${cachedExtensionSchemas.length} data extension schema(s), ${fieldCount} field(s)`
|
|
130
|
+
);
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.error("[wix-stores] Failed to load data extension schemas:", error);
|
|
133
|
+
cachedExtensionSchemas = [];
|
|
134
|
+
}
|
|
135
|
+
return cachedExtensionSchemas;
|
|
113
136
|
}
|
|
114
137
|
};
|
|
115
138
|
registerService(WIX_STORES_SERVICE_MARKER, service);
|
|
@@ -1194,6 +1217,18 @@ var MediaType = /* @__PURE__ */ ((MediaType2) => {
|
|
|
1194
1217
|
MediaType2[MediaType2["VIDEO"] = 1] = "VIDEO";
|
|
1195
1218
|
return MediaType2;
|
|
1196
1219
|
})(MediaType || {});
|
|
1220
|
+
function mapExtendedFields(product) {
|
|
1221
|
+
const raw = product.extendedFields?.namespaces?.["_user_fields"] ?? {};
|
|
1222
|
+
const result = {};
|
|
1223
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
1224
|
+
if (Array.isArray(value)) {
|
|
1225
|
+
result[key] = value.map((item, i) => typeof item === "object" && item !== null ? { ...item, _index: i } : { value: item, _index: i });
|
|
1226
|
+
} else {
|
|
1227
|
+
result[key] = value;
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
return result;
|
|
1231
|
+
}
|
|
1197
1232
|
async function* loadProductParams([wixStores]) {
|
|
1198
1233
|
const template = wixStores.urls.product;
|
|
1199
1234
|
const needsPrefix = template.includes("{prefix}");
|
|
@@ -1402,7 +1437,8 @@ async function renderSlowlyChanging$1(props, wixStores) {
|
|
|
1402
1437
|
productType: mapProductType(productType),
|
|
1403
1438
|
options: mapOptionsToSlowVS(options),
|
|
1404
1439
|
infoSections: mapInfoSections(infoSections),
|
|
1405
|
-
modifiers: mapModifiersToSlowVS(modifiers)
|
|
1440
|
+
modifiers: mapModifiersToSlowVS(modifiers),
|
|
1441
|
+
extendedFields: mapExtendedFields(product)
|
|
1406
1442
|
},
|
|
1407
1443
|
headTags: mapSeoHeadTags(seoData),
|
|
1408
1444
|
carryForward: {
|
|
@@ -1665,11 +1701,272 @@ async function generateWixStoresReferences(ctx) {
|
|
|
1665
1701
|
),
|
|
1666
1702
|
"utf-8"
|
|
1667
1703
|
);
|
|
1704
|
+
let extensionFieldCount = 0;
|
|
1705
|
+
try {
|
|
1706
|
+
const extensionSchemas = await storesService.getDataExtensionSchemas();
|
|
1707
|
+
const userFieldsSchema = extensionSchemas.find(
|
|
1708
|
+
(s) => s.namespace === "_user_fields"
|
|
1709
|
+
);
|
|
1710
|
+
const properties = userFieldsSchema?.jsonSchema?.properties;
|
|
1711
|
+
if (properties && Object.keys(properties).length > 0) {
|
|
1712
|
+
extensionFieldCount = Object.keys(properties).length;
|
|
1713
|
+
const extensionPath = path.join(ctx.referencesDir, "data-extension-fields.yaml");
|
|
1714
|
+
fs.writeFileSync(
|
|
1715
|
+
extensionPath,
|
|
1716
|
+
yaml.dump(
|
|
1717
|
+
{
|
|
1718
|
+
_description: "Product data extension fields (custom fields defined in Wix dashboard).",
|
|
1719
|
+
fqdn: "wix.stores.v3.product",
|
|
1720
|
+
namespace: "_user_fields",
|
|
1721
|
+
fieldCount: extensionFieldCount,
|
|
1722
|
+
fields: Object.fromEntries(
|
|
1723
|
+
Object.entries(properties).map(([key, prop]) => [
|
|
1724
|
+
key,
|
|
1725
|
+
{ type: prop.type }
|
|
1726
|
+
])
|
|
1727
|
+
)
|
|
1728
|
+
},
|
|
1729
|
+
{ indent: 2, lineWidth: 120, noRefs: true }
|
|
1730
|
+
),
|
|
1731
|
+
"utf-8"
|
|
1732
|
+
);
|
|
1733
|
+
}
|
|
1734
|
+
} catch (error) {
|
|
1735
|
+
console.error("[wix-stores] Failed to fetch data extension schemas:", error);
|
|
1736
|
+
}
|
|
1737
|
+
const referencesCreated = [`agent-kit/references/${ctx.pluginName}/categories.yaml`];
|
|
1738
|
+
if (extensionFieldCount > 0) {
|
|
1739
|
+
referencesCreated.push(`agent-kit/references/${ctx.pluginName}/data-extension-fields.yaml`);
|
|
1740
|
+
}
|
|
1668
1741
|
return {
|
|
1669
|
-
referencesCreated
|
|
1670
|
-
message: `${allCategories.length} categories (${roots.length} root)`
|
|
1742
|
+
referencesCreated,
|
|
1743
|
+
message: `${allCategories.length} categories (${roots.length} root), ${extensionFieldCount} extension fields`
|
|
1671
1744
|
};
|
|
1672
1745
|
}
|
|
1746
|
+
function jsonTypeToContractType(type) {
|
|
1747
|
+
switch (type) {
|
|
1748
|
+
case "boolean":
|
|
1749
|
+
return "boolean";
|
|
1750
|
+
case "number":
|
|
1751
|
+
case "integer":
|
|
1752
|
+
return "number";
|
|
1753
|
+
default:
|
|
1754
|
+
return "string";
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
function dataTag(key, type, indent) {
|
|
1758
|
+
const prefix = " ".repeat(indent);
|
|
1759
|
+
return `${prefix}- {tag: ${key}, type: data, dataType: ${type}}`;
|
|
1760
|
+
}
|
|
1761
|
+
function primitiveArraySubContract(key, itemType, indent) {
|
|
1762
|
+
const prefix = " ".repeat(indent);
|
|
1763
|
+
const innerIndent = indent + 2;
|
|
1764
|
+
const indexTag = dataTag("_index", "number", innerIndent);
|
|
1765
|
+
const valueTag = dataTag("value", jsonTypeToContractType(itemType), innerIndent);
|
|
1766
|
+
return `${prefix}- tag: ${key}
|
|
1767
|
+
${prefix} type: sub-contract
|
|
1768
|
+
${prefix} repeated: true
|
|
1769
|
+
${prefix} trackBy: _index
|
|
1770
|
+
${prefix} description: ${key}
|
|
1771
|
+
${prefix} tags:
|
|
1772
|
+
${indexTag}
|
|
1773
|
+
${valueTag}`;
|
|
1774
|
+
}
|
|
1775
|
+
function objectSubContract(key, properties, repeated, indent) {
|
|
1776
|
+
const prefix = " ".repeat(indent);
|
|
1777
|
+
const innerTags = jsonSchemaToContractTags(properties, indent + 2);
|
|
1778
|
+
if (repeated) {
|
|
1779
|
+
const indexTag = dataTag("_index", "number", indent + 2);
|
|
1780
|
+
return `${prefix}- tag: ${key}
|
|
1781
|
+
${prefix} type: sub-contract
|
|
1782
|
+
${prefix} repeated: true
|
|
1783
|
+
${prefix} trackBy: _index
|
|
1784
|
+
${prefix} description: ${key}
|
|
1785
|
+
${prefix} tags:
|
|
1786
|
+
${indexTag}
|
|
1787
|
+
${innerTags.join("\n")}`;
|
|
1788
|
+
}
|
|
1789
|
+
return `${prefix}- tag: ${key}
|
|
1790
|
+
${prefix} type: sub-contract
|
|
1791
|
+
${prefix} description: ${key}
|
|
1792
|
+
${prefix} tags:
|
|
1793
|
+
${innerTags.join("\n")}`;
|
|
1794
|
+
}
|
|
1795
|
+
function jsonSchemaToContractTags(properties, indent = 4) {
|
|
1796
|
+
const tags = [];
|
|
1797
|
+
for (const [key, prop] of Object.entries(properties)) {
|
|
1798
|
+
switch (prop.type) {
|
|
1799
|
+
case "string":
|
|
1800
|
+
case "boolean":
|
|
1801
|
+
case "number":
|
|
1802
|
+
case "integer":
|
|
1803
|
+
tags.push(dataTag(key, jsonTypeToContractType(prop.type), indent));
|
|
1804
|
+
break;
|
|
1805
|
+
case "array": {
|
|
1806
|
+
const items = prop.items;
|
|
1807
|
+
if (!items) {
|
|
1808
|
+
tags.push(dataTag(key, "string", indent));
|
|
1809
|
+
} else if (items.type === "object" && items.properties) {
|
|
1810
|
+
tags.push(objectSubContract(key, items.properties, true, indent));
|
|
1811
|
+
} else {
|
|
1812
|
+
tags.push(primitiveArraySubContract(key, items.type || "string", indent));
|
|
1813
|
+
}
|
|
1814
|
+
break;
|
|
1815
|
+
}
|
|
1816
|
+
case "object":
|
|
1817
|
+
if (prop.properties) {
|
|
1818
|
+
tags.push(objectSubContract(key, prop.properties, false, indent));
|
|
1819
|
+
} else {
|
|
1820
|
+
tags.push(dataTag(key, "string", indent));
|
|
1821
|
+
}
|
|
1822
|
+
break;
|
|
1823
|
+
default:
|
|
1824
|
+
tags.push(dataTag(key, "string", indent));
|
|
1825
|
+
break;
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
return tags;
|
|
1829
|
+
}
|
|
1830
|
+
function buildExtendedFieldsSubContract(schemas2, indent = 2) {
|
|
1831
|
+
const userFieldsSchema = schemas2.find((s) => s.namespace === "_user_fields");
|
|
1832
|
+
const properties = userFieldsSchema?.jsonSchema?.properties;
|
|
1833
|
+
if (!properties || Object.keys(properties).length === 0) {
|
|
1834
|
+
return null;
|
|
1835
|
+
}
|
|
1836
|
+
const prefix = " ".repeat(indent);
|
|
1837
|
+
const innerTags = jsonSchemaToContractTags(properties, indent + 2);
|
|
1838
|
+
return `${prefix}- tag: extendedFields
|
|
1839
|
+
${prefix} type: sub-contract
|
|
1840
|
+
${prefix} description: Custom product fields from data extension schema
|
|
1841
|
+
${prefix} tags:
|
|
1842
|
+
${innerTags.join("\n")}`;
|
|
1843
|
+
}
|
|
1844
|
+
const BASE_CONTRACT_YAML = `name: product-page
|
|
1845
|
+
description: Full product detail page with variants, options, media gallery, and add-to-cart. Use for individual product pages.
|
|
1846
|
+
params:
|
|
1847
|
+
slug: string
|
|
1848
|
+
prefix: string?
|
|
1849
|
+
category: string?
|
|
1850
|
+
tags:
|
|
1851
|
+
- {tag: _id, type: data, dataType: string, description: Product GUID}
|
|
1852
|
+
- {tag: productName, type: data, dataType: string, required: true, description: Product name}
|
|
1853
|
+
|
|
1854
|
+
- tag: mediaGallery
|
|
1855
|
+
type: sub-contract
|
|
1856
|
+
phase: fast+interactive
|
|
1857
|
+
link: "@jay-framework/wix-stores/media-gallery"
|
|
1858
|
+
|
|
1859
|
+
- {tag: description, type: data, dataType: string, description: Product description}
|
|
1860
|
+
- {tag: brand, type: data, dataType: string, description: Brand name}
|
|
1861
|
+
- {tag: ribbon, type: data, dataType: string, description: "Ribbon text (e.g., \\"New\\", \\"Sale\\")"}
|
|
1862
|
+
- {tag: productType, type: variant, dataType: "enum (PHYSICAL | DIGITAL)", description: Product type }
|
|
1863
|
+
|
|
1864
|
+
- {tag: sku, type: data, dataType: string, phase: fast+interactive, description: Product SKU, or chosen variant SKU}
|
|
1865
|
+
- {tag: price, type: data, dataType: string, phase: fast+interactive, description: The product or variant price}
|
|
1866
|
+
- {tag: strikethroughPrice, type: data, dataType: string, phase: fast+interactive, description: A Strikethrough product price for sales}
|
|
1867
|
+
- {tag: pricePerUnit, type: data, dataType: string, phase: fast+interactive, description: formatted price per unit, if used}
|
|
1868
|
+
- {tag: stockStatus, type: variant, dataType: "enum (OUT_OF_STOCK | IN_STOCK)", phase: fast+interactive, description: indicator if the product or current variant are in stock }
|
|
1869
|
+
|
|
1870
|
+
- tag: quantity
|
|
1871
|
+
type: sub-contract
|
|
1872
|
+
description: Quantity selection controls
|
|
1873
|
+
tags:
|
|
1874
|
+
- {tag: decrementButton, type: interactive, elementType: HTMLButtonElement, description: Button to decrease quantity}
|
|
1875
|
+
- {tag: incrementButton, type: interactive, elementType: HTMLButtonElement, description: Button to increase quantity}
|
|
1876
|
+
- {tag: quantity, type: [data, interactive], dataType: number, elementType: HTMLInputElement, description: Selected Quantity and Direct quantity input field}
|
|
1877
|
+
|
|
1878
|
+
# Call to action
|
|
1879
|
+
- {tag: addToCartButton, type: interactive, elementType: HTMLButtonElement, required: true, description: Add product to cart button}
|
|
1880
|
+
- {tag: buyNowButton, type: interactive, elementType: HTMLButtonElement, required: true, description: Buy now button}
|
|
1881
|
+
- {tag: actionsEnabled, type: variant, dataType: boolean, phase: fast+interactive, description: should the add to cart and buy now buttons be enabled}
|
|
1882
|
+
- {tag: isAddingToCart, type: variant, dataType: boolean, phase: fast+interactive, description: Whether an add-to-cart request is currently in progress}
|
|
1883
|
+
|
|
1884
|
+
- tag: options
|
|
1885
|
+
type: sub-contract
|
|
1886
|
+
repeated: true
|
|
1887
|
+
trackBy: _id
|
|
1888
|
+
description: Product customization options that generate variants
|
|
1889
|
+
tags:
|
|
1890
|
+
- {tag: _id, type: data, dataType: string, description: "Option GUID (customization ID)"}
|
|
1891
|
+
- {tag: name, type: data, dataType: string, description: "Option name (e.g., \\"Color\\", \\"Size\\")"}
|
|
1892
|
+
- {tag: optionRenderType, type: variant, dataType: "enum (TEXT_CHOICES | COLOR_SWATCH_CHOICES)", description: How the option should be rendered}
|
|
1893
|
+
- {tag: textChoice, type: interactive, elementType: HTMLSelectElement, description: dropdown for text choice}
|
|
1894
|
+
- {tag: textChoiceSelection, type: data, dataType: string, phase: fast+interactive, description: the selected text option}
|
|
1895
|
+
|
|
1896
|
+
- tag: choices
|
|
1897
|
+
type: sub-contract
|
|
1898
|
+
repeated: true
|
|
1899
|
+
trackBy: choiceId
|
|
1900
|
+
description: Available choices for this option
|
|
1901
|
+
tags:
|
|
1902
|
+
- {tag: choiceId, type: data, dataType: string, description: Choice GUID}
|
|
1903
|
+
- {tag: choiceType, type: variant, dataType: "enum (CHOICE_TEXT | ONE_COLOR)", description: Type of choice}
|
|
1904
|
+
- {tag: name, type: data, dataType: string, description: "Choice name (e.g., \\"Red\\", \\"Large\\")"}
|
|
1905
|
+
- {tag: colorCode, type: data, dataType: string, description: Color code in HEX format (for color choices)}
|
|
1906
|
+
- {tag: inStock, type: data, dataType: boolean, description: Whether at least one variant with this choice is in stock}
|
|
1907
|
+
- {tag: isSelected, type: variant, dataType: boolean, phase: fast+interactive, description: Whether this choice is currently selected (UI state)}
|
|
1908
|
+
- {tag: choiceButton, type: interactive, elementType: HTMLButtonElement, description: Button to select this choice}
|
|
1909
|
+
|
|
1910
|
+
# Additional info sections (from Wix Stores API)
|
|
1911
|
+
- tag: infoSections
|
|
1912
|
+
type: sub-contract
|
|
1913
|
+
repeated: true
|
|
1914
|
+
trackBy: _id
|
|
1915
|
+
description: Additional product information sections
|
|
1916
|
+
tags:
|
|
1917
|
+
- {tag: _id, type: data, dataType: string, description: Info section GUID}
|
|
1918
|
+
- {tag: title, type: data, dataType: string, description: Info section title}
|
|
1919
|
+
- {tag: plainDescription, type: data, dataType: string, description: Info section description in HTML}
|
|
1920
|
+
|
|
1921
|
+
- tag: modifiers
|
|
1922
|
+
type: sub-contract
|
|
1923
|
+
repeated: true
|
|
1924
|
+
trackBy: _id
|
|
1925
|
+
description: Product customization options that do not generate variants
|
|
1926
|
+
tags:
|
|
1927
|
+
- {tag: _id, type: data, dataType: string, description: "modifier id"}
|
|
1928
|
+
- {tag: name, type: data, dataType: string, description: "modifier name (e.g., \\"Color\\", \\"Size\\")"}
|
|
1929
|
+
- {tag: modifierType, type: variant, dataType: "enum (TEXT_CHOICES | COLOR_SWATCH_CHOICES | FREE_TEXT)", description: What type of modifier to use?}
|
|
1930
|
+
- {tag: textModifier, type: interactive, elementType: HTMLSelectElement, description: dropdown for text modifier}
|
|
1931
|
+
- {tag: textModifierSelection, type: data, dataType: string, phase: fast+interactive, description: the selected text modifier}
|
|
1932
|
+
- {tag: textInput, type: interactive, elementType: HTMLInputElement | HTMLAreaElement, description: text input for free text}
|
|
1933
|
+
- {tag: textInputLength, type: data, dataType: number, description: the limit on the length of free text}
|
|
1934
|
+
- {tag: textInputRequired, type: data, dataType: boolean, description: Is the free text input required?}
|
|
1935
|
+
|
|
1936
|
+
- tag: choices
|
|
1937
|
+
type: sub-contract
|
|
1938
|
+
repeated: true
|
|
1939
|
+
trackBy: choiceId
|
|
1940
|
+
description: Available choices for this Modifier
|
|
1941
|
+
tags:
|
|
1942
|
+
- {tag: choiceId, type: data, dataType: string, description: Choice GUID}
|
|
1943
|
+
- {tag: choiceType, type: variant, dataType: "enum (CHOICE_TEXT | ONE_COLOR)", description: Type of choice}
|
|
1944
|
+
- {tag: name, type: data, dataType: string, description: "Choice name (e.g., \\"Red\\", \\"Large\\")"}
|
|
1945
|
+
- {tag: colorCode, type: data, dataType: string, description: Color code in HEX format (for color choices)}
|
|
1946
|
+
- {tag: isSelected, type: variant, dataType: boolean, phase: fast+interactive, description: Whether this choice is currently selected (UI state)}
|
|
1947
|
+
- {tag: choiceButton, type: interactive, elementType: HTMLButtonElement, description: Button to select this choice}
|
|
1948
|
+
|
|
1949
|
+
# SEO data is injected into <head> via headTags (Design Log #127), not part of the contract view state.`;
|
|
1950
|
+
const generator = makeContractGenerator().withServices(WIX_STORES_SERVICE_MARKER).generateWith(async (wixStoresService) => {
|
|
1951
|
+
const schemas2 = await wixStoresService.getDataExtensionSchemas();
|
|
1952
|
+
const extendedFieldsBlock = buildExtendedFieldsSubContract(schemas2);
|
|
1953
|
+
let yaml2 = BASE_CONTRACT_YAML;
|
|
1954
|
+
if (extendedFieldsBlock) {
|
|
1955
|
+
yaml2 = yaml2 + "\n\n" + extendedFieldsBlock;
|
|
1956
|
+
}
|
|
1957
|
+
return [
|
|
1958
|
+
{
|
|
1959
|
+
yaml: yaml2,
|
|
1960
|
+
description: "Product page with data extension fields",
|
|
1961
|
+
metadata: {
|
|
1962
|
+
extendedFieldCount: schemas2.reduce(
|
|
1963
|
+
(count, s) => count + Object.keys(s.jsonSchema?.properties ?? {}).length,
|
|
1964
|
+
0
|
|
1965
|
+
)
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
];
|
|
1969
|
+
});
|
|
1673
1970
|
export {
|
|
1674
1971
|
WIX_CART_CONTEXT,
|
|
1675
1972
|
WIX_CART_SERVICE,
|
|
@@ -1689,6 +1986,7 @@ export {
|
|
|
1689
1986
|
getVariantStock,
|
|
1690
1987
|
init,
|
|
1691
1988
|
productPage,
|
|
1989
|
+
generator as productPageContractGenerator,
|
|
1692
1990
|
productSearch,
|
|
1693
1991
|
provideWixCartContext,
|
|
1694
1992
|
provideWixCartService,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jay-framework/wix-stores",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Wix Stores API client for Jay Framework",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
"./client": "./dist/index.client.js",
|
|
15
15
|
"./plugin.yaml": "./plugin.yaml",
|
|
16
16
|
"./product-page.jay-contract": "./dist/contracts/product-page.jay-contract",
|
|
17
|
+
"./media.jay-contract": "./dist/contracts/media.jay-contract",
|
|
18
|
+
"./media-gallery.jay-contract": "./dist/contracts/media-gallery.jay-contract",
|
|
17
19
|
"./product-search.jay-contract": "./dist/contracts/product-search.jay-contract",
|
|
18
20
|
"./category-list.jay-contract": "./dist/contracts/category-list.jay-contract",
|
|
19
21
|
"./search-products.jay-action": "./dist/actions/search-products.jay-action",
|
|
@@ -35,17 +37,18 @@
|
|
|
35
37
|
"test": ":"
|
|
36
38
|
},
|
|
37
39
|
"dependencies": {
|
|
38
|
-
"@jay-framework/component": "^0.16.
|
|
39
|
-
"@jay-framework/fullstack-component": "^0.16.
|
|
40
|
-
"@jay-framework/reactive": "^0.16.
|
|
41
|
-
"@jay-framework/runtime": "^0.16.
|
|
42
|
-
"@jay-framework/secure": "^0.16.
|
|
43
|
-
"@jay-framework/stack-client-runtime": "^0.16.
|
|
44
|
-
"@jay-framework/stack-server-runtime": "^0.16.
|
|
45
|
-
"@jay-framework/wix-cart": "^0.16.
|
|
46
|
-
"@jay-framework/wix-server-client": "^0.16.
|
|
47
|
-
"@jay-framework/wix-utils": "^0.16.
|
|
40
|
+
"@jay-framework/component": "^0.16.5",
|
|
41
|
+
"@jay-framework/fullstack-component": "^0.16.5",
|
|
42
|
+
"@jay-framework/reactive": "^0.16.5",
|
|
43
|
+
"@jay-framework/runtime": "^0.16.5",
|
|
44
|
+
"@jay-framework/secure": "^0.16.5",
|
|
45
|
+
"@jay-framework/stack-client-runtime": "^0.16.5",
|
|
46
|
+
"@jay-framework/stack-server-runtime": "^0.16.5",
|
|
47
|
+
"@jay-framework/wix-cart": "^0.16.5",
|
|
48
|
+
"@jay-framework/wix-server-client": "^0.16.5",
|
|
49
|
+
"@jay-framework/wix-utils": "^0.16.5",
|
|
48
50
|
"@wix/categories": "^1.0.185",
|
|
51
|
+
"@wix/data-extension-schema": "^1.0.221",
|
|
49
52
|
"@wix/sdk": "^1.21.5",
|
|
50
53
|
"@wix/sdk-runtime": "^1.0.11",
|
|
51
54
|
"@wix/stores": "^1.0.742",
|
|
@@ -55,10 +58,10 @@
|
|
|
55
58
|
"@babel/core": "^7.23.7",
|
|
56
59
|
"@babel/preset-env": "^7.23.8",
|
|
57
60
|
"@babel/preset-typescript": "^7.23.3",
|
|
58
|
-
"@jay-framework/compiler-jay-stack": "^0.16.
|
|
59
|
-
"@jay-framework/jay-cli": "^0.16.
|
|
60
|
-
"@jay-framework/jay-stack-cli": "^0.16.
|
|
61
|
-
"@jay-framework/vite-plugin": "^0.16.
|
|
61
|
+
"@jay-framework/compiler-jay-stack": "^0.16.5",
|
|
62
|
+
"@jay-framework/jay-cli": "^0.16.5",
|
|
63
|
+
"@jay-framework/jay-stack-cli": "^0.16.5",
|
|
64
|
+
"@jay-framework/vite-plugin": "^0.16.5",
|
|
62
65
|
"nodemon": "^3.0.3",
|
|
63
66
|
"rimraf": "^5.0.5",
|
|
64
67
|
"tslib": "^2.6.2",
|
package/plugin.yaml
CHANGED
|
@@ -2,10 +2,6 @@ name: wix-stores
|
|
|
2
2
|
# No module field for NPM packages - uses package main export by default
|
|
3
3
|
|
|
4
4
|
contracts:
|
|
5
|
-
- name: product-page
|
|
6
|
-
contract: product-page.jay-contract # Export subpath (matches package.json exports)
|
|
7
|
-
component: productPage # Exported member name from index.ts
|
|
8
|
-
description: Complete headless product page with server-side rendering and client interactivity
|
|
9
5
|
- name: product-search
|
|
10
6
|
contract: product-search.jay-contract
|
|
11
7
|
component: productSearch
|
|
@@ -16,6 +12,13 @@ contracts:
|
|
|
16
12
|
component: categoryList
|
|
17
13
|
description: Category list listing the categories
|
|
18
14
|
|
|
15
|
+
# Dynamic contracts — materialized at setup time from site-specific data
|
|
16
|
+
dynamic_contracts:
|
|
17
|
+
# Product page — base contract extended with data extension fields
|
|
18
|
+
- prefix: 'product-page'
|
|
19
|
+
component: productPage
|
|
20
|
+
generator: productPageContractGenerator
|
|
21
|
+
|
|
19
22
|
# Server actions (named exports from main module)
|
|
20
23
|
actions:
|
|
21
24
|
- name: searchProducts
|