@wix/agent-skills 1.20.1 → 1.22.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 (262) hide show
  1. package/package.json +1 -1
  2. package/skills/wix-app/SKILL.md +71 -113
  3. package/skills/wix-app/references/APP_TOOLS.md +2 -1
  4. package/skills/wix-app/references/BACKEND_EVENT.md +3 -3
  5. package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +41 -152
  6. package/skills/wix-app/references/DASHBOARD_MODAL.md +4 -4
  7. package/skills/wix-app/references/DASHBOARD_PAGE.md +11 -25
  8. package/skills/wix-app/references/DATA_COLLECTION.md +16 -219
  9. package/skills/wix-app/references/SDK_MODULE_MAP.md +44 -0
  10. package/skills/wix-app/references/SITE_PLUGIN.md +36 -190
  11. package/skills/wix-app/references/app-tools/TOOLS.md +3 -1
  12. package/skills/wix-app/references/custom-element-widget/SETTINGS_PANEL.md +21 -0
  13. package/skills/wix-app/references/dashboard-page/DATA_SOURCES.md +182 -0
  14. package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE.md +97 -0
  15. package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_COLLECTION.md +184 -0
  16. package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_ROUTER.md +203 -0
  17. package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_SETTINGS.md +44 -0
  18. package/skills/wix-app/references/dashboard-page/ECOM_NAVIGATION.md +17 -0
  19. package/skills/wix-app/references/dashboard-page/QUERY_AND_PAGING.md +182 -0
  20. package/skills/wix-app/references/dashboard-page/TABLE_STATE.md +133 -0
  21. package/skills/wix-app/references/dashboard-page/UX_SUCCESS_MODEL.md +10 -5
  22. package/skills/wix-app/references/dashboard-plugin/SLOTS.md +4 -18
  23. package/skills/wix-app/references/data-collection/LIFECYCLE.md +68 -0
  24. package/skills/wix-app/references/data-collection/PERMISSIONS.md +47 -0
  25. package/skills/wix-app/references/data-collection/SCHEMA.md +181 -0
  26. package/skills/wix-app/references/data-collection/WIX_DATA.md +38 -66
  27. package/skills/wix-app/references/site-plugin/EXAMPLES.md +1 -1
  28. package/skills/wix-headless-fast/SKILL.md +144 -221
  29. package/skills/wix-headless-fast/cold-start/bootstrap.mjs +156 -0
  30. package/skills/wix-headless-fast/{entry/skill.md → cold-start/cold-start.md} +15 -15
  31. package/skills/wix-headless-fast/guides/existing-site.md +76 -0
  32. package/skills/wix-headless-fast/guides/reference-mode.md +97 -0
  33. package/skills/wix-headless-fast/install/AGENTS.md +35 -0
  34. package/skills/wix-headless-fast/install/agents-md.mjs +39 -0
  35. package/skills/wix-headless-fast/install/attach.mjs +161 -86
  36. package/skills/wix-headless-fast/install/deploy.mjs +21 -60
  37. package/skills/wix-headless-fast/install/lock.mjs +55 -0
  38. package/skills/wix-headless-fast/install/setup.mjs +259 -0
  39. package/skills/wix-headless-fast/install/templates.mjs +168 -0
  40. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-create-coupon.md +10 -19
  41. package/skills/wix-manage/references/events/create-wix-event.md +5 -1
  42. package/skills/wix-manage/references/google-ads/google-ads-dashboard-navigation.md +27 -0
  43. package/skills/wix-manage/references/google-ads/manage-campaign-success-guide.md +83 -37
  44. package/skills/wix-headless-fast/install/fast-path.mjs +0 -181
  45. package/skills/wix-headless-fast/references/blog/INSTRUCTIONS.md +0 -301
  46. package/skills/wix-headless-fast/references/blog/app/components/blog/BlogFeedView.tsx +0 -136
  47. package/skills/wix-headless-fast/references/blog/app/components/blog/PostView.tsx +0 -112
  48. package/skills/wix-headless-fast/references/blog/app/components/blog/RichContent.tsx +0 -42
  49. package/skills/wix-headless-fast/references/blog/app/hooks/blog/useBlogFeed.ts +0 -31
  50. package/skills/wix-headless-fast/references/blog/app/hooks/blog/usePost.ts +0 -22
  51. package/skills/wix-headless-fast/references/blog/app/wix/blog/blog-feed-store.ts +0 -137
  52. package/skills/wix-headless-fast/references/blog/app/wix/blog/post-store.ts +0 -78
  53. package/skills/wix-headless-fast/references/blog/app/wix/blog/posts-core.ts +0 -117
  54. package/skills/wix-headless-fast/references/blog/app/wix/blog/posts.ts +0 -52
  55. package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy-core.ts +0 -47
  56. package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy.ts +0 -58
  57. package/skills/wix-headless-fast/references/blog/app/wix/blog/types.ts +0 -62
  58. package/skills/wix-headless-fast/references/blog/app-astro/layouts/SiteLayout.astro +0 -40
  59. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog/[...slug].astro +0 -97
  60. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog.astro +0 -24
  61. package/skills/wix-headless-fast/references/blog/lock/astro/package-lock.json +0 -16156
  62. package/skills/wix-headless-fast/references/blog/rest/posts.ts +0 -42
  63. package/skills/wix-headless-fast/references/blog/rest/taxonomy.ts +0 -62
  64. package/skills/wix-headless-fast/references/blog/seed/SEED.md +0 -81
  65. package/skills/wix-headless-fast/references/blog/seed/seed-blog.mjs +0 -287
  66. package/skills/wix-headless-fast/references/bookings/INSTRUCTIONS.md +0 -275
  67. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServiceBookingView.tsx +0 -144
  68. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServicesView.tsx +0 -119
  69. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useBookingFlow.ts +0 -32
  70. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useServices.ts +0 -23
  71. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-core.ts +0 -218
  72. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-flow-store.ts +0 -169
  73. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking.ts +0 -121
  74. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-core.ts +0 -92
  75. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-store.ts +0 -90
  76. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services.ts +0 -57
  77. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/types.ts +0 -72
  78. package/skills/wix-headless-fast/references/bookings/app-astro/layouts/SiteLayout.astro +0 -40
  79. package/skills/wix-headless-fast/references/bookings/app-astro/pages/services/[slug].astro +0 -76
  80. package/skills/wix-headless-fast/references/bookings/app-astro/pages/services.astro +0 -22
  81. package/skills/wix-headless-fast/references/bookings/lock/astro/package-lock.json +0 -11962
  82. package/skills/wix-headless-fast/references/bookings/rest/booking.ts +0 -113
  83. package/skills/wix-headless-fast/references/bookings/rest/services.ts +0 -55
  84. package/skills/wix-headless-fast/references/bookings/seed/SEED.md +0 -71
  85. package/skills/wix-headless-fast/references/bookings/seed/seed-bookings.mjs +0 -302
  86. package/skills/wix-headless-fast/references/cms/INSTRUCTIONS.md +0 -353
  87. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useCollection.ts +0 -50
  88. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useItem.ts +0 -37
  89. package/skills/wix-headless-fast/references/cms/app/wix/cms/collection-store.ts +0 -158
  90. package/skills/wix-headless-fast/references/cms/app/wix/cms/item-store.ts +0 -93
  91. package/skills/wix-headless-fast/references/cms/app/wix/cms/items-core.ts +0 -177
  92. package/skills/wix-headless-fast/references/cms/app/wix/cms/items.ts +0 -123
  93. package/skills/wix-headless-fast/references/cms/app/wix/cms/types.ts +0 -75
  94. package/skills/wix-headless-fast/references/cms/app-astro/layouts/SiteLayout.astro +0 -41
  95. package/skills/wix-headless-fast/references/cms/lock/astro/package-lock.json +0 -11262
  96. package/skills/wix-headless-fast/references/cms/rest/items.ts +0 -125
  97. package/skills/wix-headless-fast/references/cms/seed/SEED.md +0 -112
  98. package/skills/wix-headless-fast/references/cms/seed/seed-cms.mjs +0 -324
  99. package/skills/wix-headless-fast/references/events/INSTRUCTIONS.md +0 -305
  100. package/skills/wix-headless-fast/references/events/app/components/events/EventConfirmationView.tsx +0 -66
  101. package/skills/wix-headless-fast/references/events/app/components/events/EventRegistrationView.tsx +0 -178
  102. package/skills/wix-headless-fast/references/events/app/components/events/EventsView.tsx +0 -118
  103. package/skills/wix-headless-fast/references/events/app/hooks/events/useEventRegistration.ts +0 -35
  104. package/skills/wix-headless-fast/references/events/app/hooks/events/useEvents.ts +0 -24
  105. package/skills/wix-headless-fast/references/events/app/wix/events/events-core.ts +0 -130
  106. package/skills/wix-headless-fast/references/events/app/wix/events/events-store.ts +0 -97
  107. package/skills/wix-headless-fast/references/events/app/wix/events/events.ts +0 -55
  108. package/skills/wix-headless-fast/references/events/app/wix/events/registration-core.ts +0 -113
  109. package/skills/wix-headless-fast/references/events/app/wix/events/registration-store.ts +0 -156
  110. package/skills/wix-headless-fast/references/events/app/wix/events/registration.ts +0 -97
  111. package/skills/wix-headless-fast/references/events/app/wix/events/types.ts +0 -61
  112. package/skills/wix-headless-fast/references/events/app-astro/layouts/SiteLayout.astro +0 -40
  113. package/skills/wix-headless-fast/references/events/app-astro/pages/event-confirmation.astro +0 -12
  114. package/skills/wix-headless-fast/references/events/app-astro/pages/events/[slug].astro +0 -80
  115. package/skills/wix-headless-fast/references/events/app-astro/pages/events.astro +0 -21
  116. package/skills/wix-headless-fast/references/events/lock/astro/package-lock.json +0 -11884
  117. package/skills/wix-headless-fast/references/events/rest/events.ts +0 -57
  118. package/skills/wix-headless-fast/references/events/rest/registration.ts +0 -83
  119. package/skills/wix-headless-fast/references/events/seed/SEED.md +0 -95
  120. package/skills/wix-headless-fast/references/events/seed/seed-events.mjs +0 -276
  121. package/skills/wix-headless-fast/references/forms/INSTRUCTIONS.md +0 -338
  122. package/skills/wix-headless-fast/references/forms/app/hooks/forms/useWixForm.ts +0 -85
  123. package/skills/wix-headless-fast/references/forms/app/wix/forms/form-store.ts +0 -332
  124. package/skills/wix-headless-fast/references/forms/app/wix/forms/forms-core.ts +0 -238
  125. package/skills/wix-headless-fast/references/forms/app/wix/forms/forms.ts +0 -54
  126. package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions-core.ts +0 -216
  127. package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions.ts +0 -59
  128. package/skills/wix-headless-fast/references/forms/app/wix/forms/types.ts +0 -135
  129. package/skills/wix-headless-fast/references/forms/lock/astro/package-lock.json +0 -10593
  130. package/skills/wix-headless-fast/references/forms/rest/forms.ts +0 -34
  131. package/skills/wix-headless-fast/references/forms/rest/submissions.ts +0 -56
  132. package/skills/wix-headless-fast/references/forms/seed/SEED.md +0 -116
  133. package/skills/wix-headless-fast/references/forms/seed/seed-forms.mjs +0 -327
  134. package/skills/wix-headless-fast/references/members/INSTRUCTIONS.md +0 -314
  135. package/skills/wix-headless-fast/references/members/app/components/members/AccountView.tsx +0 -60
  136. package/skills/wix-headless-fast/references/members/app/components/members/LoginForm.tsx +0 -155
  137. package/skills/wix-headless-fast/references/members/app/components/members/MemberMenu.tsx +0 -78
  138. package/skills/wix-headless-fast/references/members/app/components/members/RequireAuth.tsx +0 -47
  139. package/skills/wix-headless-fast/references/members/app/hooks/members/useMember.ts +0 -66
  140. package/skills/wix-headless-fast/references/members/app/wix/members/auth-core.ts +0 -105
  141. package/skills/wix-headless-fast/references/members/app/wix/members/auth.ts +0 -59
  142. package/skills/wix-headless-fast/references/members/app/wix/members/client.ts +0 -53
  143. package/skills/wix-headless-fast/references/members/app/wix/members/member-store.ts +0 -122
  144. package/skills/wix-headless-fast/references/members/app/wix/members/members-core.ts +0 -43
  145. package/skills/wix-headless-fast/references/members/app/wix/members/members.ts +0 -29
  146. package/skills/wix-headless-fast/references/members/app/wix/members/types.ts +0 -21
  147. package/skills/wix-headless-fast/references/members/app-astro/layouts/SiteLayout.astro +0 -42
  148. package/skills/wix-headless-fast/references/members/app-astro/pages/account.astro +0 -10
  149. package/skills/wix-headless-fast/references/members/app-astro/pages/login.astro +0 -11
  150. package/skills/wix-headless-fast/references/members/lock/astro/package-lock.json +0 -10329
  151. package/skills/wix-headless-fast/references/members/rest/auth.ts +0 -215
  152. package/skills/wix-headless-fast/references/members/rest/members.ts +0 -26
  153. package/skills/wix-headless-fast/references/members/seed/SEED.md +0 -39
  154. package/skills/wix-headless-fast/references/members/seed/seed-members.mjs +0 -94
  155. package/skills/wix-headless-fast/references/portfolio/INSTRUCTIONS.md +0 -313
  156. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionProjectsView.tsx +0 -110
  157. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionsView.tsx +0 -90
  158. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/GalleryMedia.tsx +0 -35
  159. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/ProjectDetailView.tsx +0 -85
  160. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollectionProjects.ts +0 -32
  161. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollections.ts +0 -21
  162. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useProjectDetail.ts +0 -31
  163. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collection-projects-store.ts +0 -82
  164. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collections-store.ts +0 -58
  165. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio-core.ts +0 -177
  166. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio.ts +0 -78
  167. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/project-detail-store.ts +0 -81
  168. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/types.ts +0 -55
  169. package/skills/wix-headless-fast/references/portfolio/app-astro/layouts/SiteLayout.astro +0 -40
  170. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio/[slug].astro +0 -30
  171. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio.astro +0 -21
  172. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/projects/[slug].astro +0 -29
  173. package/skills/wix-headless-fast/references/portfolio/lock/astro/package-lock.json +0 -10197
  174. package/skills/wix-headless-fast/references/portfolio/rest/portfolio.ts +0 -75
  175. package/skills/wix-headless-fast/references/portfolio/seed/SEED.md +0 -86
  176. package/skills/wix-headless-fast/references/portfolio/seed/seed-portfolio.mjs +0 -258
  177. package/skills/wix-headless-fast/references/pricing-plans/INSTRUCTIONS.md +0 -294
  178. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlanDetailView.tsx +0 -47
  179. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlansView.tsx +0 -101
  180. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/SubscribeButton.tsx +0 -41
  181. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlanPurchase.ts +0 -16
  182. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlans.ts +0 -22
  183. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plan-purchase-store.ts +0 -54
  184. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-core.ts +0 -106
  185. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-store.ts +0 -64
  186. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans.ts +0 -27
  187. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase-core.ts +0 -43
  188. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase.ts +0 -22
  189. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/types.ts +0 -30
  190. package/skills/wix-headless-fast/references/pricing-plans/app-astro/layouts/SiteLayout.astro +0 -41
  191. package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans/[slug].astro +0 -40
  192. package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans.astro +0 -21
  193. package/skills/wix-headless-fast/references/pricing-plans/lock/astro/package-lock.json +0 -11226
  194. package/skills/wix-headless-fast/references/pricing-plans/rest/plans.ts +0 -31
  195. package/skills/wix-headless-fast/references/pricing-plans/rest/purchase.ts +0 -20
  196. package/skills/wix-headless-fast/references/pricing-plans/seed/SEED.md +0 -79
  197. package/skills/wix-headless-fast/references/pricing-plans/seed/seed-pricing-plans.mjs +0 -279
  198. package/skills/wix-headless-fast/references/restaurants/INSTRUCTIONS.md +0 -358
  199. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/MenuView.tsx +0 -142
  200. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartButton.tsx +0 -26
  201. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartDrawer.tsx +0 -121
  202. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/ReservationView.tsx +0 -155
  203. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useMenus.ts +0 -34
  204. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useOrderCart.ts +0 -43
  205. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useReservation.ts +0 -34
  206. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-core.ts +0 -155
  207. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-store.ts +0 -89
  208. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu.ts +0 -71
  209. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/order-store.ts +0 -103
  210. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering-core.ts +0 -124
  211. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering.ts +0 -185
  212. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservation-store.ts +0 -193
  213. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations-core.ts +0 -94
  214. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations.ts +0 -74
  215. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/types.ts +0 -168
  216. package/skills/wix-headless-fast/references/restaurants/app-astro/layouts/SiteLayout.astro +0 -47
  217. package/skills/wix-headless-fast/references/restaurants/app-astro/pages/menu.astro +0 -22
  218. package/skills/wix-headless-fast/references/restaurants/app-astro/pages/reservations.astro +0 -12
  219. package/skills/wix-headless-fast/references/restaurants/lock/astro/package-lock.json +0 -12560
  220. package/skills/wix-headless-fast/references/restaurants/rest/menu.ts +0 -60
  221. package/skills/wix-headless-fast/references/restaurants/rest/ordering.ts +0 -169
  222. package/skills/wix-headless-fast/references/restaurants/rest/reservations.ts +0 -68
  223. package/skills/wix-headless-fast/references/restaurants/seed/SEED.md +0 -89
  224. package/skills/wix-headless-fast/references/restaurants/seed/seed-restaurants.mjs +0 -479
  225. package/skills/wix-headless-fast/references/shared/CONTENT.md +0 -22
  226. package/skills/wix-headless-fast/references/shared/CUSTOM_OPERATIONS.md +0 -73
  227. package/skills/wix-headless-fast/references/shared/DESIGN.md +0 -26
  228. package/skills/wix-headless-fast/references/shared/SUPPLIED-CONTENT.md +0 -23
  229. package/skills/wix-headless-fast/references/shared/app/styles/global.css +0 -52
  230. package/skills/wix-headless-fast/references/shared/app/wix/config.ts +0 -15
  231. package/skills/wix-headless-fast/references/shared/app/wix/media.ts +0 -81
  232. package/skills/wix-headless-fast/references/shared/app/wix/money.ts +0 -24
  233. package/skills/wix-headless-fast/references/shared/app/wix/sdk.ts +0 -89
  234. package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app/wix/media-upload/client.ts +0 -46
  235. package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app-astro/pages/api/wix/media-upload.ts +0 -46
  236. package/skills/wix-headless-fast/references/shared/rest/client.ts +0 -155
  237. package/skills/wix-headless-fast/references/shared/rest/config.ts +0 -3
  238. package/skills/wix-headless-fast/references/shared/rest/media.ts +0 -65
  239. package/skills/wix-headless-fast/references/shared/seed/images.mjs +0 -145
  240. package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +0 -608
  241. package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartButton.tsx +0 -26
  242. package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartDrawer.tsx +0 -155
  243. package/skills/wix-headless-fast/references/storefront/app/components/storefront/FilterPanel.tsx +0 -266
  244. package/skills/wix-headless-fast/references/storefront/app/components/storefront/OptionPicker.tsx +0 -95
  245. package/skills/wix-headless-fast/references/storefront/app/components/storefront/QuickAdd.tsx +0 -136
  246. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useCart.ts +0 -48
  247. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useProductDetail.ts +0 -39
  248. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +0 -34
  249. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-core.ts +0 -121
  250. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-store.ts +0 -107
  251. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart.ts +0 -138
  252. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog-core.ts +0 -309
  253. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +0 -133
  254. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/product-detail-store.ts +0 -147
  255. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/shop-store.ts +0 -289
  256. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/types.ts +0 -167
  257. package/skills/wix-headless-fast/references/storefront/app-astro/layouts/SiteLayout.astro +0 -65
  258. package/skills/wix-headless-fast/references/storefront/lock/astro/package-lock.json +0 -12247
  259. package/skills/wix-headless-fast/references/storefront/rest/cart.ts +0 -132
  260. package/skills/wix-headless-fast/references/storefront/rest/catalog.ts +0 -123
  261. package/skills/wix-headless-fast/references/storefront/seed/SEED.md +0 -124
  262. package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +0 -525
