@wix/agent-skills 1.21.0 → 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 (258) hide show
  1. package/package.json +1 -1
  2. package/skills/wix-app/SKILL.md +60 -4
  3. package/skills/wix-app/references/DASHBOARD_PAGE.md +11 -25
  4. package/skills/wix-app/references/DATA_COLLECTION.md +16 -219
  5. package/skills/wix-app/references/dashboard-page/DATA_SOURCES.md +182 -0
  6. package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE.md +97 -0
  7. package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_COLLECTION.md +184 -0
  8. package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_ROUTER.md +203 -0
  9. package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_SETTINGS.md +44 -0
  10. package/skills/wix-app/references/dashboard-page/QUERY_AND_PAGING.md +182 -0
  11. package/skills/wix-app/references/dashboard-page/TABLE_STATE.md +133 -0
  12. package/skills/wix-app/references/dashboard-page/UX_SUCCESS_MODEL.md +10 -5
  13. package/skills/wix-app/references/data-collection/LIFECYCLE.md +68 -0
  14. package/skills/wix-app/references/data-collection/PERMISSIONS.md +47 -0
  15. package/skills/wix-app/references/data-collection/SCHEMA.md +181 -0
  16. package/skills/wix-app/references/data-collection/WIX_DATA.md +38 -66
  17. package/skills/wix-headless-fast/SKILL.md +61 -223
  18. package/skills/wix-headless-fast/cold-start/bootstrap.mjs +156 -0
  19. package/skills/wix-headless-fast/{entry/skill.md → cold-start/cold-start.md} +11 -12
  20. package/skills/wix-headless-fast/guides/existing-site.md +76 -0
  21. package/skills/wix-headless-fast/guides/reference-mode.md +97 -0
  22. package/skills/wix-headless-fast/install/AGENTS.md +6 -3
  23. package/skills/wix-headless-fast/install/attach.mjs +15 -47
  24. package/skills/wix-headless-fast/install/deploy.mjs +21 -60
  25. package/skills/wix-headless-fast/install/lock.mjs +55 -0
  26. package/skills/wix-headless-fast/install/setup.mjs +32 -12
  27. package/skills/wix-headless-fast/install/templates.mjs +168 -0
  28. package/skills/wix-manage/references/google-ads/google-ads-dashboard-navigation.md +27 -0
  29. package/skills/wix-manage/references/google-ads/manage-campaign-success-guide.md +83 -37
  30. package/skills/wix-headless-fast/references/blog/INSTRUCTIONS.md +0 -303
  31. package/skills/wix-headless-fast/references/blog/app/components/blog/BlogFeedView.tsx +0 -136
  32. package/skills/wix-headless-fast/references/blog/app/components/blog/PostView.tsx +0 -112
  33. package/skills/wix-headless-fast/references/blog/app/components/blog/RichContent.tsx +0 -42
  34. package/skills/wix-headless-fast/references/blog/app/hooks/blog/useBlogFeed.ts +0 -31
  35. package/skills/wix-headless-fast/references/blog/app/hooks/blog/usePost.ts +0 -22
  36. package/skills/wix-headless-fast/references/blog/app/wix/blog/blog-feed-store.ts +0 -137
  37. package/skills/wix-headless-fast/references/blog/app/wix/blog/post-store.ts +0 -78
  38. package/skills/wix-headless-fast/references/blog/app/wix/blog/posts-core.ts +0 -117
  39. package/skills/wix-headless-fast/references/blog/app/wix/blog/posts.ts +0 -52
  40. package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy-core.ts +0 -47
  41. package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy.ts +0 -58
  42. package/skills/wix-headless-fast/references/blog/app/wix/blog/types.ts +0 -62
  43. package/skills/wix-headless-fast/references/blog/app-astro/layouts/SiteLayout.astro +0 -40
  44. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog/[...slug].astro +0 -97
  45. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog.astro +0 -24
  46. package/skills/wix-headless-fast/references/blog/lock/astro/package-lock.json +0 -16156
  47. package/skills/wix-headless-fast/references/blog/rest/posts.ts +0 -42
  48. package/skills/wix-headless-fast/references/blog/rest/taxonomy.ts +0 -62
  49. package/skills/wix-headless-fast/references/blog/seed/SEED.md +0 -81
  50. package/skills/wix-headless-fast/references/blog/seed/read-site.mjs +0 -22
  51. package/skills/wix-headless-fast/references/blog/seed/seed-blog.mjs +0 -287
  52. package/skills/wix-headless-fast/references/bookings/INSTRUCTIONS.md +0 -277
  53. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServiceBookingView.tsx +0 -144
  54. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServicesView.tsx +0 -119
  55. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useBookingFlow.ts +0 -32
  56. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useServices.ts +0 -23
  57. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-core.ts +0 -218
  58. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-flow-store.ts +0 -169
  59. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking.ts +0 -121
  60. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-core.ts +0 -92
  61. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-store.ts +0 -90
  62. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services.ts +0 -57
  63. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/types.ts +0 -72
  64. package/skills/wix-headless-fast/references/bookings/app-astro/layouts/SiteLayout.astro +0 -40
  65. package/skills/wix-headless-fast/references/bookings/app-astro/pages/services/[slug].astro +0 -76
  66. package/skills/wix-headless-fast/references/bookings/app-astro/pages/services.astro +0 -22
  67. package/skills/wix-headless-fast/references/bookings/lock/astro/package-lock.json +0 -11962
  68. package/skills/wix-headless-fast/references/bookings/rest/booking.ts +0 -113
  69. package/skills/wix-headless-fast/references/bookings/rest/services.ts +0 -55
  70. package/skills/wix-headless-fast/references/bookings/seed/SEED.md +0 -71
  71. package/skills/wix-headless-fast/references/bookings/seed/read-site.mjs +0 -28
  72. package/skills/wix-headless-fast/references/bookings/seed/seed-bookings.mjs +0 -302
  73. package/skills/wix-headless-fast/references/cms/INSTRUCTIONS.md +0 -355
  74. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useCollection.ts +0 -50
  75. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useItem.ts +0 -37
  76. package/skills/wix-headless-fast/references/cms/app/wix/cms/collection-store.ts +0 -158
  77. package/skills/wix-headless-fast/references/cms/app/wix/cms/item-store.ts +0 -93
  78. package/skills/wix-headless-fast/references/cms/app/wix/cms/items-core.ts +0 -177
  79. package/skills/wix-headless-fast/references/cms/app/wix/cms/items.ts +0 -123
  80. package/skills/wix-headless-fast/references/cms/app/wix/cms/types.ts +0 -75
  81. package/skills/wix-headless-fast/references/cms/app-astro/layouts/SiteLayout.astro +0 -41
  82. package/skills/wix-headless-fast/references/cms/lock/astro/package-lock.json +0 -11262
  83. package/skills/wix-headless-fast/references/cms/rest/items.ts +0 -125
  84. package/skills/wix-headless-fast/references/cms/seed/SEED.md +0 -112
  85. package/skills/wix-headless-fast/references/cms/seed/read-site.mjs +0 -20
  86. package/skills/wix-headless-fast/references/cms/seed/seed-cms.mjs +0 -324
  87. package/skills/wix-headless-fast/references/events/INSTRUCTIONS.md +0 -307
  88. package/skills/wix-headless-fast/references/events/app/components/events/EventConfirmationView.tsx +0 -66
  89. package/skills/wix-headless-fast/references/events/app/components/events/EventRegistrationView.tsx +0 -178
  90. package/skills/wix-headless-fast/references/events/app/components/events/EventsView.tsx +0 -118
  91. package/skills/wix-headless-fast/references/events/app/hooks/events/useEventRegistration.ts +0 -35
  92. package/skills/wix-headless-fast/references/events/app/hooks/events/useEvents.ts +0 -24
  93. package/skills/wix-headless-fast/references/events/app/wix/events/events-core.ts +0 -130
  94. package/skills/wix-headless-fast/references/events/app/wix/events/events-store.ts +0 -97
  95. package/skills/wix-headless-fast/references/events/app/wix/events/events.ts +0 -55
  96. package/skills/wix-headless-fast/references/events/app/wix/events/registration-core.ts +0 -113
  97. package/skills/wix-headless-fast/references/events/app/wix/events/registration-store.ts +0 -156
  98. package/skills/wix-headless-fast/references/events/app/wix/events/registration.ts +0 -97
  99. package/skills/wix-headless-fast/references/events/app/wix/events/types.ts +0 -61
  100. package/skills/wix-headless-fast/references/events/app-astro/layouts/SiteLayout.astro +0 -40
  101. package/skills/wix-headless-fast/references/events/app-astro/pages/event-confirmation.astro +0 -12
  102. package/skills/wix-headless-fast/references/events/app-astro/pages/events/[slug].astro +0 -80
  103. package/skills/wix-headless-fast/references/events/app-astro/pages/events.astro +0 -21
  104. package/skills/wix-headless-fast/references/events/lock/astro/package-lock.json +0 -11884
  105. package/skills/wix-headless-fast/references/events/rest/events.ts +0 -57
  106. package/skills/wix-headless-fast/references/events/rest/registration.ts +0 -83
  107. package/skills/wix-headless-fast/references/events/seed/SEED.md +0 -95
  108. package/skills/wix-headless-fast/references/events/seed/read-site.mjs +0 -26
  109. package/skills/wix-headless-fast/references/events/seed/seed-events.mjs +0 -276
  110. package/skills/wix-headless-fast/references/forms/INSTRUCTIONS.md +0 -340
  111. package/skills/wix-headless-fast/references/forms/app/hooks/forms/useWixForm.ts +0 -85
  112. package/skills/wix-headless-fast/references/forms/app/wix/forms/form-store.ts +0 -332
  113. package/skills/wix-headless-fast/references/forms/app/wix/forms/forms-core.ts +0 -238
  114. package/skills/wix-headless-fast/references/forms/app/wix/forms/forms.ts +0 -54
  115. package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions-core.ts +0 -216
  116. package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions.ts +0 -59
  117. package/skills/wix-headless-fast/references/forms/app/wix/forms/types.ts +0 -135
  118. package/skills/wix-headless-fast/references/forms/lock/astro/package-lock.json +0 -10593
  119. package/skills/wix-headless-fast/references/forms/rest/forms.ts +0 -34
  120. package/skills/wix-headless-fast/references/forms/rest/submissions.ts +0 -56
  121. package/skills/wix-headless-fast/references/forms/seed/SEED.md +0 -116
  122. package/skills/wix-headless-fast/references/forms/seed/read-site.mjs +0 -20
  123. package/skills/wix-headless-fast/references/forms/seed/seed-forms.mjs +0 -327
  124. package/skills/wix-headless-fast/references/members/INSTRUCTIONS.md +0 -316
  125. package/skills/wix-headless-fast/references/members/app/components/members/AccountView.tsx +0 -60
  126. package/skills/wix-headless-fast/references/members/app/components/members/LoginForm.tsx +0 -155
  127. package/skills/wix-headless-fast/references/members/app/components/members/MemberMenu.tsx +0 -78
  128. package/skills/wix-headless-fast/references/members/app/components/members/RequireAuth.tsx +0 -47
  129. package/skills/wix-headless-fast/references/members/app/hooks/members/useMember.ts +0 -66
  130. package/skills/wix-headless-fast/references/members/app/wix/members/auth-core.ts +0 -105
  131. package/skills/wix-headless-fast/references/members/app/wix/members/auth.ts +0 -59
  132. package/skills/wix-headless-fast/references/members/app/wix/members/client.ts +0 -53
  133. package/skills/wix-headless-fast/references/members/app/wix/members/member-store.ts +0 -122
  134. package/skills/wix-headless-fast/references/members/app/wix/members/members-core.ts +0 -43
  135. package/skills/wix-headless-fast/references/members/app/wix/members/members.ts +0 -29
  136. package/skills/wix-headless-fast/references/members/app/wix/members/types.ts +0 -21
  137. package/skills/wix-headless-fast/references/members/app-astro/layouts/SiteLayout.astro +0 -42
  138. package/skills/wix-headless-fast/references/members/app-astro/pages/account.astro +0 -10
  139. package/skills/wix-headless-fast/references/members/app-astro/pages/login.astro +0 -11
  140. package/skills/wix-headless-fast/references/members/lock/astro/package-lock.json +0 -10329
  141. package/skills/wix-headless-fast/references/members/rest/auth.ts +0 -215
  142. package/skills/wix-headless-fast/references/members/rest/members.ts +0 -26
  143. package/skills/wix-headless-fast/references/members/seed/SEED.md +0 -39
  144. package/skills/wix-headless-fast/references/members/seed/read-site.mjs +0 -15
  145. package/skills/wix-headless-fast/references/members/seed/seed-members.mjs +0 -94
  146. package/skills/wix-headless-fast/references/portfolio/INSTRUCTIONS.md +0 -315
  147. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionProjectsView.tsx +0 -110
  148. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionsView.tsx +0 -90
  149. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/GalleryMedia.tsx +0 -35
  150. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/ProjectDetailView.tsx +0 -85
  151. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollectionProjects.ts +0 -32
  152. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollections.ts +0 -21
  153. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useProjectDetail.ts +0 -31
  154. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collection-projects-store.ts +0 -82
  155. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collections-store.ts +0 -58
  156. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio-core.ts +0 -177
  157. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio.ts +0 -78
  158. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/project-detail-store.ts +0 -81
  159. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/types.ts +0 -55
  160. package/skills/wix-headless-fast/references/portfolio/app-astro/layouts/SiteLayout.astro +0 -40
  161. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio/[slug].astro +0 -30
  162. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio.astro +0 -21
  163. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/projects/[slug].astro +0 -29
  164. package/skills/wix-headless-fast/references/portfolio/lock/astro/package-lock.json +0 -10197
  165. package/skills/wix-headless-fast/references/portfolio/rest/portfolio.ts +0 -75
  166. package/skills/wix-headless-fast/references/portfolio/seed/SEED.md +0 -86
  167. package/skills/wix-headless-fast/references/portfolio/seed/read-site.mjs +0 -20
  168. package/skills/wix-headless-fast/references/portfolio/seed/seed-portfolio.mjs +0 -256
  169. package/skills/wix-headless-fast/references/pricing-plans/INSTRUCTIONS.md +0 -296
  170. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlanDetailView.tsx +0 -47
  171. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlansView.tsx +0 -101
  172. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/SubscribeButton.tsx +0 -41
  173. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlanPurchase.ts +0 -16
  174. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlans.ts +0 -22
  175. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plan-purchase-store.ts +0 -54
  176. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-core.ts +0 -106
  177. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-store.ts +0 -64
  178. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans.ts +0 -27
  179. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase-core.ts +0 -43
  180. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase.ts +0 -22
  181. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/types.ts +0 -30
  182. package/skills/wix-headless-fast/references/pricing-plans/app-astro/layouts/SiteLayout.astro +0 -41
  183. package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans/[slug].astro +0 -40
  184. package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans.astro +0 -21
  185. package/skills/wix-headless-fast/references/pricing-plans/lock/astro/package-lock.json +0 -11226
  186. package/skills/wix-headless-fast/references/pricing-plans/rest/plans.ts +0 -31
  187. package/skills/wix-headless-fast/references/pricing-plans/rest/purchase.ts +0 -20
  188. package/skills/wix-headless-fast/references/pricing-plans/seed/SEED.md +0 -79
  189. package/skills/wix-headless-fast/references/pricing-plans/seed/read-site.mjs +0 -21
  190. package/skills/wix-headless-fast/references/pricing-plans/seed/seed-pricing-plans.mjs +0 -279
  191. package/skills/wix-headless-fast/references/restaurants/INSTRUCTIONS.md +0 -360
  192. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/MenuView.tsx +0 -142
  193. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartButton.tsx +0 -26
  194. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartDrawer.tsx +0 -121
  195. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/ReservationView.tsx +0 -155
  196. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useMenus.ts +0 -34
  197. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useOrderCart.ts +0 -43
  198. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useReservation.ts +0 -34
  199. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-core.ts +0 -155
  200. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-store.ts +0 -89
  201. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu.ts +0 -71
  202. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/order-store.ts +0 -103
  203. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering-core.ts +0 -124
  204. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering.ts +0 -185
  205. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservation-store.ts +0 -193
  206. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations-core.ts +0 -94
  207. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations.ts +0 -74
  208. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/types.ts +0 -168
  209. package/skills/wix-headless-fast/references/restaurants/app-astro/layouts/SiteLayout.astro +0 -47
  210. package/skills/wix-headless-fast/references/restaurants/app-astro/pages/menu.astro +0 -22
  211. package/skills/wix-headless-fast/references/restaurants/app-astro/pages/reservations.astro +0 -12
  212. package/skills/wix-headless-fast/references/restaurants/lock/astro/package-lock.json +0 -12560
  213. package/skills/wix-headless-fast/references/restaurants/rest/menu.ts +0 -60
  214. package/skills/wix-headless-fast/references/restaurants/rest/ordering.ts +0 -169
  215. package/skills/wix-headless-fast/references/restaurants/rest/reservations.ts +0 -68
  216. package/skills/wix-headless-fast/references/restaurants/seed/SEED.md +0 -89
  217. package/skills/wix-headless-fast/references/restaurants/seed/read-site.mjs +0 -25
  218. package/skills/wix-headless-fast/references/restaurants/seed/seed-restaurants.mjs +0 -499
  219. package/skills/wix-headless-fast/references/shared/CONTENT.md +0 -22
  220. package/skills/wix-headless-fast/references/shared/CUSTOM_OPERATIONS.md +0 -73
  221. package/skills/wix-headless-fast/references/shared/DESIGN.md +0 -26
  222. package/skills/wix-headless-fast/references/shared/SUPPLIED-CONTENT.md +0 -23
  223. package/skills/wix-headless-fast/references/shared/app/styles/global.css +0 -52
  224. package/skills/wix-headless-fast/references/shared/app/wix/config.ts +0 -15
  225. package/skills/wix-headless-fast/references/shared/app/wix/media.ts +0 -81
  226. package/skills/wix-headless-fast/references/shared/app/wix/money.ts +0 -24
  227. package/skills/wix-headless-fast/references/shared/app/wix/sdk.ts +0 -89
  228. package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app/wix/media-upload/client.ts +0 -46
  229. package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app-astro/pages/api/wix/media-upload.ts +0 -46
  230. package/skills/wix-headless-fast/references/shared/rest/client.ts +0 -155
  231. package/skills/wix-headless-fast/references/shared/rest/config.ts +0 -3
  232. package/skills/wix-headless-fast/references/shared/rest/media.ts +0 -65
  233. package/skills/wix-headless-fast/references/shared/seed/images.mjs +0 -145
  234. package/skills/wix-headless-fast/references/shared/seed/read-site.mjs +0 -99
  235. package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +0 -612
  236. package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartButton.tsx +0 -26
  237. package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartDrawer.tsx +0 -155
  238. package/skills/wix-headless-fast/references/storefront/app/components/storefront/FilterPanel.tsx +0 -266
  239. package/skills/wix-headless-fast/references/storefront/app/components/storefront/OptionPicker.tsx +0 -95
  240. package/skills/wix-headless-fast/references/storefront/app/components/storefront/QuickAdd.tsx +0 -136
  241. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useCart.ts +0 -48
  242. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useProductDetail.ts +0 -39
  243. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +0 -34
  244. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-core.ts +0 -121
  245. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-store.ts +0 -107
  246. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart.ts +0 -138
  247. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog-core.ts +0 -314
  248. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +0 -133
  249. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/product-detail-store.ts +0 -147
  250. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/shop-store.ts +0 -289
  251. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/types.ts +0 -169
  252. package/skills/wix-headless-fast/references/storefront/app-astro/layouts/SiteLayout.astro +0 -65
  253. package/skills/wix-headless-fast/references/storefront/lock/astro/package-lock.json +0 -12247
  254. package/skills/wix-headless-fast/references/storefront/rest/cart.ts +0 -132
  255. package/skills/wix-headless-fast/references/storefront/rest/catalog.ts +0 -123
  256. package/skills/wix-headless-fast/references/storefront/seed/SEED.md +0 -130
  257. package/skills/wix-headless-fast/references/storefront/seed/read-site.mjs +0 -38
  258. package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +0 -561
