@wix/agent-skills 1.15.0 → 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 (355) hide show
  1. package/README.md +5 -1
  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 +6 -4
  8. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +28 -7
  9. package/skills/wix-app/references/SERVICE_PLUGIN.md +12 -10
  10. package/skills/wix-app/references/STORES_VERSIONING.md +9 -211
  11. package/skills/wix-app/references/app-tools/TOOLS.md +75 -0
  12. package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +5 -0
  13. package/skills/wix-app/references/dashboard-page/DASHBOARD_API.md +2 -2
  14. package/skills/wix-app/references/editor-react-component/A11Y-REVIEW-REFERENCE.md +172 -0
  15. package/skills/wix-app/references/editor-react-component/A11Y-REVIEW.md +138 -0
  16. package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +172 -0
  17. package/skills/wix-app/references/editor-react-component/BRANDED-COMPONENTS.md +29 -0
  18. package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +1 -1
  19. package/skills/wix-app/references/editor-react-component/COMPONENT-PREVIEW.md +57 -0
  20. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +33 -2
  21. package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +5 -3
  22. package/skills/wix-app/references/editor-react-component/DIRECTIONALITY.md +18 -1
  23. package/skills/wix-app/references/editor-react-component/PARTS.md +15 -2
  24. package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +4 -3
  25. package/skills/wix-app/references/service-plugin/BOOKINGS-STAFF-SORTING.md +13 -9
  26. package/skills/wix-app/references/service-plugin/DISCOUNT-TRIGGERS.md +4 -0
  27. package/skills/wix-app/references/service-plugin/GIFT-CARDS.md +4 -0
  28. package/skills/wix-app/references/service-plugin/PAYMENT-SETTINGS.md +3 -1
  29. package/skills/wix-app/references/service-plugin/SHIPPING-RATES.md +4 -0
  30. package/skills/wix-app/references/service-plugin/TOOLS_PROVIDER.md +54 -0
  31. package/skills/wix-app/references/stores/CATEGORIES.md +22 -0
  32. package/skills/wix-app/references/stores/GET_PRODUCT.md +99 -0
  33. package/skills/wix-app/references/stores/INVENTORY.md +37 -0
  34. package/skills/wix-app/references/stores/QUERY.md +119 -0
  35. package/skills/wix-app/references/stores/WRITE.md +55 -0
  36. package/skills/wix-docs/SKILL.md +35 -3
  37. package/skills/wix-headless/SKILL.md +9 -2
  38. package/skills/wix-headless/entry/bootstrap.mjs +2 -2
  39. package/skills/wix-headless/entry/skill.md +0 -2
  40. package/skills/wix-headless/references/CAPABILITIES.md +6 -4
  41. package/skills/wix-headless/references/CONTENT.md +36 -0
  42. package/skills/wix-headless/references/DESIGN.md +54 -0
  43. package/skills/wix-headless/references/DISCOVERY.md +25 -1
  44. package/skills/wix-headless/references/FEEDBACK.md +16 -5
  45. package/skills/wix-headless/references/IMAGE_GENERATION.md +10 -0
  46. package/skills/wix-headless/references/SDK_HANDOFF.md +2 -0
  47. package/skills/wix-headless/references/SEED.md +3 -1
  48. package/skills/wix-headless/references/SETUP.md +1 -1
  49. package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +3 -2
  50. package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-reservations.md +42 -2
  51. package/skills/wix-headless/references/inline-recipes/setup-bookings.md +5 -1
  52. package/skills/wix-headless/references/inline-recipes/setup-forms.md +1 -1
  53. package/skills/wix-headless/references/inline-recipes/setup-online-store.md +33 -8
  54. package/skills/wix-headless/references/inline-recipes/setup-portfolio.md +3 -1
  55. package/skills/wix-headless/references/inline-recipes/setup-restaurant-experiences.md +73 -0
  56. package/skills/wix-headless/references/inline-recipes/setup-restaurant-orders.md +38 -2
  57. package/skills/wix-headless/references/inline-recipes/setup-restaurant-reservations.md +20 -1
  58. package/skills/wix-headless/references/inline-recipes/setup-restaurants.md +1 -1
  59. package/skills/wix-headless/references/managed/CONNECT.md +2 -2
  60. package/skills/wix-headless/references/managed/CREATE.md +15 -1
  61. package/skills/wix-headless/references/managed/DEPLOYMENT.md +47 -0
  62. package/skills/wix-headless/references/self-managed/DEPLOYMENT.md +8 -0
  63. package/skills/wix-headless/references/stripe/DEPLOYMENT.md +8 -0
  64. package/skills/wix-manage/SKILL.md +131 -12
  65. package/skills/wix-manage/references/analytics/analytics-dashboard-navigation.md +41 -0
  66. package/skills/wix-manage/references/analytics/query-site-analytics.md +66 -9
  67. package/skills/wix-manage/references/app-installation/app-installation-dashboard-navigation.md +28 -0
  68. package/skills/wix-manage/references/app-installation/install-wix-apps.md +3 -0
  69. package/skills/wix-manage/references/blog/blog-dashboard-navigation.md +56 -0
  70. package/skills/wix-manage/references/blog/how-to-create-blog-posts.md +31 -6
  71. package/skills/wix-manage/references/bookings/booking-service-policy-setup.md +3 -1
  72. package/skills/wix-manage/references/bookings/bookings-dashboard-navigation.md +63 -0
  73. package/skills/wix-manage/references/bookings/create-booking-service-from-prompt.md +6 -5
  74. package/skills/wix-manage/references/bookings/create-course-service.md +30 -5
  75. package/skills/wix-manage/references/bookings/diagnose-availability-issues.md +85 -42
  76. package/skills/wix-manage/references/cms/cms-dashboard-navigation.md +44 -0
  77. package/skills/wix-manage/references/cms/cms-data-items-crud.md +31 -3
  78. package/skills/wix-manage/references/cms/cms-publishing-flow.md +287 -0
  79. package/skills/wix-manage/references/cms/cms-schema-management.md +33 -1
  80. package/skills/wix-manage/references/contacts/contacts-dashboard-navigation.md +46 -0
  81. package/skills/wix-manage/references/contacts/create-a-contact.md +82 -0
  82. package/skills/wix-manage/references/contacts/update-a-contact.md +119 -0
  83. package/skills/wix-manage/references/dashboard-navigation/dashboard-navigation.md +82 -0
  84. package/skills/wix-manage/references/dashboard-navigation/routes.json +1733 -0
  85. package/skills/wix-manage/references/domains/domains-dashboard-navigation.md +32 -0
  86. package/skills/wix-manage/references/ecommerce/ecom-pricing.md +4 -4
  87. package/skills/wix-manage/references/ecommerce/ecom-shipping.md +1 -1
  88. package/skills/wix-manage/references/ecommerce/gift-cards/ecom-gift-cards-goal-sell-gift-cards.md +338 -0
  89. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-create-discount-rule.md +42 -78
  90. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-bundle-and-save.md +1 -1
  91. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-stock-mover.md +1 -1
  92. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-upsell-boost.md +1 -1
  93. package/skills/wix-manage/references/ecommerce/recommend-ecommerce-strategy.md +90 -92
  94. package/skills/wix-manage/references/events/create-wix-event.md +176 -0
  95. package/skills/wix-manage/references/events/manage-wix-events.md +174 -0
  96. package/skills/wix-manage/references/forms/forms-dashboard-navigation.md +44 -0
  97. package/skills/wix-manage/references/get-paid/get-paid-dashboard-navigation.md +52 -0
  98. package/skills/wix-manage/references/get-paid/how-to-setup-wix-payments.md +30 -7
  99. package/skills/wix-manage/references/google-ads/billing-and-payment.md +80 -0
  100. package/skills/wix-manage/references/google-ads/create-performance-max-campaign.md +212 -0
  101. package/skills/wix-manage/references/google-ads/get-campaign-suggestions.md +110 -0
  102. package/skills/wix-manage/references/google-ads/google-ads-dashboard-navigation.md +25 -0
  103. package/skills/wix-manage/references/google-ads/install-and-create-account.md +155 -0
  104. package/skills/wix-manage/references/google-ads/manage-campaign-lifecycle.md +63 -0
  105. package/skills/wix-manage/references/google-ads/query-campaign-analytics.md +155 -0
  106. package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +225 -144
  107. package/skills/wix-manage/references/marketing/generate-and-publish-marketing-plan.md +19 -10
  108. package/skills/wix-manage/references/marketing/marketing-dashboard-navigation.md +52 -0
  109. package/skills/wix-manage/references/pricing-plans/create-and-update-pricing-plans.md +99 -1
  110. package/skills/wix-manage/references/pricing-plans/pricing-plans-dashboard-navigation.md +45 -0
  111. package/skills/wix-manage/references/restaurants/restaurants-dashboard-navigation.md +68 -0
  112. package/skills/wix-manage/references/restaurants/wix-restaurants-setup.md +94 -125
  113. package/skills/wix-manage/references/site-properties/change-payment-currency-site-properties.md +48 -9
  114. package/skills/wix-manage/references/site-properties/site-properties-dashboard-navigation.md +31 -0
  115. package/skills/wix-manage/references/sites/create-headless-site.md +52 -0
  116. package/skills/wix-manage/references/sites/create-site-from-template.md +2 -25
  117. package/skills/wix-manage/references/sites/site-import.md +243 -0
  118. package/skills/wix-manage/references/sites/sites-dashboard-navigation.md +29 -0
  119. package/skills/wix-manage/references/stores/add-store-pages-to-site.md +17 -1
  120. package/skills/wix-manage/references/stores/create-product-from-image.md +8 -6
  121. package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +16 -10
  122. package/skills/wix-manage/references/stores/find-products-query-and-search-catalog-v3.md +26 -8
  123. package/skills/wix-manage/references/stores/stores-dashboard-navigation.md +65 -0
  124. package/skills/wix-manage/references/stores/update-product-with-options.md +39 -7
  125. package/skills/wix-replatform/.publish-manifest.json +8 -0
  126. package/skills/wix-replatform/SKILL.md +693 -0
  127. package/skills/wix-replatform/lib/artifact-freshness.js +215 -0
  128. package/skills/wix-replatform/lib/completion-report.js +200 -0
  129. package/skills/wix-replatform/lib/config-env.js +59 -0
  130. package/skills/wix-replatform/lib/execution-manifest.js +185 -0
  131. package/skills/wix-replatform/lib/execution-state.js +173 -0
  132. package/skills/wix-replatform/lib/import-recovery.js +313 -0
  133. package/skills/wix-replatform/lib/local-state.js +642 -0
  134. package/skills/wix-replatform/lib/orchestration-preflight.js +143 -0
  135. package/skills/wix-replatform/lib/orchestration-router.js +122 -0
  136. package/skills/wix-replatform/lib/orchestration-state.js +455 -0
  137. package/skills/wix-replatform/lib/progress-log.js +224 -0
  138. package/skills/wix-replatform/lib/progress-log.sh +140 -0
  139. package/skills/wix-replatform/lib/url-preservation-state.js +391 -0
  140. package/skills/wix-replatform/resources/rp-discovery/SKILL.md +184 -0
  141. package/skills/wix-replatform/resources/rp-execute-import/SKILL.md +529 -0
  142. package/skills/wix-replatform/resources/rp-execute-setup/SKILL.md +316 -0
  143. package/skills/wix-replatform/resources/rp-execute-setup/scripts/mint-token.sh +64 -0
  144. package/skills/wix-replatform/resources/rp-import-codegen/SKILL.md +1114 -0
  145. package/skills/wix-replatform/resources/rp-mapper/SKILL.md +430 -0
  146. package/skills/wix-replatform/resources/rp-mapper/lib/mapping-resolve.js +217 -0
  147. package/skills/wix-replatform/resources/rp-mapper/scripts/resolve-mapping.js +148 -0
  148. package/skills/wix-replatform/resources/rp-mapper/wix-business-solutions-taxonomy.md +378 -0
  149. package/skills/wix-replatform/resources/rp-setup-discovery/SKILL.md +183 -0
  150. package/skills/wix-replatform/resources/rp-source-csv/SKILL.md +478 -0
  151. package/skills/wix-replatform/resources/rp-source-csv/lib/canonical-record.js +136 -0
  152. package/skills/wix-replatform/resources/rp-source-csv/lib/csv-fileset.js +0 -0
  153. package/skills/wix-replatform/resources/rp-source-csv/lib/csv-fingerprint.js +310 -0
  154. package/skills/wix-replatform/resources/rp-source-csv/lib/csv-layout.js +1081 -0
  155. package/skills/wix-replatform/resources/rp-source-csv/lib/csv-parse.js +618 -0
  156. package/skills/wix-replatform/resources/rp-source-csv/scripts/csv-discovery.js +949 -0
  157. package/skills/wix-replatform/resources/rp-source-csv/source-schema.example.json +196 -0
  158. package/skills/wix-replatform/resources/rp-source-csv/vendors/bigcommerce.json +66 -0
  159. package/skills/wix-replatform/resources/rp-source-csv/vendors/magento.json +60 -0
  160. package/skills/wix-replatform/resources/rp-source-csv/vendors/shopify.json +95 -0
  161. package/skills/wix-replatform/resources/rp-source-csv/vendors/woocommerce.json +82 -0
  162. package/skills/wix-replatform/resources/rp-source-wordpress/SKILL.md +256 -0
  163. package/skills/wix-replatform/resources/rp-source-wordpress/lib/wp-http.js +249 -0
  164. package/skills/wix-replatform/resources/rp-source-wordpress/lib/wp-route-classifier.js +444 -0
  165. package/skills/wix-replatform/resources/rp-source-wordpress/scripts/wp-discovery.js +774 -0
  166. package/skills/wix-replatform/resources/rp-source-wordpress/source-schema.example.json +71 -0
  167. package/skills/wix-replatform/resources/rp-target-wix/SKILL.md +632 -0
  168. package/skills/wix-replatform/resources/rp-target-wix/SPEC-product-reviews-and-blog-authorship.md +330 -0
  169. package/skills/wix-replatform/resources/rp-target-wix/domains/README.md +21 -0
  170. package/skills/wix-replatform/resources/rp-target-wix/domains/blog/domain.json +19 -0
  171. package/skills/wix-replatform/resources/rp-target-wix/domains/blog/entities/category.json +37 -0
  172. package/skills/wix-replatform/resources/rp-target-wix/domains/blog/entities/comment.json +37 -0
  173. package/skills/wix-replatform/resources/rp-target-wix/domains/blog/entities/post.json +39 -0
  174. package/skills/wix-replatform/resources/rp-target-wix/domains/blog/entities/tag.json +35 -0
  175. package/skills/wix-replatform/resources/rp-target-wix/domains/cms/domain.json +14 -0
  176. package/skills/wix-replatform/resources/rp-target-wix/domains/cms/entities/collection.json +35 -0
  177. package/skills/wix-replatform/resources/rp-target-wix/domains/cms/entities/data-item.json +36 -0
  178. package/skills/wix-replatform/resources/rp-target-wix/domains/cms/entities/reference.json +35 -0
  179. package/skills/wix-replatform/resources/rp-target-wix/domains/crm/domain.json +14 -0
  180. package/skills/wix-replatform/resources/rp-target-wix/domains/crm/entities/contact.json +131 -0
  181. package/skills/wix-replatform/resources/rp-target-wix/domains/crm/entities/email-subscription.json +37 -0
  182. package/skills/wix-replatform/resources/rp-target-wix/domains/crm/entities/label.json +37 -0
  183. package/skills/wix-replatform/resources/rp-target-wix/domains/ecom/domain.json +21 -0
  184. package/skills/wix-replatform/resources/rp-target-wix/domains/ecom/entities/order-line-item.json +37 -0
  185. package/skills/wix-replatform/resources/rp-target-wix/domains/ecom/entities/order-refund.json +37 -0
  186. package/skills/wix-replatform/resources/rp-target-wix/domains/ecom/entities/order.json +97 -0
  187. package/skills/wix-replatform/resources/rp-target-wix/domains/index.json +528 -0
  188. package/skills/wix-replatform/resources/rp-target-wix/domains/media/domain.json +14 -0
  189. package/skills/wix-replatform/resources/rp-target-wix/domains/media/entities/media-file.json +38 -0
  190. package/skills/wix-replatform/resources/rp-target-wix/domains/media/entities/media-folder.json +37 -0
  191. package/skills/wix-replatform/resources/rp-target-wix/domains/members/domain.json +13 -0
  192. package/skills/wix-replatform/resources/rp-target-wix/domains/members/entities/badge.json +37 -0
  193. package/skills/wix-replatform/resources/rp-target-wix/domains/members/entities/member.json +53 -0
  194. package/skills/wix-replatform/resources/rp-target-wix/domains/schema.json +84 -0
  195. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/domain.json +25 -0
  196. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/category.json +37 -0
  197. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/coupon.json +37 -0
  198. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/inventory-item.json +38 -0
  199. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/product-tag.json +37 -0
  200. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/product.json +90 -0
  201. package/skills/wix-replatform/resources/rp-target-wix/lib/audit-summary.js +64 -0
  202. package/skills/wix-replatform/resources/rp-target-wix/lib/contract-ledger.js +141 -0
  203. package/skills/wix-replatform/resources/rp-target-wix/lib/domain-knowledge.js +384 -0
  204. package/skills/wix-replatform/resources/rp-target-wix/lib/ndjson.js +260 -0
  205. package/skills/wix-replatform/resources/rp-target-wix/lib/stores-verification.js +238 -0
  206. package/skills/wix-replatform/resources/rp-target-wix/lib/wix-build.js +237 -0
  207. package/skills/wix-replatform/resources/rp-target-wix/lib/wix-target-spec.js +238 -0
  208. package/skills/wix-replatform/resources/rp-target-wix/lib/wix-writers.js +2219 -0
  209. package/skills/wix-replatform/resources/rp-target-wix/scripts/domain-knowledge-validate.js +31 -0
  210. package/skills/wix-replatform/resources/rp-target-wix/scripts/domain-knowledge.js +100 -0
  211. package/skills/wix-replatform/resources/rp-target-wix/scripts/verify-stores.js +107 -0
  212. package/skills/wix-replatform/resources/rp-telemetry/SKILL.md +344 -0
  213. package/skills/wix-replatform/resources/rp-telemetry/lib/bi-sink.js +250 -0
  214. package/skills/wix-replatform/resources/rp-telemetry/lib/telemetry-recorder.js +1927 -0
  215. package/skills/wix-replatform/resources/rp-telemetry/scripts/meter-from-audit.js +83 -0
  216. package/skills/wix-replatform/resources/rp-telemetry/scripts/rp-telemetry.js +141 -0
  217. package/skills/wix-replatform/scripts/artifact-freshness.js +76 -0
  218. package/skills/wix-replatform/scripts/execution-manifest-validate.js +43 -0
  219. package/skills/wix-replatform/scripts/execution-state-prepare.js +128 -0
  220. package/skills/wix-replatform/scripts/orchestration-preflight.js +48 -0
  221. package/skills/wix-replatform/scripts/orchestration-route.js +46 -0
  222. package/skills/wix-replatform/scripts/orchestration-state.js +245 -0
  223. package/skills/wix-vibe-headless/SKILL.md +54 -25
  224. package/skills/wix-vibe-headless/install/deploy.cjs +95 -0
  225. package/skills/wix-vibe-headless/install/pin-agents-md.cjs +34 -0
  226. package/skills/wix-vibe-headless/platforms/README.md +26 -0
  227. package/skills/wix-vibe-headless/platforms/base44.md +177 -0
  228. package/skills/wix-vibe-headless/platforms/generic.md +122 -0
  229. package/skills/wix-vibe-headless/references/blog/INSTRUCTIONS.md +230 -119
  230. package/skills/wix-vibe-headless/references/blog/app/components/PostCard.jsx +43 -0
  231. package/skills/wix-vibe-headless/references/blog/app/components/PostChips.jsx +25 -0
  232. package/skills/wix-vibe-headless/references/blog/app/components/PostGrid.jsx +15 -0
  233. package/skills/wix-vibe-headless/references/blog/app/context/TaxonomyContext.jsx +35 -0
  234. package/skills/wix-vibe-headless/references/blog/app/hooks/usePostDetail.js +38 -0
  235. package/skills/wix-vibe-headless/references/blog/app/pages/Blog.jsx +40 -0
  236. package/skills/wix-vibe-headless/references/blog/app/pages/CategoryPage.jsx +54 -0
  237. package/skills/wix-vibe-headless/references/blog/app/pages/PostDetail.jsx +65 -0
  238. package/skills/wix-vibe-headless/references/blog/app/pages/TagPage.jsx +50 -0
  239. package/skills/wix-vibe-headless/references/blog/seed/SEED.md +103 -0
  240. package/skills/wix-vibe-headless/references/blog/seed/seed-blog.js +270 -0
  241. package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +260 -145
  242. package/skills/wix-vibe-headless/references/bookings/app/components/BookingForm.jsx +65 -0
  243. package/skills/wix-vibe-headless/references/bookings/app/components/ServiceCard.jsx +47 -0
  244. package/skills/wix-vibe-headless/references/bookings/app/components/ServiceGrid.jsx +13 -0
  245. package/skills/wix-vibe-headless/references/bookings/app/components/SlotPicker.jsx +126 -0
  246. package/skills/wix-vibe-headless/references/bookings/app/hooks/useServiceDetail.js +108 -0
  247. package/skills/wix-vibe-headless/references/bookings/app/hooks/useServices.js +58 -0
  248. package/skills/wix-vibe-headless/references/bookings/app/lib/serviceFacts.js +95 -0
  249. package/skills/wix-vibe-headless/references/bookings/app/pages/ServiceDetail.jsx +94 -0
  250. package/skills/wix-vibe-headless/references/bookings/app/pages/Services.jsx +89 -0
  251. package/skills/wix-vibe-headless/references/bookings/{wix-bookings-checkout.js → app/rest/wix-bookings-checkout.js} +1 -1
  252. package/skills/wix-vibe-headless/references/bookings/{wix-bookings-services.js → app/rest/wix-bookings-services.js} +90 -12
  253. package/skills/wix-vibe-headless/references/bookings/seed/SEED.md +117 -0
  254. package/skills/wix-vibe-headless/references/bookings/seed/seed-bookings.js +333 -0
  255. package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +169 -147
  256. package/skills/wix-vibe-headless/references/cms/app/collection.config.js +31 -0
  257. package/skills/wix-vibe-headless/references/cms/app/lib/wixImage.js +18 -0
  258. package/skills/wix-vibe-headless/references/cms/{wix-cms.js → app/rest/wix-cms.js} +47 -2
  259. package/skills/wix-vibe-headless/references/cms/seed/SEED.md +145 -0
  260. package/skills/wix-vibe-headless/references/events/INSTRUCTIONS.md +228 -131
  261. package/skills/wix-vibe-headless/references/events/app/components/CategoryFilter.jsx +23 -0
  262. package/skills/wix-vibe-headless/references/events/app/components/EventCard.jsx +43 -0
  263. package/skills/wix-vibe-headless/references/events/app/components/EventGrid.jsx +13 -0
  264. package/skills/wix-vibe-headless/references/events/app/components/EventRegistration.jsx +29 -0
  265. package/skills/wix-vibe-headless/references/events/app/components/RsvpForm.jsx +57 -0
  266. package/skills/wix-vibe-headless/references/events/app/components/TicketPicker.jsx +78 -0
  267. package/skills/wix-vibe-headless/references/events/app/hooks/useEventDetail.js +27 -0
  268. package/skills/wix-vibe-headless/references/events/app/hooks/useEventsList.js +54 -0
  269. package/skills/wix-vibe-headless/references/events/app/hooks/useRsvpForm.js +40 -0
  270. package/skills/wix-vibe-headless/references/events/app/hooks/useTicketing.js +81 -0
  271. package/skills/wix-vibe-headless/references/events/app/pages/EventDetail.jsx +48 -0
  272. package/skills/wix-vibe-headless/references/events/app/pages/Events.jsx +36 -0
  273. package/skills/wix-vibe-headless/references/events/{wix-events-browse.js → app/rest/wix-events-browse.js} +3 -2
  274. package/skills/wix-vibe-headless/references/events/seed/SEED.md +107 -0
  275. package/skills/wix-vibe-headless/references/events/seed/seed-events.js +251 -0
  276. package/skills/wix-vibe-headless/references/members/INSTRUCTIONS.md +276 -188
  277. package/skills/wix-vibe-headless/references/members/app/components/LoginForm.jsx +101 -0
  278. package/skills/wix-vibe-headless/references/members/app/components/MemberMenu.jsx +33 -0
  279. package/skills/wix-vibe-headless/references/members/app/components/RequireAuth.jsx +21 -0
  280. package/skills/wix-vibe-headless/references/members/app/components/SocialButtons.jsx +29 -0
  281. package/skills/wix-vibe-headless/references/members/app/context/MemberContext.jsx +54 -0
  282. package/skills/wix-vibe-headless/references/members/app/hooks/useLoginForm.js +77 -0
  283. package/skills/wix-vibe-headless/references/members/app/pages/Account.jsx +36 -0
  284. package/skills/wix-vibe-headless/references/members/app/pages/Callback.jsx +32 -0
  285. package/skills/wix-vibe-headless/references/members/app/pages/Login.jsx +35 -0
  286. package/skills/wix-vibe-headless/references/members/{wix-members-auth.js → app/rest/wix-members-auth.js} +6 -3
  287. package/skills/wix-vibe-headless/references/members/install/Register.jsx +22 -0
  288. package/skills/wix-vibe-headless/references/members/seed/SEED.md +22 -0
  289. package/skills/wix-vibe-headless/references/portfolio/INSTRUCTIONS.md +233 -104
  290. package/skills/wix-vibe-headless/references/portfolio/app/components/CollectionCard.jsx +31 -0
  291. package/skills/wix-vibe-headless/references/portfolio/app/components/CollectionGrid.jsx +15 -0
  292. package/skills/wix-vibe-headless/references/portfolio/app/components/ProjectCard.jsx +39 -0
  293. package/skills/wix-vibe-headless/references/portfolio/app/components/ProjectGrid.jsx +15 -0
  294. package/skills/wix-vibe-headless/references/portfolio/app/components/ProjectMedia.jsx +29 -0
  295. package/skills/wix-vibe-headless/references/portfolio/app/hooks/useCollectionProjects.js +35 -0
  296. package/skills/wix-vibe-headless/references/portfolio/app/hooks/usePortfolioGallery.js +27 -0
  297. package/skills/wix-vibe-headless/references/portfolio/app/hooks/useProjectDetail.js +25 -0
  298. package/skills/wix-vibe-headless/references/portfolio/app/pages/CollectionPage.jsx +39 -0
  299. package/skills/wix-vibe-headless/references/portfolio/app/pages/Portfolio.jsx +27 -0
  300. package/skills/wix-vibe-headless/references/portfolio/app/pages/ProjectDetail.jsx +60 -0
  301. package/skills/wix-vibe-headless/references/portfolio/{wix-portfolio.js → app/rest/wix-portfolio.js} +84 -55
  302. package/skills/wix-vibe-headless/references/portfolio/seed/SEED.md +94 -0
  303. package/skills/wix-vibe-headless/references/portfolio/seed/seed-portfolio.js +236 -0
  304. package/skills/wix-vibe-headless/references/pricing-plans/INSTRUCTIONS.md +240 -117
  305. package/skills/wix-vibe-headless/references/pricing-plans/app/components/OrderCard.jsx +35 -0
  306. package/skills/wix-vibe-headless/references/pricing-plans/app/components/PlanCard.jsx +48 -0
  307. package/skills/wix-vibe-headless/references/pricing-plans/app/components/PlanGrid.jsx +16 -0
  308. package/skills/wix-vibe-headless/references/pricing-plans/app/components/PlanPrice.jsx +35 -0
  309. package/skills/wix-vibe-headless/references/pricing-plans/app/hooks/useMyPlans.js +25 -0
  310. package/skills/wix-vibe-headless/references/pricing-plans/app/hooks/usePlanDetail.js +28 -0
  311. package/skills/wix-vibe-headless/references/pricing-plans/app/hooks/usePlans.js +30 -0
  312. package/skills/wix-vibe-headless/references/pricing-plans/app/pages/MyPlans.jsx +30 -0
  313. package/skills/wix-vibe-headless/references/pricing-plans/app/pages/PlanDetail.jsx +53 -0
  314. package/skills/wix-vibe-headless/references/pricing-plans/app/pages/Plans.jsx +28 -0
  315. package/skills/wix-vibe-headless/references/pricing-plans/seed/SEED.md +86 -0
  316. package/skills/wix-vibe-headless/references/pricing-plans/seed/seed-pricing-plans.js +251 -0
  317. package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +248 -124
  318. package/skills/wix-vibe-headless/references/restaurants/app/components/ItemDialog.jsx +81 -0
  319. package/skills/wix-vibe-headless/references/restaurants/app/components/MenuItemCard.jsx +71 -0
  320. package/skills/wix-vibe-headless/references/restaurants/app/components/MenuList.jsx +43 -0
  321. package/skills/wix-vibe-headless/references/restaurants/app/components/OrderCartButton.jsx +21 -0
  322. package/skills/wix-vibe-headless/references/restaurants/app/components/OrderCartDrawer.jsx +60 -0
  323. package/skills/wix-vibe-headless/references/restaurants/app/context/OrderCartContext.jsx +63 -0
  324. package/skills/wix-vibe-headless/references/restaurants/app/hooks/useItemOrder.js +32 -0
  325. package/skills/wix-vibe-headless/references/restaurants/app/hooks/useReservation.js +73 -0
  326. package/skills/wix-vibe-headless/references/restaurants/app/pages/Menu.jsx +28 -0
  327. package/skills/wix-vibe-headless/references/restaurants/app/pages/Reservations.jsx +102 -0
  328. package/skills/wix-vibe-headless/references/restaurants/seed/SEED.md +180 -0
  329. package/skills/wix-vibe-headless/references/restaurants/seed/seed-restaurants.js +452 -0
  330. package/skills/wix-vibe-headless/references/shared/app/components/WixManageBanner.jsx +56 -0
  331. package/skills/wix-vibe-headless/references/shared/{wix-client.js → app/rest/wix-client.js} +6 -8
  332. package/skills/wix-vibe-headless/references/shared/app/rest/wix-config.js +6 -0
  333. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +263 -148
  334. package/skills/wix-vibe-headless/references/storefront/app/components/CartButton.jsx +20 -0
  335. package/skills/wix-vibe-headless/references/storefront/app/components/CartDrawer.jsx +150 -0
  336. package/skills/wix-vibe-headless/references/storefront/app/components/ProductCard.jsx +167 -0
  337. package/skills/wix-vibe-headless/references/storefront/app/components/ProductGallery.jsx +51 -0
  338. package/skills/wix-vibe-headless/references/storefront/app/components/ProductGrid.jsx +54 -0
  339. package/skills/wix-vibe-headless/references/storefront/app/components/VariantPicker.jsx +119 -0
  340. package/skills/wix-vibe-headless/references/storefront/app/context/CartContext.jsx +71 -0
  341. package/skills/wix-vibe-headless/references/storefront/app/hooks/useProductDetail.js +109 -0
  342. package/skills/wix-vibe-headless/references/storefront/app/hooks/useShop.js +98 -0
  343. package/skills/wix-vibe-headless/references/storefront/app/lib/storeImage.js +27 -0
  344. package/skills/wix-vibe-headless/references/storefront/app/pages/ProductDetail.jsx +139 -0
  345. package/skills/wix-vibe-headless/references/storefront/app/pages/Shop.jsx +75 -0
  346. package/skills/wix-vibe-headless/references/storefront/{wix-store-cart.js → app/rest/wix-store-cart.js} +1 -1
  347. package/skills/wix-vibe-headless/references/storefront/{wix-store-catalog.js → app/rest/wix-store-catalog.js} +25 -2
  348. package/skills/wix-vibe-headless/references/storefront/seed/SEED.md +111 -0
  349. package/skills/wix-vibe-headless/references/storefront/seed/seed-store.js +299 -0
  350. /package/skills/wix-vibe-headless/references/blog/{wix-blog.js → app/rest/wix-blog.js} +0 -0
  351. /package/skills/wix-vibe-headless/references/events/{wix-events-registration.js → app/rest/wix-events-registration.js} +0 -0
  352. /package/skills/wix-vibe-headless/references/pricing-plans/{wix-pricing-plans.js → app/rest/wix-pricing-plans.js} +0 -0
  353. /package/skills/wix-vibe-headless/references/restaurants/{wix-restaurants-menu.js → app/rest/wix-restaurants-menu.js} +0 -0
  354. /package/skills/wix-vibe-headless/references/restaurants/{wix-restaurants-ordering.js → app/rest/wix-restaurants-ordering.js} +0 -0
  355. /package/skills/wix-vibe-headless/references/restaurants/{wix-restaurants-reservations.js → app/rest/wix-restaurants-reservations.js} +0 -0
