@wix/agent-skills 1.15.1 → 1.16.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 (322) hide show
  1. package/README.md +3 -7
  2. package/package.json +1 -1
  3. package/skills/wix-app/SKILL.md +4 -1
  4. package/skills/wix-app/references/APP_TOOLS.md +134 -0
  5. package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +1 -1
  6. package/skills/wix-app/references/DASHBOARD_PAGE.md +0 -10
  7. package/skills/wix-app/references/DATA_COLLECTION.md +1 -1
  8. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +28 -9
  9. package/skills/wix-app/references/SERVICE_PLUGIN.md +12 -10
  10. package/skills/wix-app/references/app-tools/TOOLS.md +75 -0
  11. package/skills/wix-app/references/dashboard-page/DASHBOARD_API.md +2 -2
  12. package/skills/wix-app/references/editor-react-component/A11Y-REVIEW-REFERENCE.md +172 -0
  13. package/skills/wix-app/references/editor-react-component/A11Y-REVIEW.md +138 -0
  14. package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +23 -2
  15. package/skills/wix-app/references/editor-react-component/BRANDED-COMPONENTS.md +29 -0
  16. package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +1 -1
  17. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +27 -2
  18. package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +5 -3
  19. package/skills/wix-app/references/editor-react-component/DIRECTIONALITY.md +18 -1
  20. package/skills/wix-app/references/editor-react-component/PARTS.md +15 -2
  21. package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +2 -3
  22. package/skills/wix-app/references/service-plugin/BOOKINGS-STAFF-SORTING.md +13 -9
  23. package/skills/wix-app/references/service-plugin/DISCOUNT-TRIGGERS.md +4 -0
  24. package/skills/wix-app/references/service-plugin/GIFT-CARDS.md +4 -0
  25. package/skills/wix-app/references/service-plugin/PAYMENT-SETTINGS.md +3 -1
  26. package/skills/wix-app/references/service-plugin/SHIPPING-RATES.md +4 -0
  27. package/skills/wix-app/references/service-plugin/TOOLS_PROVIDER.md +54 -0
  28. package/skills/wix-app/references/stores/QUERY.md +32 -0
  29. package/skills/wix-docs/SKILL.md +35 -3
  30. package/skills/wix-headless/SKILL.md +3 -1
  31. package/skills/wix-headless/references/CONTENT.md +36 -0
  32. package/skills/wix-headless/references/DESIGN.md +54 -0
  33. package/skills/wix-headless/references/DISCOVERY.md +24 -0
  34. package/skills/wix-headless/references/IMAGE_GENERATION.md +10 -0
  35. package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +3 -2
  36. package/skills/wix-headless/references/inline-recipes/setup-online-store.md +32 -23
  37. package/skills/wix-headless/references/managed/CONNECT.md +1 -1
  38. package/skills/wix-headless/references/managed/CREATE.md +14 -0
  39. package/skills/wix-headless/references/managed/DEPLOYMENT.md +25 -0
  40. package/skills/wix-manage/SKILL.md +123 -7
  41. package/skills/wix-manage/references/analytics/analytics-dashboard-navigation.md +41 -0
  42. package/skills/wix-manage/references/app-installation/app-installation-dashboard-navigation.md +28 -0
  43. package/skills/wix-manage/references/blog/blog-dashboard-navigation.md +56 -0
  44. package/skills/wix-manage/references/blog/how-to-create-blog-posts.md +31 -6
  45. package/skills/wix-manage/references/bookings/booking-service-policy-setup.md +3 -1
  46. package/skills/wix-manage/references/bookings/bookings-dashboard-navigation.md +63 -0
  47. package/skills/wix-manage/references/bookings/diagnose-availability-issues.md +10 -1
  48. package/skills/wix-manage/references/cms/cms-dashboard-navigation.md +44 -0
  49. package/skills/wix-manage/references/cms/cms-data-items-crud.md +31 -3
  50. package/skills/wix-manage/references/cms/cms-publishing-flow.md +287 -0
  51. package/skills/wix-manage/references/cms/cms-schema-management.md +27 -1
  52. package/skills/wix-manage/references/contacts/contacts-dashboard-navigation.md +46 -0
  53. package/skills/wix-manage/references/contacts/create-a-contact.md +82 -0
  54. package/skills/wix-manage/references/contacts/update-a-contact.md +119 -0
  55. package/skills/wix-manage/references/dashboard-navigation/dashboard-navigation.md +82 -0
  56. package/skills/wix-manage/references/dashboard-navigation/routes.json +1733 -0
  57. package/skills/wix-manage/references/domains/domains-dashboard-navigation.md +32 -0
  58. package/skills/wix-manage/references/ecommerce/ecom-pricing.md +4 -4
  59. package/skills/wix-manage/references/ecommerce/ecom-shipping.md +1 -1
  60. package/skills/wix-manage/references/ecommerce/gift-cards/ecom-gift-cards-goal-sell-gift-cards.md +338 -0
  61. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-create-discount-rule.md +42 -78
  62. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-bundle-and-save.md +1 -1
  63. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-stock-mover.md +1 -1
  64. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-upsell-boost.md +1 -1
  65. package/skills/wix-manage/references/ecommerce/recommend-ecommerce-strategy.md +90 -92
  66. package/skills/wix-manage/references/events/create-wix-event.md +176 -0
  67. package/skills/wix-manage/references/events/manage-wix-events.md +174 -0
  68. package/skills/wix-manage/references/forms/forms-dashboard-navigation.md +44 -0
  69. package/skills/wix-manage/references/get-paid/get-paid-dashboard-navigation.md +52 -0
  70. package/skills/wix-manage/references/google-ads/billing-and-payment.md +80 -0
  71. package/skills/wix-manage/references/google-ads/create-performance-max-campaign.md +212 -0
  72. package/skills/wix-manage/references/google-ads/get-campaign-suggestions.md +110 -0
  73. package/skills/wix-manage/references/google-ads/google-ads-dashboard-navigation.md +25 -0
  74. package/skills/wix-manage/references/google-ads/install-and-create-account.md +155 -0
  75. package/skills/wix-manage/references/google-ads/manage-campaign-lifecycle.md +63 -0
  76. package/skills/wix-manage/references/google-ads/query-campaign-analytics.md +155 -0
  77. package/skills/wix-manage/references/marketing/marketing-dashboard-navigation.md +52 -0
  78. package/skills/wix-manage/references/pricing-plans/create-and-update-pricing-plans.md +99 -1
  79. package/skills/wix-manage/references/pricing-plans/pricing-plans-dashboard-navigation.md +45 -0
  80. package/skills/wix-manage/references/restaurants/restaurants-dashboard-navigation.md +68 -0
  81. package/skills/wix-manage/references/restaurants/wix-restaurants-setup.md +94 -125
  82. package/skills/wix-manage/references/site-properties/change-payment-currency-site-properties.md +48 -9
  83. package/skills/wix-manage/references/site-properties/site-properties-dashboard-navigation.md +31 -0
  84. package/skills/wix-manage/references/sites/create-headless-site.md +52 -0
  85. package/skills/wix-manage/references/sites/create-site-from-template.md +2 -25
  86. package/skills/wix-manage/references/sites/site-import.md +163 -190
  87. package/skills/wix-manage/references/sites/sites-dashboard-navigation.md +29 -0
  88. package/skills/wix-manage/references/stores/add-store-pages-to-site.md +17 -1
  89. package/skills/wix-manage/references/stores/find-products-query-and-search-catalog-v3.md +26 -8
  90. package/skills/wix-manage/references/stores/stores-dashboard-navigation.md +65 -0
  91. package/skills/wix-manage/references/stores/update-product-with-options.md +39 -7
  92. package/skills/wix-replatform/.publish-manifest.json +8 -0
  93. package/skills/wix-replatform/SKILL.md +693 -0
  94. package/skills/wix-replatform/lib/artifact-freshness.js +215 -0
  95. package/skills/wix-replatform/lib/completion-report.js +200 -0
  96. package/skills/wix-replatform/lib/config-env.js +59 -0
  97. package/skills/wix-replatform/lib/execution-manifest.js +185 -0
  98. package/skills/wix-replatform/lib/execution-state.js +173 -0
  99. package/skills/wix-replatform/lib/import-recovery.js +313 -0
  100. package/skills/wix-replatform/lib/local-state.js +642 -0
  101. package/skills/wix-replatform/lib/orchestration-preflight.js +143 -0
  102. package/skills/wix-replatform/lib/orchestration-router.js +122 -0
  103. package/skills/wix-replatform/lib/orchestration-state.js +455 -0
  104. package/skills/wix-replatform/lib/progress-log.js +224 -0
  105. package/skills/wix-replatform/lib/progress-log.sh +140 -0
  106. package/skills/wix-replatform/lib/url-preservation-state.js +391 -0
  107. package/skills/wix-replatform/resources/rp-discovery/SKILL.md +184 -0
  108. package/skills/wix-replatform/resources/rp-execute-import/SKILL.md +529 -0
  109. package/skills/wix-replatform/resources/rp-execute-setup/SKILL.md +316 -0
  110. package/skills/wix-replatform/resources/rp-execute-setup/scripts/mint-token.sh +64 -0
  111. package/skills/wix-replatform/resources/rp-import-codegen/SKILL.md +1114 -0
  112. package/skills/wix-replatform/resources/rp-mapper/SKILL.md +430 -0
  113. package/skills/wix-replatform/resources/rp-mapper/lib/mapping-resolve.js +217 -0
  114. package/skills/wix-replatform/resources/rp-mapper/scripts/resolve-mapping.js +148 -0
  115. package/skills/wix-replatform/resources/rp-mapper/wix-business-solutions-taxonomy.md +378 -0
  116. package/skills/wix-replatform/resources/rp-setup-discovery/SKILL.md +183 -0
  117. package/skills/wix-replatform/resources/rp-source-csv/SKILL.md +478 -0
  118. package/skills/wix-replatform/resources/rp-source-csv/lib/canonical-record.js +136 -0
  119. package/skills/wix-replatform/resources/rp-source-csv/lib/csv-fileset.js +0 -0
  120. package/skills/wix-replatform/resources/rp-source-csv/lib/csv-fingerprint.js +310 -0
  121. package/skills/wix-replatform/resources/rp-source-csv/lib/csv-layout.js +1081 -0
  122. package/skills/wix-replatform/resources/rp-source-csv/lib/csv-parse.js +618 -0
  123. package/skills/wix-replatform/resources/rp-source-csv/scripts/csv-discovery.js +949 -0
  124. package/skills/wix-replatform/resources/rp-source-csv/source-schema.example.json +196 -0
  125. package/skills/wix-replatform/resources/rp-source-csv/vendors/bigcommerce.json +66 -0
  126. package/skills/wix-replatform/resources/rp-source-csv/vendors/magento.json +60 -0
  127. package/skills/wix-replatform/resources/rp-source-csv/vendors/shopify.json +95 -0
  128. package/skills/wix-replatform/resources/rp-source-csv/vendors/woocommerce.json +82 -0
  129. package/skills/wix-replatform/resources/rp-source-wordpress/SKILL.md +256 -0
  130. package/skills/wix-replatform/resources/rp-source-wordpress/lib/wp-http.js +249 -0
  131. package/skills/wix-replatform/resources/rp-source-wordpress/lib/wp-route-classifier.js +444 -0
  132. package/skills/wix-replatform/resources/rp-source-wordpress/scripts/wp-discovery.js +774 -0
  133. package/skills/wix-replatform/resources/rp-source-wordpress/source-schema.example.json +71 -0
  134. package/skills/wix-replatform/resources/rp-target-wix/SKILL.md +632 -0
  135. package/skills/wix-replatform/resources/rp-target-wix/SPEC-product-reviews-and-blog-authorship.md +330 -0
  136. package/skills/wix-replatform/resources/rp-target-wix/domains/README.md +21 -0
  137. package/skills/wix-replatform/resources/rp-target-wix/domains/blog/domain.json +19 -0
  138. package/skills/wix-replatform/resources/rp-target-wix/domains/blog/entities/category.json +37 -0
  139. package/skills/wix-replatform/resources/rp-target-wix/domains/blog/entities/comment.json +37 -0
  140. package/skills/wix-replatform/resources/rp-target-wix/domains/blog/entities/post.json +39 -0
  141. package/skills/wix-replatform/resources/rp-target-wix/domains/blog/entities/tag.json +35 -0
  142. package/skills/wix-replatform/resources/rp-target-wix/domains/cms/domain.json +14 -0
  143. package/skills/wix-replatform/resources/rp-target-wix/domains/cms/entities/collection.json +35 -0
  144. package/skills/wix-replatform/resources/rp-target-wix/domains/cms/entities/data-item.json +36 -0
  145. package/skills/wix-replatform/resources/rp-target-wix/domains/cms/entities/reference.json +35 -0
  146. package/skills/wix-replatform/resources/rp-target-wix/domains/crm/domain.json +14 -0
  147. package/skills/wix-replatform/resources/rp-target-wix/domains/crm/entities/contact.json +131 -0
  148. package/skills/wix-replatform/resources/rp-target-wix/domains/crm/entities/email-subscription.json +37 -0
  149. package/skills/wix-replatform/resources/rp-target-wix/domains/crm/entities/label.json +37 -0
  150. package/skills/wix-replatform/resources/rp-target-wix/domains/ecom/domain.json +21 -0
  151. package/skills/wix-replatform/resources/rp-target-wix/domains/ecom/entities/order-line-item.json +37 -0
  152. package/skills/wix-replatform/resources/rp-target-wix/domains/ecom/entities/order-refund.json +37 -0
  153. package/skills/wix-replatform/resources/rp-target-wix/domains/ecom/entities/order.json +97 -0
  154. package/skills/wix-replatform/resources/rp-target-wix/domains/index.json +528 -0
  155. package/skills/wix-replatform/resources/rp-target-wix/domains/media/domain.json +14 -0
  156. package/skills/wix-replatform/resources/rp-target-wix/domains/media/entities/media-file.json +38 -0
  157. package/skills/wix-replatform/resources/rp-target-wix/domains/media/entities/media-folder.json +37 -0
  158. package/skills/wix-replatform/resources/rp-target-wix/domains/members/domain.json +13 -0
  159. package/skills/wix-replatform/resources/rp-target-wix/domains/members/entities/badge.json +37 -0
  160. package/skills/wix-replatform/resources/rp-target-wix/domains/members/entities/member.json +53 -0
  161. package/skills/wix-replatform/resources/rp-target-wix/domains/schema.json +84 -0
  162. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/domain.json +25 -0
  163. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/category.json +37 -0
  164. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/coupon.json +37 -0
  165. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/inventory-item.json +38 -0
  166. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/product-tag.json +37 -0
  167. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/product.json +90 -0
  168. package/skills/wix-replatform/resources/rp-target-wix/lib/audit-summary.js +64 -0
  169. package/skills/wix-replatform/resources/rp-target-wix/lib/contract-ledger.js +141 -0
  170. package/skills/wix-replatform/resources/rp-target-wix/lib/domain-knowledge.js +384 -0
  171. package/skills/wix-replatform/resources/rp-target-wix/lib/ndjson.js +260 -0
  172. package/skills/wix-replatform/resources/rp-target-wix/lib/stores-verification.js +238 -0
  173. package/skills/wix-replatform/resources/rp-target-wix/lib/wix-build.js +237 -0
  174. package/skills/wix-replatform/resources/rp-target-wix/lib/wix-target-spec.js +238 -0
  175. package/skills/wix-replatform/resources/rp-target-wix/lib/wix-writers.js +2219 -0
  176. package/skills/wix-replatform/resources/rp-target-wix/scripts/domain-knowledge-validate.js +31 -0
  177. package/skills/wix-replatform/resources/rp-target-wix/scripts/domain-knowledge.js +100 -0
  178. package/skills/wix-replatform/resources/rp-target-wix/scripts/verify-stores.js +107 -0
  179. package/skills/wix-replatform/resources/rp-telemetry/SKILL.md +344 -0
  180. package/skills/wix-replatform/resources/rp-telemetry/lib/bi-sink.js +250 -0
  181. package/skills/wix-replatform/resources/rp-telemetry/lib/telemetry-recorder.js +1927 -0
  182. package/skills/wix-replatform/resources/rp-telemetry/scripts/meter-from-audit.js +83 -0
  183. package/skills/wix-replatform/resources/rp-telemetry/scripts/rp-telemetry.js +141 -0
  184. package/skills/wix-replatform/scripts/artifact-freshness.js +76 -0
  185. package/skills/wix-replatform/scripts/execution-manifest-validate.js +43 -0
  186. package/skills/wix-replatform/scripts/execution-state-prepare.js +128 -0
  187. package/skills/wix-replatform/scripts/orchestration-preflight.js +48 -0
  188. package/skills/wix-replatform/scripts/orchestration-route.js +46 -0
  189. package/skills/wix-replatform/scripts/orchestration-state.js +245 -0
  190. package/skills/wix-vibe-headless/SKILL.md +48 -25
  191. package/skills/wix-vibe-headless/install/deploy.cjs +95 -0
  192. package/skills/wix-vibe-headless/install/pin-agents-md.cjs +34 -0
  193. package/skills/wix-vibe-headless/platforms/README.md +8 -4
  194. package/skills/wix-vibe-headless/platforms/base44.md +133 -98
  195. package/skills/wix-vibe-headless/platforms/generic.md +99 -64
  196. package/skills/wix-vibe-headless/references/blog/INSTRUCTIONS.md +230 -119
  197. package/skills/wix-vibe-headless/references/blog/app/components/PostCard.jsx +43 -0
  198. package/skills/wix-vibe-headless/references/blog/app/components/PostChips.jsx +25 -0
  199. package/skills/wix-vibe-headless/references/blog/app/components/PostGrid.jsx +15 -0
  200. package/skills/wix-vibe-headless/references/blog/app/context/TaxonomyContext.jsx +35 -0
  201. package/skills/wix-vibe-headless/references/blog/app/hooks/usePostDetail.js +38 -0
  202. package/skills/wix-vibe-headless/references/blog/app/pages/Blog.jsx +40 -0
  203. package/skills/wix-vibe-headless/references/blog/app/pages/CategoryPage.jsx +54 -0
  204. package/skills/wix-vibe-headless/references/blog/app/pages/PostDetail.jsx +65 -0
  205. package/skills/wix-vibe-headless/references/blog/app/pages/TagPage.jsx +50 -0
  206. package/skills/wix-vibe-headless/references/blog/seed/SEED.md +103 -0
  207. package/skills/wix-vibe-headless/references/blog/seed/seed-blog.js +270 -0
  208. package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +260 -149
  209. package/skills/wix-vibe-headless/references/bookings/app/components/BookingForm.jsx +65 -0
  210. package/skills/wix-vibe-headless/references/bookings/app/components/ServiceCard.jsx +47 -0
  211. package/skills/wix-vibe-headless/references/bookings/app/components/ServiceGrid.jsx +13 -0
  212. package/skills/wix-vibe-headless/references/bookings/app/components/SlotPicker.jsx +126 -0
  213. package/skills/wix-vibe-headless/references/bookings/app/hooks/useServiceDetail.js +108 -0
  214. package/skills/wix-vibe-headless/references/bookings/app/hooks/useServices.js +58 -0
  215. package/skills/wix-vibe-headless/references/bookings/app/lib/serviceFacts.js +95 -0
  216. package/skills/wix-vibe-headless/references/bookings/app/pages/ServiceDetail.jsx +94 -0
  217. package/skills/wix-vibe-headless/references/bookings/app/pages/Services.jsx +89 -0
  218. package/skills/wix-vibe-headless/references/bookings/{wix-bookings-checkout.js → app/rest/wix-bookings-checkout.js} +1 -1
  219. package/skills/wix-vibe-headless/references/bookings/{wix-bookings-services.js → app/rest/wix-bookings-services.js} +87 -11
  220. package/skills/wix-vibe-headless/references/bookings/seed/SEED.md +117 -0
  221. package/skills/wix-vibe-headless/references/bookings/seed/seed-bookings.js +333 -0
  222. package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +169 -147
  223. package/skills/wix-vibe-headless/references/cms/app/collection.config.js +31 -0
  224. package/skills/wix-vibe-headless/references/cms/app/lib/wixImage.js +18 -0
  225. package/skills/wix-vibe-headless/references/cms/{wix-cms.js → app/rest/wix-cms.js} +47 -2
  226. package/skills/wix-vibe-headless/references/cms/seed/SEED.md +145 -0
  227. package/skills/wix-vibe-headless/references/events/INSTRUCTIONS.md +228 -131
  228. package/skills/wix-vibe-headless/references/events/app/components/CategoryFilter.jsx +23 -0
  229. package/skills/wix-vibe-headless/references/events/app/components/EventCard.jsx +43 -0
  230. package/skills/wix-vibe-headless/references/events/app/components/EventGrid.jsx +13 -0
  231. package/skills/wix-vibe-headless/references/events/app/components/EventRegistration.jsx +29 -0
  232. package/skills/wix-vibe-headless/references/events/app/components/RsvpForm.jsx +57 -0
  233. package/skills/wix-vibe-headless/references/events/app/components/TicketPicker.jsx +78 -0
  234. package/skills/wix-vibe-headless/references/events/app/hooks/useEventDetail.js +27 -0
  235. package/skills/wix-vibe-headless/references/events/app/hooks/useEventsList.js +54 -0
  236. package/skills/wix-vibe-headless/references/events/app/hooks/useRsvpForm.js +40 -0
  237. package/skills/wix-vibe-headless/references/events/app/hooks/useTicketing.js +81 -0
  238. package/skills/wix-vibe-headless/references/events/app/pages/EventDetail.jsx +48 -0
  239. package/skills/wix-vibe-headless/references/events/app/pages/Events.jsx +36 -0
  240. package/skills/wix-vibe-headless/references/events/{wix-events-browse.js → app/rest/wix-events-browse.js} +1 -1
  241. package/skills/wix-vibe-headless/references/events/seed/SEED.md +107 -0
  242. package/skills/wix-vibe-headless/references/events/seed/seed-events.js +251 -0
  243. package/skills/wix-vibe-headless/references/members/INSTRUCTIONS.md +276 -188
  244. package/skills/wix-vibe-headless/references/members/app/components/LoginForm.jsx +101 -0
  245. package/skills/wix-vibe-headless/references/members/app/components/MemberMenu.jsx +33 -0
  246. package/skills/wix-vibe-headless/references/members/app/components/RequireAuth.jsx +21 -0
  247. package/skills/wix-vibe-headless/references/members/app/components/SocialButtons.jsx +29 -0
  248. package/skills/wix-vibe-headless/references/members/app/context/MemberContext.jsx +54 -0
  249. package/skills/wix-vibe-headless/references/members/app/hooks/useLoginForm.js +77 -0
  250. package/skills/wix-vibe-headless/references/members/app/pages/Account.jsx +36 -0
  251. package/skills/wix-vibe-headless/references/members/app/pages/Callback.jsx +32 -0
  252. package/skills/wix-vibe-headless/references/members/app/pages/Login.jsx +35 -0
  253. package/skills/wix-vibe-headless/references/members/{wix-members-auth.js → app/rest/wix-members-auth.js} +6 -3
  254. package/skills/wix-vibe-headless/references/members/install/Register.jsx +22 -0
  255. package/skills/wix-vibe-headless/references/members/seed/SEED.md +22 -0
  256. package/skills/wix-vibe-headless/references/portfolio/INSTRUCTIONS.md +233 -104
  257. package/skills/wix-vibe-headless/references/portfolio/app/components/CollectionCard.jsx +31 -0
  258. package/skills/wix-vibe-headless/references/portfolio/app/components/CollectionGrid.jsx +15 -0
  259. package/skills/wix-vibe-headless/references/portfolio/app/components/ProjectCard.jsx +39 -0
  260. package/skills/wix-vibe-headless/references/portfolio/app/components/ProjectGrid.jsx +15 -0
  261. package/skills/wix-vibe-headless/references/portfolio/app/components/ProjectMedia.jsx +29 -0
  262. package/skills/wix-vibe-headless/references/portfolio/app/hooks/useCollectionProjects.js +35 -0
  263. package/skills/wix-vibe-headless/references/portfolio/app/hooks/usePortfolioGallery.js +27 -0
  264. package/skills/wix-vibe-headless/references/portfolio/app/hooks/useProjectDetail.js +25 -0
  265. package/skills/wix-vibe-headless/references/portfolio/app/pages/CollectionPage.jsx +39 -0
  266. package/skills/wix-vibe-headless/references/portfolio/app/pages/Portfolio.jsx +27 -0
  267. package/skills/wix-vibe-headless/references/portfolio/app/pages/ProjectDetail.jsx +60 -0
  268. package/skills/wix-vibe-headless/references/portfolio/seed/SEED.md +94 -0
  269. package/skills/wix-vibe-headless/references/portfolio/seed/seed-portfolio.js +236 -0
  270. package/skills/wix-vibe-headless/references/pricing-plans/INSTRUCTIONS.md +240 -117
  271. package/skills/wix-vibe-headless/references/pricing-plans/app/components/OrderCard.jsx +35 -0
  272. package/skills/wix-vibe-headless/references/pricing-plans/app/components/PlanCard.jsx +48 -0
  273. package/skills/wix-vibe-headless/references/pricing-plans/app/components/PlanGrid.jsx +16 -0
  274. package/skills/wix-vibe-headless/references/pricing-plans/app/components/PlanPrice.jsx +35 -0
  275. package/skills/wix-vibe-headless/references/pricing-plans/app/hooks/useMyPlans.js +25 -0
  276. package/skills/wix-vibe-headless/references/pricing-plans/app/hooks/usePlanDetail.js +28 -0
  277. package/skills/wix-vibe-headless/references/pricing-plans/app/hooks/usePlans.js +30 -0
  278. package/skills/wix-vibe-headless/references/pricing-plans/app/pages/MyPlans.jsx +30 -0
  279. package/skills/wix-vibe-headless/references/pricing-plans/app/pages/PlanDetail.jsx +53 -0
  280. package/skills/wix-vibe-headless/references/pricing-plans/app/pages/Plans.jsx +28 -0
  281. package/skills/wix-vibe-headless/references/pricing-plans/seed/SEED.md +86 -0
  282. package/skills/wix-vibe-headless/references/pricing-plans/seed/seed-pricing-plans.js +251 -0
  283. package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +248 -124
  284. package/skills/wix-vibe-headless/references/restaurants/app/components/ItemDialog.jsx +81 -0
  285. package/skills/wix-vibe-headless/references/restaurants/app/components/MenuItemCard.jsx +71 -0
  286. package/skills/wix-vibe-headless/references/restaurants/app/components/MenuList.jsx +43 -0
  287. package/skills/wix-vibe-headless/references/restaurants/app/components/OrderCartButton.jsx +21 -0
  288. package/skills/wix-vibe-headless/references/restaurants/app/components/OrderCartDrawer.jsx +60 -0
  289. package/skills/wix-vibe-headless/references/restaurants/app/context/OrderCartContext.jsx +63 -0
  290. package/skills/wix-vibe-headless/references/restaurants/app/hooks/useItemOrder.js +32 -0
  291. package/skills/wix-vibe-headless/references/restaurants/app/hooks/useReservation.js +73 -0
  292. package/skills/wix-vibe-headless/references/restaurants/app/pages/Menu.jsx +28 -0
  293. package/skills/wix-vibe-headless/references/restaurants/app/pages/Reservations.jsx +102 -0
  294. package/skills/wix-vibe-headless/references/restaurants/seed/SEED.md +180 -0
  295. package/skills/wix-vibe-headless/references/restaurants/seed/seed-restaurants.js +452 -0
  296. package/skills/wix-vibe-headless/references/shared/app/components/WixManageBanner.jsx +56 -0
  297. package/skills/wix-vibe-headless/references/shared/{wix-client.js → app/rest/wix-client.js} +6 -8
  298. package/skills/wix-vibe-headless/references/shared/app/rest/wix-config.js +6 -0
  299. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +263 -157
  300. package/skills/wix-vibe-headless/references/storefront/app/components/CartButton.jsx +20 -0
  301. package/skills/wix-vibe-headless/references/storefront/app/components/CartDrawer.jsx +150 -0
  302. package/skills/wix-vibe-headless/references/storefront/app/components/ProductCard.jsx +167 -0
  303. package/skills/wix-vibe-headless/references/storefront/app/components/ProductGallery.jsx +51 -0
  304. package/skills/wix-vibe-headless/references/storefront/app/components/ProductGrid.jsx +54 -0
  305. package/skills/wix-vibe-headless/references/storefront/app/components/VariantPicker.jsx +119 -0
  306. package/skills/wix-vibe-headless/references/storefront/app/context/CartContext.jsx +71 -0
  307. package/skills/wix-vibe-headless/references/storefront/app/hooks/useProductDetail.js +109 -0
  308. package/skills/wix-vibe-headless/references/storefront/app/hooks/useShop.js +98 -0
  309. package/skills/wix-vibe-headless/references/storefront/app/lib/storeImage.js +27 -0
  310. package/skills/wix-vibe-headless/references/storefront/app/pages/ProductDetail.jsx +139 -0
  311. package/skills/wix-vibe-headless/references/storefront/app/pages/Shop.jsx +75 -0
  312. package/skills/wix-vibe-headless/references/storefront/{wix-store-cart.js → app/rest/wix-store-cart.js} +1 -1
  313. package/skills/wix-vibe-headless/references/storefront/{wix-store-catalog.js → app/rest/wix-store-catalog.js} +20 -1
  314. package/skills/wix-vibe-headless/references/storefront/seed/SEED.md +111 -0
  315. package/skills/wix-vibe-headless/references/storefront/seed/seed-store.js +299 -0
  316. /package/skills/wix-vibe-headless/references/blog/{wix-blog.js → app/rest/wix-blog.js} +0 -0
  317. /package/skills/wix-vibe-headless/references/events/{wix-events-registration.js → app/rest/wix-events-registration.js} +0 -0
  318. /package/skills/wix-vibe-headless/references/portfolio/{wix-portfolio.js → app/rest/wix-portfolio.js} +0 -0
  319. /package/skills/wix-vibe-headless/references/pricing-plans/{wix-pricing-plans.js → app/rest/wix-pricing-plans.js} +0 -0
  320. /package/skills/wix-vibe-headless/references/restaurants/{wix-restaurants-menu.js → app/rest/wix-restaurants-menu.js} +0 -0
  321. /package/skills/wix-vibe-headless/references/restaurants/{wix-restaurants-ordering.js → app/rest/wix-restaurants-ordering.js} +0 -0
  322. /package/skills/wix-vibe-headless/references/restaurants/{wix-restaurants-reservations.js → app/rest/wix-restaurants-reservations.js} +0 -0