@@ -1,332 +0,0 @@
1
- // One form as a framework-free store — the logic behind useWixForm, usable from React (useWixForm
2
- // wraps it with useSyncExternalStore), from a static page or Vue/Svelte (subscribe and render), or
3
- // as the specification for a port. Schema in, validated submission out, minus the markup: load the
4
- // form, hold the visitor's values, validate them against the schema's own rules in our wording,
5
- // upload attachments, create the submission, and map a rejection back onto the controls.
6
- //
7
- // It imports the data layer by names the REST twin exports identically (getForm, uploadFiles,
8
- // createSubmission, submissionErrors, toSubmissionValues), so the same file runs over the SDK in
9
- // Astro/React and over REST on a static page.
10
- //
11
- // SSR-friendly: pass a server-fetched FormDto as `initialForm` and no client fetch happens;
12
- // `start()` then does nothing. Without it `start()` loads the schema. One store per mounted form:
13
- // createFormStore(), not a singleton — a page can hold two forms.
14
- import { getForm } from "./forms";
15
- import {
16
- createSubmission,
17
- normalizePhone,
18
- submissionErrors,
19
- toSubmissionValues,
20
- uploadFiles,
21
- } from "./submissions";
22
- import type { FormDto, FormErrors, FormFieldDto, FormValues } from "./types";
23
-
24
- /**
25
- * The key in `errors` for a message that belongs to the FORM rather than one field — a schema
26
- * that failed to load, or a rejection with no per-field violations. `@` cannot appear in a
27
- * form `target`, so this never collides with a field's own error.
28
- */
29
- export const FORM_ERROR = "@form";
30
-
31
- /** The empty form: every field at a value of the shape its control binds to. */
32
- export function defaultValues(fields: FormFieldDto[]): FormValues {
33
- const values: FormValues = {};
34
- for (const f of fields) values[f.target] = Array.isArray(f.defaultValue) ? [...f.defaultValue] : f.defaultValue;
35
- return values;
36
- }
37
-
38
- /**
39
- * Check one field's value against its own schema. A plain function — usable outside the store,
40
- * and the place to look when a message needs rewording.
41
- *
42
- * Every rule comes from the schema, never from a field's NAME. (The classic mistake is keying
43
- * the email check on `target === "email"`; deriving it from `format` means an owner-added
44
- * PHONE/URL/length rule is honored with no code change.)
45
- *
46
- * A client check LAXER than the server's is worse than none — the visitor then learns about
47
- * the problem only after a round trip, in the server's wording rather than yours.
48
- */
49
- export function validateValue(field: FormFieldDto, value: unknown): string {
50
- const v = String(value ?? "").trim();
51
- const rules = field.validation;
52
-
53
- if (field.required && !v) return `${field.label} is required.`;
54
- if (!v) return ""; // optional and empty → fine
55
-
56
- if (field.control === "number" || field.control === "rating") {
57
- // The control hands back a string, so parse before comparing: "9" > 10 is false but
58
- // "9" > "10" is true.
59
- const n = Number(v);
60
- if (!Number.isFinite(n)) return `${field.label} must be a number.`;
61
- if (rules.minimum != null && n < rules.minimum) return `${field.label} must be ${rules.minimum} or more.`;
62
- if (rules.maximum != null && n > rules.maximum) return `${field.label} must be ${rules.maximum} or less.`;
63
- return "";
64
- }
65
-
66
- if (rules.minLength && v.length < rules.minLength)
67
- return `${field.label} must be at least ${rules.minLength} characters.`;
68
- if (rules.maxLength && v.length > rules.maxLength)
69
- return `${field.label} must be at most ${rules.maxLength} characters.`;
70
- if (rules.format === "EMAIL" && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v))
71
- return "Please enter a valid email address.";
72
- if (rules.format === "URL" && !/^https?:\/\/.+/.test(v)) return "Please enter a valid URL.";
73
- // PHONE is E.164 server-side: leading +, country code, digits. Strip formatting first —
74
- // visitors add spaces, dashes and parens, and rejecting those is a UX bug, not validation.
75
- if (rules.format === "PHONE" && !/^\+[1-9]\d{6,14}$/.test(normalizePhone(v)))
76
- return "Use international format, starting with + and the country code.";
77
- if (rules.pattern && !new RegExp(rules.pattern).test(v))
78
- return `${field.label} is not in the expected format.`;
79
- return "";
80
- }
81
-
82
- /**
83
- * One field's error entries, keyed the way the controls are named. A plain field yields at most
84
- * one (`target`); an ADDRESS yields one per failing subfield (`target/sub`).
85
- *
86
- * An address subfield gets the `required` check only — `country` and `subdivision` are
87
- * country-dependent enums the schema does not enumerate, so their content is the server's call.
88
- */
89
- export function errorsForField(field: FormFieldDto, values: FormValues): FormErrors {
90
- const errors: FormErrors = {};
91
-
92
- if (field.control === "address") {
93
- const parts = (values[field.target] ?? {}) as Record<string, unknown>;
94
- for (const { sub, label, required } of field.addressParts) {
95
- if (required && !String(parts[sub] ?? "").trim()) errors[`${field.target}/${sub}`] = `${label} is required.`;
96
- }
97
- return errors;
98
- }
99
-
100
- if (field.control === "file" || field.control === "signature") {
101
- // Files are File objects, which no string rule can judge — check the count instead.
102
- const picked = ([] as unknown[]).concat(values[field.target] ?? []).filter(Boolean);
103
- const limit = field.validation.fileLimit;
104
- if (field.required && !picked.length) errors[field.target] = `${field.label} is required.`;
105
- else if (limit && picked.length > limit)
106
- errors[field.target] = `Attach at most ${limit} file${limit === 1 ? "" : "s"}.`;
107
- return errors;
108
- }
109
-
110
- if (field.inputType === "ARRAY") {
111
- const picked = (Array.isArray(values[field.target]) ? (values[field.target] as unknown[]) : []).filter(Boolean);
112
- const { minItems, maxItems } = field.validation;
113
- if (field.required && !picked.length) errors[field.target] = `${field.label} is required.`;
114
- else if (minItems && picked.length < minItems) errors[field.target] = `Choose at least ${minItems}.`;
115
- else if (maxItems && picked.length > maxItems) errors[field.target] = `Choose at most ${maxItems}.`;
116
- return errors;
117
- }
118
-
119
- if (field.control === "checkbox") {
120
- if (field.required && values[field.target] !== true) errors[field.target] = `${field.label} is required.`;
121
- return errors;
122
- }
123
-
124
- const message = validateValue(field, values[field.target]);
125
- if (message) errors[field.target] = message;
126
- return errors;
127
- }
128
-
129
- export function errorsForForm(fields: FormFieldDto[], values: FormValues): FormErrors {
130
- const errors: FormErrors = {};
131
- for (const field of fields) Object.assign(errors, errorsForField(field, values));
132
- return errors;
133
- }
134
-
135
- /**
136
- * Move focus to a control by input name. `namedItem` returns a RadioNodeList for a radio or
137
- * checkbox group and an element for everything else — a guard checking only for an element
138
- * silently skips every choice group. FOCUS, not scrollIntoView: scrolling moves the viewport and
139
- * nothing else, leaving a keyboard or screen-reader user where they were.
140
- */
141
- export function focusControl(formEl: HTMLFormElement | null, name: string): void {
142
- const control = formEl?.elements?.namedItem?.(name) as unknown;
143
- const node =
144
- typeof RadioNodeList !== "undefined" && control instanceof RadioNodeList
145
- ? (control[0] as HTMLElement | undefined)
146
- : (control as HTMLElement | undefined);
147
- node?.focus?.();
148
- }
149
-
150
- export interface FormStoreOptions {
151
- /** The form to load (the seed's `formId`). Ignored when `initialForm` is given. */
152
- formId: string;
153
- /** Server-fetched form (Astro frontmatter) — skips the client fetch entirely. */
154
- initialForm?: FormDto;
155
- }
156
-
157
- /** Everything a form surface renders from. Read it with getState() or through a subscription. */
158
- export interface FormState {
159
- /** null while the schema is loading — render a skeleton, not an empty form. */
160
- form: FormDto | null;
161
- /** `target` → current value. Arrays for multi-choice and files, objects for an address. */
162
- values: FormValues;
163
- /** `target` (or `target/sub`) → a visitor-facing message; errors[FORM_ERROR] is form-level. */
164
- errors: FormErrors;
165
- /** Loading the schema, or submitting. */
166
- loading: boolean;
167
- }
168
-
169
- /** A submit event as the store needs it — a React SyntheticEvent or a native Event both fit. */
170
- export type FormSubmitEvent = { preventDefault?: () => void; currentTarget?: unknown };
171
-
172
- export interface FormStore {
173
- getState(): FormState;
174
- subscribe(listener: () => void): () => void;
175
- /** Load the schema when no `initialForm` was given. Call once when mounted. */
176
- start(): void;
177
- /** Stop reacting; drop a late schema response. */
178
- stop(): void;
179
- setValues(next: FormValues | ((prev: FormValues) => FormValues)): void;
180
- /** One field's value — what a control's change handler calls. */
181
- setValue(target: string, value: unknown): void;
182
- /** One field, one address subfield (`target/sub`), or the whole form when called with nothing. */
183
- validate(target?: string): boolean;
184
- /**
185
- * The `onSubmit` handler. Client validation in our wording first (focus lands on the first
186
- * invalid control), then uploads, then the create. Resolves TRUE when the submission was
187
- * created — that IS the success signal; the values are back at the schema's defaults.
188
- */
189
- submit(event?: FormSubmitEvent): Promise<boolean>;
190
- }
191
-
192
- export function createFormStore({ formId, initialForm }: FormStoreOptions): FormStore {
193
- let form: FormDto | null = initialForm ?? null;
194
- // The empty form to reset to after a successful submit — the schema's own defaults.
195
- let empty: FormValues = defaultValues(form?.fields ?? []);
196
- let values: FormValues = empty;
197
- let errors: FormErrors = {};
198
- let loading = !initialForm;
199
- let started = false;
200
- let generation = 0;
201
- const listeners = new Set<() => void>();
202
- let snapshot: FormState | null = null;
203
- const emit = () => { snapshot = null; for (const fn of listeners) fn(); };
204
- const fields = (): FormFieldDto[] => form?.fields ?? [];
205
-
206
- function getState(): FormState {
207
- if (snapshot) return snapshot;
208
- snapshot = { form, values, errors, loading };
209
- return snapshot;
210
- }
211
-
212
- function adopt(loaded: FormDto): void {
213
- form = loaded;
214
- // Seed the controls once the schema is in: every control is controlled from the first
215
- // render, so each target holds a value of the right shape before any of them mount.
216
- empty = defaultValues(loaded.fields);
217
- values = empty;
218
- errors = {};
219
- loading = false;
220
- emit();
221
- }
222
-
223
- function setErrors(next: FormErrors): void { errors = next; emit(); }
224
-
225
- return {
226
- getState,
227
- subscribe(fn) { listeners.add(fn); return () => listeners.delete(fn); },
228
- start() {
229
- if (started) return;
230
- started = true;
231
- if (form) return; // the SSR pass already answered this
232
- if (!formId) {
233
- loading = false;
234
- errors = { [FORM_ERROR]: "No formId — pass one from the seed's forms map." };
235
- emit();
236
- return;
237
- }
238
- const id = ++generation;
239
- loading = true;
240
- emit();
241
- getForm(formId)
242
- .then((loaded) => { if (started && generation === id) adopt(loaded); })
243
- .catch((e: unknown) => {
244
- if (!started || generation !== id) return;
245
- // Fail loudly. A form that cannot load is a setup problem — never fall back to a
246
- // hand-built form, which would drop real enquiries silently.
247
- loading = false;
248
- errors = { [FORM_ERROR]: e instanceof Error ? e.message : "Could not load the form." };
249
- emit();
250
- });
251
- },
252
- stop() { started = false; generation++; },
253
- setValues(next) {
254
- values = typeof next === "function" ? next(values) : next;
255
- emit();
256
- },
257
- setValue(target, value) {
258
- values = { ...values, [target]: value };
259
- emit();
260
- },
261
- validate(target) {
262
- if (!target) {
263
- const all = errorsForForm(fields(), values);
264
- setErrors(all);
265
- return Object.keys(all).length === 0;
266
- }
267
- const key = String(target);
268
- const field = fields().find((f) => f.target === key.split("/")[0]);
269
- if (!field) return true;
270
-
271
- // The keys this call owns, so a re-check CLEARS what it fixed as well as flagging what it
272
- // did not: one key for a plain field, or every subfield when an address itself is named.
273
- const owned = key.includes("/")
274
- ? [key]
275
- : field.control === "address"
276
- ? field.addressParts.map(({ sub }) => `${field.target}/${sub}`)
277
- : [field.target];
278
-
279
- const found = errorsForField(field, values);
280
- const next = { ...errors };
281
- for (const k of owned) {
282
- delete next[k];
283
- if (found[k]) next[k] = found[k];
284
- }
285
- setErrors(next);
286
- return owned.every((k) => !found[k]);
287
- },
288
- async submit(event) {
289
- event?.preventDefault?.();
290
- // Capture the <form> NOW: React clears currentTarget once the handler returns, so reading
291
- // it after the await below (to focus a server-rejected control) comes back null.
292
- const formEl = (event?.currentTarget ?? null) as HTMLFormElement | null;
293
- if (!form) return false;
294
- const current = form;
295
- const currentFields = current.fields;
296
-
297
- // Client pass first, so the visitor gets inline feedback in OUR wording before a round trip.
298
- const clientErrors = errorsForForm(currentFields, values);
299
- if (Object.keys(clientErrors).length) {
300
- setErrors(clientErrors);
301
- focusControl(formEl, Object.keys(clientErrors)[0]);
302
- return false;
303
- }
304
-
305
- loading = true;
306
- emit();
307
- try {
308
- // Attachments go up FIRST — a File is not something the submission API takes, and its
309
- // value is the upload URL this hands back. No file fields → nothing happens here.
310
- const uploaded = await uploadFiles(current.id, currentFields, values);
311
- values = uploaded; // keep the URLs, so a rejection on another field never re-uploads
312
- emit();
313
- await createSubmission(current.id, toSubmissionValues(currentFields, uploaded));
314
- errors = {};
315
- values = empty; // back to the schema's defaults, ready for another
316
- return true;
317
- } catch (e) {
318
- const mapped = submissionErrors(e, currentFields);
319
- if (Object.keys(mapped).length) {
320
- errors = mapped;
321
- focusControl(formEl, Object.keys(mapped)[0]);
322
- } else {
323
- errors = { [FORM_ERROR]: e instanceof Error ? e.message : "Could not send the form. Please try again." };
324
- }
325
- return false;
326
- } finally {
327
- loading = false;
328
- emit();
329
- }
330
- },
331
- };
332
- }
@@ -1,238 +0,0 @@
1
- // Form-schema rules and DTO mapping — transport-agnostic, imported by BOTH transports: ./forms.ts
2
- // (the SDK, managed Astro and React) and the REST twin in references/forms/rest/forms.ts (fetch, a
3
- // static site or a port to another language). Every rule about how a raw Form Schemas v4 entity
4
- // flattens into a FormDto lives HERE, once. A raw form may come from the SDK (`_id`) or from REST
5
- // (`id`); the mappers accept both. Imports are type-only so a strip to JS emits no imports.
6
- // docs: https://dev.wix.com/docs/api-reference/crm/forms/form-schemas/about-form-fields.md
7
- import type {
8
- FormAddressPart,
9
- FormChoice,
10
- FormControl,
11
- FormDto,
12
- FormFieldDto,
13
- FormValidation,
14
- } from "./types";
15
-
16
- /** A raw Form Schemas v4 entity as either transport returns it. */
17
- export type Raw = Record<string, any>;
18
-
19
- /** The Wix Forms app namespace. Every form this vertical touches lives here. */
20
- export const FORMS_NAMESPACE = "wix.form_app.form";
21
-
22
- const id = (raw: Raw | undefined): string => raw?._id ?? raw?.id ?? "";
23
-
24
- // A field's settings nest TWO levels deep, under blocks named after its own enums:
25
- // inputOptions.<inputType block>.<componentType block>.label
26
- // These tables resolve those names. Spelling them at a call site is one typo away from
27
- // silently reading back no label at all — which is the whole reason this file exists.
28
- const INPUT_BLOCK: Record<string, string> = {
29
- STRING: "stringOptions",
30
- NUMBER: "numberOptions",
31
- BOOLEAN: "booleanOptions",
32
- ARRAY: "arrayOptions",
33
- ADDRESS: "addressOptions",
34
- WIX_FILE: "wixFileOptions",
35
- PAYMENT: "paymentOptions",
36
- SCHEDULING: "schedulingOptions",
37
- };
38
-
39
- const COMPONENT_BLOCK: Record<string, string> = {
40
- TEXT_INPUT: "textInputOptions",
41
- NUMBER_INPUT: "numberInputOptions",
42
- RATING_INPUT: "ratingInputOptions",
43
- PHONE_INPUT: "phoneInputOptions",
44
- DATE_INPUT: "dateInputOptions",
45
- DATE_PICKER: "datePickerOptions",
46
- DATE_TIME: "dateTimeOptions",
47
- TIME_INPUT: "timeInputOptions",
48
- CHECKBOX: "checkboxOptions",
49
- CHECKBOX_GROUP: "checkboxGroupOptions",
50
- RADIO_GROUP: "radioGroupOptions",
51
- DROPDOWN: "dropdownOptions",
52
- TAGS: "tagsOptions",
53
- MULTILINE_ADDRESS: "multilineAddressOptions",
54
- FILE_UPLOAD: "fileUploadOptions",
55
- SIGNATURE: "signatureOptions",
56
- FIXED_PAYMENT: "fixedPaymentOptions",
57
- PAYMENT_INPUT: "paymentInputOptions",
58
- DONATION_INPUT: "donationInputOptions",
59
- APPOINTMENT: "appointmentOptions",
60
- SERVICES_DROPDOWN: "servicesDropdownOptions",
61
- SERVICES_CHECKBOX_GROUP: "servicesCheckboxGroupOptions",
62
- };
63
-
64
- // componentType → the control to render. Several field kinds share one component (short and
65
- // long answer are both TEXT_INPUT), so `format` and `inputType` refine it below.
66
- const CONTROL: Record<string, FormControl> = {
67
- TEXT_INPUT: "text",
68
- NUMBER_INPUT: "number",
69
- RATING_INPUT: "rating",
70
- PHONE_INPUT: "phone",
71
- DATE_INPUT: "date",
72
- DATE_PICKER: "date",
73
- DATE_TIME: "datetime",
74
- TIME_INPUT: "time",
75
- CHECKBOX: "checkbox",
76
- CHECKBOX_GROUP: "checkboxGroup",
77
- RADIO_GROUP: "radio",
78
- DROPDOWN: "select",
79
- TAGS: "tags",
80
- MULTILINE_ADDRESS: "address",
81
- FILE_UPLOAD: "file",
82
- SIGNATURE: "signature",
83
- FIXED_PAYMENT: "payment",
84
- PAYMENT_INPUT: "payment",
85
- DONATION_INPUT: "payment",
86
- SERVICES_DROPDOWN: "select",
87
- SERVICES_CHECKBOX_GROUP: "checkboxGroup",
88
- APPOINTMENT: "appointment",
89
- };
90
-
91
- // An enum missing from a table means Wix added a type. Say so ONCE — a silent empty block
92
- // renders a field labelled by its storage key with none of its settings.
93
- const warned = new Set<string>();
94
- function blockName(table: Record<string, string>, key: string | undefined, what: string): string | undefined {
95
- const name = key ? table[key] : undefined;
96
- if (!name && key && !warned.has(what + key)) {
97
- warned.add(what + key);
98
- console.warn(
99
- `forms: no ${what} block mapped for "${key}" — that field renders without its label or ` +
100
- `options. Add it to the table in wix/forms/forms-core.ts.`,
101
- );
102
- }
103
- return name;
104
- }
105
-
106
- /** A BOOLEAN consent field labels itself with Ricos rich content; take its plain text. */
107
- export function plainText(label: unknown): string {
108
- if (typeof label === "string") return label;
109
- const nodes = (label as Raw)?.nodes;
110
- if (!Array.isArray(nodes)) return "";
111
- const walk = (list: Raw[]): string =>
112
- list
113
- .map((n) => (n?.textData?.text ?? "") + (Array.isArray(n?.nodes) ? walk(n.nodes) : ""))
114
- .join("");
115
- return walk(nodes).trim();
116
- }
117
-
118
- /** `postalCode` → "Postal code". A subfield is a key; the schema carries no label for it. */
119
- export function humanizeSub(sub: string): string {
120
- const words = sub.replace(/([A-Z])|(\d+)/g, " $1$2").toLowerCase().trim();
121
- return words.charAt(0).toUpperCase() + words.slice(1);
122
- }
123
-
124
- export function toField(raw: Raw): FormFieldDto {
125
- const input = raw.inputOptions ?? {};
126
- const inputType: string = input.inputType ?? "";
127
- const optionsBlock: Raw = input[blockName(INPUT_BLOCK, inputType, "inputType") ?? ""] ?? {};
128
- const componentType: string = optionsBlock.componentType ?? "";
129
- const component: Raw = optionsBlock[blockName(COMPONENT_BLOCK, componentType, "componentType") ?? ""] ?? {};
130
- const rules: Raw = optionsBlock.validation ?? {};
131
-
132
- const validation: FormValidation = {
133
- ...(rules.format ? { format: rules.format } : {}),
134
- ...(rules.minLength != null ? { minLength: rules.minLength } : {}),
135
- ...(rules.maxLength != null ? { maxLength: rules.maxLength } : {}),
136
- ...(rules.pattern ? { pattern: rules.pattern } : {}),
137
- // JSON-Schema spelling everywhere else in this block; minValue/maxValue is read too since
138
- // the public reference documents neither and an older schema may carry them.
139
- ...((rules.minimum ?? rules.minValue) != null ? { minimum: rules.minimum ?? rules.minValue } : {}),
140
- ...((rules.maximum ?? rules.maxValue) != null ? { maximum: rules.maximum ?? rules.maxValue } : {}),
141
- ...(rules.fileLimit != null ? { fileLimit: rules.fileLimit } : {}),
142
- ...(rules.minItems != null ? { minItems: rules.minItems } : {}),
143
- ...(rules.maxItems != null ? { maxItems: rules.maxItems } : {}),
144
- };
145
-
146
- // TEXT_INPUT covers short answer, long answer, email, url and phone — and a long answer is
147
- // NOT flagged on the component (no `multiline`, no `numberOfLines`). Only `identifier` says
148
- // TEXT_AREA, which is why it is carried on the DTO.
149
- const identifier: string = raw.identifier ?? "";
150
- let control: FormControl = CONTROL[componentType] ?? "unknown";
151
- // A product list is a PAYMENT field wearing a CHECKBOX_GROUP component — typed by its
152
- // component it would look like a multi-choice and be bound to an array of strings, when what
153
- // it submits is a payment structure. The input type wins.
154
- if (inputType === "PAYMENT") control = "payment";
155
- if (control === "text") {
156
- if (identifier === "TEXT_AREA" || component.multiline || component.numberOfLines > 1) control = "textarea";
157
- else if (rules.format === "EMAIL") control = "email";
158
- else if (rules.format === "URL") control = "url";
159
- else if (rules.format === "PHONE") control = "phone";
160
- }
161
-
162
- const choices: FormChoice[] = Array.isArray(component.options)
163
- ? component.options.map((o: Raw) => ({ value: String(o.value), label: String(o.label ?? o.value) }))
164
- : [];
165
-
166
- const addressParts: FormAddressPart[] = Object.entries((rules.fields ?? {}) as Raw)
167
- // Only addressLine2 carries a visibility setting; hide it when the owner turned it off.
168
- .filter(([sub]) => component.fieldSettings?.[sub]?.show !== false)
169
- .map(([sub, cfg]) => ({ sub, label: humanizeSub(sub), required: (cfg as Raw)?.required ?? false }));
170
-
171
- const target: string = input.target ?? "";
172
- const label = plainText(component.label) || target;
173
-
174
- // Every control is controlled from the first render, so each field starts at a value of the
175
- // right SHAPE — [] for multi-choice and files, {} for an address, the owner's prefill else "".
176
- // Wix spells the prefill `default` on most components and `defaultValue` on a rating.
177
- const prefill = component.default ?? component.defaultValue;
178
- const defaultValue =
179
- control === "address" ? {} :
180
- inputType === "ARRAY" || inputType === "WIX_FILE" ? [] :
181
- // a consent checkbox is a BOOLEAN: "" would bind to `checked` as false and work by
182
- // accident, but the DTO promises the shape its control writes back
183
- inputType === "BOOLEAN" ? ((prefill as boolean | undefined) ?? false) :
184
- (prefill as string | number | boolean | undefined) ?? "";
185
-
186
- return {
187
- target,
188
- label,
189
- control,
190
- required: input.required ?? false,
191
- ...(component.placeholder ? { placeholder: String(component.placeholder) } : {}),
192
- ...(component.description ? { description: plainText(component.description) } : {}),
193
- defaultValue,
194
- choices,
195
- addressParts,
196
- validation,
197
- ...(component.defaultCountryCode || rules.phoneOptions?.allowedCountryCodes?.[0]
198
- ? { phoneCountry: component.defaultCountryCode ?? rules.phoneOptions.allowedCountryCodes[0] }
199
- : {}),
200
- identifier,
201
- inputType,
202
- componentType,
203
- };
204
- }
205
-
206
- /**
207
- * Display order comes from `steps[].layout`, NOT from `formFields[]` array order. Sort WITHIN
208
- * each step and concatenate in step order: `row` restarts at 0 in every step, so one sort
209
- * across the flattened list interleaves them. A field the owner never placed sorts LAST — it
210
- * still stores values. The submit button is `fieldType: "DISPLAY"`, so filtering to INPUT
211
- * drops it automatically.
212
- */
213
- export function orderedInputs(raw: Raw): Raw[] {
214
- const order = new Map<string, number>(
215
- ((raw.steps ?? []) as Raw[])
216
- .flatMap((s) =>
217
- ((s.layout?.large?.items ?? s.layout?.medium?.items ?? s.layout?.small?.items ?? []) as Raw[])
218
- .slice()
219
- .sort((a, b) => a.row - b.row || a.column - b.column),
220
- )
221
- .map((item, i) => [item.fieldId as string, i] as const),
222
- );
223
- return ((raw.formFields ?? []) as Raw[])
224
- .filter((f) => f.fieldType === "INPUT" && !f.hidden)
225
- .sort((a, b) => (order.get(a.id) ?? Infinity) - (order.get(b.id) ?? Infinity));
226
- }
227
-
228
- export function toForm(raw: Raw): FormDto {
229
- const submit = ((raw.formFields ?? []) as Raw[]).find((f) => f.identifier === "SUBMIT_BUTTON");
230
- return {
231
- id: id(raw),
232
- name: raw.name ?? "",
233
- fields: orderedInputs(raw).map(toField),
234
- // The submit wording lives on a DISPLAY field, nested under pageNavigationOptions because
235
- // one control drives both multi-page navigation and the final submit.
236
- submitText: submit?.displayOptions?.pageNavigationOptions?.submitText ?? "",
237
- };
238
- }
@@ -1,54 +0,0 @@
1
- // Wix Forms schema reads — the only file that touches a raw Form on this transport. Returns flat
2
- // FormDto / FormFieldDto from ./types. The flattening rules live in ./forms-core (shared with the
3
- // REST twin in references/forms/rest/); this file is the transport only. Copy as-is; extend by
4
- // adding functions.
5
- //
6
- // The reads go over `wixFetch` (the SDK's own authenticated fetch), NOT the `forms` module of
7
- // @wix/forms: that generated module is 15 MB. Bundled server-side it pushes a Wix deploy past its
8
- // size limit (HTTP 413 on release); bundled client-side every visitor downloads it. The
9
- // submissions module (./submissions.ts) is 100 KB and stays on the SDK.
10
- //
11
- // The visitor token is enough, and the spec says otherwise. Every schema read is listed under
12
- // the owner scope `SCOPE.FORMS.VIEW-FORM`, and returns 200 on an anonymous visitor: Wix grants
13
- // implicit visitor access so a published site can render its own forms. Do NOT add a backend, a
14
- // connector token, or auth.elevate to make a form load.
15
- //
16
- // docs: https://dev.wix.com/docs/sdk/business-solutions/forms/forms/get-form.md
17
- // docs: https://dev.wix.com/docs/sdk/business-solutions/forms/forms/list-forms.md
18
- // docs: https://dev.wix.com/docs/api-reference/crm/forms/form-schemas/about-form-fields.md
19
- import { wixFetch } from "../sdk";
20
- import { FORMS_NAMESPACE, toForm, type Raw } from "./forms-core";
21
- import type { FormDto } from "./types";
22
-
23
- export { FORMS_NAMESPACE };
24
-
25
- async function getJson(path: string): Promise<Raw> {
26
- const res = await wixFetch(path);
27
- if (!res.ok) throw new Error(`forms: GET ${path} failed (${res.status}).`);
28
- return (await res.json()) as Raw;
29
- }
30
-
31
- /**
32
- * Read one form by id. Throws when the id is wrong or the form was deleted — a form that
33
- * cannot load is a setup problem, so fail loudly rather than rendering a hand-built fallback
34
- * that would drop real enquiries silently.
35
- */
36
- export async function getForm(formId: string): Promise<FormDto> {
37
- // GET /form-schema-service/v4/forms/{formId} → { form }; 404 FORM_NOT_FOUND on a wrong id.
38
- const res = await getJson(`/form-schema-service/v4/forms/${encodeURIComponent(formId)}`);
39
- if (!res?.form) throw new Error(`forms: form "${formId}" not found.`);
40
- return toForm(res.form as Raw);
41
- }
42
-
43
- /**
44
- * Every form on the site, in the Wix Forms namespace. Use ONE call for several forms on a page
45
- * rather than a getForm each.
46
- *
47
- * Returns only ENABLED forms — a form the owner disabled vanishes from the listing rather
48
- * than erroring. That is usually right for a public site.
49
- */
50
- export async function listForms(): Promise<FormDto[]> {
51
- // GET /form-schema-service/v4/forms?namespace=… → { forms }; the namespace is required (400 without).
52
- const res = await getJson(`/form-schema-service/v4/forms?namespace=${encodeURIComponent(FORMS_NAMESPACE)}`);
53
- return ((res?.forms ?? []) as Raw[]).map(toForm);
54
- }