@wix/agent-skills 1.16.3 → 1.18.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.
Files changed (283) hide show
  1. package/package.json +1 -1
  2. package/skills/wix-app/SKILL.md +115 -12
  3. package/skills/wix-app/references/APP_MARKET_REVIEW.md +1 -1
  4. package/skills/wix-app/references/BACKEND_API.md +18 -0
  5. package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +6 -0
  6. package/skills/wix-app/references/DASHBOARD_MODAL.md +10 -2
  7. package/skills/wix-app/references/DASHBOARD_PAGE.md +32 -70
  8. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +145 -127
  9. package/skills/wix-app/references/SITE_PLUGIN.md +14 -2
  10. package/skills/wix-app/references/WIX_PATTERNS_DOCS.md +74 -68
  11. package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +2 -2
  12. package/skills/wix-app/references/dashboard-page/COLLECTION_TOOLKIT.md +79 -0
  13. package/skills/wix-app/references/dashboard-page/ENTITY_PAGE_TOOLKIT.md +73 -0
  14. package/skills/wix-app/references/dashboard-page/PATTERNS_BUNDLE_READING.md +52 -0
  15. package/skills/wix-app/references/dashboard-page/UX_SUCCESS_MODEL.md +184 -0
  16. package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +182 -99
  17. package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +94 -49
  18. package/skills/wix-app/references/editor-react-component/BRANDED-COMPONENTS.md +16 -6
  19. package/skills/wix-app/references/editor-react-component/BROWSER-SUPPORT.md +56 -0
  20. package/skills/wix-app/references/editor-react-component/COMPONENT-CONTRACT.md +275 -0
  21. package/skills/wix-app/references/editor-react-component/COMPONENT-PREVIEW.md +35 -40
  22. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +167 -445
  23. package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +56 -29
  24. package/skills/wix-app/references/editor-react-component/DIRECTIONALITY.md +53 -158
  25. package/skills/wix-app/references/editor-react-component/EDITOR-EXTENSION-CONFIGURATION.md +78 -0
  26. package/skills/wix-app/references/editor-react-component/FUNCTION-HANDLERS.md +42 -134
  27. package/skills/wix-app/references/editor-react-component/MANIFEST-ERRORS.md +11 -3
  28. package/skills/wix-app/references/editor-react-component/PARTS.md +46 -24
  29. package/skills/wix-app/references/editor-react-component/PROPS-VS-CSS.md +63 -179
  30. package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +79 -163
  31. package/skills/wix-app/references/editor-react-component/SITE-CONTEXT-HOOKS.md +36 -21
  32. package/skills/wix-app/references/editor-react-component/SSR.md +30 -99
  33. package/skills/wix-base44-connector/SKILL.md +156 -50
  34. package/skills/wix-base44-connector/references/CAPABILITY_MAP.md +78 -0
  35. package/skills/wix-base44-connector/scripts/utils.js +239 -45
  36. package/skills/wix-headless/entry/bootstrap.mjs +9 -2
  37. package/skills/wix-headless/entry/skill.md +1 -1
  38. package/skills/wix-headless/references/CAPABILITIES.md +9 -1
  39. package/skills/wix-headless/references/DESIGN.md +1 -0
  40. package/skills/wix-headless/references/DISCOVERY.md +2 -1
  41. package/skills/wix-headless/references/IMAGE_GENERATION.md +1 -0
  42. package/skills/wix-headless/references/SDK_HANDOFF.md +5 -2
  43. package/skills/wix-headless/references/SEED.md +2 -1
  44. package/skills/wix-headless/references/SETUP.md +1 -0
  45. package/skills/wix-headless/references/inline-recipes/how-to-code-a-blog.md +2 -2
  46. package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +68 -31
  47. package/skills/wix-headless/references/inline-recipes/how-to-code-forms.md +26 -10
  48. package/skills/wix-headless/references/inline-recipes/how-to-code-members-astro.md +8 -8
  49. package/skills/wix-headless/references/inline-recipes/how-to-code-members-custom-login.md +1 -1
  50. package/skills/wix-headless/references/inline-recipes/how-to-code-members-non-astro.md +1 -1
  51. package/skills/wix-headless/references/inline-recipes/how-to-code-pricing-plans.md +10 -8
  52. package/skills/wix-headless/references/inline-recipes/how-to-code-rentals.md +254 -0
  53. package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-orders.md +27 -24
  54. package/skills/wix-headless/references/inline-recipes/setup-online-store.md +13 -0
  55. package/skills/wix-headless/references/inline-recipes/setup-rentals.md +254 -0
  56. package/skills/wix-headless/references/managed/AUTHENTICATION.md +5 -0
  57. package/skills/wix-headless/references/non-astro.md +1 -1
  58. package/skills/wix-headless-fast/SKILL.md +166 -0
  59. package/skills/wix-headless-fast/entry/skill.md +99 -0
  60. package/skills/wix-headless-fast/install/deploy.mjs +433 -0
  61. package/skills/wix-headless-fast/install/fast-path.mjs +141 -0
  62. package/skills/wix-headless-fast/references/blog/INSTRUCTIONS.md +137 -0
  63. package/skills/wix-headless-fast/references/blog/app/components/blog/BlogFeedView.tsx +137 -0
  64. package/skills/wix-headless-fast/references/blog/app/components/blog/PostView.tsx +113 -0
  65. package/skills/wix-headless-fast/references/blog/app/components/blog/RichContent.tsx +42 -0
  66. package/skills/wix-headless-fast/references/blog/app/hooks/blog/useBlogFeed.ts +123 -0
  67. package/skills/wix-headless-fast/references/blog/app/hooks/blog/usePost.ts +70 -0
  68. package/skills/wix-headless-fast/references/blog/app/wix/blog/posts.ts +99 -0
  69. package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy.ts +76 -0
  70. package/skills/wix-headless-fast/references/blog/app/wix/blog/types.ts +62 -0
  71. package/skills/wix-headless-fast/references/blog/app-astro/layouts/SiteLayout.astro +40 -0
  72. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog/[...slug].astro +99 -0
  73. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog.astro +24 -0
  74. package/skills/wix-headless-fast/references/blog/lock/astro/package-lock.json +16156 -0
  75. package/skills/wix-headless-fast/references/blog/seed/SEED.md +72 -0
  76. package/skills/wix-headless-fast/references/blog/seed/seed-blog.mjs +287 -0
  77. package/skills/wix-headless-fast/references/bookings/INSTRUCTIONS.md +129 -0
  78. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServiceBookingView.tsx +143 -0
  79. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServicesView.tsx +119 -0
  80. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useBookingFlow.ts +138 -0
  81. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useServices.ts +54 -0
  82. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking.ts +206 -0
  83. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services.ts +96 -0
  84. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/types.ts +70 -0
  85. package/skills/wix-headless-fast/references/bookings/app-astro/layouts/SiteLayout.astro +40 -0
  86. package/skills/wix-headless-fast/references/bookings/app-astro/pages/services/[slug].astro +76 -0
  87. package/skills/wix-headless-fast/references/bookings/app-astro/pages/services.astro +22 -0
  88. package/skills/wix-headless-fast/references/bookings/lock/astro/package-lock.json +11962 -0
  89. package/skills/wix-headless-fast/references/bookings/seed/SEED.md +61 -0
  90. package/skills/wix-headless-fast/references/bookings/seed/seed-bookings.mjs +302 -0
  91. package/skills/wix-headless-fast/references/cms/INSTRUCTIONS.md +179 -0
  92. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useCollection.ts +83 -0
  93. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useItem.ts +57 -0
  94. package/skills/wix-headless-fast/references/cms/app/wix/cms/items.ts +151 -0
  95. package/skills/wix-headless-fast/references/cms/app/wix/cms/types.ts +75 -0
  96. package/skills/wix-headless-fast/references/cms/app-astro/layouts/SiteLayout.astro +41 -0
  97. package/skills/wix-headless-fast/references/cms/lock/astro/package-lock.json +11262 -0
  98. package/skills/wix-headless-fast/references/cms/seed/SEED.md +103 -0
  99. package/skills/wix-headless-fast/references/cms/seed/seed-cms.mjs +324 -0
  100. package/skills/wix-headless-fast/references/events/INSTRUCTIONS.md +149 -0
  101. package/skills/wix-headless-fast/references/events/app/components/events/EventConfirmationView.tsx +66 -0
  102. package/skills/wix-headless-fast/references/events/app/components/events/EventRegistrationView.tsx +176 -0
  103. package/skills/wix-headless-fast/references/events/app/components/events/EventsView.tsx +118 -0
  104. package/skills/wix-headless-fast/references/events/app/hooks/events/useEventRegistration.ts +117 -0
  105. package/skills/wix-headless-fast/references/events/app/hooks/events/useEvents.ts +59 -0
  106. package/skills/wix-headless-fast/references/events/app/wix/events/events.ts +136 -0
  107. package/skills/wix-headless-fast/references/events/app/wix/events/registration.ts +128 -0
  108. package/skills/wix-headless-fast/references/events/app/wix/events/types.ts +61 -0
  109. package/skills/wix-headless-fast/references/events/app-astro/layouts/SiteLayout.astro +40 -0
  110. package/skills/wix-headless-fast/references/events/app-astro/pages/event-confirmation.astro +12 -0
  111. package/skills/wix-headless-fast/references/events/app-astro/pages/events/[slug].astro +80 -0
  112. package/skills/wix-headless-fast/references/events/app-astro/pages/events.astro +21 -0
  113. package/skills/wix-headless-fast/references/events/lock/astro/package-lock.json +11884 -0
  114. package/skills/wix-headless-fast/references/events/seed/SEED.md +86 -0
  115. package/skills/wix-headless-fast/references/events/seed/seed-events.mjs +276 -0
  116. package/skills/wix-headless-fast/references/forms/INSTRUCTIONS.md +150 -0
  117. package/skills/wix-headless-fast/references/forms/app/hooks/forms/useWixForm.ts +317 -0
  118. package/skills/wix-headless-fast/references/forms/app/wix/forms/forms.ts +269 -0
  119. package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions.ts +231 -0
  120. package/skills/wix-headless-fast/references/forms/app/wix/forms/types.ts +135 -0
  121. package/skills/wix-headless-fast/references/forms/lock/astro/package-lock.json +10593 -0
  122. package/skills/wix-headless-fast/references/forms/seed/SEED.md +108 -0
  123. package/skills/wix-headless-fast/references/forms/seed/seed-forms.mjs +320 -0
  124. package/skills/wix-headless-fast/references/members/INSTRUCTIONS.md +63 -0
  125. package/skills/wix-headless-fast/references/members/app/components/members/AccountView.tsx +60 -0
  126. package/skills/wix-headless-fast/references/members/app/components/members/LoginForm.tsx +155 -0
  127. package/skills/wix-headless-fast/references/members/app/components/members/MemberMenu.tsx +78 -0
  128. package/skills/wix-headless-fast/references/members/app/components/members/RequireAuth.tsx +47 -0
  129. package/skills/wix-headless-fast/references/members/app/hooks/members/useMember.ts +66 -0
  130. package/skills/wix-headless-fast/references/members/app/wix/members/auth.ts +88 -0
  131. package/skills/wix-headless-fast/references/members/app/wix/members/client.ts +53 -0
  132. package/skills/wix-headless-fast/references/members/app/wix/members/member-store.ts +122 -0
  133. package/skills/wix-headless-fast/references/members/app/wix/members/members.ts +50 -0
  134. package/skills/wix-headless-fast/references/members/app/wix/members/types.ts +21 -0
  135. package/skills/wix-headless-fast/references/members/app-astro/layouts/SiteLayout.astro +42 -0
  136. package/skills/wix-headless-fast/references/members/app-astro/pages/account.astro +10 -0
  137. package/skills/wix-headless-fast/references/members/app-astro/pages/login.astro +11 -0
  138. package/skills/wix-headless-fast/references/members/lock/astro/package-lock.json +10329 -0
  139. package/skills/wix-headless-fast/references/members/seed/SEED.md +39 -0
  140. package/skills/wix-headless-fast/references/members/seed/seed-members.mjs +94 -0
  141. package/skills/wix-headless-fast/references/portfolio/INSTRUCTIONS.md +134 -0
  142. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionProjectsView.tsx +110 -0
  143. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionsView.tsx +90 -0
  144. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/ProjectDetailView.tsx +115 -0
  145. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollectionProjects.ts +59 -0
  146. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollections.ts +39 -0
  147. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useProjectDetail.ts +58 -0
  148. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio.ts +165 -0
  149. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/types.ts +55 -0
  150. package/skills/wix-headless-fast/references/portfolio/app-astro/layouts/SiteLayout.astro +40 -0
  151. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio/[slug].astro +30 -0
  152. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio.astro +21 -0
  153. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/projects/[slug].astro +29 -0
  154. package/skills/wix-headless-fast/references/portfolio/lock/astro/package-lock.json +10197 -0
  155. package/skills/wix-headless-fast/references/portfolio/seed/SEED.md +78 -0
  156. package/skills/wix-headless-fast/references/portfolio/seed/seed-portfolio.mjs +258 -0
  157. package/skills/wix-headless-fast/references/pricing-plans/INSTRUCTIONS.md +133 -0
  158. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlanDetailView.tsx +58 -0
  159. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlansView.tsx +126 -0
  160. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlanPurchase.ts +37 -0
  161. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlans.ts +39 -0
  162. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans.ts +75 -0
  163. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase.ts +45 -0
  164. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/types.ts +30 -0
  165. package/skills/wix-headless-fast/references/pricing-plans/app-astro/layouts/SiteLayout.astro +41 -0
  166. package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans/[slug].astro +40 -0
  167. package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans.astro +21 -0
  168. package/skills/wix-headless-fast/references/pricing-plans/lock/astro/package-lock.json +11226 -0
  169. package/skills/wix-headless-fast/references/pricing-plans/seed/SEED.md +71 -0
  170. package/skills/wix-headless-fast/references/pricing-plans/seed/seed-pricing-plans.mjs +279 -0
  171. package/skills/wix-headless-fast/references/restaurants/INSTRUCTIONS.md +165 -0
  172. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/MenuView.tsx +142 -0
  173. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartButton.tsx +26 -0
  174. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartDrawer.tsx +121 -0
  175. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/ReservationView.tsx +155 -0
  176. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useMenus.ts +55 -0
  177. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useOrderCart.ts +43 -0
  178. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useReservation.ts +177 -0
  179. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu.ts +165 -0
  180. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/order-store.ts +103 -0
  181. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering.ts +254 -0
  182. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations.ts +146 -0
  183. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/types.ts +168 -0
  184. package/skills/wix-headless-fast/references/restaurants/app-astro/layouts/SiteLayout.astro +47 -0
  185. package/skills/wix-headless-fast/references/restaurants/app-astro/pages/menu.astro +22 -0
  186. package/skills/wix-headless-fast/references/restaurants/app-astro/pages/reservations.astro +12 -0
  187. package/skills/wix-headless-fast/references/restaurants/lock/astro/package-lock.json +12560 -0
  188. package/skills/wix-headless-fast/references/restaurants/seed/SEED.md +81 -0
  189. package/skills/wix-headless-fast/references/restaurants/seed/seed-restaurants.mjs +479 -0
  190. package/skills/wix-headless-fast/references/shared/CONTENT.md +22 -0
  191. package/skills/wix-headless-fast/references/shared/CUSTOM_OPERATIONS.md +73 -0
  192. package/skills/wix-headless-fast/references/shared/DESIGN.md +26 -0
  193. package/skills/wix-headless-fast/references/shared/app/styles/global.css +52 -0
  194. package/skills/wix-headless-fast/references/shared/app/wix/config.ts +15 -0
  195. package/skills/wix-headless-fast/references/shared/app/wix/media.ts +27 -0
  196. package/skills/wix-headless-fast/references/shared/app/wix/money.ts +24 -0
  197. package/skills/wix-headless-fast/references/shared/app/wix/sdk.ts +76 -0
  198. package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app/wix/media-upload/client.ts +46 -0
  199. package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app-astro/pages/api/wix/media-upload.ts +46 -0
  200. package/skills/wix-headless-fast/references/shared/seed/images.mjs +145 -0
  201. package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +149 -0
  202. package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartButton.tsx +26 -0
  203. package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartDrawer.tsx +121 -0
  204. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductCard.tsx +100 -0
  205. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductDetailView.tsx +130 -0
  206. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductGrid.tsx +48 -0
  207. package/skills/wix-headless-fast/references/storefront/app/components/storefront/ShopView.tsx +66 -0
  208. package/skills/wix-headless-fast/references/storefront/app/components/storefront/VariantPicker.tsx +103 -0
  209. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useCart.ts +48 -0
  210. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useProductDetail.ts +140 -0
  211. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +80 -0
  212. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-store.ts +101 -0
  213. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart.ts +221 -0
  214. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +215 -0
  215. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/types.ts +109 -0
  216. package/skills/wix-headless-fast/references/storefront/app-astro/layouts/SiteLayout.astro +46 -0
  217. package/skills/wix-headless-fast/references/storefront/app-astro/pages/products/[slug].astro +56 -0
  218. package/skills/wix-headless-fast/references/storefront/app-astro/pages/shop.astro +23 -0
  219. package/skills/wix-headless-fast/references/storefront/lock/astro/package-lock.json +12247 -0
  220. package/skills/wix-headless-fast/references/storefront/seed/SEED.md +85 -0
  221. package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +415 -0
  222. package/skills/wix-manage/SKILL.md +28 -2
  223. package/skills/wix-manage/references/bookings/booking-system-integration-gaps.md +20 -13
  224. package/skills/wix-manage/references/bookings/end-to-end-booking-flow.md +24 -11
  225. package/skills/wix-manage/references/cms/cms-ecommerce-catalog-integration.md +5 -5
  226. package/skills/wix-manage/references/google-ads/manage-campaign-success-guide.md +141 -0
  227. package/skills/wix-manage/references/google-business-profile/connect-google-business-profile.md +134 -0
  228. package/skills/wix-manage/references/google-business-profile/manage-google-business-profile-locations.md +182 -0
  229. package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +3 -0
  230. package/skills/wix-manage/references/seo/manage-seo-tags.md +315 -0
  231. package/skills/wix-manage/references/seo/manage-url-redirects.md +250 -0
  232. package/skills/wix-manage/references/sites/query-sites.md +72 -161
  233. package/skills/wix-manage/references/stores/create-product-catalog-v3.md +21 -6
  234. package/skills/wix-manage/references/stores/update-product-with-options.md +83 -0
  235. package/skills/wix-replatform/resources/rp-mapper/wix-business-solutions-taxonomy.md +5 -6
  236. package/skills/wix-vibe-headless/SKILL.md +18 -4
  237. package/skills/wix-vibe-headless/install/deploy.cjs +12 -4
  238. package/skills/wix-vibe-headless/install/pin-agents-md.cjs +2 -1
  239. package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed.md +16 -10
  240. package/skills/wix-vibe-headless/platforms/base44-ecom-light.md +13 -8
  241. package/skills/wix-vibe-headless/platforms/base44.md +27 -62
  242. package/skills/wix-vibe-headless/platforms/generic.md +6 -3
  243. package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +45 -0
  244. package/skills/wix-vibe-headless/references/bookings/app/components/RentalDurationPicker.jsx +67 -0
  245. package/skills/wix-vibe-headless/references/bookings/app/hooks/useRentalDuration.js +128 -0
  246. package/skills/wix-vibe-headless/references/bookings/app/hooks/useServiceDetail.js +5 -3
  247. package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-checkout.js +9 -8
  248. package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-rentals.js +250 -0
  249. package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-services.js +12 -5
  250. package/skills/wix-vibe-headless/references/bookings/seed/SEED.md +41 -0
  251. package/skills/wix-vibe-headless/references/bookings/seed/seed-rentals.js +267 -0
  252. package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +6 -3
  253. package/skills/wix-vibe-headless/references/forms/INSTRUCTIONS.md +470 -0
  254. package/skills/wix-vibe-headless/references/forms/app/hooks/useWixForm.js +425 -0
  255. package/skills/wix-vibe-headless/references/forms/app/lib/wix-form-schema-utils.js +187 -0
  256. package/skills/wix-vibe-headless/references/forms/app/rest/wix-forms-submissions.js +238 -0
  257. package/skills/wix-vibe-headless/references/forms/app/rest/wix-forms.js +108 -0
  258. package/skills/wix-vibe-headless/references/forms/seed/SEED.md +1762 -0
  259. package/skills/wix-vibe-headless/references/rentals/INSTRUCTIONS.md +13 -0
  260. package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +4 -1
  261. package/skills/wix-vibe-headless/references/restaurants/app/components/OrderCartDrawer.jsx +23 -11
  262. package/skills/wix-vibe-headless/references/restaurants/app/context/OrderCartContext.jsx +1 -1
  263. package/skills/wix-vibe-headless/references/restaurants/app/rest/wix-restaurants-ordering.js +29 -31
  264. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +152 -92
  265. package/skills/wix-vibe-headless/references/storefront/app/components/CartDrawer.jsx +37 -38
  266. package/skills/wix-vibe-headless/references/storefront/app/context/CartContext.jsx +2 -2
  267. package/skills/wix-vibe-headless/references/storefront/app/hooks/useProductDetail.js +15 -8
  268. package/skills/wix-vibe-headless/references/storefront/app/lib/storeImage.js +37 -0
  269. package/skills/wix-vibe-headless/references/storefront/app/rest/wix-store-cart.js +35 -35
  270. package/skills/wix-vibe-headless/references/storefront/app/rest/wix-store-catalog.js +18 -6
  271. package/skills/wix-vibe-headless/references/storefront/seed/SEED.md +30 -7
  272. package/skills/wix-vibe-headless/references/storefront/seed/seed-store.js +46 -10
  273. package/skills/wix-app/references/editor-react-component/A11Y-REVIEW-REFERENCE.md +0 -172
  274. package/skills/wix-app/references/editor-react-component/A11Y-REVIEW.md +0 -143
  275. package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +0 -516
  276. package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +0 -225
  277. package/skills/wix-app/references/editor-react-component/EDIT-FLOW.md +0 -6
  278. package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +0 -95
  279. package/skills/wix-vibe-headless/references/storefront/app/components/ProductCard.jsx +0 -110
  280. package/skills/wix-vibe-headless/references/storefront/app/components/ProductGallery.jsx +0 -51
  281. package/skills/wix-vibe-headless/references/storefront/app/components/ProductGrid.jsx +0 -49
  282. package/skills/wix-vibe-headless/references/storefront/app/components/VariantPicker.jsx +0 -92
  283. package/skills/wix-vibe-headless/references/storefront/app/pages/ProductDetail.jsx +0 -139
