@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 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
- 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, productSearch, provideWixStoresService, searchProducts, setupWixStores };
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: [`agent-kit/references/${ctx.pluginName}/categories.yaml`],
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",
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.3",
39
- "@jay-framework/fullstack-component": "^0.16.3",
40
- "@jay-framework/reactive": "^0.16.3",
41
- "@jay-framework/runtime": "^0.16.3",
42
- "@jay-framework/secure": "^0.16.3",
43
- "@jay-framework/stack-client-runtime": "^0.16.3",
44
- "@jay-framework/stack-server-runtime": "^0.16.3",
45
- "@jay-framework/wix-cart": "^0.16.3",
46
- "@jay-framework/wix-server-client": "^0.16.3",
47
- "@jay-framework/wix-utils": "^0.16.3",
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.3",
59
- "@jay-framework/jay-cli": "^0.16.3",
60
- "@jay-framework/jay-stack-cli": "^0.16.3",
61
- "@jay-framework/vite-plugin": "^0.16.3",
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