@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
@@ -0,0 +1,108 @@
1
+ # Forms — seed contract
2
+
3
+ `seed-forms.mjs` takes a plain-data plan and creates the site's forms. You write labels and
4
+ kinds; the seed derives everything the API demands — per-field UUIDs, the two-level options
5
+ nesting, the validation block that must exist even when empty, the choice enum that has to
6
+ agree with the component's options, the immutable `target`, and a layout referencing every
7
+ field. Those are the rules a hand-built payload gets wrong while still returning `200`.
8
+
9
+ **⚠️ Seed BEFORE building the form UI.** This is the one vertical that does not run in parallel
10
+ with the client: the page renders the fields this creates, and imports the id it returns.
11
+
12
+ **Additive only** — an existing form with the same name is left exactly as it is and reported
13
+ with `created: false`. Re-running never makes a second copy and never edits one.
14
+
15
+ ## Run
16
+
17
+ ```bash
18
+ node <SKILL_ROOT>/references/forms/seed/seed-forms.mjs plan.json # from the project root
19
+ ```
20
+
21
+ ## Plan
22
+
23
+ ```json
24
+ {
25
+ "forms": [
26
+ {
27
+ "name": "Contact",
28
+ "submitText": "Send enquiry",
29
+ "fields": [
30
+ { "label": "Your name", "kind": "text", "required": true },
31
+ { "label": "Email", "kind": "email", "required": true },
32
+ { "label": "Phone", "kind": "phone" },
33
+ { "label": "Project type", "kind": "select", "choices": ["Brand identity", "Website redesign"] },
34
+ { "label": "Services", "kind": "multi", "choices": ["SEO", "Copywriting"] },
35
+ { "label": "Budget", "kind": "number", "min": 500, "max": 50000 },
36
+ { "label": "Message", "kind": "textarea", "placeholder": "Tell us about the project" },
37
+ { "label": "I accept the terms", "kind": "checkbox", "required": true }
38
+ ]
39
+ }
40
+ ]
41
+ }
42
+ ```
43
+
44
+ | key | meaning |
45
+ |---|---|
46
+ | `name` | the form's name in the owner's dashboard, and the idempotency key |
47
+ | `submitText` | the submit button's wording (default `"Submit"`) |
48
+ | `fields[].label` | what the visitor reads — also the basis of the storage key |
49
+ | `fields[].kind` | one of the kinds below |
50
+ | `fields[].required` | default `false` |
51
+ | `fields[].placeholder` · `default` | optional; passed to the control |
52
+ | `fields[].choices` | `select` · `radio` · `multi` — strings, or `{ value, label }` |
53
+ | `fields[].min` · `max` | `number` · `rating` bounds |
54
+ | `fields[].maxLength` | text length cap |
55
+ | `fields[].fileLimit` | `file` — how many files (default 1) |
56
+ | `fields[].lines` | `textarea` — rows (default 4) |
57
+
58
+ ### Kinds
59
+
60
+ `text` · `textarea` · `email` · `phone` · `url` · `firstName` · `lastName` · `company` ·
61
+ `date` · `number` · `rating` · `select` · `radio` · `multi` · `checkbox` · `file` · `address`
62
+
63
+ `email`, `phone`, `firstName`, `lastName`, `company` are the CONTACTS kinds — Wix maps them
64
+ onto the owner's CRM contact, so prefer them over a plain `text` field for those.
65
+
66
+ ## Result
67
+
68
+ ```json
69
+ { "forms": [ { "name": "Contact",
70
+ "formId": "0e0…",
71
+ "created": true,
72
+ "fields": [ { "target": "your_name_k3f9x2", "label": "Your name" }, … ],
73
+ "fieldsLive": 8,
74
+ "degraded": [] } ] }
75
+ ```
76
+
77
+ **`formId` is what the page imports.** `fields[].target` is each input's `name` — the page
78
+ does not need them (it renders `form.fields` from the live schema), but they are the keys the
79
+ owner's submissions are stored under.
80
+
81
+ **`degraded` must be empty.** It is the read-back check: the seed re-reads the created form and
82
+ compares each field's `componentType` against what it sent. A non-empty list means a field was
83
+ accepted and then stored as something else — almost always a choice field that lost its options
84
+ and became a plain text box. Fix the plan, delete nothing, and create the form again under a
85
+ new name; a `200` on create does not mean the field survived.
86
+
87
+ ## What the seed does
88
+
89
+ 1. Installs the Wix Forms app (idempotent).
90
+ 2. Lists existing forms in the `wix.form_app.form` namespace — a name match is skipped.
91
+ 3. Expands each field, creates the form, reads it back and checks every `componentType`.
92
+
93
+ ## Traps this seed already handles
94
+
95
+ Listed because a hand-rolled payload hits all of them, and each returns `200` first:
96
+
97
+ - **A choice field declares its options twice** — the component's `options[]` and the
98
+ validation `enum` (or `items.stringOptions.enum` + `itemType` for a multi). Disagree and the
99
+ field is created as a plain text box.
100
+ - **`validation` must be present even when empty**, nested under the *input-type* block, not
101
+ the component one. Absent, the target is not registered as an accepted value and every
102
+ submission is rejected with `UNKNOWN_VALUE_ERROR` on a key that IS in the schema.
103
+ - **`required` lives at `inputOptions.required`**, never inside a validation block.
104
+ - **`steps` must reference every field, the submit button included.** A field missing from the
105
+ layout never appears in the owner's dashboard — they cannot edit what the site renders.
106
+ - **`target` is immutable** and must be unique within the form: letters, digits and single
107
+ underscores, starting with a letter.
108
+ - **Use `formFields`, never `fields`** — the latter is the legacy API.
@@ -0,0 +1,320 @@
1
+ // Forms seed — a BUILD-TIME script, never shipped in the app. Run from the project root
2
+ // (where wix.config.json lives) with a plan file:
3
+ //
4
+ // node <SKILL_ROOT>/references/forms/seed/seed-forms.mjs plan.json
5
+ //
6
+ // It mints its own site token via the Wix CLI, installs the Wix Forms app if needed, expands
7
+ // each plan field into the nested Form Schemas v4 shape, creates the forms, and READS EACH ONE
8
+ // BACK to prove the fields survived (a create returns 200 even when a choice field silently
9
+ // degraded to a plain text box). Prints a JSON result to stdout.
10
+ //
11
+ // Plan shape (see SEED.md):
12
+ // { "forms": [{ "name", "submitText"?, "fields": [
13
+ // { "label", "kind", "required"?, "placeholder"?, "choices"?, "min"?, "max"? } ] }] }
14
+ //
15
+ // The plan is PLAIN DATA — labels and kinds. Everything the API demands and the docs bury is
16
+ // derived here: per-field UUIDs, the two-level options nesting, the validation block that must
17
+ // exist even when empty, the choice enum that must agree with the component's options, the
18
+ // snake_case+suffix target, and a `steps` layout referencing every field including the submit
19
+ // button (a field missing from `steps` never appears in the owner's dashboard).
20
+ //
21
+ // Seeding is ADDITIVE — never deletes or overwrites existing forms.
22
+ import { execFileSync } from "node:child_process";
23
+ import { readFileSync } from "node:fs";
24
+ import { randomUUID } from "node:crypto";
25
+
26
+ const API = "https://www.wixapis.com";
27
+ const FORMS_APP_ID = "225dd912-7dea-4738-8688-4b8c6955ffc2";
28
+ const NAMESPACE = "wix.form_app.form";
29
+
30
+ export function makeCtx({ cwd = process.cwd() } = {}) {
31
+ const config = JSON.parse(readFileSync(`${cwd}/wix.config.json`, "utf8"));
32
+ const siteId = config.siteId ?? config.projectId;
33
+ if (!siteId) throw new Error("wix.config.json has no siteId — is this a Wix CLI project?");
34
+ const token = execFileSync("npx", ["@wix/cli@latest", "token", "--site", siteId], {
35
+ encoding: "utf8",
36
+ cwd,
37
+ }).trim();
38
+ if (!token) throw new Error("The Wix CLI returned no token — run `npx @wix/cli@latest login` first.");
39
+ return { token, siteId };
40
+ }
41
+
42
+ async function req(ctx, path, { method = "POST", body } = {}) {
43
+ const res = await fetch(API + path, {
44
+ method,
45
+ headers: {
46
+ Authorization: `Bearer ${ctx.token}`,
47
+ "wix-site-id": ctx.siteId,
48
+ "Content-Type": "application/json",
49
+ },
50
+ body: body ? JSON.stringify(body) : undefined,
51
+ });
52
+ const json = await res.json().catch(() => ({}));
53
+ if (!res.ok) throw new Error(`${method} ${path} -> ${res.status}: ${JSON.stringify(json).slice(0, 400)}`);
54
+ return json;
55
+ }
56
+
57
+ /** Idempotent. Nothing here works until the app is installed. */
58
+ export async function installFormsApp(ctx) {
59
+ try {
60
+ await req(ctx, "/apps-installer-service/v1/app-instance/install", {
61
+ body: {
62
+ tenant: { tenantType: "SITE", id: ctx.siteId },
63
+ appInstance: { appDefId: FORMS_APP_ID, enabled: true },
64
+ },
65
+ });
66
+ } catch {
67
+ /* already installed is fine */
68
+ }
69
+ }
70
+
71
+ // ---- field expansion -------------------------------------------------------------------------
72
+
73
+ // kind → { inputType, componentType, identifier, block, componentBlock, format? }
74
+ // The two block names are what the API nests settings under, and they are named after the
75
+ // field's own enums — which is why they are looked up here rather than spelled at each call.
76
+ const KINDS = {
77
+ text: { inputType: "STRING", componentType: "TEXT_INPUT", identifier: "TEXT_INPUT" },
78
+ textarea: { inputType: "STRING", componentType: "TEXT_INPUT", identifier: "TEXT_AREA" },
79
+ email: { inputType: "STRING", componentType: "TEXT_INPUT", identifier: "CONTACTS_EMAIL", format: "EMAIL" },
80
+ phone: { inputType: "STRING", componentType: "TEXT_INPUT", identifier: "CONTACTS_PHONE", format: "PHONE" },
81
+ url: { inputType: "STRING", componentType: "TEXT_INPUT", identifier: "URL_INPUT", format: "URL" },
82
+ firstName: { inputType: "STRING", componentType: "TEXT_INPUT", identifier: "CONTACTS_FIRST_NAME" },
83
+ lastName: { inputType: "STRING", componentType: "TEXT_INPUT", identifier: "CONTACTS_LAST_NAME" },
84
+ company: { inputType: "STRING", componentType: "TEXT_INPUT", identifier: "CONTACTS_COMPANY" },
85
+ date: { inputType: "STRING", componentType: "DATE_PICKER", identifier: "DATE_PICKER", format: "DATE" },
86
+ number: { inputType: "NUMBER", componentType: "NUMBER_INPUT", identifier: "NUMBER_INPUT" },
87
+ rating: { inputType: "NUMBER", componentType: "RATING_INPUT", identifier: "RATING_INPUT" },
88
+ select: { inputType: "STRING", componentType: "DROPDOWN", identifier: "DROPDOWN" },
89
+ radio: { inputType: "STRING", componentType: "RADIO_GROUP", identifier: "RADIO_GROUP" },
90
+ multi: { inputType: "ARRAY", componentType: "CHECKBOX_GROUP", identifier: "CHECKBOX_GROUP" },
91
+ checkbox: { inputType: "BOOLEAN", componentType: "CHECKBOX", identifier: "CHECKBOX" },
92
+ file: { inputType: "WIX_FILE", componentType: "FILE_UPLOAD", identifier: "FILE_UPLOAD" },
93
+ address: { inputType: "ADDRESS", componentType: "MULTILINE_ADDRESS", identifier: "MULTILINE_ADDRESS" },
94
+ };
95
+
96
+ const INPUT_BLOCK = {
97
+ STRING: "stringOptions", NUMBER: "numberOptions", BOOLEAN: "booleanOptions",
98
+ ARRAY: "arrayOptions", ADDRESS: "addressOptions", WIX_FILE: "wixFileOptions",
99
+ };
100
+ const COMPONENT_BLOCK = {
101
+ TEXT_INPUT: "textInputOptions", NUMBER_INPUT: "numberInputOptions",
102
+ RATING_INPUT: "ratingInputOptions", DATE_PICKER: "datePickerOptions",
103
+ CHECKBOX: "checkboxOptions", CHECKBOX_GROUP: "checkboxGroupOptions",
104
+ RADIO_GROUP: "radioGroupOptions", DROPDOWN: "dropdownOptions",
105
+ MULTILINE_ADDRESS: "multilineAddressOptions", FILE_UPLOAD: "fileUploadOptions",
106
+ };
107
+
108
+ /**
109
+ * `target` is the IMMUTABLE submission key: starts with a letter, letters/digits/underscore
110
+ * only, no doubled underscore, unique within the form. The random suffix is what keeps two
111
+ * fields with the same label apart.
112
+ */
113
+ function targetFor(label, taken) {
114
+ const base =
115
+ String(label)
116
+ .toLowerCase()
117
+ .replace(/[^a-z0-9]+/g, "_")
118
+ .replace(/_+/g, "_")
119
+ .replace(/^_|_$/g, "")
120
+ .replace(/^(?=\d)/, "f_")
121
+ .slice(0, 40) || "field";
122
+ let target;
123
+ do {
124
+ target = `${base}_${Math.random().toString(36).slice(2, 8)}`;
125
+ } while (taken.has(target));
126
+ taken.add(target);
127
+ return target;
128
+ }
129
+
130
+ function buildField(spec, taken) {
131
+ const kind = KINDS[spec.kind];
132
+ if (!kind) {
133
+ throw new Error(
134
+ `field "${spec.label}": unknown kind "${spec.kind}" — one of ${Object.keys(KINDS).join(", ")}`,
135
+ );
136
+ }
137
+ const choices = spec.choices ?? [];
138
+ if ((spec.kind === "select" || spec.kind === "radio" || spec.kind === "multi") && !choices.length) {
139
+ throw new Error(`field "${spec.label}": kind "${spec.kind}" needs a non-empty choices array`);
140
+ }
141
+
142
+ const target = targetFor(spec.label, taken);
143
+ const options = choices.map((c) => {
144
+ const value = typeof c === "string" ? c : c.value;
145
+ return { id: randomUUID(), label: typeof c === "string" ? c : (c.label ?? c.value), value };
146
+ });
147
+ const values = options.map((o) => o.value);
148
+
149
+ // A choice field declares its options TWICE — here and in the validation enum — and the two
150
+ // must agree. Disagree and the create still returns 200: the field is created as a plain
151
+ // text box, losing its choices. Both are derived from the same list, so they cannot drift.
152
+ const validation = {};
153
+ if (kind.format) validation.format = kind.format;
154
+ if (spec.min != null) validation.minimum = spec.min;
155
+ if (spec.max != null) validation.maximum = spec.max;
156
+ if (spec.maxLength != null) validation.maxLength = spec.maxLength;
157
+ if (values.length) {
158
+ if (kind.inputType === "ARRAY") {
159
+ validation.itemType = "STRING";
160
+ validation.items = { stringOptions: { enum: values } };
161
+ } else {
162
+ validation.enum = values;
163
+ }
164
+ }
165
+ if (spec.kind === "file") validation.fileLimit = spec.fileLimit ?? 1;
166
+
167
+ const component = { label: spec.label, showLabel: true };
168
+ if (spec.placeholder) component.placeholder = spec.placeholder;
169
+ if (options.length) component.options = options;
170
+ if (spec.kind === "textarea") component.numberOfLines = spec.lines ?? 4;
171
+ if (spec.default != null) component.default = spec.default;
172
+
173
+ return {
174
+ id: randomUUID(),
175
+ identifier: kind.identifier,
176
+ fieldType: "INPUT",
177
+ inputOptions: {
178
+ target,
179
+ inputType: kind.inputType,
180
+ // `required` lives HERE, never inside the validation block.
181
+ required: spec.required ?? false,
182
+ [INPUT_BLOCK[kind.inputType]]: {
183
+ // `validation` is always present, even as {}, and nests under the INPUT-TYPE block —
184
+ // not the component one. Absent, the target is not registered as an accepted value and
185
+ // every submission comes back UNKNOWN_VALUE_ERROR on a key that IS in the schema.
186
+ validation,
187
+ componentType: kind.componentType,
188
+ [COMPONENT_BLOCK[kind.componentType]]: component,
189
+ },
190
+ },
191
+ };
192
+ }
193
+
194
+ function buildForm(planForm) {
195
+ const taken = new Set();
196
+ const fields = (planForm.fields ?? []).map((f) => buildField(f, taken));
197
+ if (!fields.length) throw new Error(`form "${planForm.name}": no fields`);
198
+
199
+ const submit = {
200
+ id: randomUUID(),
201
+ identifier: "SUBMIT_BUTTON",
202
+ fieldType: "DISPLAY",
203
+ displayOptions: {
204
+ displayFieldType: "SUBMIT_BUTTON",
205
+ pageNavigationOptions: { submitText: planForm.submitText ?? "Submit" },
206
+ },
207
+ };
208
+
209
+ // `steps` must reference EVERY field, the submit button included — a field missing from the
210
+ // layout never appears in the owner's dashboard, so they cannot edit what the site renders.
211
+ const items = [...fields, submit].map((f, i) => ({
212
+ fieldId: f.id,
213
+ row: i,
214
+ column: 0,
215
+ width: 12,
216
+ }));
217
+
218
+ return {
219
+ name: planForm.name,
220
+ namespace: NAMESPACE,
221
+ formFields: [...fields, submit],
222
+ steps: [{ id: randomUUID(), layout: { large: { items }, medium: { items }, small: { items } } }],
223
+ };
224
+ }
225
+
226
+ // ---- operations ------------------------------------------------------------------------------
227
+
228
+ /**
229
+ * Read the form back and confirm each field kept its componentType. A create returns 200 even
230
+ * when a choice field degraded to a plain text box, so this is the only check that catches it.
231
+ */
232
+ async function verifyForm(ctx, formId, expected) {
233
+ const { form } = await req(ctx, `/form-schema-service/v4/forms/${formId}`, { method: "GET" });
234
+ const live = new Map(
235
+ (form?.formFields ?? [])
236
+ .filter((f) => f.fieldType === "INPUT")
237
+ .map((f) => {
238
+ const block = f.inputOptions?.[INPUT_BLOCK[f.inputOptions?.inputType]] ?? {};
239
+ return [f.inputOptions?.target, block.componentType];
240
+ }),
241
+ );
242
+ const degraded = expected
243
+ .filter((e) => live.get(e.target) !== e.componentType)
244
+ .map((e) => `${e.target}: expected ${e.componentType}, got ${live.get(e.target) ?? "MISSING"}`);
245
+ return { fieldsLive: live.size, degraded };
246
+ }
247
+
248
+ /**
249
+ * Create every form in the plan. Existing forms are left alone — matching by name, since a
250
+ * re-run must not create a second copy of the same form.
251
+ */
252
+ export async function setupForms(ctx, plan) {
253
+ await installFormsApp(ctx);
254
+
255
+ const existing = await req(
256
+ ctx,
257
+ `/form-schema-service/v4/forms?namespace=${encodeURIComponent(NAMESPACE)}`,
258
+ { method: "GET" },
259
+ ).catch(() => ({ forms: [] }));
260
+ const byName = new Map((existing.forms ?? []).map((f) => [f.name, f]));
261
+
262
+ const out = [];
263
+ for (const planForm of plan.forms ?? []) {
264
+ const already = byName.get(planForm.name);
265
+ if (already) {
266
+ out.push({
267
+ name: planForm.name,
268
+ formId: already.id ?? already._id,
269
+ created: false,
270
+ fields: (already.formFields ?? [])
271
+ .filter((f) => f.fieldType === "INPUT")
272
+ .map((f) => ({ target: f.inputOptions?.target, label: planForm.name })),
273
+ });
274
+ continue;
275
+ }
276
+
277
+ const body = buildForm(planForm);
278
+ const { form } = await req(ctx, "/form-schema-service/v4/forms", { body: { form: body } });
279
+ const formId = form?.id ?? form?._id;
280
+ if (!formId) throw new Error(`form "${planForm.name}": created but no id returned`);
281
+
282
+ const expected = body.formFields
283
+ .filter((f) => f.fieldType === "INPUT")
284
+ .map((f) => ({
285
+ target: f.inputOptions.target,
286
+ componentType: f.inputOptions[INPUT_BLOCK[f.inputOptions.inputType]].componentType,
287
+ }));
288
+ const check = await verifyForm(ctx, formId, expected);
289
+
290
+ out.push({
291
+ name: planForm.name,
292
+ formId,
293
+ created: true,
294
+ fields: body.formFields
295
+ .filter((f) => f.fieldType === "INPUT")
296
+ .map((f, i) => ({ target: f.inputOptions.target, label: planForm.fields[i].label })),
297
+ ...check,
298
+ });
299
+ }
300
+ return { forms: out };
301
+ }
302
+
303
+ // ---- CLI entry -------------------------------------------------------------------------------
304
+
305
+ const invokedDirectly = process.argv[1] && import.meta.url.endsWith(process.argv[1].split("/").pop());
306
+ if (invokedDirectly) {
307
+ const planPath = process.argv[2];
308
+ if (!planPath) {
309
+ console.error("usage: node seed-forms.mjs <plan.json> (run from the project root)");
310
+ process.exit(1);
311
+ }
312
+ const plan = JSON.parse(readFileSync(planPath, "utf8"));
313
+ const ctx = makeCtx();
314
+ setupForms(ctx, plan)
315
+ .then((result) => console.log(JSON.stringify(result, null, 2)))
316
+ .catch((e) => {
317
+ console.error(e.message);
318
+ process.exit(1);
319
+ });
320
+ }
@@ -0,0 +1,63 @@
1
+ # Members — custom in-app login
2
+
3
+ The Members vertical ships a **custom credential login**, not the Wix-hosted
4
+ login-page redirect. Members sign up and sign in on `/login` with email and
5
+ password; the shipped client exchanges a direct-login session into member
6
+ tokens into the managed `wixSession` cookie. That makes the member identity
7
+ available to both the custom client and Astro's ambient SDK calls after the
8
+ next navigation. Do not replace the auth implementation or add a second client.
9
+
10
+ ## Shipped files
11
+
12
+ | File | Purpose |
13
+ | ------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
14
+ | `wix/members/client.ts` | Explicit `OAuthStrategy` client that syncs direct-login tokens to Astro. |
15
+ | `wix/members/auth.ts` | Direct `register`, `login`, verification, and logout state machine. |
16
+ | `wix/members/member-store.ts` + `hooks/members/useMember.ts` | Module-scoped session state shared by Astro islands. |
17
+ | `components/members/LoginForm.tsx` | Branded in-app sign-in/sign-up and verification UI. |
18
+ | `components/members/MemberMenu.tsx`, `RequireAuth.tsx`, `AccountView.tsx` | Header control, client gate, and account surface references. |
19
+ | `pages/login.astro`, `pages/account.astro` | Custom-login and gated-account routes. |
20
+
21
+ ## Wire it
22
+
23
+ 1. Keep `<MemberMenu client:only="react" />` in the winning site header.
24
+ 2. Keep the shipped `/login` route. It is the only login surface; never link to
25
+ `/api/auth/login`, build an OAuth callback page, or redirect to Wix login.
26
+ 3. Keep `/account` client-gated with `<RequireAuth>`. A visitor sees a link to
27
+ `/login`; a member sees their actual profile.
28
+ 4. Build your own visual chrome around these shipped components using the site
29
+ tokens. Do not mock a signed-in member or infer identity from local UI state.
30
+
31
+ ## Direct-login contract
32
+
33
+ - `login(email, password)` and `register(email, password, profile)` return all
34
+ Wix states: `SUCCESS`, `EMAIL_VERIFICATION_REQUIRED`,
35
+ `OWNER_APPROVAL_REQUIRED`, or `FAILURE`. The shipped form handles each one.
36
+ - A successful state calls `getMemberTokensForDirectLogin` then `setTokens` on
37
+ the same client. It writes Astro's `wixSession` cookie, so the next page
38
+ request and browser islands run later SDK calls as that member.
39
+ - No login redirect URI is required for credential login. Password-reset and
40
+ logout return URLs remain the only optional redirect surfaces.
41
+ - The public OAuth client ID is written as `WIX_MEMBERS_CLIENT_ID` by deploy,
42
+ even for managed Astro. It is public; never add an OAuth secret to the app.
43
+ - Identity needs no Members Area app. Profile data and custom profile fields do;
44
+ the member seed installs the Members Area app.
45
+
46
+ ## Rules
47
+
48
+ - No Wix-hosted login flow, `/api/auth/login`, OAuth callback, or callback URI
49
+ requirement for credential login.
50
+ - Keep one explicit custom-members client. Do not instantiate one per component.
51
+ - Do not use `auth.elevate()` for a member reading their own records.
52
+ - Surface login failure and the verification/approval states; never silently
53
+ fall back to anonymous UI.
54
+
55
+ ## Verify
56
+
57
+ - [ ] `/login` renders an in-app email/password sign-in and sign-up form.
58
+ - [ ] A successful sign-in changes the header and unlocks `/account` without a
59
+ Wix-hosted login redirect.
60
+ - [ ] Email verification and owner approval are rendered as states, not errors.
61
+ - [ ] Reload preserves the member session; the next server render also sees it;
62
+ logout clears it.
63
+ - [ ] No mocked member data, redirect-based login, or extra auth client exists.
@@ -0,0 +1,60 @@
1
+ // REFERENCE account surface: profile card + log-out on the @theme tokens. Correct and
2
+ // complete; per the skill's model you design your own on useMember. On Astro the page
3
+ // passes the SSR-resolved member as initialMember; a SPA mounts it inside <RequireAuth>.
4
+ import { useMember } from "../../hooks/members/useMember";
5
+ import type { CurrentMember } from "../../wix/members/types";
6
+
7
+ export interface AccountViewProps {
8
+ initialMember?: CurrentMember | null;
9
+ }
10
+
11
+ export default function AccountView({ initialMember }: AccountViewProps) {
12
+ const { member, loggedIn, loading, error, logout } = useMember({ initialMember });
13
+
14
+ if (loading) {
15
+ return (
16
+ <div className="mx-auto max-w-md" aria-busy="true">
17
+ <div className="h-40 animate-pulse rounded-lg bg-secondary" />
18
+ </div>
19
+ );
20
+ }
21
+
22
+ if (!loggedIn) {
23
+ return <p className="py-16 text-center text-muted-foreground">You're logged out.</p>;
24
+ }
25
+
26
+ return (
27
+ <div className="mx-auto max-w-md rounded-lg border border-border p-8">
28
+ <div className="flex items-center gap-4">
29
+ {member?.photoUrl ? (
30
+ <img src={member.photoUrl} alt="" className="h-16 w-16 rounded-full object-cover" />
31
+ ) : (
32
+ <span className="flex h-16 w-16 items-center justify-center rounded-full bg-secondary text-xl font-semibold">
33
+ {(member?.displayName ?? "M").slice(0, 1).toUpperCase()}
34
+ </span>
35
+ )}
36
+ <div>
37
+ <p className="text-lg font-semibold text-foreground">{member?.displayName ?? "Member"}</p>
38
+ {member?.loginEmail && <p className="text-sm text-muted-foreground">{member.loginEmail}</p>}
39
+ {member?.memberSince && (
40
+ <p className="mt-0.5 text-xs text-muted-foreground">Member since {member.memberSince}</p>
41
+ )}
42
+ </div>
43
+ </div>
44
+ {!member && (
45
+ <p className="mt-4 text-sm text-muted-foreground">
46
+ Logged in, but profile details are unavailable — the Wix Members Area app isn't installed
47
+ on this site.
48
+ </p>
49
+ )}
50
+ {error && <p className="mt-4 text-sm text-red-600">{error}</p>}
51
+ <button
52
+ type="button"
53
+ onClick={() => void logout()}
54
+ className="mt-6 rounded-full border border-border px-5 py-2 text-sm font-medium text-foreground transition-colors hover:bg-secondary"
55
+ >
56
+ Log out
57
+ </button>
58
+ </div>
59
+ );
60
+ }