@@ -0,0 +1,384 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+ const wixWriters = require('./wix-writers.js');
6
+
7
+ const CLASSIFICATIONS = new Set([
8
+ 'native',
9
+ 'cms',
10
+ 'native-plus-cms',
11
+ 'setup-config',
12
+ 'skip-by-default',
13
+ 'unsupported-native-gap',
14
+ ]);
15
+ const ID_POLICIES = new Set(['client-assigned', 'server-assigned', 'natural-key', 'not-applicable']);
16
+ const VERIFICATIONS = new Set(['verified-live', 'docs', 'source-review', 'internal-only', 'unverified', 'none']);
17
+ const RELIABILITY = new Set(['reliable', 'partially-reliable', 'unreliable', 'unknown']);
18
+ const SAFE_MODE_CONTACT_KINDS = new Set(['email', 'phone']);
19
+ const WRITER_IDS = new Set(Object.keys(wixWriters).filter((name) => typeof wixWriters[name] === 'function'));
20
+
21
+ function knowledgeRoot(rootDir = path.resolve(__dirname, '..')) {
22
+ return path.join(rootDir, 'domains');
23
+ }
24
+
25
+ function readJson(filePath) {
26
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
27
+ }
28
+
29
+ function writeJson(filePath, value) {
30
+ fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`);
31
+ }
32
+
33
+ function entityRef(entity) {
34
+ return `${entity.domain}/${entity.entity}`;
35
+ }
36
+
37
+ function listDomainDirs(domainsDir) {
38
+ return fs
39
+ .readdirSync(domainsDir, { withFileTypes: true })
40
+ .filter((entry) => entry.isDirectory())
41
+ .map((entry) => entry.name)
42
+ .sort();
43
+ }
44
+
45
+ function listEntityFiles(domainDir) {
46
+ const entitiesDir = path.join(domainDir, 'entities');
47
+ if (!fs.existsSync(entitiesDir)) return [];
48
+ return fs
49
+ .readdirSync(entitiesDir, { withFileTypes: true })
50
+ .filter((entry) => entry.isFile() && entry.name.endsWith('.json'))
51
+ .map((entry) => entry.name)
52
+ .sort();
53
+ }
54
+
55
+ function loadDomain(domainsDir, domain) {
56
+ return readJson(path.join(domainsDir, domain, 'domain.json'));
57
+ }
58
+
59
+ function loadEntity(domainsDir, domain, entity) {
60
+ return readJson(path.join(domainsDir, domain, 'entities', `${entity}.json`));
61
+ }
62
+
63
+ function generateIndex(domainsDir) {
64
+ const index = {
65
+ schemaVersion: 1,
66
+ domains: {},
67
+ sourceAliasIndex: {},
68
+ routeAliasIndex: {},
69
+ flags: {},
70
+ };
71
+
72
+ for (const domain of listDomainDirs(domainsDir)) {
73
+ const domainPath = path.join(domain, 'domain.json');
74
+ const domainJson = loadDomain(domainsDir, domain);
75
+ const entities = {};
76
+ for (const fileName of listEntityFiles(path.join(domainsDir, domain))) {
77
+ const entityId = fileName.replace(/\.json$/, '');
78
+ const entityPath = path.join(domain, 'entities', fileName);
79
+ const entity = readJson(path.join(domainsDir, entityPath));
80
+ entities[entityId] = {
81
+ path: `domains/${entityPath}`,
82
+ displayName: entity.displayName,
83
+ classification: entity.target && entity.target.classification,
84
+ reliabilityStatus: entity.reliability && entity.reliability.status,
85
+ reliabilityFlags: (entity.reliability && entity.reliability.flags) || [],
86
+ summary: firstPitfallOrGuidance(entity),
87
+ };
88
+ for (const alias of entity.sourceAliases || []) {
89
+ const key = `${alias.sourceSystem}:${alias.sourceEntity}`;
90
+ if (!index.sourceAliasIndex[key]) index.sourceAliasIndex[key] = [];
91
+ index.sourceAliasIndex[key].push(`${domain}/${entityId}`);
92
+ for (const route of alias.routes || []) {
93
+ if (!index.routeAliasIndex[route]) index.routeAliasIndex[route] = [];
94
+ index.routeAliasIndex[route].push(`${domain}/${entityId}`);
95
+ }
96
+ }
97
+ for (const flag of (entity.reliability && entity.reliability.flags) || []) {
98
+ if (!index.flags[flag]) index.flags[flag] = [];
99
+ index.flags[flag].push(`${domain}/${entityId}`);
100
+ }
101
+ }
102
+ index.domains[domain] = {
103
+ path: `domains/${domainPath}`,
104
+ displayName: domainJson.displayName,
105
+ ownerHint: domainJson.ownerHint,
106
+ entities,
107
+ };
108
+ }
109
+
110
+ for (const collection of [index.sourceAliasIndex, index.routeAliasIndex, index.flags]) {
111
+ for (const key of Object.keys(collection)) collection[key] = Array.from(new Set(collection[key])).sort();
112
+ }
113
+
114
+ return index;
115
+ }
116
+
117
+ function firstPitfallOrGuidance(entity) {
118
+ if (Array.isArray(entity.pitfalls) && entity.pitfalls[0] && entity.pitfalls[0].summary) {
119
+ return entity.pitfalls[0].summary;
120
+ }
121
+ if (Array.isArray(entity.mappingGuidance) && entity.mappingGuidance[0]) return entity.mappingGuidance[0];
122
+ return '';
123
+ }
124
+
125
+ function validateKnowledge(domainsDir) {
126
+ const errors = [];
127
+ const indexPath = path.join(domainsDir, 'index.json');
128
+ const index = fs.existsSync(indexPath) ? readJson(indexPath) : null;
129
+ const generated = generateIndex(domainsDir);
130
+
131
+ if (!fs.existsSync(path.join(domainsDir, 'schema.json'))) {
132
+ errors.push('domains/schema.json is missing');
133
+ }
134
+
135
+ for (const domain of listDomainDirs(domainsDir)) {
136
+ const domainFile = path.join(domainsDir, domain, 'domain.json');
137
+ if (!fs.existsSync(domainFile)) {
138
+ errors.push(`${domain}: missing domain.json`);
139
+ continue;
140
+ }
141
+ const domainJson = readJson(domainFile);
142
+ requireFields(domainJson, ['schemaVersion', 'domain', 'displayName', 'ownerHint', 'defaultImportOrder', 'evidence'], `${domain}/domain.json`, errors);
143
+ if (domainJson.schemaVersion !== 1) errors.push(`${domain}/domain.json: schemaVersion must be 1`);
144
+ if (domainJson.domain !== domain) errors.push(`${domain}/domain.json: domain must match directory`);
145
+ for (const entityId of domainJson.defaultImportOrder || []) {
146
+ if (!fs.existsSync(path.join(domainsDir, domain, 'entities', `${entityId}.json`))) {
147
+ errors.push(`${domain}/domain.json: defaultImportOrder references missing entity ${entityId}`);
148
+ }
149
+ }
150
+ validateEvidence(domainJson.evidence || [], `${domain}/domain.json`, errors);
151
+
152
+ for (const fileName of listEntityFiles(path.join(domainsDir, domain))) {
153
+ const entityId = fileName.replace(/\.json$/, '');
154
+ const entity = loadEntity(domainsDir, domain, entityId);
155
+ const label = `${domain}/entities/${fileName}`;
156
+ validateEntity(entity, domain, entityId, label, errors);
157
+ }
158
+ }
159
+
160
+ if (!index) {
161
+ errors.push('domains/index.json is missing; run domain-knowledge-validate.js --write-index');
162
+ } else {
163
+ const current = JSON.stringify(index);
164
+ const expected = JSON.stringify(generated);
165
+ if (current !== expected) {
166
+ errors.push('domains/index.json is stale; run domain-knowledge-validate.js --write-index');
167
+ }
168
+ validateIndexConsistency(index, domainsDir, errors);
169
+ }
170
+
171
+ return { ok: errors.length === 0, errors, generatedIndex: generated };
172
+ }
173
+
174
+ function requireFields(value, fields, label, errors) {
175
+ for (const field of fields) {
176
+ if (value[field] === undefined) errors.push(`${label}: missing required field ${field}`);
177
+ }
178
+ }
179
+
180
+ function validateEntity(entity, domain, entityId, label, errors) {
181
+ requireFields(entity, ['schemaVersion', 'domain', 'entity', 'displayName', 'target', 'sourceAliases', 'preferredWrite', 'reliability', 'pitfalls', 'mappingGuidance', 'evidence'], label, errors);
182
+ if (entity.schemaVersion !== 1) errors.push(`${label}: schemaVersion must be 1`);
183
+ if (entity.domain !== domain) errors.push(`${label}: domain must match file path`);
184
+ if (entity.entity !== entityId) errors.push(`${label}: entity must match file path`);
185
+ if (!CLASSIFICATIONS.has(entity.target && entity.target.classification)) errors.push(`${label}: invalid target.classification`);
186
+ if (!ID_POLICIES.has(entity.target && entity.target.idPolicy)) errors.push(`${label}: invalid target.idPolicy`);
187
+ if (typeof (entity.target && entity.target.crosswalkRequired) !== 'boolean') errors.push(`${label}: target.crosswalkRequired must be boolean`);
188
+ if (!VERIFICATIONS.has(entity.preferredWrite && entity.preferredWrite.verification)) errors.push(`${label}: invalid preferredWrite.verification`);
189
+ if (!RELIABILITY.has(entity.reliability && entity.reliability.status)) errors.push(`${label}: invalid reliability.status`);
190
+ if (!Array.isArray(entity.reliability && entity.reliability.flags)) errors.push(`${label}: reliability.flags must be an array`);
191
+ if (entity.preferredWrite && entity.preferredWrite.writerId !== null && !WRITER_IDS.has(entity.preferredWrite.writerId)) {
192
+ errors.push(`${label}: writerId ${entity.preferredWrite.writerId} is not exported by wix-writers.js`);
193
+ }
194
+ if (entity.target && entity.target.classification !== 'cms' && entity.target.idPolicy === 'server-assigned' && entity.target.crosswalkRequired !== true) {
195
+ errors.push(`${label}: server-assigned non-CMS targets must require crosswalk`);
196
+ }
197
+ for (const alias of entity.sourceAliases || []) {
198
+ if (!alias.sourceSystem || !alias.sourceEntity) errors.push(`${label}: sourceAliases entries must include sourceSystem and sourceEntity`);
199
+ }
200
+ validateSafeModeContactFields(entity.safeModeContactFields, label, errors);
201
+ validateEvidence(entity.evidence || [], label, errors);
202
+ }
203
+
204
+ function validateSafeModeContactFields(fields, label, errors) {
205
+ if (fields === undefined) return;
206
+ if (!Array.isArray(fields)) {
207
+ errors.push(`${label}: safeModeContactFields must be an array when present`);
208
+ return;
209
+ }
210
+ for (const [index, field] of fields.entries()) {
211
+ const fieldLabel = `${label}: safeModeContactFields[${index}]`;
212
+ if (!field || typeof field !== 'object' || Array.isArray(field)) {
213
+ errors.push(`${fieldLabel} must be an object`);
214
+ continue;
215
+ }
216
+ if (!SAFE_MODE_CONTACT_KINDS.has(field.kind)) errors.push(`${fieldLabel}.kind must be email or phone`);
217
+ if (!field.targetPath || typeof field.targetPath !== 'string') errors.push(`${fieldLabel}.targetPath must be a non-empty string`);
218
+ if (!field.source || typeof field.source !== 'string') errors.push(`${fieldLabel}.source must be a non-empty string`);
219
+ }
220
+ }
221
+
222
+ function validateEvidence(items, label, errors) {
223
+ if (!Array.isArray(items) || items.length === 0) {
224
+ errors.push(`${label}: evidence must be a non-empty array`);
225
+ return;
226
+ }
227
+ for (const item of items) {
228
+ if (!item.url && !item.path) errors.push(`${label}: every evidence item must include url or path`);
229
+ }
230
+ }
231
+
232
+ function validateIndexConsistency(index, domainsDir, errors) {
233
+ const flagged = new Set(index.flags && index.flags.IMPORT_UNRELIABLE ? index.flags.IMPORT_UNRELIABLE : []);
234
+ const entityFlagged = new Set();
235
+
236
+ for (const [domain, domainEntry] of Object.entries(index.domains || {})) {
237
+ if (!fs.existsSync(path.join(domainsDir, domain, 'domain.json'))) errors.push(`index: missing domain file for ${domain}`);
238
+ for (const [entityId, entityEntry] of Object.entries(domainEntry.entities || {})) {
239
+ const ref = `${domain}/${entityId}`;
240
+ const entityPath = path.join(domainsDir, domain, 'entities', `${entityId}.json`);
241
+ if (!fs.existsSync(entityPath)) {
242
+ errors.push(`index: missing entity file for ${ref}`);
243
+ continue;
244
+ }
245
+ const entity = readJson(entityPath);
246
+ if ((entity.reliability.flags || []).includes('IMPORT_UNRELIABLE')) entityFlagged.add(ref);
247
+ if (entityEntry.path !== `domains/${domain}/entities/${entityId}.json`) {
248
+ errors.push(`index: invalid path for ${ref}`);
249
+ }
250
+ }
251
+ }
252
+
253
+ for (const ref of entityFlagged) {
254
+ if (!flagged.has(ref)) errors.push(`index: ${ref} has IMPORT_UNRELIABLE but is missing from flags`);
255
+ }
256
+ for (const ref of flagged) {
257
+ if (!entityFlagged.has(ref)) errors.push(`index: ${ref} is flagged IMPORT_UNRELIABLE but entity file is not`);
258
+ }
259
+ }
260
+
261
+ function loadIndex(domainsDir) {
262
+ return readJson(path.join(domainsDir, 'index.json'));
263
+ }
264
+
265
+ function listDomains(domainsDir) {
266
+ const index = loadIndex(domainsDir);
267
+ return Object.entries(index.domains || {}).map(([domain, info]) => ({
268
+ domain,
269
+ displayName: info.displayName,
270
+ ownerHint: info.ownerHint,
271
+ path: info.path,
272
+ }));
273
+ }
274
+
275
+ function listEntities(domainsDir, domain) {
276
+ const index = loadIndex(domainsDir);
277
+ const domainInfo = index.domains && index.domains[domain];
278
+ if (!domainInfo) throw new Error(`Unknown domain: ${domain}`);
279
+ return Object.entries(domainInfo.entities || {}).map(([entity, info]) => ({
280
+ ref: `${domain}/${entity}`,
281
+ entity,
282
+ displayName: info.displayName,
283
+ classification: info.classification,
284
+ reliabilityStatus: info.reliabilityStatus,
285
+ reliabilityFlags: info.reliabilityFlags,
286
+ path: info.path,
287
+ }));
288
+ }
289
+
290
+ function readEntityByRef(domainsDir, ref) {
291
+ const [domain, entity] = ref.split('/');
292
+ if (!domain || !entity) throw new Error(`Invalid ref: ${ref}`);
293
+ return loadEntity(domainsDir, domain, entity);
294
+ }
295
+
296
+ function resolveSource(domainsDir, { sourceSystem, sourceEntity, route }) {
297
+ const index = loadIndex(domainsDir);
298
+ const refs = new Set();
299
+ if (sourceSystem && sourceEntity) {
300
+ for (const ref of index.sourceAliasIndex[`${sourceSystem}:${sourceEntity}`] || []) refs.add(ref);
301
+ }
302
+ if (route) {
303
+ for (const [pattern, patternRefs] of Object.entries(index.routeAliasIndex || {})) {
304
+ if (route === pattern || routeMatches(pattern, route)) {
305
+ for (const ref of patternRefs) refs.add(ref);
306
+ }
307
+ }
308
+ }
309
+ return Array.from(refs).sort().map((ref) => {
310
+ const entity = readEntityByRef(domainsDir, ref);
311
+ return {
312
+ ref,
313
+ confidence: bestAliasConfidence(entity, { sourceSystem, sourceEntity, route }),
314
+ sourceAliases: (entity.sourceAliases || []).filter((alias) => aliasMatches(alias, { sourceSystem, sourceEntity, route })),
315
+ };
316
+ });
317
+ }
318
+
319
+ function routeMatches(pattern, route) {
320
+ if (!pattern.includes('{') && !pattern.includes(':')) return false;
321
+ const escaped = pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/\\\{[^}]+\\\}/g, '[^/]+').replace(/:[A-Za-z0-9_-]+/g, '[^/]+');
322
+ return new RegExp(`^${escaped}$`).test(route);
323
+ }
324
+
325
+ function aliasMatches(alias, query) {
326
+ const sourceMatches = (!query.sourceSystem || alias.sourceSystem === query.sourceSystem) && (!query.sourceEntity || alias.sourceEntity === query.sourceEntity);
327
+ const routeMatchesAlias = !query.route || (alias.routes || []).some((pattern) => query.route === pattern || routeMatches(pattern, query.route));
328
+ return sourceMatches && routeMatchesAlias;
329
+ }
330
+
331
+ function bestAliasConfidence(entity, query) {
332
+ const order = { high: 3, medium: 2, low: 1 };
333
+ let best = 'low';
334
+ for (const alias of entity.sourceAliases || []) {
335
+ if (aliasMatches(alias, query) && (order[alias.confidence] || 0) > (order[best] || 0)) best = alias.confidence;
336
+ }
337
+ return best;
338
+ }
339
+
340
+ function listFlagged(domainsDir, flag) {
341
+ const index = loadIndex(domainsDir);
342
+ return (index.flags && index.flags[flag] ? index.flags[flag] : []).map((ref) => {
343
+ const entity = readEntityByRef(domainsDir, ref);
344
+ return {
345
+ ref,
346
+ displayName: entity.displayName,
347
+ classification: entity.target.classification,
348
+ reliabilityStatus: entity.reliability.status,
349
+ summary: firstPitfallOrGuidance(entity),
350
+ };
351
+ });
352
+ }
353
+
354
+ function summarizeEntities(domainsDir, refs, { includeEvidence = false } = {}) {
355
+ return refs.map((ref) => {
356
+ const entity = readEntityByRef(domainsDir, ref);
357
+ const summary = {
358
+ ref,
359
+ displayName: entity.displayName,
360
+ target: entity.target,
361
+ preferredWrite: entity.preferredWrite,
362
+ reliability: entity.reliability,
363
+ pitfalls: entity.pitfalls,
364
+ mappingGuidance: entity.mappingGuidance,
365
+ setupRequirements: entity.setupRequirements || [],
366
+ fieldContracts: entity.fieldContracts || [],
367
+ };
368
+ if (includeEvidence) summary.evidence = entity.evidence;
369
+ return summary;
370
+ });
371
+ }
372
+
373
+ module.exports = {
374
+ knowledgeRoot,
375
+ generateIndex,
376
+ validateKnowledge,
377
+ writeJson,
378
+ listDomains,
379
+ listEntities,
380
+ readEntityByRef,
381
+ resolveSource,
382
+ listFlagged,
383
+ summarizeEntities,
384
+ };
@@ -0,0 +1,260 @@
1
+ 'use strict';
2
+
3
+ // rp-target-wix — NDJSON record-stream I/O for migration data files.
4
+ //
5
+ // Every migration writes the same shape of intermediate data: a long stream of per-entity
6
+ // records that a later stage scans, batches and cursors through. That is a line-delimited
7
+ // format, not a single JSON document, so it is built once here rather than re-derived by
8
+ // codegen per project.
9
+ //
10
+ // WHY NDJSON over a JSON array (`{ entity, records: [...] }`):
11
+ // - scan: counting or filtering never parses the whole file, and never holds it in memory
12
+ // - batch: a bulk endpoint's page is `readBatches(file, 100)` — no slicing a giant array.
13
+ // Use `readBatchesByLimits` when the endpoint caps several dimensions at once (Wix bulk
14
+ // product create caps products, variants AND options per request).
15
+ // - cursor: resume from record N is a byte offset or a line skip, not a full re-parse
16
+ // - append: a producer can emit records as it finds them; a crash leaves a valid prefix
17
+ // - a single malformed record is one bad line, not an unparseable file
18
+ //
19
+ // USE IT FOR record streams (`data/source-extract/<entity>.ndjson`, crosswalks, audit logs).
20
+ // Do NOT use it for single documents — a manifest, mapping plan, decisions or completion
21
+ // report is one object and stays `.json`. Line-delimiting a document buys nothing and makes
22
+ // it unreadable.
23
+ //
24
+ // Dependency-free and streaming, like the source adapters' transport modules. Codegen
25
+ // vendors a copy into the project (e.g. `src/lib/ndjson.js`) and imports from it.
26
+
27
+ const fs = require('node:fs');
28
+ const fsp = require('node:fs/promises');
29
+ const path = require('node:path');
30
+ const readline = require('node:readline');
31
+
32
+ const EXT = '.ndjson';
33
+
34
+ function ensureDir(filePath) {
35
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
36
+ }
37
+
38
+ // One record per line. JSON.stringify escapes embedded newlines, so a record can never
39
+ // break the line framing.
40
+ function encodeRecord(record) {
41
+ if (record === undefined) throw new Error('ndjson: cannot encode undefined');
42
+ const line = JSON.stringify(record);
43
+ if (line === undefined) throw new Error('ndjson: record is not JSON-serialisable');
44
+ return `${line}\n`;
45
+ }
46
+
47
+ // --- writing ---------------------------------------------------------------
48
+
49
+ // Streaming write of a whole stream. Accepts arrays, generators and async generators, so a
50
+ // reader can hand over records as it produces them without materialising them all.
51
+ async function writeRecords(filePath, records) {
52
+ ensureDir(filePath);
53
+ const out = fs.createWriteStream(filePath, { flags: 'w' });
54
+ let count = 0;
55
+ try {
56
+ for await (const record of records) {
57
+ count += 1;
58
+ if (!out.write(encodeRecord(record))) {
59
+ await new Promise((resolve) => out.once('drain', resolve));
60
+ }
61
+ }
62
+ } finally {
63
+ await new Promise((resolve, reject) => {
64
+ out.end((err) => (err ? reject(err) : resolve()));
65
+ });
66
+ }
67
+ return count;
68
+ }
69
+
70
+ // Incremental appender for producers that emit over time (crosswalk, audit log). `flush`
71
+ // is per-record and O(1) — the whole point of not rewriting a JSON array each time.
72
+ function createAppender(filePath) {
73
+ ensureDir(filePath);
74
+ let count = 0;
75
+ return {
76
+ file: filePath,
77
+ append(record) {
78
+ fs.appendFileSync(filePath, encodeRecord(record));
79
+ count += 1;
80
+ return record;
81
+ },
82
+ appendAll(records) {
83
+ let buffer = '';
84
+ for (const record of records) buffer += encodeRecord(record);
85
+ if (buffer) fs.appendFileSync(filePath, buffer);
86
+ count += records.length;
87
+ return records.length;
88
+ },
89
+ written: () => count,
90
+ };
91
+ }
92
+
93
+ // --- reading ---------------------------------------------------------------
94
+
95
+ // Streams records without loading the file. readline handles \n, \r\n and the chunk-boundary
96
+ // case that a naive split('\n') gets wrong.
97
+ //
98
+ // A blank line is skipped (a trailing newline is normal). A malformed line throws, naming the
99
+ // line number — silently dropping records would corrupt a migration invisibly.
100
+ async function* readRecords(filePath, { skipMalformed = false, onMalformed = null } = {}) {
101
+ if (!fs.existsSync(filePath)) return;
102
+ const input = fs.createReadStream(filePath, { encoding: 'utf8' });
103
+ const rl = readline.createInterface({ input, crlfDelay: Infinity });
104
+ let lineNumber = 0;
105
+ try {
106
+ for await (const line of rl) {
107
+ lineNumber += 1;
108
+ if (line.trim() === '') continue;
109
+ let record;
110
+ try {
111
+ record = JSON.parse(line);
112
+ } catch (err) {
113
+ const detail = `${filePath}:${lineNumber} is not valid JSON (${err.message})`;
114
+ if (onMalformed) onMalformed({ file: filePath, line: lineNumber, raw: line, error: err.message });
115
+ if (skipMalformed) continue;
116
+ throw new Error(`ndjson: ${detail}. Refusing to continue — a dropped record is invisible data loss.`);
117
+ }
118
+ yield record;
119
+ }
120
+ } finally {
121
+ rl.close();
122
+ input.destroy();
123
+ }
124
+ }
125
+
126
+ // The batching primitive bulk endpoints consume. `size` is a record count; when a target
127
+ // caps something else too (Wix bulk product create allows 100 products AND 1000 variants
128
+ // per request) use readBatchesBy instead.
129
+ async function* readBatches(filePath, size = 100, options = {}) {
130
+ if (!Number.isInteger(size) || size < 1) throw new Error('ndjson: batch size must be a positive integer');
131
+ let batch = [];
132
+ for await (const record of readRecords(filePath, options)) {
133
+ batch.push(record);
134
+ if (batch.length >= size) {
135
+ yield batch;
136
+ batch = [];
137
+ }
138
+ }
139
+ if (batch.length) yield batch;
140
+ }
141
+
142
+ // Batch against SEVERAL simultaneous caps. Real bulk endpoints rarely have just one: Wix
143
+ // bulk product create allows 100 products AND 1000 variants AND 100 options AND 100
144
+ // modifiers AND 100 infoSections per request, and exceeding any single one rejects the whole
145
+ // batch. Batching on record count alone silently produces requests that 428.
146
+ //
147
+ // readBatchesByLimits(file, {
148
+ // limits: { records: 100, variants: 1000, options: 100 },
149
+ // cost: (p) => ({ variants: p.variants.length, options: p.options.length }),
150
+ // })
151
+ //
152
+ // `records` is implicit and always counted. Any dimension absent from `limits` is ignored,
153
+ // so a cost function may report more than the caller caps.
154
+ //
155
+ // A single record that alone exceeds a cap is still emitted, in a batch of one, with
156
+ // `oversized` reported through `onOversized`. Dropping it would be silent data loss and
157
+ // splitting it is impossible — the caller has to decide (skip it, or fail loudly).
158
+ async function* readBatchesByLimits(filePath, { limits = {}, cost = () => ({}), onOversized = null, ...options } = {}) {
159
+ const caps = { records: 100, ...limits };
160
+ for (const [dim, cap] of Object.entries(caps)) {
161
+ if (!(Number.isFinite(cap) && cap >= 1)) throw new Error(`ndjson: limit "${dim}" must be a number >= 1 (got ${cap})`);
162
+ }
163
+
164
+ let batch = [];
165
+ let running = {};
166
+ const costOf = (record) => {
167
+ const c = cost(record) || {};
168
+ return { ...c, records: 1 };
169
+ };
170
+ const wouldExceed = (c) => Object.keys(caps).some((dim) => (running[dim] || 0) + (c[dim] || 0) > caps[dim]);
171
+ const aloneExceeds = (c) => Object.keys(caps).some((dim) => (c[dim] || 0) > caps[dim]);
172
+
173
+ for await (const record of readRecords(filePath, options)) {
174
+ const c = costOf(record);
175
+ if (batch.length && wouldExceed(c)) {
176
+ yield batch;
177
+ batch = [];
178
+ running = {};
179
+ }
180
+ if (aloneExceeds(c) && onOversized) {
181
+ const over = Object.keys(caps).filter((dim) => (c[dim] || 0) > caps[dim]);
182
+ onOversized({ record, cost: c, exceeded: over, caps });
183
+ }
184
+ batch.push(record);
185
+ for (const dim of Object.keys(c)) running[dim] = (running[dim] || 0) + c[dim];
186
+ }
187
+ if (batch.length) yield batch;
188
+ }
189
+
190
+ // Single-dimension convenience wrapper over readBatchesByLimits, kept because plenty of
191
+ // endpoints really do have just one cap.
192
+ async function* readBatchesBy(filePath, { maxCount = 100, maxCost = Infinity, cost = () => 1, ...options } = {}) {
193
+ const limits = { records: maxCount };
194
+ if (Number.isFinite(maxCost)) limits.cost = maxCost;
195
+ yield* readBatchesByLimits(filePath, { ...options, limits, cost: (r) => ({ cost: cost(r) }) });
196
+ }
197
+
198
+ // Cursor: skip `offset` records, take at most `limit`. Used for resume — no need to parse
199
+ // what has already been processed into objects.
200
+ async function* readSlice(filePath, { offset = 0, limit = Infinity, ...options } = {}) {
201
+ let index = 0;
202
+ let taken = 0;
203
+ for await (const record of readRecords(filePath, options)) {
204
+ if (index++ < offset) continue;
205
+ if (taken++ >= limit) return;
206
+ yield record;
207
+ }
208
+ }
209
+
210
+ // Cheap count — parses nothing, just counts non-empty lines.
211
+ async function countRecords(filePath) {
212
+ if (!fs.existsSync(filePath)) return 0;
213
+ const input = fs.createReadStream(filePath, { encoding: 'utf8' });
214
+ const rl = readline.createInterface({ input, crlfDelay: Infinity });
215
+ let count = 0;
216
+ try {
217
+ for await (const line of rl) if (line.trim() !== '') count += 1;
218
+ } finally {
219
+ rl.close();
220
+ input.destroy();
221
+ }
222
+ return count;
223
+ }
224
+
225
+ // Escape hatch for small streams that genuinely need to be in memory at once (a 6-record
226
+ // category list). Named so that using it on a large stream is an obvious mistake.
227
+ async function readAllRecords(filePath, options = {}) {
228
+ const out = [];
229
+ for await (const record of readRecords(filePath, options)) out.push(record);
230
+ return out;
231
+ }
232
+
233
+ // --- migration of existing projects ---------------------------------------
234
+
235
+ // Converts a legacy `{ entity, recordCount, records: [...] }` document to NDJSON. Kept so a
236
+ // project generated before this format change can be moved forward without re-extracting.
237
+ async function convertLegacyJsonFile(jsonPath, ndjsonPath, { recordsKey = 'records' } = {}) {
238
+ const parsed = JSON.parse(await fsp.readFile(jsonPath, 'utf8'));
239
+ const records = Array.isArray(parsed) ? parsed : parsed[recordsKey];
240
+ if (!Array.isArray(records)) {
241
+ throw new Error(`ndjson: ${jsonPath} has no array at "${recordsKey}" to convert`);
242
+ }
243
+ const count = await writeRecords(ndjsonPath, records);
244
+ return { from: jsonPath, to: ndjsonPath, count };
245
+ }
246
+
247
+ module.exports = {
248
+ EXT,
249
+ encodeRecord,
250
+ writeRecords,
251
+ createAppender,
252
+ readRecords,
253
+ readBatches,
254
+ readBatchesBy,
255
+ readBatchesByLimits,
256
+ readSlice,
257
+ countRecords,
258
+ readAllRecords,
259
+ convertLegacyJsonFile,
260
+ };