@@ -0,0 +1,642 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs/promises');
4
+ const path = require('node:path');
5
+
6
+ const SCHEMA_VERSION = 1;
7
+
8
+ const CROSSWALK_STATUS = new Set(['imported']);
9
+ const ATTEMPT_STATUS = new Set([
10
+ 'started',
11
+ 'succeeded_unverified',
12
+ 'imported',
13
+ 'failed_retryable',
14
+ 'failed_terminal',
15
+ 'deferred',
16
+ 'needs_verification',
17
+ 'skipped_already_imported',
18
+ 'skipped_safe_mode_blocked',
19
+ ]);
20
+
21
+ function stateDir(projectDir) {
22
+ return path.join(projectDir, 'state');
23
+ }
24
+
25
+ function crosswalkDir(projectDir) {
26
+ return path.join(stateDir(projectDir), 'crosswalk');
27
+ }
28
+
29
+ function crosswalkPath(projectDir) {
30
+ return path.join(crosswalkDir(projectDir), 'crosswalk.ndjson');
31
+ }
32
+
33
+ function crosswalkIndexDir(projectDir) {
34
+ return path.join(crosswalkDir(projectDir), 'indexes');
35
+ }
36
+
37
+ function attemptsDir(projectDir) {
38
+ return path.join(stateDir(projectDir), 'attempts');
39
+ }
40
+
41
+ function attemptJournalPath(projectDir) {
42
+ return path.join(attemptsDir(projectDir), 'write-attempts.ndjson');
43
+ }
44
+
45
+ function wixRequestCapturesPath(projectDir) {
46
+ return path.join(attemptsDir(projectDir), 'wix-request-captures.ndjson');
47
+ }
48
+
49
+ function cmsMirrorDir(projectDir) {
50
+ return path.join(stateDir(projectDir), 'cms-mirror');
51
+ }
52
+
53
+ function safeModeDir(projectDir) {
54
+ return path.join(stateDir(projectDir), 'safe-mode');
55
+ }
56
+
57
+ function safeModeEmailReplacementsPath(projectDir) {
58
+ return path.join(safeModeDir(projectDir), 'email-replacements.ndjson');
59
+ }
60
+
61
+ function safeModeBlockedRecordsPath(projectDir) {
62
+ return path.join(safeModeDir(projectDir), 'blocked-records.ndjson');
63
+ }
64
+
65
+ function dryRunCrosswalkPath(projectDir) {
66
+ return path.join(crosswalkDir(projectDir), 'dry-run-crosswalk.ndjson');
67
+ }
68
+
69
+ async function mkdirp(dirPath) {
70
+ await fs.mkdir(dirPath, { recursive: true });
71
+ }
72
+
73
+ async function pathExists(filePath) {
74
+ try {
75
+ await fs.access(filePath);
76
+ return true;
77
+ } catch (error) {
78
+ if (error && error.code === 'ENOENT') {
79
+ return false;
80
+ }
81
+ throw error;
82
+ }
83
+ }
84
+
85
+ async function writeJsonAtomic(filePath, data) {
86
+ await mkdirp(path.dirname(filePath));
87
+ const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
88
+ await fs.writeFile(tempPath, `${JSON.stringify(data, null, 2)}\n`, 'utf8');
89
+ await fs.rename(tempPath, filePath);
90
+ }
91
+
92
+ async function writeTextAtomic(filePath, text) {
93
+ await mkdirp(path.dirname(filePath));
94
+ const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
95
+ await fs.writeFile(tempPath, text, 'utf8');
96
+ await fs.rename(tempPath, filePath);
97
+ }
98
+
99
+ async function appendNdjson(filePath, row) {
100
+ await mkdirp(path.dirname(filePath));
101
+ await fs.appendFile(filePath, `${JSON.stringify(row)}\n`, 'utf8');
102
+ }
103
+
104
+ async function readNdjson(filePath) {
105
+ let raw;
106
+ try {
107
+ raw = await fs.readFile(filePath, 'utf8');
108
+ } catch (error) {
109
+ if (error && error.code === 'ENOENT') {
110
+ return [];
111
+ }
112
+ throw error;
113
+ }
114
+ const rows = [];
115
+ const lines = raw.split(/\r?\n/);
116
+ for (let index = 0; index < lines.length; index += 1) {
117
+ const line = lines[index].trim();
118
+ if (!line) {
119
+ continue;
120
+ }
121
+ try {
122
+ rows.push(JSON.parse(line));
123
+ } catch (error) {
124
+ throw new Error(`${filePath}:${index + 1} invalid NDJSON: ${error.message}`);
125
+ }
126
+ }
127
+ return rows;
128
+ }
129
+
130
+ function assertObject(row, label) {
131
+ if (!row || typeof row !== 'object' || Array.isArray(row)) {
132
+ throw new Error(`${label} must be an object`);
133
+ }
134
+ }
135
+
136
+ function requireString(row, field, label, errors) {
137
+ if (!row[field] || typeof row[field] !== 'string') {
138
+ errors.push(`${label}.${field} must be a non-empty string`);
139
+ }
140
+ }
141
+
142
+ function validateCrosswalkRow(row, { allowThrow = true, label = 'crosswalk row' } = {}) {
143
+ const errors = [];
144
+ try {
145
+ assertObject(row, label);
146
+ } catch (error) {
147
+ if (allowThrow) {
148
+ throw error;
149
+ }
150
+ return { ok: false, errors: [error.message] };
151
+ }
152
+ if (row.schemaVersion !== SCHEMA_VERSION) {
153
+ errors.push(`${label}.schemaVersion must be ${SCHEMA_VERSION}`);
154
+ }
155
+ for (const field of [
156
+ 'sourceSystem',
157
+ 'sourceEntityType',
158
+ 'sourceId',
159
+ 'sourceStableKey',
160
+ 'targetSystem',
161
+ 'targetEntityType',
162
+ 'targetId',
163
+ 'status',
164
+ ]) {
165
+ requireString(row, field, label, errors);
166
+ }
167
+ if (row.status && !CROSSWALK_STATUS.has(row.status)) {
168
+ errors.push(`${label}.status must be one of: ${Array.from(CROSSWALK_STATUS).join(', ')}`);
169
+ }
170
+ if (row.updatedAt !== undefined && Number.isNaN(Date.parse(row.updatedAt))) {
171
+ errors.push(`${label}.updatedAt must be an ISO timestamp when present`);
172
+ }
173
+ if (errors.length && allowThrow) {
174
+ throw new Error(errors.join('; '));
175
+ }
176
+ return { ok: errors.length === 0, errors };
177
+ }
178
+
179
+ function validateAttemptRow(row, { allowThrow = true, label = 'attempt row' } = {}) {
180
+ const errors = [];
181
+ try {
182
+ assertObject(row, label);
183
+ } catch (error) {
184
+ if (allowThrow) {
185
+ throw error;
186
+ }
187
+ return { ok: false, errors: [error.message] };
188
+ }
189
+ if (row.schemaVersion !== SCHEMA_VERSION) {
190
+ errors.push(`${label}.schemaVersion must be ${SCHEMA_VERSION}`);
191
+ }
192
+ for (const field of ['attemptId', 'sourceStableKey', 'writeSpecId', 'operation', 'targetEntityType', 'status']) {
193
+ requireString(row, field, label, errors);
194
+ }
195
+ if (row.status && !ATTEMPT_STATUS.has(row.status)) {
196
+ errors.push(`${label}.status must be one of: ${Array.from(ATTEMPT_STATUS).join(', ')}`);
197
+ }
198
+ if (errors.length && allowThrow) {
199
+ throw new Error(errors.join('; '));
200
+ }
201
+ return { ok: errors.length === 0, errors };
202
+ }
203
+
204
+ function validateSafeModeEmailReplacementRow(row, { allowThrow = true, label = 'safe-mode email replacement row' } = {}) {
205
+ const errors = [];
206
+ try {
207
+ assertObject(row, label);
208
+ } catch (error) {
209
+ if (allowThrow) {
210
+ throw error;
211
+ }
212
+ return { ok: false, errors: [error.message] };
213
+ }
214
+ if (row.schemaVersion !== SCHEMA_VERSION) {
215
+ errors.push(`${label}.schemaVersion must be ${SCHEMA_VERSION}`);
216
+ }
217
+ for (const field of [
218
+ 'runId',
219
+ 'sourceSystem',
220
+ 'sourceEntityType',
221
+ 'sourceId',
222
+ 'sourceStableKey',
223
+ 'targetSystem',
224
+ 'targetEntityType',
225
+ 'targetId',
226
+ 'sourceEmail',
227
+ 'targetEmail',
228
+ 'createdAt',
229
+ ]) {
230
+ requireString(row, field, label, errors);
231
+ }
232
+ if (row.createdAt !== undefined && Number.isNaN(Date.parse(row.createdAt))) {
233
+ errors.push(`${label}.createdAt must be an ISO timestamp`);
234
+ }
235
+ if (errors.length && allowThrow) {
236
+ throw new Error(errors.join('; '));
237
+ }
238
+ return { ok: errors.length === 0, errors };
239
+ }
240
+
241
+ function validateSafeModeBlockedRecordRow(row, { allowThrow = true, label = 'safe-mode blocked record row' } = {}) {
242
+ const errors = [];
243
+ try {
244
+ assertObject(row, label);
245
+ } catch (error) {
246
+ if (allowThrow) {
247
+ throw error;
248
+ }
249
+ return { ok: false, errors: [error.message] };
250
+ }
251
+ if (row.schemaVersion !== SCHEMA_VERSION) {
252
+ errors.push(`${label}.schemaVersion must be ${SCHEMA_VERSION}`);
253
+ }
254
+ for (const field of [
255
+ 'runId',
256
+ 'sourceSystem',
257
+ 'sourceEntityType',
258
+ 'sourceId',
259
+ 'sourceStableKey',
260
+ 'targetSystem',
261
+ 'targetEntityType',
262
+ 'reason',
263
+ 'createdAt',
264
+ ]) {
265
+ requireString(row, field, label, errors);
266
+ }
267
+ if (!Array.isArray(row.paths) || row.paths.some((item) => typeof item !== 'string' || !item)) {
268
+ errors.push(`${label}.paths must be an array of non-empty strings`);
269
+ }
270
+ if (row.reason && row.reason !== 'SAFE_MODE_SUSPICIOUS_EMAIL') {
271
+ errors.push(`${label}.reason must be SAFE_MODE_SUSPICIOUS_EMAIL`);
272
+ }
273
+ if (row.createdAt !== undefined && Number.isNaN(Date.parse(row.createdAt))) {
274
+ errors.push(`${label}.createdAt must be an ISO timestamp`);
275
+ }
276
+ if (errors.length && allowThrow) {
277
+ throw new Error(errors.join('; '));
278
+ }
279
+ return { ok: errors.length === 0, errors };
280
+ }
281
+
282
+ function validateWixRequestCaptureRow(row, { allowThrow = true, label = 'Wix request capture row' } = {}) {
283
+ const errors = [];
284
+ try {
285
+ assertObject(row, label);
286
+ } catch (error) {
287
+ if (allowThrow) {
288
+ throw error;
289
+ }
290
+ return { ok: false, errors: [error.message] };
291
+ }
292
+ if (row.schemaVersion !== SCHEMA_VERSION) {
293
+ errors.push(`${label}.schemaVersion must be ${SCHEMA_VERSION}`);
294
+ }
295
+ for (const field of ['requestCaptureId', 'timestamp', 'runId', 'phase', 'method', 'endpoint', 'result']) {
296
+ requireString(row, field, label, errors);
297
+ }
298
+ if (row.phase && !['setup', 'import'].includes(row.phase)) {
299
+ errors.push(`${label}.phase must be setup or import`);
300
+ }
301
+ if (row.result && row.result !== 'dry_run_skipped_wix_call') {
302
+ errors.push(`${label}.result must be dry_run_skipped_wix_call`);
303
+ }
304
+ if (row.headers !== undefined && (!row.headers || typeof row.headers !== 'object' || Array.isArray(row.headers))) {
305
+ errors.push(`${label}.headers must be an object when present`);
306
+ }
307
+ if (row.headers && Object.prototype.hasOwnProperty.call(row.headers, 'Authorization')) {
308
+ errors.push(`${label}.headers must not include Authorization`);
309
+ }
310
+ if (Number.isNaN(Date.parse(row.timestamp))) {
311
+ errors.push(`${label}.timestamp must be an ISO timestamp`);
312
+ }
313
+ if (errors.length && allowThrow) {
314
+ throw new Error(errors.join('; '));
315
+ }
316
+ return { ok: errors.length === 0, errors };
317
+ }
318
+
319
+ function validateDryRunCrosswalkRow(row, { allowThrow = true, label = 'dry-run crosswalk row' } = {}) {
320
+ const errors = [];
321
+ try {
322
+ assertObject(row, label);
323
+ } catch (error) {
324
+ if (allowThrow) {
325
+ throw error;
326
+ }
327
+ return { ok: false, errors: [error.message] };
328
+ }
329
+ if (row.schemaVersion !== SCHEMA_VERSION) {
330
+ errors.push(`${label}.schemaVersion must be ${SCHEMA_VERSION}`);
331
+ }
332
+ for (const field of [
333
+ 'runId',
334
+ 'sourceSystem',
335
+ 'sourceEntityType',
336
+ 'sourceId',
337
+ 'sourceStableKey',
338
+ 'targetSystem',
339
+ 'targetEntityType',
340
+ 'placeholderTargetId',
341
+ 'operation',
342
+ 'createdAt',
343
+ ]) {
344
+ requireString(row, field, label, errors);
345
+ }
346
+ if (row.dryRun !== true) {
347
+ errors.push(`${label}.dryRun must be true`);
348
+ }
349
+ if (row.placeholder !== true) {
350
+ errors.push(`${label}.placeholder must be true`);
351
+ }
352
+ if (row.createdAt !== undefined && Number.isNaN(Date.parse(row.createdAt))) {
353
+ errors.push(`${label}.createdAt must be an ISO timestamp`);
354
+ }
355
+ if (errors.length && allowThrow) {
356
+ throw new Error(errors.join('; '));
357
+ }
358
+ return { ok: errors.length === 0, errors };
359
+ }
360
+
361
+ function indexCrosswalkRows(rows) {
362
+ const bySource = {};
363
+ const byTarget = {};
364
+ for (const row of rows) {
365
+ bySource[row.sourceStableKey] = row;
366
+ byTarget[row.targetId] = row;
367
+ }
368
+ return { bySource, byTarget };
369
+ }
370
+
371
+ async function loadCrosswalk(projectDir) {
372
+ const rows = await readNdjson(crosswalkPath(projectDir));
373
+ for (const row of rows) {
374
+ validateCrosswalkRow(row);
375
+ }
376
+ const { bySource, byTarget } = indexCrosswalkRows(rows);
377
+ return { rows, bySource, byTarget };
378
+ }
379
+
380
+ async function appendCrosswalkRow(projectDir, row) {
381
+ validateCrosswalkRow(row);
382
+ await appendNdjson(crosswalkPath(projectDir), row);
383
+ return row;
384
+ }
385
+
386
+ async function upsertCrosswalkRow(projectDir, row) {
387
+ validateCrosswalkRow(row);
388
+ const current = await loadCrosswalk(projectDir);
389
+ current.bySource[row.sourceStableKey] = row;
390
+ const rows = Object.values(current.bySource).sort((a, b) => a.sourceStableKey.localeCompare(b.sourceStableKey));
391
+ const text = rows.map((item) => JSON.stringify(item)).join('\n');
392
+ await writeTextAtomic(crosswalkPath(projectDir), text ? `${text}\n` : '');
393
+ await rebuildCrosswalkIndexes(projectDir);
394
+ return row;
395
+ }
396
+
397
+ function foldAttempts(rows) {
398
+ const byAttemptId = {};
399
+ for (const row of rows) {
400
+ byAttemptId[row.attemptId] = {
401
+ ...(byAttemptId[row.attemptId] || {}),
402
+ ...row,
403
+ };
404
+ }
405
+ return byAttemptId;
406
+ }
407
+
408
+ async function loadAttemptJournal(projectDir) {
409
+ const rows = await readNdjson(attemptJournalPath(projectDir));
410
+ for (const row of rows) {
411
+ validateAttemptRow(row);
412
+ }
413
+ return { rows, byAttemptId: foldAttempts(rows) };
414
+ }
415
+
416
+ async function appendAttempt(projectDir, row) {
417
+ validateAttemptRow(row);
418
+ await appendNdjson(attemptJournalPath(projectDir), row);
419
+ return row;
420
+ }
421
+
422
+ async function appendSafeModeEmailReplacement(projectDir, row) {
423
+ validateSafeModeEmailReplacementRow(row);
424
+ await appendNdjson(safeModeEmailReplacementsPath(projectDir), row);
425
+ return row;
426
+ }
427
+
428
+ async function appendSafeModeBlockedRecord(projectDir, row) {
429
+ validateSafeModeBlockedRecordRow(row);
430
+ await appendNdjson(safeModeBlockedRecordsPath(projectDir), row);
431
+ return row;
432
+ }
433
+
434
+ async function appendWixRequestCapture(projectDir, row) {
435
+ validateWixRequestCaptureRow(row);
436
+ await appendNdjson(wixRequestCapturesPath(projectDir), row);
437
+ return row;
438
+ }
439
+
440
+ async function loadWixRequestCaptures(projectDir) {
441
+ const rows = await readNdjson(wixRequestCapturesPath(projectDir));
442
+ for (const row of rows) {
443
+ validateWixRequestCaptureRow(row);
444
+ }
445
+ return rows;
446
+ }
447
+
448
+ async function appendDryRunCrosswalkRow(projectDir, row) {
449
+ validateDryRunCrosswalkRow(row);
450
+ await appendNdjson(dryRunCrosswalkPath(projectDir), row);
451
+ return row;
452
+ }
453
+
454
+ async function loadDryRunCrosswalk(projectDir) {
455
+ const rows = await readNdjson(dryRunCrosswalkPath(projectDir));
456
+ for (const row of rows) {
457
+ validateDryRunCrosswalkRow(row);
458
+ }
459
+ return rows;
460
+ }
461
+
462
+ function dryRunUpsertDecision({ localCrosswalkRow = null, requiresRevision = false, hasLocalRevision = false, supportsRevisionFreeRequestBuild = false } = {}) {
463
+ if (localCrosswalkRow) {
464
+ return {
465
+ dryRun: true,
466
+ decision: 'based_on_local_crosswalk',
467
+ targetId: localCrosswalkRow.targetId,
468
+ stateKnown: true,
469
+ };
470
+ }
471
+ if (requiresRevision && !hasLocalRevision) {
472
+ return {
473
+ dryRun: true,
474
+ decision: 'would_require_live_lookup',
475
+ stateKnown: false,
476
+ canBuildRequest: Boolean(supportsRevisionFreeRequestBuild),
477
+ };
478
+ }
479
+ return {
480
+ dryRun: true,
481
+ decision: 'would_create_if_not_found',
482
+ stateKnown: false,
483
+ canBuildRequest: true,
484
+ };
485
+ }
486
+
487
+ async function markAttempt(projectDir, attemptId, patch) {
488
+ if (!attemptId || typeof attemptId !== 'string') {
489
+ throw new Error('attemptId must be a non-empty string');
490
+ }
491
+ assertObject(patch, 'attempt patch');
492
+ const journal = await loadAttemptJournal(projectDir);
493
+ const current = journal.byAttemptId[attemptId];
494
+ if (!current) {
495
+ throw new Error(`unknown attemptId: ${attemptId}`);
496
+ }
497
+ const row = {
498
+ ...current,
499
+ ...patch,
500
+ attemptId,
501
+ };
502
+ validateAttemptRow(row);
503
+ await appendNdjson(attemptJournalPath(projectDir), row);
504
+ return row;
505
+ }
506
+
507
+ async function rebuildCrosswalkIndexes(projectDir) {
508
+ const { bySource, byTarget } = await loadCrosswalk(projectDir);
509
+ await writeJsonAtomic(path.join(crosswalkIndexDir(projectDir), 'by-source.json'), bySource);
510
+ await writeJsonAtomic(path.join(crosswalkIndexDir(projectDir), 'by-target.json'), byTarget);
511
+ return { bySource, byTarget };
512
+ }
513
+
514
+ async function localCrosswalkStateExists(projectDir) {
515
+ if (!(await pathExists(crosswalkPath(projectDir)))) {
516
+ return false;
517
+ }
518
+ await loadCrosswalk(projectDir);
519
+ return true;
520
+ }
521
+
522
+ function newestRow(a, b) {
523
+ const aTime = Date.parse(a.updatedAt);
524
+ const bTime = Date.parse(b.updatedAt);
525
+ if (Number.isNaN(aTime) || Number.isNaN(bTime) || aTime === bTime) {
526
+ return null;
527
+ }
528
+ return bTime > aTime ? b : a;
529
+ }
530
+
531
+ async function seedCrosswalkFromCmsMirror(projectDir, rows) {
532
+ if (!Array.isArray(rows)) {
533
+ throw new Error('CMS mirror rows must be an array');
534
+ }
535
+ if (await localCrosswalkStateExists(projectDir)) {
536
+ return { seeded: false, reason: 'local_crosswalk_exists', accepted: 0, rejected: 0, conflicts: 0 };
537
+ }
538
+
539
+ const rejected = [];
540
+ const conflicts = [];
541
+ const bySource = {};
542
+
543
+ for (const row of rows) {
544
+ const validation = validateCrosswalkRow(row, { allowThrow: false, label: 'CMS mirror row' });
545
+ if (!validation.ok) {
546
+ rejected.push({ row, errors: validation.errors });
547
+ continue;
548
+ }
549
+
550
+ const current = bySource[row.sourceStableKey];
551
+ if (!current) {
552
+ bySource[row.sourceStableKey] = row;
553
+ continue;
554
+ }
555
+
556
+ const winner = newestRow(current, row);
557
+ if (!winner) {
558
+ if (current.targetId !== row.targetId) {
559
+ conflicts.push(current, row);
560
+ }
561
+ continue;
562
+ }
563
+ bySource[row.sourceStableKey] = winner;
564
+ }
565
+
566
+ await mkdirp(cmsMirrorDir(projectDir));
567
+ await writeTextAtomic(
568
+ path.join(cmsMirrorDir(projectDir), 'imported-from-cms.ndjson'),
569
+ rows.map((row) => JSON.stringify(row)).join('\n') + (rows.length ? '\n' : ''),
570
+ );
571
+ if (rejected.length) {
572
+ await writeTextAtomic(
573
+ path.join(cmsMirrorDir(projectDir), 'rejected.ndjson'),
574
+ rejected.map((item) => JSON.stringify(item)).join('\n') + '\n',
575
+ );
576
+ }
577
+ if (conflicts.length) {
578
+ await writeTextAtomic(
579
+ path.join(cmsMirrorDir(projectDir), 'conflicts.ndjson'),
580
+ conflicts.map((row) => JSON.stringify(row)).join('\n') + '\n',
581
+ );
582
+ throw new Error(`CMS mirror seed has ${conflicts.length} conflicting rows; see state/cms-mirror/conflicts.ndjson`);
583
+ }
584
+
585
+ const acceptedRows = Object.values(bySource).sort((a, b) => a.sourceStableKey.localeCompare(b.sourceStableKey));
586
+ const text = acceptedRows.map((row) => JSON.stringify(row)).join('\n');
587
+ await writeTextAtomic(crosswalkPath(projectDir), text ? `${text}\n` : '');
588
+ await rebuildCrosswalkIndexes(projectDir);
589
+ return { seeded: true, accepted: acceptedRows.length, rejected: rejected.length, conflicts: 0 };
590
+ }
591
+
592
+ async function withStateLock(projectDir, fn) {
593
+ const lockPath = path.join(stateDir(projectDir), '.lock');
594
+ await mkdirp(stateDir(projectDir));
595
+ try {
596
+ await fs.mkdir(lockPath);
597
+ } catch (error) {
598
+ if (error && error.code === 'EEXIST') {
599
+ throw new Error(`state lock already held: ${lockPath}`);
600
+ }
601
+ throw error;
602
+ }
603
+ try {
604
+ return await fn();
605
+ } finally {
606
+ await fs.rm(lockPath, { recursive: true, force: true });
607
+ }
608
+ }
609
+
610
+ module.exports = {
611
+ SCHEMA_VERSION,
612
+ stateDir,
613
+ crosswalkPath,
614
+ attemptJournalPath,
615
+ wixRequestCapturesPath,
616
+ cmsMirrorDir,
617
+ safeModeDir,
618
+ safeModeEmailReplacementsPath,
619
+ safeModeBlockedRecordsPath,
620
+ dryRunCrosswalkPath,
621
+ loadCrosswalk,
622
+ appendCrosswalkRow,
623
+ upsertCrosswalkRow,
624
+ loadAttemptJournal,
625
+ appendAttempt,
626
+ appendSafeModeEmailReplacement,
627
+ appendSafeModeBlockedRecord,
628
+ appendWixRequestCapture,
629
+ loadWixRequestCaptures,
630
+ appendDryRunCrosswalkRow,
631
+ loadDryRunCrosswalk,
632
+ dryRunUpsertDecision,
633
+ validateSafeModeEmailReplacementRow,
634
+ validateSafeModeBlockedRecordRow,
635
+ validateWixRequestCaptureRow,
636
+ validateDryRunCrosswalkRow,
637
+ markAttempt,
638
+ rebuildCrosswalkIndexes,
639
+ localCrosswalkStateExists,
640
+ seedCrosswalkFromCmsMirror,
641
+ withStateLock,
642
+ };