@@ -10,6 +10,43 @@ export function storeImage(value) {
10
10
  return url;
11
11
  }
12
12
 
13
+ // A Wix media id (e.g. "abc123~mv2.jpg") is NOT a URL — build the static CDN url for it.
14
+ export function wixMediaUrl(mediaId) {
15
+ if (!mediaId || typeof mediaId !== "string") return null;
16
+ if (mediaId.startsWith("http") || mediaId.startsWith("//")) return storeImage(mediaId);
17
+ return `https://static.wixstatic.com/media/${mediaId}`;
18
+ }
19
+
20
+ // The media id inside a Wix image url (…/media/<id>/v1/… or a bare …/media/<id>). Compare two urls of
21
+ // the SAME image that differ only in sizing/format params by their id, not full-string equality.
22
+ export function wixMediaId(url) {
23
+ const m = typeof url === "string" && url.match(/\/media\/([^/?]+)/);
24
+ return m ? m[1] : url;
25
+ }
26
+
27
+ // The image assigned to a product OPTION CHOICE (e.g. a colour swatch). The storefront fetches with the
28
+ // PRODUCT_CHOICES_MEDIA_REFERENCES field, so Wix returns the choice image at choice.media.items[].mediaId
29
+ // and returns choice.linkedMedia EMPTY. Read media.items — do NOT switch this to choice.linkedMedia even
30
+ // if a direct admin/API probe shows linkedMedia populated: a probe made WITHOUT that field mask returns
31
+ // linkedMedia, but the storefront requests the mask, which blanks linkedMedia and returns media.items.
32
+ export function choiceImage(choice) {
33
+ const mediaId = choice?.media?.items?.[0]?.mediaId;
34
+ return mediaId ? wixMediaUrl(mediaId) : null;
35
+ }
36
+
37
+ // The image for a resolved VARIANT (a full choice combination). Wix computes variant.media from the
38
+ // picked choices' media, so this is the exact image for the current selection — prefer it over a
39
+ // single choice's image once all options are chosen.
40
+ // ⚠️ Read `media.image.url` (the URL the API already returns), or build from `media.id` — the
41
+ // `~mv2` file id. NOT `media.uploadId`: that's a dashed GUID (the id the file was uploaded with),
42
+ // and https://static.wixstatic.com/media/<uploadId> is a 403. Variants without media (a fresh
43
+ // template's demo products) return null, and the caller falls back to the choice's own image.
44
+ export function variantImage(variant) {
45
+ const m = variant?.media;
46
+ if (!m) return null;
47
+ return storeImage(m.image?.url) || wixMediaUrl(m.id) || storeImage(m.thumbnail?.url);
48
+ }
49
+
13
50
  // The main catalog image for a product (grid tiles, cart fallbacks).