@@ -1,34 +0,0 @@
1
- // Form-schema reads over REST — the twin of app/wix/forms/forms.ts. Same exports, same FormDto; the
2
- // flattening rules come from forms-core (the SAME file the SDK transport uses, deployed flat next
3
- // to this one by deploy.mjs --stack static), so this file is only the transport: one fetch per
4
- // function. Both calls run with the visitor token — the schema read is listed under an owner scope
5
- // and still returns 200 to an anonymous visitor, so a published site can render its own forms.
6
- // Porting: keep the paths, keep the query, port the core once.
7
- // docs: https://dev.wix.com/docs/api-reference/crm/forms/form-schemas/get-form.md
8
- // docs: https://dev.wix.com/docs/api-reference/crm/forms/form-schemas/list-forms.md
9
- import { wixRequest } from "./client.js";
10
- import { FORMS_NAMESPACE, toForm, type Raw } from "./forms-core.js";
11
- import type { FormDto } from "./types.js";
12
-
13
- export { FORMS_NAMESPACE };
14
-
15
- /**
16
- * One form by id. Throws (a WixApiError, 404 FORM_NOT_FOUND) when the id is wrong or the form was
17
- * deleted — a form that cannot load is a setup problem; never render a hand-built fallback.
18
- * GET /form-schema-service/v4/forms/{formId} → { form }
19
- */
20
- export async function getForm(formId: string): Promise<FormDto> {
21
- const res = await wixRequest<Raw>(`/form-schema-service/v4/forms/${encodeURIComponent(formId)}`, { method: "GET" });
22
- if (!res?.form) throw new Error(`forms: form "${formId}" not found.`);
23
- return toForm(res.form);
24
- }
25
-
26
- /**
27
- * Every ENABLED form in the Wix Forms namespace (a disabled form vanishes from the listing rather
28
- * than erroring). `namespace` is required — without it the call is a 400.
29
- * GET /form-schema-service/v4/forms?namespace=wix.form_app.form → { forms, pagingMetadata }
30
- */
31
- export async function listForms(): Promise<FormDto[]> {
32
- const res = await wixRequest<Raw>("/form-schema-service/v4/forms", { method: "GET", query: { namespace: FORMS_NAMESPACE } });
33
- return ((res?.forms ?? []) as Raw[]).map(toForm);
34
- }
@@ -1,56 +0,0 @@
1
- // Submissions over REST — the twin of app/wix/forms/submissions.ts. Same exports, same
2
- // SubmissionDto; the rules come from submissions-core (the SAME file the SDK transport uses,
3
- // deployed flat next to this one). Both calls run with the visitor token: `CreateSubmission` is
4
- // listed under an owner scope and still returns 200 to an anonymous visitor, so a published site
5
- // can submit its own forms. Submissions are write-only from a visitor — the resolved create IS
6
- // the confirmation. A rejection throws a WixApiError whose `details` block `submissionErrors`
7
- // maps onto the controls; let it throw.
8
- // docs: https://dev.wix.com/docs/api-reference/crm/forms/form-submissions/create-submission.md
9
- // docs: https://dev.wix.com/docs/api-reference/crm/forms/form-submissions/get-media-upload-url.md
10
- import { wixRequest } from "./client.js";
11
- import type { Raw } from "./forms-core.js";
12
- import {
13
- SUBMITTED_OK,
14
- normalizePhone,
15
- putUpload,
16
- submissionErrors,
17
- toSubmission,
18
- toSubmissionValues,
19
- uploadFilesWith,
20
- uploadMimeType,
21
- } from "./submissions-core.js";
22
- import type { FormFieldDto, FormValues, SubmissionDto } from "./types.js";
23
-
24
- export { SUBMITTED_OK, normalizePhone, submissionErrors, toSubmissionValues };
25
-
26
- const SUBMISSIONS = "/form-submission-service/v4/submissions";
27
-
28
- /**
29
- * Upload one File and return the value to submit for its field (the upload URL itself).
30
- * POST /form-submission-service/v4/submissions/media-upload-url { formId, filename, mimeType } → { uploadUrl }
31
- * then PUT the bytes to that URL with plain fetch (submissions-core.putUpload).
32
- */
33
- export async function uploadFile(formId: string, file: File): Promise<string> {
34
- const mimeType = uploadMimeType(file);
35
- const res = await wixRequest<Raw>(`${SUBMISSIONS}/media-upload-url`, { body: { formId, filename: file.name, mimeType } });
36
- const uploadUrl: string | undefined = res?.uploadUrl;
37
- if (!uploadUrl) throw new Error(`forms: no upload URL for "${file.name}".`);
38
- return putUpload(uploadUrl, file, mimeType);
39
- }
40
-
41
- /** Upload every File in the form's values; returns a copy with each file field holding its URL(s). */
42
- export async function uploadFiles(formId: string, fields: FormFieldDto[], values: FormValues): Promise<FormValues> {
43
- return uploadFilesWith(uploadFile, formId, fields, values);
44
- }
45
-
46
- /**
47
- * Create the submission — the write, and the only confirmation there is. `values` is
48
- * toSubmissionValues(fields, values): every key a field `target`, every value in that field's
49
- * shape. A 400 carries details.validationError.fieldViolations[].data.errors[] (errorPath,
50
- * errorType) on the thrown WixApiError.
51
- * POST /form-submission-service/v4/submissions { submission: { formId, submissions } } → { submission: { id, status, … } }
52
- */
53
- export async function createSubmission(formId: string, values: Record<string, unknown>): Promise<SubmissionDto> {
54
- const created = await wixRequest<Raw>(SUBMISSIONS, { body: { submission: { formId, submissions: values } } });
55
- return toSubmission(created);
56
- }
@@ -1,116 +0,0 @@
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.
109
-
110
- ## Supplied content
111
-
112
- The general rules are in `references/shared/SUPPLIED-CONTENT.md`. For forms the user usually hands
113
- over the form itself: a list of questions, or a PDF or screenshot of the form they use today. Each
114
- question becomes a field, with the `kind` its answer implies (an email address → `email`, a fixed set
115
- of answers → `select`, `radio` or `multi`, a long answer → `textarea`); a required mark becomes
116
- `required`; the button label becomes `submitText`. Question wording verbatim.
@@ -1,327 +0,0 @@
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, format?, contact? }
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
- // `contact` is the per-field contactMapping: it is what makes a submission create or update the
77
- // site's CRM contact (the older postSubmissionTriggers.upsertContact is ignored by v4).
78
- const KINDS = {
79
- text: { inputType: "STRING", componentType: "TEXT_INPUT", identifier: "TEXT_INPUT" },
80
- textarea: { inputType: "STRING", componentType: "TEXT_INPUT", identifier: "TEXT_AREA" },
81
- email: { inputType: "STRING", componentType: "TEXT_INPUT", identifier: "CONTACTS_EMAIL", format: "EMAIL", contact: { contactField: "EMAIL", emailInfo: { tag: "UNTAGGED" } } },
82
- phone: { inputType: "STRING", componentType: "PHONE_INPUT", identifier: "CONTACTS_PHONE", format: "PHONE", contact: { contactField: "PHONE", phoneInfo: { tag: "UNTAGGED" } } },
83
- url: { inputType: "STRING", componentType: "TEXT_INPUT", identifier: "URL_INPUT", format: "URL" },
84
- firstName: { inputType: "STRING", componentType: "TEXT_INPUT", identifier: "CONTACTS_FIRST_NAME", contact: { contactField: "FIRST_NAME" } },
85
- lastName: { inputType: "STRING", componentType: "TEXT_INPUT", identifier: "CONTACTS_LAST_NAME", contact: { contactField: "LAST_NAME" } },
86
- company: { inputType: "STRING", componentType: "TEXT_INPUT", identifier: "CONTACTS_COMPANY", contact: { contactField: "COMPANY" } },
87
- date: { inputType: "STRING", componentType: "DATE_PICKER", identifier: "DATE_PICKER", format: "DATE" },
88
- number: { inputType: "NUMBER", componentType: "NUMBER_INPUT", identifier: "NUMBER_INPUT" },
89
- rating: { inputType: "NUMBER", componentType: "RATING_INPUT", identifier: "RATING_INPUT" },
90
- select: { inputType: "STRING", componentType: "DROPDOWN", identifier: "DROPDOWN" },
91
- radio: { inputType: "STRING", componentType: "RADIO_GROUP", identifier: "RADIO_GROUP" },
92
- multi: { inputType: "ARRAY", componentType: "CHECKBOX_GROUP", identifier: "CHECKBOX_GROUP" },
93
- checkbox: { inputType: "BOOLEAN", componentType: "CHECKBOX", identifier: "CHECKBOX" },
94
- file: { inputType: "WIX_FILE", componentType: "FILE_UPLOAD", identifier: "FILE_UPLOAD" },
95
- address: { inputType: "ADDRESS", componentType: "MULTILINE_ADDRESS", identifier: "MULTILINE_ADDRESS" },
96
- };
97
-
98
- const INPUT_BLOCK = {
99
- STRING: "stringOptions", NUMBER: "numberOptions", BOOLEAN: "booleanOptions",
100
- ARRAY: "arrayOptions", ADDRESS: "addressOptions", WIX_FILE: "wixFileOptions",
101
- };
102
- const COMPONENT_BLOCK = {
103
- TEXT_INPUT: "textInputOptions", PHONE_INPUT: "phoneInputOptions", NUMBER_INPUT: "numberInputOptions",
104
- RATING_INPUT: "ratingInputOptions", DATE_PICKER: "datePickerOptions",
105
- CHECKBOX: "checkboxOptions", CHECKBOX_GROUP: "checkboxGroupOptions",
106
- RADIO_GROUP: "radioGroupOptions", DROPDOWN: "dropdownOptions",
107
- MULTILINE_ADDRESS: "multilineAddressOptions", FILE_UPLOAD: "fileUploadOptions",
108
- };
109
-
110
- /**
111
- * `target` is the IMMUTABLE submission key: starts with a letter, letters/digits/underscore
112
- * only, no doubled underscore, unique within the form. The random suffix is what keeps two
113
- * fields with the same label apart.
114
- */
115
- function targetFor(label, taken) {
116
- const base =
117
- String(label)
118
- .toLowerCase()
119
- .replace(/[^a-z0-9]+/g, "_")
120
- .replace(/_+/g, "_")
121
- .replace(/^_|_$/g, "")
122
- .replace(/^(?=\d)/, "f_")
123
- .slice(0, 40) || "field";
124
- let target;
125
- do {
126
- target = `${base}_${Math.random().toString(36).slice(2, 8)}`;
127
- } while (taken.has(target));
128
- taken.add(target);
129
- return target;
130
- }
131
-
132
- function buildField(spec, taken) {
133
- const kind = KINDS[spec.kind];
134
- if (!kind) {
135
- throw new Error(
136
- `field "${spec.label}": unknown kind "${spec.kind}" — one of ${Object.keys(KINDS).join(", ")}`,
137
- );
138
- }
139
- const choices = spec.choices ?? [];
140
- if ((spec.kind === "select" || spec.kind === "radio" || spec.kind === "multi") && !choices.length) {
141
- throw new Error(`field "${spec.label}": kind "${spec.kind}" needs a non-empty choices array`);
142
- }
143
-
144
- const target = targetFor(spec.label, taken);
145
- const options = choices.map((c) => {
146
- const value = typeof c === "string" ? c : c.value;
147
- return { id: randomUUID(), label: typeof c === "string" ? c : (c.label ?? c.value), value };
148
- });
149
- const values = options.map((o) => o.value);
150
-
151
- // A choice field declares its options TWICE — here and in the validation enum — and the two
152
- // must agree. Disagree and the create still returns 200: the field is created as a plain
153
- // text box, losing its choices. Both are derived from the same list, so they cannot drift.
154
- const validation = {};
155
- if (kind.format) validation.format = kind.format;
156
- if (spec.min != null) validation.minimum = spec.min;
157
- if (spec.max != null) validation.maximum = spec.max;
158
- if (spec.maxLength != null) validation.maxLength = spec.maxLength;
159
- if (values.length) {
160
- if (kind.inputType === "ARRAY") {
161
- validation.itemType = "STRING";
162
- validation.items = { stringOptions: { enum: values } };
163
- } else {
164
- validation.enum = values;
165
- }
166
- }
167
- if (spec.kind === "file") validation.fileLimit = spec.fileLimit ?? 1;
168
-
169
- const component = { label: spec.label, showLabel: true };
170
- if (spec.placeholder) component.placeholder = spec.placeholder;
171
- if (options.length) component.options = options;
172
- if (spec.kind === "textarea") component.numberOfLines = spec.lines ?? 4;
173
- if (spec.default != null) component.default = spec.default;
174
-
175
- return {
176
- id: randomUUID(),
177
- identifier: kind.identifier,
178
- fieldType: "INPUT",
179
- inputOptions: {
180
- target,
181
- inputType: kind.inputType,
182
- // `required` lives HERE, never inside the validation block.
183
- required: spec.required ?? false,
184
- // Contact fields carry pii and the CRM mapping; without contactMapping a submission is
185
- // stored but no contact is created or updated.
186
- ...(kind.contact ? { pii: true, contactMapping: kind.contact } : {}),
187
- [INPUT_BLOCK[kind.inputType]]: {
188
- // `validation` is always present, even as {}, and nests under the INPUT-TYPE block —
189
- // not the component one. Absent, the target is not registered as an accepted value and
190
- // every submission comes back UNKNOWN_VALUE_ERROR on a key that IS in the schema.
191
- validation,
192
- componentType: kind.componentType,
193
- [COMPONENT_BLOCK[kind.componentType]]: component,
194
- },
195
- },
196
- };
197
- }
198
-
199
- function buildForm(planForm) {
200
- const taken = new Set();
201
- const fields = (planForm.fields ?? []).map((f) => buildField(f, taken));
202
- if (!fields.length) throw new Error(`form "${planForm.name}": no fields`);
203
-
204
- const submit = {
205
- id: randomUUID(),
206
- identifier: "SUBMIT_BUTTON",
207
- fieldType: "DISPLAY",
208
- displayOptions: {
209
- // The button's identifier is SUBMIT_BUTTON; its display type is PAGE_NAVIGATION (the enum
210
- // has no SUBMIT_BUTTON value — the create is a 400 with anything else).
211
- displayFieldType: "PAGE_NAVIGATION",
212
- pageNavigationOptions: { submitText: planForm.submitText ?? "Submit" },
213
- },
214
- };
215
-
216
- // `steps` must reference EVERY field, the submit button included — a field missing from the
217
- // layout never appears in the owner's dashboard, so they cannot edit what the site renders.
218
- const items = [...fields, submit].map((f, i) => ({
219
- fieldId: f.id,
220
- row: i,
221
- column: 0,
222
- width: 12,
223
- }));
224
-
225
- return {
226
- name: planForm.name,
227
- namespace: NAMESPACE,
228
- formFields: [...fields, submit],
229
- steps: [{ id: randomUUID(), layout: { large: { items }, medium: { items }, small: { items } } }],
230
- };
231
- }
232
-
233
- // ---- operations ------------------------------------------------------------------------------
234
-
235
- /**
236
- * Read the form back and confirm each field kept its componentType. A create returns 200 even
237
- * when a choice field degraded to a plain text box, so this is the only check that catches it.
238
- */
239
- async function verifyForm(ctx, formId, expected) {
240
- const { form } = await req(ctx, `/form-schema-service/v4/forms/${formId}`, { method: "GET" });
241
- const live = new Map(
242
- (form?.formFields ?? [])
243
- .filter((f) => f.fieldType === "INPUT")
244
- .map((f) => {
245
- const block = f.inputOptions?.[INPUT_BLOCK[f.inputOptions?.inputType]] ?? {};
246
- return [f.inputOptions?.target, block.componentType];
247
- }),
248
- );
249
- const degraded = expected
250
- .filter((e) => live.get(e.target) !== e.componentType)
251
- .map((e) => `${e.target}: expected ${e.componentType}, got ${live.get(e.target) ?? "MISSING"}`);
252
- return { fieldsLive: live.size, degraded };
253
- }
254
-
255
- /**
256
- * Create every form in the plan. Existing forms are left alone — matching by name, since a
257
- * re-run must not create a second copy of the same form.
258
- */
259
- export async function setupForms(ctx, plan) {
260
- await installFormsApp(ctx);
261
-
262
- const existing = await req(
263
- ctx,
264
- `/form-schema-service/v4/forms?namespace=${encodeURIComponent(NAMESPACE)}`,
265
- { method: "GET" },
266
- ).catch(() => ({ forms: [] }));
267
- const byName = new Map((existing.forms ?? []).map((f) => [f.name, f]));
268
-
269
- const out = [];
270
- for (const planForm of plan.forms ?? []) {
271
- const already = byName.get(planForm.name);
272
- if (already) {
273
- out.push({
274
- name: planForm.name,
275
- formId: already.id ?? already._id,
276
- created: false,
277
- fields: (already.formFields ?? [])
278
- .filter((f) => f.fieldType === "INPUT")
279
- .map((f) => ({ target: f.inputOptions?.target, label: planForm.name })),
280
- });
281
- continue;
282
- }
283
-
284
- const body = buildForm(planForm);
285
- const { form } = await req(ctx, "/form-schema-service/v4/forms", { body: { form: body } });
286
- const formId = form?.id ?? form?._id;
287
- if (!formId) throw new Error(`form "${planForm.name}": created but no id returned`);
288
-
289
- const expected = body.formFields
290
- .filter((f) => f.fieldType === "INPUT")
291
- .map((f) => ({
292
- target: f.inputOptions.target,
293
- componentType: f.inputOptions[INPUT_BLOCK[f.inputOptions.inputType]].componentType,
294
- }));
295
- const check = await verifyForm(ctx, formId, expected);
296
-
297
- out.push({
298
- name: planForm.name,
299
- formId,
300
- created: true,
301
- fields: body.formFields
302
- .filter((f) => f.fieldType === "INPUT")
303
- .map((f, i) => ({ target: f.inputOptions.target, label: planForm.fields[i].label })),
304
- ...check,
305
- });
306
- }
307
- return { forms: out };
308
- }
309
-
310
- // ---- CLI entry -------------------------------------------------------------------------------
311
-
312
- const invokedDirectly = process.argv[1] && import.meta.url.endsWith(process.argv[1].split("/").pop());
313
- if (invokedDirectly) {
314
- const planPath = process.argv[2];
315
- if (!planPath) {
316
- console.error("usage: node seed-forms.mjs <plan.json> (run from the project root)");
317
- process.exit(1);
318
- }
319
- const plan = JSON.parse(readFileSync(planPath, "utf8"));
320
- const ctx = makeCtx();
321
- setupForms(ctx, plan)
322
- .then((result) => console.log(JSON.stringify(result, null, 2)))
323
- .catch((e) => {
324
- console.error(e.message);
325
- process.exit(1);
326
- });
327
- }