14
51
  export function productImage(product) {
15
52
  return storeImage(product?.media?.main?.image?.url);
@@ -7,20 +7,22 @@ import { wixApiRequest } from "./wix-client.js";
7
7
  const STORES_APP_ID = "215238eb-22a5-4c36-9e7b-e7c08025e04e";
8
8
 
9
9
  /**
10
- * Wix eCom Cart — key fields for building a cart UI.
10
+ * Wix eCom Cart V2 — key fields for building a cart UI.
11
11
  * Full model: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart-v2/get-current-cart.md
12
12
  *
13
- * id {string}, currency {string},
13
+ * id {string} — the cart id IS the checkout id (currency lives under businessInfo.currencyCode / customerInfo.currencyCode, not at the cart root),
14
14
  * lineItems[].id {string} — lineItemId for update/remove (NOT catalogItemId),
15
- * lineItems[].quantity {number},
16
- * lineItems[].catalogReference.catalogItemId {string},
17
- * lineItems[].productName.original {string},
18
- * lineItems[].price.formattedAmount {string} — after discounts with currency symbol,
19
- * lineItems[].fullPrice.formattedAmount {string} — before discount (strikethrough),
20
- * lineItems[].descriptionLines {array} — human-readable option/modifier labels:
15
+ * lineItems[].quantityInfo.confirmedQuantity {number},
16
+ * lineItems[].source.catalogReference.catalogItemId {string} — NOT top-level in V2,
17
+ * lineItems[].name.original {string},
18
+ * lineItems[].pricing.unitPrice {ConvertedMoney} — per-unit price after discounts,
19
+ * lineItems[].pricing.totalPrice {ConvertedMoney} — line total after discounts,
20
+ * ConvertedMoney is { amount, convertedAmount } with NO formatted string — `amount` is in the
21
+ * site currency, `convertedAmount` in the display currency; format the number client-side.
22
+ * lineItems[].attributes.descriptionLines {array} — human-readable option/modifier labels:
21
23
  * [{ name: { original }, plainText: { original } OR colorInfo: { original, code } }],
22
- * lineItems[].image.url {string},
23
- * lineItems[].availability.status {string} — "AVAILABLE"|"NOT_AVAILABLE"|"PARTIALLY_AVAILABLE"|"NOT_FOUND"
24
+ * lineItems[].attributes.image {object} — { id, url, height, width, altText } (use .url),
25
+ * lineItems[].status {string} — "IN_STOCK"|"PARTIALLY_IN_STOCK"|"OUT_OF_STOCK"|"REMOVED_FROM_CATALOG"
24
26
  */
25
27
 
26
28
  /**
@@ -52,20 +54,22 @@ export async function addToCart(catalogItemId, variantId, quantity = 1, { modifi
52
54
 
53
55
  const catalogReference = { appId: STORES_APP_ID, catalogItemId };
54
56
  if (Object.keys(catalogReferenceOptions).length) catalogReference.options = catalogReferenceOptions;
55
- const res = await wixApiRequest("/ecom/v1/carts/current/add-to-cart", {
57
+ const res = await wixApiRequest("/ecom/v2/carts/current/add-line-items", {
56
58
  method: "POST",
57
- body: { lineItems: [{ catalogReference, quantity }] },
59
+ body: { catalogItems: [{ catalogReference, quantity }] },
58
60
  });
61
+ // V2 nests the reference under `source` — a top-level lineItem.catalogReference no longer exists.
59
62
  const line = (res?.cart?.lineItems ?? []).find(
60
- (l) => l.catalogReference?.catalogItemId === catalogItemId && (!variantId || l.catalogReference?.options?.variantId === variantId),
63
+ (l) => l.source?.catalogReference?.catalogItemId === catalogItemId && (!variantId || l.source?.catalogReference?.options?.variantId === variantId),
61
64
  );
62
- // Wix returns 200 even when the line is silently rejected — guard both signals:
63
- // 1. availability.status set to something other than AVAILABLE
64
- // 2. no matching line at all (quantity 0 / line absent)
65
- if (line?.availability?.status && line.availability.status !== "AVAILABLE") {
66
- throw new Error(`Item not available for sale (status: ${line.availability.status}). Is it in stock?`);
65
+ // Cart V2 rejects an unbuyable line with an explicit error rather than silently dropping it, but
66
+ // guard both signals defensively:
67
+ // 1. status set to something other than IN_STOCK
68
+ // 2. no matching line at all (confirmed quantity 0 / line absent)
69
+ if (line?.status && line.status !== "IN_STOCK") {
70
+ throw new Error(`Item not available for sale (status: ${line.status}). Is it in stock?`);
67
71
  }
68
- if (!line || line.quantity === 0) {
72
+ if (!line || line.quantityInfo?.confirmedQuantity === 0) {
69
73
  // A missing line usually means a required selection wasn't sent — a mandatory modifier
70
74
  // (pass modifierChoices/customTextFields) or the variantId for a product with options —
71
75
  // not necessarily out of stock. Verify every required choice is included in this call.
@@ -81,7 +85,7 @@ export async function addToCart(catalogItemId, variantId, quantity = 1, { modifi
81
85
  /** Read the visitor's current cart. Returns null if no cart exists yet. */
82
86
  export async function getCurrentCart() {
83
87
  try {
84
- const res = await wixApiRequest("/ecom/v1/carts/current", { method: "GET" });
88
+ const res = await wixApiRequest("/ecom/v2/carts/current", { method: "GET" });
85
89
  return res?.cart ?? null;
86
90
  } catch {
87
91
  return null;
@@ -89,7 +93,9 @@ export async function getCurrentCart() {
89
93
  }
90
94
 
91
95
  /**
92
- * Create a checkout from the current cart and return the hosted checkout URL.
96
+ * Start the hosted checkout for the current cart and return its URL.
97
+ * In Cart V2 the cart id IS the checkout id — there is no separate checkout-creation call; the
98
+ * redirect session is created straight from the current cart's id.
93
99
  * Throws on empty cart, unavailable lines, or a missing redirect URL.
94
100
  * Usage: window.location.href = await checkout()
95
101
  * @returns {Promise<string>}
@@ -98,22 +104,16 @@ export async function checkout() {
98
104
  const cart = await getCurrentCart();
99
105
  const lines = cart?.lineItems ?? [];
100
106
  if (!lines.length) throw new Error("Cannot check out: the cart is empty.");
101
- const unavailable = lines.filter((l) => l.availability?.status && l.availability.status !== "AVAILABLE");
107
+ const unavailable = lines.filter((l) => l.status && l.status !== "IN_STOCK");
102
108
  if (unavailable.length) {
103
- const names = unavailable.map((l) => l.productName?.original ?? l.catalogReference?.catalogItemId).join(", ");
109
+ const names = unavailable.map((l) => l.name?.original ?? l.source?.catalogReference?.catalogItemId).join(", ");
104
110
  throw new Error(`Cannot check out: ${unavailable.length} item(s) not available — ${names}.`);
105
111
  }
106
-
107
- const checkoutRes = await wixApiRequest("/ecom/v1/carts/current/create-checkout", {
108
- method: "POST",
109
- body: { channelType: "WEB" },
110
- });
111
- const checkoutId = checkoutRes?.checkoutId;
112
- if (!checkoutId) throw new Error("Failed to create checkout from the current cart.");
112
+ if (!cart.id) throw new Error("Failed to check out: the current cart has no id.");
113
113
 
114
114
  const redirect = await wixApiRequest("/headless/v1/redirect-session", {
115
115
  method: "POST",
116
- body: { ecomCheckout: { checkoutId }, callbacks: { postFlowUrl: window.location.href } },
116
+ body: { ecomCheckout: { checkoutId: cart.id }, callbacks: { postFlowUrl: window.location.href } },
117
117
  });
118
118
  const url = redirect?.redirectSession?.fullUrl;
119
119
  if (!url) throw new Error("Failed to create the checkout redirect session.");
@@ -122,13 +122,13 @@ export async function checkout() {
122
122
 
123
123
  /**
124
124
  * Update the quantity of a cart line. lineItemId is cart.lineItems[].id, not catalogItemId.
125
- * Wix caps the result at remaining stock — returned quantity may be lower than requested.
125
+ * Cart V2 rejects an over-stock quantity with an explicit error rather than clamping it.
126
126
  * @returns {Promise<object>} Updated cart.
127
127
  */
128
128
  export async function updateCartItemQuantity(lineItemId, quantity) {
129
- const res = await wixApiRequest("/ecom/v1/carts/current/update-line-items-quantity", {
129
+ const res = await wixApiRequest("/ecom/v2/carts/current/update-line-items", {
130
130
  method: "POST",
131
- body: { lineItems: [{ id: lineItemId, quantity }] },
131
+ body: { lineItems: [{ lineItemId, quantity: { newQuantity: quantity } }] },
132
132
  });
133
133
  return res?.cart;
134
134
  }
@@ -139,7 +139,7 @@ export async function updateCartItemQuantity(lineItemId, quantity) {
139
139
  * @returns {Promise<object>} Updated cart.
140
140
  */
141
141
  export async function removeFromCart(lineItemId) {
142
- const res = await wixApiRequest("/ecom/v1/carts/current/remove-line-items", {
142
+ const res = await wixApiRequest("/ecom/v2/carts/current/remove-line-items", {
143
143
  method: "POST",
144
144
  body: { lineItemIds: [lineItemId] },
145
145
  });
@@ -30,12 +30,13 @@ import { wixApiRequest } from "./wix-client.js";
30
30
  * options {array} — product options e.g. Size, Color:
31
31
  * [{ id, name, optionRenderType "TEXT_CHOICES"|"COLOR_CHOICES"|"SWATCH_CHOICES",
32
32
  * choicesSettings.choices [{ choiceId, key, name, inStock, visible, choiceType, colorCode,
33
- * linkedMedia }] }],
33
+ * media }] }],
34
34
  * A COLOR/SWATCH option's choices carry choiceType "ONE_COLOR" and colorCode "#395E55" — render
35
- * those as real colour swatches, not text pills. linkedMedia [{ image.url }] holds that colour's
36
- * photos, so selecting a swatch can move the gallery to the matching shot. visible false is a
37
- * retired choice the merchant no longer sells: filter it out. (TEXT_CHOICES choices are
38
- * choiceType "CHOICE_TEXT" with no colorCode.)
35
+ * those as real colour swatches, not text pills. A choice's photo is at media.items[].mediaId (a
36
+ * bare Wix media id — build https://static.wixstatic.com/media/<id>); use choiceImage() from
37
+ * lib/storeImage to resolve it. Needs the PRODUCT_CHOICES_MEDIA_REFERENCES field (requested by
38
+ * getProductBySlug below). visible false is a retired choice the merchant no longer sells: filter
39
+ * it out. (TEXT_CHOICES choices are choiceType "CHOICE_TEXT" with no colorCode.)
39
40
  * modifiers {array} — non-variant customizations (engraving, gift wrap):
40
41
  * [{ id, name, mandatory, modifierRenderType "TEXT_CHOICES"|"FREE_TEXT",
41
42
  * key, choicesSettings.choices, freeTextSettings.key }],
@@ -85,7 +86,18 @@ export async function queryProducts({ limit = 100, cursor } = {}) {
85
86
  export async function getProductBySlug(slug) {
86
87
  const res = await wixApiRequest(`/stores/v3/products/slug/${encodeURIComponent(slug)}`, {
87
88
  method: "GET",
88
- query: { fields: ["CURRENCY", "PLAIN_DESCRIPTION", "MEDIA_ITEMS_INFO"] },
89
+ // PRODUCT_CHOICES_MEDIA_REFERENCES → choice.media.items[].mediaId (the per-colour photos, needed
90
+ // for the swatch→gallery swap); VARIANT_OPTION_CHOICE_NAMES → variant choice names. Without these
91
+ // the choice media / variant data come back null.
92
+ query: {
93
+ fields: [
94
+ "CURRENCY",
95
+ "PLAIN_DESCRIPTION",
96
+ "MEDIA_ITEMS_INFO",
97
+ "PRODUCT_CHOICES_MEDIA_REFERENCES",
98
+ "VARIANT_OPTION_CHOICE_NAMES",
99
+ ],
100
+ },
89
101
  });
90
102
  return res?.product ?? null;
91
103
  }
@@ -4,6 +4,10 @@ Seed a Wix Stores catalog by **calling `seed-store.js`** — don't hand-write th
4
4
  a build-time module (run via `exec_tool`, not shipped in the app) that abstracts every Wix Stores
5
5
  seed operation. Load it and call **`setupStore` — the one-call path** — with plain data.
6
6
 
7
+ **Match each product's type to what the buyer receives** (the example shows both). *Access* — a
8
+ membership, or an online course/program the buyer enrolls in — isn't a store product at all; that's
9
+ the `pricing-plans` vertical, not here.
10
+
7
11
  ```js
8
12
  // build-time exec_tool
9
13
  const { accessToken } = await base44.asServiceRole.connectors.getConnection("wix");
@@ -22,12 +26,15 @@ const ctx = { token: accessToken, siteId: WIX_METASITE_ID };
22
26
  // generate_image runs in the background while you build, so the urls are ready by seed time.
23
27
  const result = await seed.setupStore(ctx, {
24
28
  products: [
29
+ // physical — a shipped item: carries `quantity` (the default type)
25
30
  { name: "The Glam Rocker", description: "Sequin-studded velvet legend…", price: 49.99, quantity: 12, imageUrl: imageUrls[0] },
26
31
  // a product with buyer choices — see "Options, variants and sale prices" below
27
32
  { name: "The Understudy", description: "…", price: 245, quantity: 8, imageUrl: imageUrls[1],
28
33
  options: [{ name: "Color", type: "color", choices: [{ name: "Ink", colorCode: "#1B1B2F" }, { name: "Bone", colorCode: "#EDE6D6" }] }] },
29
34
  // a product on sale — compareAtPrice drives the strikethrough + the tile's percent-off badge
30
35
  { name: "Encore Jacket", description: "…", price: 68, compareAtPrice: 129, quantity: 5, imageUrl: imageUrls[2] },
36
+ // digital — a file the buyer downloads & keeps (ebook, PDF, video): `digitalFileUrl`, NO `quantity`
37
+ { name: "Backstage Guide", description: "…", price: 12, digitalFileUrl: "https://…/guide.pdf" },
31
38
  ],
32
39
  categories: { "Legends": ["The Glam Rocker"], "Rising Stars": [] }, // omit if the brief names none
33
40
  });
@@ -37,13 +44,15 @@ const result = await seed.setupStore(ctx, {
37
44
  **Seeding is additive — never delete or overwrite existing content.** Don't clean up, don't remove
38
45
  "sample" data, don't reset. Just add.
39
46
 
40
- ## Options, variants and sale prices
47
+ ## How many, and exercising the UI
48
+
49
+ **Default to 3 products** unless the brief asks for a specific catalog — the seed shows the shape,
50
+ not a full inventory; the owner adds the rest later, from the Wix dashboard or by asking you for more.
41
51
 
42
52
  The shipped storefront renders colour options as real swatches, shows a size/colour summary on each
43
53
  tile, and puts a percent-off badge on a discounted product. A catalog of plain single-price products
44
- leaves all of that invisible, so **seed a catalog that exercises it**: unless the brief says
45
- otherwise, give at least one product a colour option and put one product on sale. Keep it truthful
46
- to the business — a ceramics studio has glaze colours, a bakery does not.
54
+ leaves all of that invisible, so **make those 3 exercise it**: unless the brief says otherwise, give
55
+ at least one product a colour option and put one product on sale. Keep it truthful to the business.
47
56
 
48
57
  ```js
49
58
  options: [
@@ -60,13 +69,27 @@ options: [
60
69
  - `compareAtPrice` (> `price`) is the "was" price: strikethrough on the PDP and a `−N%` badge on the
61
70
  tile, computed from the two amounts. It works with or without options.
62
71
 
72
+ ## Digital downloads
73
+
74
+ **Pick the product type from what the buyer receives.** A shipped physical item is the default. A
75
+ **downloadable file the buyer keeps** — ebook, PDF guide, template, preset pack, printable, music
76
+ track, downloadable video — is a **digital** product: pass its file as `digitalFileUrl`. Selling
77
+ *access* rather than a file — a membership, subscription, or an online course/program the buyer
78
+ enrolls in — is **Pricing Plans**, not a Stores product, so it isn't seeded here.
79
+
80
+ `digitalFileUrl` (plus `digitalFileName` when the url carries no filename) makes a product a digital
81
+ download — uploaded and created with both the file and stock, which is what the cart requires
82
+ (`quantity` is ignored). It's also the only way in: a file-less digital product is created
83
+ successfully, reads back healthy, and is then rejected at add-to-cart as `ITEM_NOT_FOUND_IN_CATALOG`.
84
+
63
85
  Two things this module does **not** seed, so don't try:
64
86
 
65
87
  - **Ribbons** ("New", "Best Seller"). The tile renders `product.ribbon` when it's there, but ribbons
66
88
  are set in the Wix dashboard — tell the merchant that's where to add them.
67
- - **Per-choice linked media** (`linkedMedia`), which is what makes picking a colour swap the gallery
68
- photo. Seeded swatches select and price correctly; the gallery just doesn't follow the colour until
69
- the merchant links photos to choices in the dashboard.
89
+ - **Per-choice media** — the photo that makes picking a choice swap the gallery image. Seeded swatches
90
+ select and price correctly; the gallery follows a choice once photos are linked to it (Wix dashboard,
91
+ or the wix-manage "Update Product with Options" recipe → Choice & variant fields). The shipped PDP then
92
+ follows automatically — `choiceImage()` reads it back at `media.items[].mediaId`.
70
93
 
71
94
  ## Escape hatch — individual functions
72
95
  Reach for the functions below only when the one-call `setupStore` doesn't fit (partial re-seed, custom
@@ -149,15 +149,16 @@ function buildOptions(options = []) {
149
149
  }
150
150
 
151
151
  // full Cartesian product of variants, each priced/stocked from the product; visible:true baked in
152
- function expandVariants(options = [], { price, compareAtPrice, quantity }) {
152
+ function expandVariants(options = [], { price, compareAtPrice, quantity }, digitalFileId) {
153
153
  const base = {
154
154
  price: {
155
155
  actualPrice: { amount: String(price) },
156
156
  ...(compareAtPrice ? { compareAtPrice: { amount: String(compareAtPrice) } } : {}),
157
157
  },
158
158
  visible: true,
159
- physicalProperties: {},
160
- inventoryItem: { quantity: quantity ?? 0, preorderInfo: { enabled: false } },
159
+ ...(digitalFileId
160
+ ? { digitalProperties: { digitalFile: { id: digitalFileId } }, inventoryItem: { inStock: true } }
161
+ : { physicalProperties: {}, inventoryItem: { quantity: quantity ?? 0, preorderInfo: { enabled: false } } }),
161
162
  };
162
163
  if (!options.length) return [base];
163
164
  let combos = [[]];
@@ -170,6 +171,33 @@ function expandVariants(options = [], { price, compareAtPrice, quantity }) {
170
171
  return combos.map((choices) => ({ ...base, choices }));
171
172
  }
172
173
 
174
+ // A digital variant is SELLABLE only with BOTH a file and stock: without the file the cart rejects
175
+ // it as ITEM_NOT_FOUND_IN_CATALOG, without stock as "exceeds available inventory" — and either way
176
+ // the product reads back visible and in the catalog, so nothing surfaces until a buyer tries to buy.
177
+ // `digitalFileUrl` is the only way into DIGITAL here, which makes the file-less product unbuildable.
178
+ // The bytes are PUT, not imported by url: an uploaded file is READY at once, while an imported one
179
+ // stays PENDING and the cart rejects the product until it settles.
180
+ const FILE_MIME = { pdf: "application/pdf", zip: "application/zip", epub: "application/epub+zip",
181
+ mp3: "audio/mpeg", wav: "audio/wav", mp4: "video/mp4", png: "image/png", jpg: "image/jpeg" };
182
+
183
+ async function uploadDigitalFile(ctx, url, fileName) {
184
+ const mimeType = FILE_MIME[(fileName.split(".").pop() || "").toLowerCase()];
185
+ if (!mimeType) throw new Error(`digitalFileName needs one of these extensions (${Object.keys(FILE_MIME).join(", ")}): ${fileName}`);
186
+ const { uploadUrl } = await req(ctx, "/site-media/v1/files/generate-upload-url", { body: { mimeType, fileName } });
187
+ const src = await fetch(url);
188
+ if (!src.ok) throw new Error(`digitalFileUrl ${url} -> ${src.status}`);
189
+ const res = await fetch(uploadUrl, {
190
+ method: "PUT", headers: { "Content-Type": mimeType }, body: Buffer.from(await src.arrayBuffer()),
191
+ });
192
+ const json = await res.json().catch(() => ({}));
193
+ const id = (json.file || json)?.id;
194
+ if (!res.ok || !id) throw new Error(`digital file upload failed (${res.status}): ${JSON.stringify(json).slice(0, 200)}`);
195
+ return id;
196
+ }
197
+
198
+ const digitalFileName = (p) =>
199
+ p.digitalFileName || decodeURIComponent(new URL(p.digitalFileUrl).pathname.split("/").pop() || "");
200
+
173
201
  // ---- exported operations ----
174
202
 
175
203
  async function installStoresApp(ctx) {
@@ -193,7 +221,10 @@ async function listProducts(ctx) {
193
221
  /**
194
222
  * Bulk-create products.
195
223
  * @param products [{ name, description, price, compareAtPrice?, quantity,
196
- * options?: [{ name, type?:"text"|"color", choices:["8","9"] | [{name,colorCode}] }] }]
224
+ * options?: [{ name, type?:"text"|"color", choices:["8","9"] | [{name,colorCode}] }],
225
+ * digitalFileUrl?, digitalFileName? }]
226
+ * digitalFileUrl: makes the product a DIGITAL download — the file is uploaded and the variant
227
+ * created with both the file and stock (see uploadDigitalFile). `quantity` is ignored.
197
228
  * description: plain text, or simple HTML (`<p>`, `<br/>`, `<strong>`, `<em>`) — converted to
198
229
  * Wix rich text here, so the storefront renders paragraphs and bold rather than tag text.
199
230
  * options = ONLY things the buyer selects-and-buys (Size, Color) -> become variants.
@@ -202,17 +233,20 @@ async function listProducts(ctx) {
202
233
  * @returns [{ id, slug, revision }]
203
234
  */
204
235
  async function bulkCreateProducts(ctx, products) {
236
+ const fileIds = await Promise.all(products.map((p) =>
237
+ p.digitalFileUrl ? uploadDigitalFile(ctx, p.digitalFileUrl, digitalFileName(p)) : null));
205
238
  const body = {
206
239
  returnEntity: true,
207
240
  products: products.map((p, i) => ({
208
241
  name: p.name,
209
- productType: "PHYSICAL",
210
- physicalProperties: {},
242
+ // DIGITAL drops physicalProperties and can't be POS-visible (DIGITAL_PRODUCT_CANNOT_BE_VISIBLE_IN_POS).
243
+ ...(fileIds[i]
244
+ ? { productType: "DIGITAL" }
245
+ : { productType: "PHYSICAL", physicalProperties: {}, visibleInPos: true }),
211
246
  visible: true,
212
- visibleInPos: true,
213
247
  description: mkDesc(p.description, i),
214
248
  options: buildOptions(p.options),
215
- variantsInfo: { variants: expandVariants(p.options, p) },
249
+ variantsInfo: { variants: expandVariants(p.options, p, fileIds[i]) },
216
250
  })),
217
251
  };
218
252
  const r = await req(ctx, "/stores/v3/bulk/products-with-inventory/create", { body });
@@ -221,6 +255,7 @@ async function bulkCreateProducts(ctx, products) {
221
255
  id: x.item?.id, slug: x.item?.slug, revision: x.item?.revision,
222
256
  variantId: x.item?.variantsInfo?.variants?.[0]?.id,
223
257
  hasOptions: (products[i]?.options?.length ?? 0) > 0,
258
+ isDigital: !!fileIds[i],
224
259
  quantity: products[i]?.quantity ?? 0,
225
260
  }));
226
261
  await stockOptionlessProducts(ctx, created);
@@ -233,7 +268,7 @@ async function bulkCreateProducts(ctx, products) {
233
268
  // are already stocked by the create above, so they're skipped. Backfills the default variantId from a
234
269
  // query if the create response didn't return it.
235
270
  async function stockOptionlessProducts(ctx, created) {
236
- const need = created.filter((p) => !p.hasOptions && p.id);
271
+ const need = created.filter((p) => !p.hasOptions && !p.isDigital && p.id); // digital variants ship inStock from the create
237
272
  if (!need.length) return;
238
273
  const missing = need.filter((p) => !p.variantId).map((p) => p.id);
239
274
  if (missing.length) {
@@ -300,7 +335,8 @@ async function attachProductImages(ctx, items) {
300
335
  * the DEFAULT path — call it once instead of the individual functions.
301
336
  *
302
337
  * @param plan {{
303
- * products: [{ name, description, price, compareAtPrice?, quantity, options?, imageUrl?, altText? }],
338
+ * products: [{ name, description, price, compareAtPrice?, quantity, options?, imageUrl?, altText?,
339
+ * digitalFileUrl?, digitalFileName? }],
304
340
  * categories?: { [categoryName]: string[] }, // map of category name -> product NAMES in it
305
341
  * }}
306
342
  * @returns { products: [{id,slug,revision,name}], categories: [{id,name}], imagesAttached: number }
@@ -1,172 +0,0 @@
1
- # Editor React Component A11y Review Reference
2
-
3
- Use this reference for decisions that require code inspection after running the scanners in [`A11Y-REVIEW.md`](A11Y-REVIEW.md). The scanner output owns rule-specific context: rule ID, location, message, resolution path, evidence, and confidence. Do not maintain a separate rule catalog here.
4
-
5
- ## Scanner Result Handling
6
-
7
- Treat every scanner finding as a lead until the component implementation confirms how the flagged behavior reaches the rendered element.
8
-
9
- 1. Read the full finding, including evidence and confidence when present.
10
- 2. Trace the component topology through local wrappers, shared primitives, and package implementations.
11
- 3. Deduplicate findings that identify the same issue at the same location.
12
- 4. Assign a verdict: `confirmed`, `false-positive`, or `not-relevant`.
13
- 5. Fix confirmed issues inline, then re-run both scanners on changed JSX files.
14
-
15
- When both scanners flag the same issue, keep the finding with the strongest semantic evidence. The scanners complement each other; a finding from one scanner is not automatically stronger because of its tier.
16
-
17
- ## Confidence Model
18
-
19
- ### High
20
-
21
- Use high confidence when the code and scanner evidence unambiguously show the violation, for example:
22
-
23
- - the flagged rendered element and static props establish the behavior directly
24
- - the component implementation resolves to the flagged semantic element
25
- - an explicit polymorphic prop establishes the rendered element
26
-
27
- Fix high-confidence findings immediately.
28
-
29
- ### Medium
30
-
31
- Use medium confidence when:
32
-
33
- - props strongly imply the rendered semantics
34
- - the implementation only partially resolves but preserves likely semantics
35
- - the component name, props, and surrounding evidence strongly agree
36
-
37
- Read the surrounding code. If it confirms the inference, fix the issue. If it contradicts the inference, discard the finding. If the implementation remains unresolved, treat it as low confidence.
38
-
39
- ### Low
40
-
41
- Use low confidence when:
42
-
43
- - only weak heuristics support the semantic guess
44
- - the implementation cannot be resolved
45
- - runtime props or spreads can materially change the rendered semantics
46
-
47
- Continue tracing the code. Fix only after the issue is confirmed; otherwise leave the code unchanged.
48
-
49
- ### Confidence vs. Actionability
50
-
51
- Confidence answers whether the issue is real. It does not decide whether a confirmed fix is safe.
52
-
53
- - Confirmed + safe/local fix: fix now.
54
- - Confirmed + risky behavior change or non-local refactor: leave unchanged.
55
- - Unconfirmed or ambiguous: leave unchanged.
56
-
57
- If the violation is visible in the code and has a localized, behavior-preserving fix, treat it as confirmed and apply the fix.
58
-
59
- Valid reasons to leave code unchanged:
60
-
61
- - semantics remain ambiguous after reading the available code
62
- - product intent cannot be derived from the code
63
- - the fix requires a risky behavior change or a non-local refactor
64
-
65
- Do not leave a confirmed safe/local issue unchanged because it is low severity, secondary, shared, or outside the first file in scope.
66
-
67
- ## Semantic Resolution
68
-
69
- Resolve the rendered behavior in this order:
70
-
71
- 1. The flagged JSX element and its static props
72
- 2. Explicit polymorphic props such as `as="a"` or `component="button"`
73
- 3. The local component implementation
74
- 4. Installed package source or declarations in `node_modules`
75
- 5. Prop evidence such as `href`, `to`, `src`, `alt`, and `role`
76
- 6. Component-name heuristics
77
-
78
- For local imports, follow the exported component's rendered root. Continue through local or package components until the semantics resolve or the evidence becomes too weak.
79
-
80
- For package imports, resolve the import from `node_modules` and inspect its exported entry point. If the package hides its rendered semantics, use prop and naming evidence without assigning more confidence than the evidence supports.
81
-
82
- ## Tier 2 Manual Review Checklist
83
-
84
- Run this checklist after scanner findings are triaged. Tier 2 is required even when both scanners return zero findings.
85
-
86
- ### Semantic Targeting
87
-
88
- - Do ARIA attributes land on the semantically correct element instead of a layout wrapper?
89
- - Do labels, descriptions, and roles reach the actual interactive or landmark element?
90
- - Do wrappers preserve the semantics exposed by their API?
91
-
92
- ### Icon-Only and Visual-Only States
93
-
94
- - Do icon-only buttons, links, or controls have an accessible name?
95
- - If visible text is hidden, is it visually hidden in an accessibility-safe way instead of removed from the accessibility tree?
96
- - Do meaningful icons or images expose accessible text when needed?
97
-
98
- ### CSS and Hidden Content
99
-
100
- - Does `display: none` remove content that should remain available to assistive technology?
101
- - Are hidden or collapsed states consistent across visuals, focusability, and the accessibility tree?
102
- - Do conditional classes or CSS variables create states where labels or instructions disappear from assistive technology?
103
-
104
- ### Decorative vs. Meaningful Content
105
-
106
- - Are decorative separators, ornaments, and repeated icons hidden from assistive technology?
107
- - Are meaningful visuals, status icons, or graphics named appropriately?
108
-
109
- ### Focus and Interaction Consistency
110
-
111
- - Can hidden or collapsed items still receive focus?
112
- - Do interactive-looking elements expose the correct role and keyboard behavior?
113
- - Do disabled, inert, or collapsed states behave consistently for keyboard users and assistive technology?
114
- - Search all in-scope files for `onClick` on elements without built-in interaction (`div`, `span`, `section`, `header`, `footer`, `li`, `td`, and similar tags). Include conditional patterns such as `{...(condition && { onClick: handler })}`. Verify that each match also has the required `role`, `tabIndex`, and keyboard handler (`onKeyDown` or `onKeyUp`). A missing combination is a high-confidence finding.
115
- - Before fixing missing keyboard semantics, check for nested interactive children, existing focus management, and the condition that enables interaction. Use the [pre-fix checks](#pre-fix-checks-for-adding-button-semantics-to-a-non-interactive-element).
116
-
117
- ### Structural Semantics
118
-
119
- - Are landmarks, headings, and list semantics preserved through wrappers and layout components?
120
- - When the component implements breadcrumbs, tabs, menus, dialogs, or similar patterns, do the expected semantics reach the rendered structure?
121
-
122
- ### Editor React Component Contracts
123
-
124
- - Are ARIA attributes routed through the typed `a11y` prop and converted at the correct element?
125
- - Do icon-only labels come from `constants.ts` or user-configurable `a11y` instead of hardcoded strings?
126
- - Does the component preserve direction support and isolate each `ReactNode` content prop with `dir="ltr"`?
127
- - Do extension overrides preserve a11y-relevant manifest fields generated from JSX?
128
-
129
- ## Fix Principles
130
-
131
- - Use the rule ID, message, and evidence emitted by the scanner as the rule-specific fix context.
132
- - Read the surrounding code before editing.
133
- - Preserve visual and runtime behavior.
134
- - Prefer the smallest correct change and avoid unrelated refactors.
135
- - Fix the semantic owner: the component root, the correct inner element, a shared base, or the call site that supplies the value.
136
- - When a wrapper already accepts and forwards a required prop, fix the call site. When it does not, update the wrapper contract and forwarding before fixing the call site.
137
- - Do not hardcode reusable accessibility values such as alternative text. Accept them through the component API when they depend on consumer content.
138
- - Route Editor React Component ARIA through `a11y` and `convertA11yKeysToHtmlFormat(a11y)` according to [`ACCESSIBILITY.md`](ACCESSIBILITY.md).
139
-
140
- ## Pre-Fix Checks for Adding Button Semantics to a Non-Interactive Element
141
-
142
- Before adding `role="button"`, `tabIndex`, and keyboard handlers to an element such as `<div>`, verify all four conditions below.
143
-
144
- ### 1. Interactive Children
145
-
146
- Check whether the element conditionally or unconditionally contains `<a>`, `<button>`, `<input>`, `<Link>`, or a component that resolves to an interactive element. Button semantics on the parent would create nested interaction.
147
-
148
- If interactive children are possible, either exclude that branch from the parent's interaction condition or use a separate control element.
149
-
150
- ### 2. Existing Focus Management
151
-
152
- Check whether the element already receives `tabIndex` from another source, such as `getTabIndexAttribute`, an a11y prop spread, or an interactions framework. Determine the prop merge order and keep one source authoritative.
153
-
154
- When an existing a11y spread should win, place the conditional interaction spread before it so `tabIndex: 0` only acts as a fallback.
155
-
156
- ### 3. Interaction Condition
157
-
158
- Read the full boolean expression that enables interaction. Verify that it:
159
-
160
- - excludes states that already render an interactive child
161
- - excludes editor preview, externally controlled, disabled, or reduced-motion states when required
162
- - uses explicit comparisons such as `=== undefined` or `=== true` when `true`, `false`, and `undefined` have different meanings
163
-
164
- Fix a fragile condition as part of the accessibility change. Correct semantics attached to the wrong state are still incorrect behavior.
165
-
166
- ### 4. Accessible Name Scope
167
-
168
- Decide whether an accessible label names the interaction or the component as a whole. Keep a component-level label outside the interaction condition so it persists in non-interactive states. Apply an action-specific label only while that action is available.
169
-
170
- ## After Fixing
171
-
172
- Re-run both scanners on changed `.tsx` / `.jsx` files. Continue with `npx wix build`, `npx wix generate manifest`, and the project's TypeScript check as required by [`A11Y-REVIEW.md`](A11Y-REVIEW.md#phase-5-verify).