@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.
- package/README.md +5 -1
- package/package.json +1 -1
- package/skills/wix-app/SKILL.md +4 -1
- package/skills/wix-app/references/APP_TOOLS.md +134 -0
- package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +1 -1
- package/skills/wix-app/references/DASHBOARD_PAGE.md +0 -10
- package/skills/wix-app/references/DATA_COLLECTION.md +6 -4
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +28 -7
- package/skills/wix-app/references/SERVICE_PLUGIN.md +12 -10
- package/skills/wix-app/references/STORES_VERSIONING.md +9 -211
- package/skills/wix-app/references/app-tools/TOOLS.md +75 -0
- package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +5 -0
- package/skills/wix-app/references/dashboard-page/DASHBOARD_API.md +2 -2
- package/skills/wix-app/references/editor-react-component/A11Y-REVIEW-REFERENCE.md +172 -0
- package/skills/wix-app/references/editor-react-component/A11Y-REVIEW.md +138 -0
- package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +172 -0
- package/skills/wix-app/references/editor-react-component/BRANDED-COMPONENTS.md +29 -0
- package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +1 -1
- package/skills/wix-app/references/editor-react-component/COMPONENT-PREVIEW.md +57 -0
- package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +33 -2
- package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +5 -3
- package/skills/wix-app/references/editor-react-component/DIRECTIONALITY.md +18 -1
- package/skills/wix-app/references/editor-react-component/PARTS.md +15 -2
- package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +4 -3
- package/skills/wix-app/references/service-plugin/BOOKINGS-STAFF-SORTING.md +13 -9
- package/skills/wix-app/references/service-plugin/DISCOUNT-TRIGGERS.md +4 -0
- package/skills/wix-app/references/service-plugin/GIFT-CARDS.md +4 -0
- package/skills/wix-app/references/service-plugin/PAYMENT-SETTINGS.md +3 -1
- package/skills/wix-app/references/service-plugin/SHIPPING-RATES.md +4 -0
- package/skills/wix-app/references/service-plugin/TOOLS_PROVIDER.md +54 -0
- package/skills/wix-app/references/stores/CATEGORIES.md +22 -0
- package/skills/wix-app/references/stores/GET_PRODUCT.md +99 -0
- package/skills/wix-app/references/stores/INVENTORY.md +37 -0
- package/skills/wix-app/references/stores/QUERY.md +119 -0
- package/skills/wix-app/references/stores/WRITE.md +55 -0
- package/skills/wix-docs/SKILL.md +35 -3
- package/skills/wix-headless/SKILL.md +9 -2
- package/skills/wix-headless/entry/bootstrap.mjs +2 -2
- package/skills/wix-headless/entry/skill.md +0 -2
- package/skills/wix-headless/references/CAPABILITIES.md +6 -4
- package/skills/wix-headless/references/CONTENT.md +36 -0
- package/skills/wix-headless/references/DESIGN.md +54 -0
- package/skills/wix-headless/references/DISCOVERY.md +25 -1
- package/skills/wix-headless/references/FEEDBACK.md +16 -5
- package/skills/wix-headless/references/IMAGE_GENERATION.md +10 -0
- package/skills/wix-headless/references/SDK_HANDOFF.md +2 -0
- package/skills/wix-headless/references/SEED.md +3 -1
- package/skills/wix-headless/references/SETUP.md +1 -1
- package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +3 -2
- package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-reservations.md +42 -2
- package/skills/wix-headless/references/inline-recipes/setup-bookings.md +5 -1
- package/skills/wix-headless/references/inline-recipes/setup-forms.md +1 -1
- package/skills/wix-headless/references/inline-recipes/setup-online-store.md +33 -8
- package/skills/wix-headless/references/inline-recipes/setup-portfolio.md +3 -1
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-experiences.md +73 -0
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-orders.md +38 -2
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-reservations.md +20 -1
- package/skills/wix-headless/references/inline-recipes/setup-restaurants.md +1 -1
- package/skills/wix-headless/references/managed/CONNECT.md +2 -2
- package/skills/wix-headless/references/managed/CREATE.md +15 -1
- package/skills/wix-headless/references/managed/DEPLOYMENT.md +47 -0
- package/skills/wix-headless/references/self-managed/DEPLOYMENT.md +8 -0
- package/skills/wix-headless/references/stripe/DEPLOYMENT.md +8 -0
- package/skills/wix-manage/SKILL.md +131 -12
- package/skills/wix-manage/references/analytics/analytics-dashboard-navigation.md +41 -0
- package/skills/wix-manage/references/analytics/query-site-analytics.md +66 -9
- package/skills/wix-manage/references/app-installation/app-installation-dashboard-navigation.md +28 -0
- package/skills/wix-manage/references/app-installation/install-wix-apps.md +3 -0
- package/skills/wix-manage/references/blog/blog-dashboard-navigation.md +56 -0
- package/skills/wix-manage/references/blog/how-to-create-blog-posts.md +31 -6
- package/skills/wix-manage/references/bookings/booking-service-policy-setup.md +3 -1
- package/skills/wix-manage/references/bookings/bookings-dashboard-navigation.md +63 -0
- package/skills/wix-manage/references/bookings/create-booking-service-from-prompt.md +6 -5
- package/skills/wix-manage/references/bookings/create-course-service.md +30 -5
- package/skills/wix-manage/references/bookings/diagnose-availability-issues.md +85 -42
- package/skills/wix-manage/references/cms/cms-dashboard-navigation.md +44 -0
- package/skills/wix-manage/references/cms/cms-data-items-crud.md +31 -3
- package/skills/wix-manage/references/cms/cms-publishing-flow.md +287 -0
- package/skills/wix-manage/references/cms/cms-schema-management.md +33 -1
- package/skills/wix-manage/references/contacts/contacts-dashboard-navigation.md +46 -0
- package/skills/wix-manage/references/contacts/create-a-contact.md +82 -0
- package/skills/wix-manage/references/contacts/update-a-contact.md +119 -0
- package/skills/wix-manage/references/dashboard-navigation/dashboard-navigation.md +82 -0
- package/skills/wix-manage/references/dashboard-navigation/routes.json +1733 -0
- package/skills/wix-manage/references/domains/domains-dashboard-navigation.md +32 -0
- package/skills/wix-manage/references/ecommerce/ecom-pricing.md +4 -4
- package/skills/wix-manage/references/ecommerce/ecom-shipping.md +1 -1
- package/skills/wix-manage/references/ecommerce/gift-cards/ecom-gift-cards-goal-sell-gift-cards.md +338 -0
- package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-create-discount-rule.md +42 -78
- package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-bundle-and-save.md +1 -1
- package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-stock-mover.md +1 -1
- package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-upsell-boost.md +1 -1
- package/skills/wix-manage/references/ecommerce/recommend-ecommerce-strategy.md +90 -92
- package/skills/wix-manage/references/events/create-wix-event.md +176 -0
- package/skills/wix-manage/references/events/manage-wix-events.md +174 -0
- package/skills/wix-manage/references/forms/forms-dashboard-navigation.md +44 -0
- package/skills/wix-manage/references/get-paid/get-paid-dashboard-navigation.md +52 -0
- package/skills/wix-manage/references/get-paid/how-to-setup-wix-payments.md +30 -7
- package/skills/wix-manage/references/google-ads/billing-and-payment.md +80 -0
- package/skills/wix-manage/references/google-ads/create-performance-max-campaign.md +212 -0
- package/skills/wix-manage/references/google-ads/get-campaign-suggestions.md +110 -0
- package/skills/wix-manage/references/google-ads/google-ads-dashboard-navigation.md +25 -0
- package/skills/wix-manage/references/google-ads/install-and-create-account.md +155 -0
- package/skills/wix-manage/references/google-ads/manage-campaign-lifecycle.md +63 -0
- package/skills/wix-manage/references/google-ads/query-campaign-analytics.md +155 -0
- package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +225 -144
- package/skills/wix-manage/references/marketing/generate-and-publish-marketing-plan.md +19 -10
- package/skills/wix-manage/references/marketing/marketing-dashboard-navigation.md +52 -0
- package/skills/wix-manage/references/pricing-plans/create-and-update-pricing-plans.md +99 -1
- package/skills/wix-manage/references/pricing-plans/pricing-plans-dashboard-navigation.md +45 -0
- package/skills/wix-manage/references/restaurants/restaurants-dashboard-navigation.md +68 -0
- package/skills/wix-manage/references/restaurants/wix-restaurants-setup.md +94 -125
- package/skills/wix-manage/references/site-properties/change-payment-currency-site-properties.md +48 -9
- package/skills/wix-manage/references/site-properties/site-properties-dashboard-navigation.md +31 -0
- package/skills/wix-manage/references/sites/create-headless-site.md +52 -0
- package/skills/wix-manage/references/sites/create-site-from-template.md +2 -25
- package/skills/wix-manage/references/sites/site-import.md +243 -0
- package/skills/wix-manage/references/sites/sites-dashboard-navigation.md +29 -0
- package/skills/wix-manage/references/stores/add-store-pages-to-site.md +17 -1
- package/skills/wix-manage/references/stores/create-product-from-image.md +8 -6
- package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +16 -10
- package/skills/wix-manage/references/stores/find-products-query-and-search-catalog-v3.md +26 -8
- package/skills/wix-manage/references/stores/stores-dashboard-navigation.md +65 -0
- package/skills/wix-manage/references/stores/update-product-with-options.md +39 -7
- package/skills/wix-replatform/.publish-manifest.json +8 -0
- package/skills/wix-replatform/SKILL.md +693 -0
- package/skills/wix-replatform/lib/artifact-freshness.js +215 -0
- package/skills/wix-replatform/lib/completion-report.js +200 -0
- package/skills/wix-replatform/lib/config-env.js +59 -0
- package/skills/wix-replatform/lib/execution-manifest.js +185 -0
- package/skills/wix-replatform/lib/execution-state.js +173 -0
- package/skills/wix-replatform/lib/import-recovery.js +313 -0
- package/skills/wix-replatform/lib/local-state.js +642 -0
- package/skills/wix-replatform/lib/orchestration-preflight.js +143 -0
- package/skills/wix-replatform/lib/orchestration-router.js +122 -0
- package/skills/wix-replatform/lib/orchestration-state.js +455 -0
- package/skills/wix-replatform/lib/progress-log.js +224 -0
- package/skills/wix-replatform/lib/progress-log.sh +140 -0
- package/skills/wix-replatform/lib/url-preservation-state.js +391 -0
- package/skills/wix-replatform/resources/rp-discovery/SKILL.md +184 -0
- package/skills/wix-replatform/resources/rp-execute-import/SKILL.md +529 -0
- package/skills/wix-replatform/resources/rp-execute-setup/SKILL.md +316 -0
- package/skills/wix-replatform/resources/rp-execute-setup/scripts/mint-token.sh +64 -0
- package/skills/wix-replatform/resources/rp-import-codegen/SKILL.md +1114 -0
- package/skills/wix-replatform/resources/rp-mapper/SKILL.md +430 -0
- package/skills/wix-replatform/resources/rp-mapper/lib/mapping-resolve.js +217 -0
- package/skills/wix-replatform/resources/rp-mapper/scripts/resolve-mapping.js +148 -0
- package/skills/wix-replatform/resources/rp-mapper/wix-business-solutions-taxonomy.md +378 -0
- package/skills/wix-replatform/resources/rp-setup-discovery/SKILL.md +183 -0
- package/skills/wix-replatform/resources/rp-source-csv/SKILL.md +478 -0
- package/skills/wix-replatform/resources/rp-source-csv/lib/canonical-record.js +136 -0
- package/skills/wix-replatform/resources/rp-source-csv/lib/csv-fileset.js +0 -0
- package/skills/wix-replatform/resources/rp-source-csv/lib/csv-fingerprint.js +310 -0
- package/skills/wix-replatform/resources/rp-source-csv/lib/csv-layout.js +1081 -0
- package/skills/wix-replatform/resources/rp-source-csv/lib/csv-parse.js +618 -0
- package/skills/wix-replatform/resources/rp-source-csv/scripts/csv-discovery.js +949 -0
- package/skills/wix-replatform/resources/rp-source-csv/source-schema.example.json +196 -0
- package/skills/wix-replatform/resources/rp-source-csv/vendors/bigcommerce.json +66 -0
- package/skills/wix-replatform/resources/rp-source-csv/vendors/magento.json +60 -0
- package/skills/wix-replatform/resources/rp-source-csv/vendors/shopify.json +95 -0
- package/skills/wix-replatform/resources/rp-source-csv/vendors/woocommerce.json +82 -0
- package/skills/wix-replatform/resources/rp-source-wordpress/SKILL.md +256 -0
- package/skills/wix-replatform/resources/rp-source-wordpress/lib/wp-http.js +249 -0
- package/skills/wix-replatform/resources/rp-source-wordpress/lib/wp-route-classifier.js +444 -0
- package/skills/wix-replatform/resources/rp-source-wordpress/scripts/wp-discovery.js +774 -0
- package/skills/wix-replatform/resources/rp-source-wordpress/source-schema.example.json +71 -0
- package/skills/wix-replatform/resources/rp-target-wix/SKILL.md +632 -0
- package/skills/wix-replatform/resources/rp-target-wix/SPEC-product-reviews-and-blog-authorship.md +330 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/README.md +21 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/blog/domain.json +19 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/blog/entities/category.json +37 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/blog/entities/comment.json +37 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/blog/entities/post.json +39 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/blog/entities/tag.json +35 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/cms/domain.json +14 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/cms/entities/collection.json +35 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/cms/entities/data-item.json +36 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/cms/entities/reference.json +35 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/crm/domain.json +14 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/crm/entities/contact.json +131 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/crm/entities/email-subscription.json +37 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/crm/entities/label.json +37 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/ecom/domain.json +21 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/ecom/entities/order-line-item.json +37 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/ecom/entities/order-refund.json +37 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/ecom/entities/order.json +97 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/index.json +528 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/media/domain.json +14 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/media/entities/media-file.json +38 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/media/entities/media-folder.json +37 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/members/domain.json +13 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/members/entities/badge.json +37 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/members/entities/member.json +53 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/schema.json +84 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/stores/domain.json +25 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/category.json +37 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/coupon.json +37 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/inventory-item.json +38 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/product-tag.json +37 -0
- package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/product.json +90 -0
- package/skills/wix-replatform/resources/rp-target-wix/lib/audit-summary.js +64 -0
- package/skills/wix-replatform/resources/rp-target-wix/lib/contract-ledger.js +141 -0
- package/skills/wix-replatform/resources/rp-target-wix/lib/domain-knowledge.js +384 -0
- package/skills/wix-replatform/resources/rp-target-wix/lib/ndjson.js +260 -0
- package/skills/wix-replatform/resources/rp-target-wix/lib/stores-verification.js +238 -0
- package/skills/wix-replatform/resources/rp-target-wix/lib/wix-build.js +237 -0
- package/skills/wix-replatform/resources/rp-target-wix/lib/wix-target-spec.js +238 -0
- package/skills/wix-replatform/resources/rp-target-wix/lib/wix-writers.js +2219 -0
- package/skills/wix-replatform/resources/rp-target-wix/scripts/domain-knowledge-validate.js +31 -0
- package/skills/wix-replatform/resources/rp-target-wix/scripts/domain-knowledge.js +100 -0
- package/skills/wix-replatform/resources/rp-target-wix/scripts/verify-stores.js +107 -0
- package/skills/wix-replatform/resources/rp-telemetry/SKILL.md +344 -0
- package/skills/wix-replatform/resources/rp-telemetry/lib/bi-sink.js +250 -0
- package/skills/wix-replatform/resources/rp-telemetry/lib/telemetry-recorder.js +1927 -0
- package/skills/wix-replatform/resources/rp-telemetry/scripts/meter-from-audit.js +83 -0
- package/skills/wix-replatform/resources/rp-telemetry/scripts/rp-telemetry.js +141 -0
- package/skills/wix-replatform/scripts/artifact-freshness.js +76 -0
- package/skills/wix-replatform/scripts/execution-manifest-validate.js +43 -0
- package/skills/wix-replatform/scripts/execution-state-prepare.js +128 -0
- package/skills/wix-replatform/scripts/orchestration-preflight.js +48 -0
- package/skills/wix-replatform/scripts/orchestration-route.js +46 -0
- package/skills/wix-replatform/scripts/orchestration-state.js +245 -0
- package/skills/wix-vibe-headless/SKILL.md +54 -25
- package/skills/wix-vibe-headless/install/deploy.cjs +95 -0
- package/skills/wix-vibe-headless/install/pin-agents-md.cjs +34 -0
- package/skills/wix-vibe-headless/platforms/README.md +26 -0
- package/skills/wix-vibe-headless/platforms/base44.md +177 -0
- package/skills/wix-vibe-headless/platforms/generic.md +122 -0
- package/skills/wix-vibe-headless/references/blog/INSTRUCTIONS.md +230 -119
- package/skills/wix-vibe-headless/references/blog/app/components/PostCard.jsx +43 -0
- package/skills/wix-vibe-headless/references/blog/app/components/PostChips.jsx +25 -0
- package/skills/wix-vibe-headless/references/blog/app/components/PostGrid.jsx +15 -0
- package/skills/wix-vibe-headless/references/blog/app/context/TaxonomyContext.jsx +35 -0
- package/skills/wix-vibe-headless/references/blog/app/hooks/usePostDetail.js +38 -0
- package/skills/wix-vibe-headless/references/blog/app/pages/Blog.jsx +40 -0
- package/skills/wix-vibe-headless/references/blog/app/pages/CategoryPage.jsx +54 -0
- package/skills/wix-vibe-headless/references/blog/app/pages/PostDetail.jsx +65 -0
- package/skills/wix-vibe-headless/references/blog/app/pages/TagPage.jsx +50 -0
- package/skills/wix-vibe-headless/references/blog/seed/SEED.md +103 -0
- package/skills/wix-vibe-headless/references/blog/seed/seed-blog.js +270 -0
- package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +260 -145
- package/skills/wix-vibe-headless/references/bookings/app/components/BookingForm.jsx +65 -0
- package/skills/wix-vibe-headless/references/bookings/app/components/ServiceCard.jsx +47 -0
- package/skills/wix-vibe-headless/references/bookings/app/components/ServiceGrid.jsx +13 -0
- package/skills/wix-vibe-headless/references/bookings/app/components/SlotPicker.jsx +126 -0
- package/skills/wix-vibe-headless/references/bookings/app/hooks/useServiceDetail.js +108 -0
- package/skills/wix-vibe-headless/references/bookings/app/hooks/useServices.js +58 -0
- package/skills/wix-vibe-headless/references/bookings/app/lib/serviceFacts.js +95 -0
- package/skills/wix-vibe-headless/references/bookings/app/pages/ServiceDetail.jsx +94 -0
- package/skills/wix-vibe-headless/references/bookings/app/pages/Services.jsx +89 -0
- package/skills/wix-vibe-headless/references/bookings/{wix-bookings-checkout.js → app/rest/wix-bookings-checkout.js} +1 -1
- package/skills/wix-vibe-headless/references/bookings/{wix-bookings-services.js → app/rest/wix-bookings-services.js} +90 -12
- package/skills/wix-vibe-headless/references/bookings/seed/SEED.md +117 -0
- package/skills/wix-vibe-headless/references/bookings/seed/seed-bookings.js +333 -0
- package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +169 -147
- package/skills/wix-vibe-headless/references/cms/app/collection.config.js +31 -0
- package/skills/wix-vibe-headless/references/cms/app/lib/wixImage.js +18 -0
- package/skills/wix-vibe-headless/references/cms/{wix-cms.js → app/rest/wix-cms.js} +47 -2
- package/skills/wix-vibe-headless/references/cms/seed/SEED.md +145 -0
- package/skills/wix-vibe-headless/references/events/INSTRUCTIONS.md +228 -131
- package/skills/wix-vibe-headless/references/events/app/components/CategoryFilter.jsx +23 -0
- package/skills/wix-vibe-headless/references/events/app/components/EventCard.jsx +43 -0
- package/skills/wix-vibe-headless/references/events/app/components/EventGrid.jsx +13 -0
- package/skills/wix-vibe-headless/references/events/app/components/EventRegistration.jsx +29 -0
- package/skills/wix-vibe-headless/references/events/app/components/RsvpForm.jsx +57 -0
- package/skills/wix-vibe-headless/references/events/app/components/TicketPicker.jsx +78 -0
- package/skills/wix-vibe-headless/references/events/app/hooks/useEventDetail.js +27 -0
- package/skills/wix-vibe-headless/references/events/app/hooks/useEventsList.js +54 -0
- package/skills/wix-vibe-headless/references/events/app/hooks/useRsvpForm.js +40 -0
- package/skills/wix-vibe-headless/references/events/app/hooks/useTicketing.js +81 -0
- package/skills/wix-vibe-headless/references/events/app/pages/EventDetail.jsx +48 -0
- package/skills/wix-vibe-headless/references/events/app/pages/Events.jsx +36 -0
- package/skills/wix-vibe-headless/references/events/{wix-events-browse.js → app/rest/wix-events-browse.js} +3 -2
- package/skills/wix-vibe-headless/references/events/seed/SEED.md +107 -0
- package/skills/wix-vibe-headless/references/events/seed/seed-events.js +251 -0
- package/skills/wix-vibe-headless/references/members/INSTRUCTIONS.md +276 -188
- package/skills/wix-vibe-headless/references/members/app/components/LoginForm.jsx +101 -0
- package/skills/wix-vibe-headless/references/members/app/components/MemberMenu.jsx +33 -0
- package/skills/wix-vibe-headless/references/members/app/components/RequireAuth.jsx +21 -0
- package/skills/wix-vibe-headless/references/members/app/components/SocialButtons.jsx +29 -0
- package/skills/wix-vibe-headless/references/members/app/context/MemberContext.jsx +54 -0
- package/skills/wix-vibe-headless/references/members/app/hooks/useLoginForm.js +77 -0
- package/skills/wix-vibe-headless/references/members/app/pages/Account.jsx +36 -0
- package/skills/wix-vibe-headless/references/members/app/pages/Callback.jsx +32 -0
- package/skills/wix-vibe-headless/references/members/app/pages/Login.jsx +35 -0
- package/skills/wix-vibe-headless/references/members/{wix-members-auth.js → app/rest/wix-members-auth.js} +6 -3
- package/skills/wix-vibe-headless/references/members/install/Register.jsx +22 -0
- package/skills/wix-vibe-headless/references/members/seed/SEED.md +22 -0
- package/skills/wix-vibe-headless/references/portfolio/INSTRUCTIONS.md +233 -104
- package/skills/wix-vibe-headless/references/portfolio/app/components/CollectionCard.jsx +31 -0
- package/skills/wix-vibe-headless/references/portfolio/app/components/CollectionGrid.jsx +15 -0
- package/skills/wix-vibe-headless/references/portfolio/app/components/ProjectCard.jsx +39 -0
- package/skills/wix-vibe-headless/references/portfolio/app/components/ProjectGrid.jsx +15 -0
- package/skills/wix-vibe-headless/references/portfolio/app/components/ProjectMedia.jsx +29 -0
- package/skills/wix-vibe-headless/references/portfolio/app/hooks/useCollectionProjects.js +35 -0
- package/skills/wix-vibe-headless/references/portfolio/app/hooks/usePortfolioGallery.js +27 -0
- package/skills/wix-vibe-headless/references/portfolio/app/hooks/useProjectDetail.js +25 -0
- package/skills/wix-vibe-headless/references/portfolio/app/pages/CollectionPage.jsx +39 -0
- package/skills/wix-vibe-headless/references/portfolio/app/pages/Portfolio.jsx +27 -0
- package/skills/wix-vibe-headless/references/portfolio/app/pages/ProjectDetail.jsx +60 -0
- package/skills/wix-vibe-headless/references/portfolio/{wix-portfolio.js → app/rest/wix-portfolio.js} +84 -55
- package/skills/wix-vibe-headless/references/portfolio/seed/SEED.md +94 -0
- package/skills/wix-vibe-headless/references/portfolio/seed/seed-portfolio.js +236 -0
- package/skills/wix-vibe-headless/references/pricing-plans/INSTRUCTIONS.md +240 -117
- package/skills/wix-vibe-headless/references/pricing-plans/app/components/OrderCard.jsx +35 -0
- package/skills/wix-vibe-headless/references/pricing-plans/app/components/PlanCard.jsx +48 -0
- package/skills/wix-vibe-headless/references/pricing-plans/app/components/PlanGrid.jsx +16 -0
- package/skills/wix-vibe-headless/references/pricing-plans/app/components/PlanPrice.jsx +35 -0
- package/skills/wix-vibe-headless/references/pricing-plans/app/hooks/useMyPlans.js +25 -0
- package/skills/wix-vibe-headless/references/pricing-plans/app/hooks/usePlanDetail.js +28 -0
- package/skills/wix-vibe-headless/references/pricing-plans/app/hooks/usePlans.js +30 -0
- package/skills/wix-vibe-headless/references/pricing-plans/app/pages/MyPlans.jsx +30 -0
- package/skills/wix-vibe-headless/references/pricing-plans/app/pages/PlanDetail.jsx +53 -0
- package/skills/wix-vibe-headless/references/pricing-plans/app/pages/Plans.jsx +28 -0
- package/skills/wix-vibe-headless/references/pricing-plans/seed/SEED.md +86 -0
- package/skills/wix-vibe-headless/references/pricing-plans/seed/seed-pricing-plans.js +251 -0
- package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +248 -124
- package/skills/wix-vibe-headless/references/restaurants/app/components/ItemDialog.jsx +81 -0
- package/skills/wix-vibe-headless/references/restaurants/app/components/MenuItemCard.jsx +71 -0
- package/skills/wix-vibe-headless/references/restaurants/app/components/MenuList.jsx +43 -0
- package/skills/wix-vibe-headless/references/restaurants/app/components/OrderCartButton.jsx +21 -0
- package/skills/wix-vibe-headless/references/restaurants/app/components/OrderCartDrawer.jsx +60 -0
- package/skills/wix-vibe-headless/references/restaurants/app/context/OrderCartContext.jsx +63 -0
- package/skills/wix-vibe-headless/references/restaurants/app/hooks/useItemOrder.js +32 -0
- package/skills/wix-vibe-headless/references/restaurants/app/hooks/useReservation.js +73 -0
- package/skills/wix-vibe-headless/references/restaurants/app/pages/Menu.jsx +28 -0
- package/skills/wix-vibe-headless/references/restaurants/app/pages/Reservations.jsx +102 -0
- package/skills/wix-vibe-headless/references/restaurants/seed/SEED.md +180 -0
- package/skills/wix-vibe-headless/references/restaurants/seed/seed-restaurants.js +452 -0
- package/skills/wix-vibe-headless/references/shared/app/components/WixManageBanner.jsx +56 -0
- package/skills/wix-vibe-headless/references/shared/{wix-client.js → app/rest/wix-client.js} +6 -8
- package/skills/wix-vibe-headless/references/shared/app/rest/wix-config.js +6 -0
- package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +263 -148
- package/skills/wix-vibe-headless/references/storefront/app/components/CartButton.jsx +20 -0
- package/skills/wix-vibe-headless/references/storefront/app/components/CartDrawer.jsx +150 -0
- package/skills/wix-vibe-headless/references/storefront/app/components/ProductCard.jsx +167 -0
- package/skills/wix-vibe-headless/references/storefront/app/components/ProductGallery.jsx +51 -0
- package/skills/wix-vibe-headless/references/storefront/app/components/ProductGrid.jsx +54 -0
- package/skills/wix-vibe-headless/references/storefront/app/components/VariantPicker.jsx +119 -0
- package/skills/wix-vibe-headless/references/storefront/app/context/CartContext.jsx +71 -0
- package/skills/wix-vibe-headless/references/storefront/app/hooks/useProductDetail.js +109 -0
- package/skills/wix-vibe-headless/references/storefront/app/hooks/useShop.js +98 -0
- package/skills/wix-vibe-headless/references/storefront/app/lib/storeImage.js +27 -0
- package/skills/wix-vibe-headless/references/storefront/app/pages/ProductDetail.jsx +139 -0
- package/skills/wix-vibe-headless/references/storefront/app/pages/Shop.jsx +75 -0
- package/skills/wix-vibe-headless/references/storefront/{wix-store-cart.js → app/rest/wix-store-cart.js} +1 -1
- package/skills/wix-vibe-headless/references/storefront/{wix-store-catalog.js → app/rest/wix-store-catalog.js} +25 -2
- package/skills/wix-vibe-headless/references/storefront/seed/SEED.md +111 -0
- package/skills/wix-vibe-headless/references/storefront/seed/seed-store.js +299 -0
- /package/skills/wix-vibe-headless/references/blog/{wix-blog.js → app/rest/wix-blog.js} +0 -0
- /package/skills/wix-vibe-headless/references/events/{wix-events-registration.js → app/rest/wix-events-registration.js} +0 -0
- /package/skills/wix-vibe-headless/references/pricing-plans/{wix-pricing-plans.js → app/rest/wix-pricing-plans.js} +0 -0
- /package/skills/wix-vibe-headless/references/restaurants/{wix-restaurants-menu.js → app/rest/wix-restaurants-menu.js} +0 -0
- /package/skills/wix-vibe-headless/references/restaurants/{wix-restaurants-ordering.js → app/rest/wix-restaurants-ordering.js} +0 -0
- /package/skills/wix-vibe-headless/references/restaurants/{wix-restaurants-reservations.js → app/rest/wix-restaurants-reservations.js} +0 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// rp-source-csv — reader shape -> CANONICAL record.
|
|
4
|
+
//
|
|
5
|
+
// This closes the seam between the two deterministic halves:
|
|
6
|
+
//
|
|
7
|
+
// csv rows --[reader]--> reader-shaped record --[HERE]--> canonical record --[wix-build]--> Wix
|
|
8
|
+
//
|
|
9
|
+
// A reader names fields the way its vendor thinks (`bodyHtml`, `vendor`, `weightKg`); `wix-build.js`
|
|
10
|
+
// consumes the vendor-neutral vocabulary from `wix-target-spec.js` (`description`, `brand`,
|
|
11
|
+
// `weight`). Without this module that rename is hand-written per project — which is exactly the
|
|
12
|
+
// improvisation the deterministic pipeline exists to remove.
|
|
13
|
+
//
|
|
14
|
+
// The maps are DATA, per vendor, so adding a vendor is a data edit plus a fixture.
|
|
15
|
+
//
|
|
16
|
+
// Longer term the readers should emit canonical records directly and this module becomes a no-op
|
|
17
|
+
// identity map. It is deliberately a separate step rather than being folded into the reader, so the
|
|
18
|
+
// change can happen per vendor without a flag day.
|
|
19
|
+
|
|
20
|
+
const { validateCanonicalPath } = require('../../rp-target-wix/lib/wix-target-spec.js');
|
|
21
|
+
|
|
22
|
+
// `rename` moves a value unchanged. `derive` computes one from the whole record — kept to genuine
|
|
23
|
+
// multi-field logic, because a derive that only reads one field should be a rename.
|
|
24
|
+
const READER_FIELD_MAPS = {
|
|
25
|
+
shopify: {
|
|
26
|
+
product: {
|
|
27
|
+
rename: {
|
|
28
|
+
title: 'name',
|
|
29
|
+
bodyHtml: 'description',
|
|
30
|
+
slug: 'slug',
|
|
31
|
+
vendor: 'brand',
|
|
32
|
+
seoTitle: 'seoTitle',
|
|
33
|
+
seoDescription: 'seoDescription',
|
|
34
|
+
images: 'images',
|
|
35
|
+
optionNames: 'optionNames',
|
|
36
|
+
categoryPath: 'categoryPath',
|
|
37
|
+
tags: 'tags',
|
|
38
|
+
sourceId: 'sourceId',
|
|
39
|
+
},
|
|
40
|
+
derive: {
|
|
41
|
+
// Shopify carries BOTH a lifecycle status and a publish flag; a product is visible only
|
|
42
|
+
// when both agree. Collapsing to either one alone silently publishes drafts.
|
|
43
|
+
visible: (record) => record.status === 'active' && record.published !== false,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
variant: {
|
|
47
|
+
rename: {
|
|
48
|
+
sku: 'sku',
|
|
49
|
+
price: 'price',
|
|
50
|
+
compareAtPrice: 'compareAtPrice',
|
|
51
|
+
// The reader has already converted grams to the site's weight unit; the canonical field
|
|
52
|
+
// carries a bare number, so the converted value is the one that travels.
|
|
53
|
+
weightKg: 'weight',
|
|
54
|
+
barcode: 'barcode',
|
|
55
|
+
cost: 'cost',
|
|
56
|
+
choices: 'choices',
|
|
57
|
+
},
|
|
58
|
+
derive: {
|
|
59
|
+
visible: () => true,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
category: {
|
|
63
|
+
rename: { name: 'name', parentPath: 'parentPath', path: 'path', sourceId: 'sourceId' },
|
|
64
|
+
derive: { visible: () => true },
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// woocommerce / magento / bigcommerce readers are not built yet. Registering them explicitly as
|
|
70
|
+
// absent is better than falling back to shopify's map and silently mis-renaming fields.
|
|
71
|
+
const SUPPORTED_VENDORS = Object.keys(READER_FIELD_MAPS);
|
|
72
|
+
|
|
73
|
+
function mapEntity(record, entityMap) {
|
|
74
|
+
const out = {};
|
|
75
|
+
for (const [readerKey, canonicalKey] of Object.entries(entityMap.rename || {})) {
|
|
76
|
+
const value = record[readerKey];
|
|
77
|
+
if (value !== undefined && value !== null) out[canonicalKey] = value;
|
|
78
|
+
}
|
|
79
|
+
for (const [canonicalKey, fn] of Object.entries(entityMap.derive || {})) {
|
|
80
|
+
out[canonicalKey] = fn(record);
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function mapFor(vendor, entity) {
|
|
86
|
+
const vendorMap = READER_FIELD_MAPS[vendor];
|
|
87
|
+
if (!vendorMap) {
|
|
88
|
+
throw new Error(
|
|
89
|
+
`canonical-record: no reader field map for vendor "${vendor}". ` +
|
|
90
|
+
`Known: ${SUPPORTED_VENDORS.join(', ')}. Add one in READER_FIELD_MAPS rather than reusing another vendor's.`,
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
const entityMap = vendorMap[entity];
|
|
94
|
+
if (!entityMap) throw new Error(`canonical-record: vendor "${vendor}" has no map for entity "${entity}"`);
|
|
95
|
+
return entityMap;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function toCanonicalProduct(record, { vendor = 'shopify' } = {}) {
|
|
99
|
+
const product = mapEntity(record, mapFor(vendor, 'product'));
|
|
100
|
+
const variantMap = mapFor(vendor, 'variant');
|
|
101
|
+
product.variants = (record.variants || []).map((variant) => mapEntity(variant, variantMap));
|
|
102
|
+
return product;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function toCanonicalCategory(record, { vendor = 'shopify' } = {}) {
|
|
106
|
+
return mapEntity(record, mapFor(vendor, 'category'));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Self-check: every canonical key a map produces must be a real canonical field. Runs at require
|
|
110
|
+
// time so a typo in the map is a load error, not a field that silently never lands in Wix.
|
|
111
|
+
function validateMaps() {
|
|
112
|
+
const problems = [];
|
|
113
|
+
for (const [vendor, entities] of Object.entries(READER_FIELD_MAPS)) {
|
|
114
|
+
for (const [entity, entityMap] of Object.entries(entities)) {
|
|
115
|
+
const keys = [...Object.values(entityMap.rename || {}), ...Object.keys(entityMap.derive || {})];
|
|
116
|
+
for (const key of keys) {
|
|
117
|
+
// Canonical paths are `<entity>.<field>`; the maps hold the bare field name.
|
|
118
|
+
if (!validateCanonicalPath(`${entity}.${key}`)) problems.push(`${vendor}.${entity} -> ${entity}.${key}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return problems;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const MAP_PROBLEMS = validateMaps();
|
|
126
|
+
if (MAP_PROBLEMS.length) {
|
|
127
|
+
throw new Error(`canonical-record: map targets are not canonical fields: ${MAP_PROBLEMS.join(', ')}`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
module.exports = {
|
|
131
|
+
READER_FIELD_MAPS,
|
|
132
|
+
SUPPORTED_VENDORS,
|
|
133
|
+
toCanonicalProduct,
|
|
134
|
+
toCanonicalCategory,
|
|
135
|
+
validateMaps,
|
|
136
|
+
};
|
|
Binary file
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Vendor detection from the header row.
|
|
4
|
+
//
|
|
5
|
+
// The header read at discovery time is authoritative; a vendor profile only
|
|
6
|
+
// (a) identifies the vendor and (b) pre-fills mappings the LLM would otherwise
|
|
7
|
+
// propose. A stale profile can therefore make the pre-fill less complete, but
|
|
8
|
+
// can never cause a wrong import — see SKILL.md → Profile drift & resilience.
|
|
9
|
+
|
|
10
|
+
const fs = require('node:fs');
|
|
11
|
+
const path = require('node:path');
|
|
12
|
+
const { normalizeHeaderName } = require('./csv-parse.js');
|
|
13
|
+
|
|
14
|
+
const VENDORS_DIR = path.join(__dirname, '..', 'vendors');
|
|
15
|
+
|
|
16
|
+
// Scoring constants. Deliberately conservative: falling back to `custom` costs
|
|
17
|
+
// the user a less complete mapping pre-fill, while a wrong vendor match costs
|
|
18
|
+
// them a wrong layout.
|
|
19
|
+
const BASE_REQUIRED = 0.5;
|
|
20
|
+
const STRONG_WEIGHT = 0.5;
|
|
21
|
+
const PARTIAL_FACTOR = 0.6;
|
|
22
|
+
const NEGATIVE_PENALTY = 0.35;
|
|
23
|
+
const MATCH_THRESHOLD = 0.7;
|
|
24
|
+
const MARGIN = 0.15;
|
|
25
|
+
const MIN_STRONG_HITS = 2;
|
|
26
|
+
const NEAR_MISS_FLOOR = 0.25;
|
|
27
|
+
const NEAR_MISS_STRONG_RATIO = 0.6;
|
|
28
|
+
|
|
29
|
+
const CUSTOM_VENDOR = 'custom';
|
|
30
|
+
|
|
31
|
+
function normalizedSet(columns) {
|
|
32
|
+
const set = new Set();
|
|
33
|
+
for (const column of columns || []) {
|
|
34
|
+
const normalized = normalizeHeaderName(column);
|
|
35
|
+
if (normalized) {
|
|
36
|
+
set.add(normalized);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return set;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function validateProfile(profile) {
|
|
43
|
+
const errors = [];
|
|
44
|
+
if (!profile || typeof profile !== 'object') {
|
|
45
|
+
return { ok: false, errors: ['profile is not an object'] };
|
|
46
|
+
}
|
|
47
|
+
if (!profile.vendor || typeof profile.vendor !== 'string') {
|
|
48
|
+
errors.push('vendor must be a non-empty string');
|
|
49
|
+
}
|
|
50
|
+
if (!profile.profileVersion) {
|
|
51
|
+
errors.push('profileVersion is required (provenance for drift)');
|
|
52
|
+
}
|
|
53
|
+
if (!profile.sourceOfTruth) {
|
|
54
|
+
errors.push('sourceOfTruth is required');
|
|
55
|
+
}
|
|
56
|
+
const anchors = profile.anchors || {};
|
|
57
|
+
if (!Array.isArray(anchors.required) || anchors.required.length === 0) {
|
|
58
|
+
errors.push('anchors.required must be a non-empty array');
|
|
59
|
+
}
|
|
60
|
+
if (!Array.isArray(anchors.strong) || anchors.strong.length < MIN_STRONG_HITS) {
|
|
61
|
+
errors.push(`anchors.strong must hold at least ${MIN_STRONG_HITS} columns`);
|
|
62
|
+
}
|
|
63
|
+
if (!profile.layout || typeof profile.layout.pattern !== 'string') {
|
|
64
|
+
errors.push('layout.pattern is required');
|
|
65
|
+
}
|
|
66
|
+
if (profile.columnMap && !Array.isArray(profile.columnMap)) {
|
|
67
|
+
errors.push('columnMap must be an array when present');
|
|
68
|
+
}
|
|
69
|
+
for (const entry of profile.columnMap || []) {
|
|
70
|
+
if (!entry.wixTarget || !Array.isArray(entry.aliases) || entry.aliases.length === 0) {
|
|
71
|
+
errors.push(`columnMap entry ${JSON.stringify(entry.wixTarget)} needs a wixTarget and a non-empty aliases array`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
for (const derived of profile.derived || []) {
|
|
75
|
+
if (!derived.entity || !derived.fromColumn) {
|
|
76
|
+
errors.push('each derived entry needs entity + fromColumn');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return { ok: errors.length === 0, errors };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function loadVendorProfiles(dir = VENDORS_DIR) {
|
|
83
|
+
const files = fs.readdirSync(dir)
|
|
84
|
+
.filter((file) => file.endsWith('.json'))
|
|
85
|
+
.sort();
|
|
86
|
+
return files.map((file) => {
|
|
87
|
+
const profile = JSON.parse(fs.readFileSync(path.join(dir, file), 'utf8'));
|
|
88
|
+
const validation = validateProfile(profile);
|
|
89
|
+
if (!validation.ok) {
|
|
90
|
+
throw new Error(`Invalid vendor profile ${file}: ${validation.errors.join('; ')}`);
|
|
91
|
+
}
|
|
92
|
+
return profile;
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function aliasIndex(profile) {
|
|
97
|
+
// normalized column name -> wixTarget, built from columnMap only.
|
|
98
|
+
const index = new Map();
|
|
99
|
+
for (const entry of profile.columnMap || []) {
|
|
100
|
+
for (const alias of entry.aliases) {
|
|
101
|
+
const normalized = normalizeHeaderName(alias);
|
|
102
|
+
if (normalized && !index.has(normalized)) {
|
|
103
|
+
index.set(normalized, { wixTarget: entry.wixTarget, alias });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return index;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Anchors match by normalized EXACT equality and never through columnMap
|
|
111
|
+
// aliases. Aliases exist to be permissive for mapping; permissiveness is poison
|
|
112
|
+
// for identification — Shopify's variant.sku aliases include a bare "SKU",
|
|
113
|
+
// which every WooCommerce and Magento export also has.
|
|
114
|
+
function scoreProfile(headerColumns, profile) {
|
|
115
|
+
const header = normalizedSet(headerColumns);
|
|
116
|
+
const anchors = profile.anchors || {};
|
|
117
|
+
const required = anchors.required || [];
|
|
118
|
+
const strong = anchors.strong || [];
|
|
119
|
+
const negative = anchors.negative || [];
|
|
120
|
+
|
|
121
|
+
const matchedRequired = required.filter((column) => header.has(normalizeHeaderName(column)));
|
|
122
|
+
const missingRequired = required.filter((column) => !header.has(normalizeHeaderName(column)));
|
|
123
|
+
const matchedStrong = strong.filter((column) => header.has(normalizeHeaderName(column)));
|
|
124
|
+
const missingStrong = strong.filter((column) => !header.has(normalizeHeaderName(column)));
|
|
125
|
+
const negativeHits = negative.filter((column) => header.has(normalizeHeaderName(column)));
|
|
126
|
+
|
|
127
|
+
const requiredRatio = required.length === 0 ? 0 : matchedRequired.length / required.length;
|
|
128
|
+
const strongRatio = strong.length === 0 ? 0 : matchedStrong.length / strong.length;
|
|
129
|
+
|
|
130
|
+
const core = BASE_REQUIRED + STRONG_WEIGHT * strongRatio;
|
|
131
|
+
let score = requiredRatio === 1 ? core : PARTIAL_FACTOR * requiredRatio * core;
|
|
132
|
+
if (negativeHits.length > 0) {
|
|
133
|
+
score *= NEGATIVE_PENALTY;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Evidence only — deliberately NOT part of the score. Coupling identification
|
|
137
|
+
// to columnMap completeness would mean adding a mapping alias could change
|
|
138
|
+
// which vendor a file is detected as.
|
|
139
|
+
const aliases = aliasIndex(profile);
|
|
140
|
+
const anchorNames = normalizedSet([...required, ...strong]);
|
|
141
|
+
const knownColumns = (headerColumns || []).filter((column) => {
|
|
142
|
+
const normalized = normalizeHeaderName(column);
|
|
143
|
+
return anchorNames.has(normalized) || aliases.has(normalized);
|
|
144
|
+
});
|
|
145
|
+
const vocabularyCoverage = headerColumns && headerColumns.length > 0
|
|
146
|
+
? knownColumns.length / headerColumns.length
|
|
147
|
+
: 0;
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
vendor: profile.vendor,
|
|
151
|
+
score: Number(score.toFixed(4)),
|
|
152
|
+
requiredRatio,
|
|
153
|
+
strongRatio,
|
|
154
|
+
matchedRequired,
|
|
155
|
+
missingRequired,
|
|
156
|
+
matchedStrong,
|
|
157
|
+
missingStrong,
|
|
158
|
+
negativeHits,
|
|
159
|
+
vocabularyCoverage: Number(vocabularyCoverage.toFixed(4)),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function evidenceLine(winner, runnerUp) {
|
|
164
|
+
const parts = [
|
|
165
|
+
`required ${winner.matchedRequired.length}/${winner.matchedRequired.length + winner.missingRequired.length}`,
|
|
166
|
+
`strong ${winner.matchedStrong.length}/${winner.matchedStrong.length + winner.missingStrong.length}`,
|
|
167
|
+
`score ${winner.score}`,
|
|
168
|
+
];
|
|
169
|
+
if (winner.negativeHits.length > 0) {
|
|
170
|
+
parts.push(`negative anchors present: ${winner.negativeHits.join(', ')}`);
|
|
171
|
+
}
|
|
172
|
+
parts.push(runnerUp ? `runner-up ${runnerUp.vendor} ${runnerUp.score}` : 'no runner-up');
|
|
173
|
+
return parts.join('; ');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function detectVendor(headerColumns, profiles, { statedVendor = null } = {}) {
|
|
177
|
+
const scores = profiles
|
|
178
|
+
.map((profile) => scoreProfile(headerColumns, profile))
|
|
179
|
+
.sort((a, b) => b.score - a.score || a.vendor.localeCompare(b.vendor));
|
|
180
|
+
|
|
181
|
+
const winner = scores[0] || null;
|
|
182
|
+
const runnerUp = scores[1] || null;
|
|
183
|
+
const profileByVendor = new Map(profiles.map((profile) => [profile.vendor, profile]));
|
|
184
|
+
|
|
185
|
+
let reason = 'match';
|
|
186
|
+
let matched = Boolean(winner);
|
|
187
|
+
if (!winner || winner.score < MATCH_THRESHOLD) {
|
|
188
|
+
matched = false;
|
|
189
|
+
reason = 'below-threshold';
|
|
190
|
+
} else if (winner.matchedStrong.length < MIN_STRONG_HITS) {
|
|
191
|
+
matched = false;
|
|
192
|
+
reason = 'insufficient-strong-anchors';
|
|
193
|
+
} else if (runnerUp && winner.score - runnerUp.score < MARGIN) {
|
|
194
|
+
matched = false;
|
|
195
|
+
reason = 'ambiguous';
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// A drifted vendor export should become a user question, not silence.
|
|
199
|
+
let nearMiss = null;
|
|
200
|
+
if (!matched) {
|
|
201
|
+
const candidate = scores.find((entry) => entry.score >= NEAR_MISS_FLOOR
|
|
202
|
+
&& entry.strongRatio >= NEAR_MISS_STRONG_RATIO
|
|
203
|
+
&& entry.requiredRatio > 0
|
|
204
|
+
&& entry.negativeHits.length === 0);
|
|
205
|
+
if (candidate) {
|
|
206
|
+
nearMiss = {
|
|
207
|
+
vendor: candidate.vendor,
|
|
208
|
+
score: candidate.score,
|
|
209
|
+
missingRequired: candidate.missingRequired,
|
|
210
|
+
missingStrong: candidate.missingStrong,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const detectedVendor = matched ? winner.vendor : CUSTOM_VENDOR;
|
|
216
|
+
|
|
217
|
+
// A user-stated vendor wins, but detection still runs so a disagreement is
|
|
218
|
+
// visible rather than silently overridden.
|
|
219
|
+
if (statedVendor) {
|
|
220
|
+
const stated = String(statedVendor).toLowerCase();
|
|
221
|
+
if (stated !== CUSTOM_VENDOR && !profileByVendor.has(stated)) {
|
|
222
|
+
throw new Error(`Unknown vendor "${statedVendor}". Known vendors: ${[...profileByVendor.keys()].join(', ')}, ${CUSTOM_VENDOR}.`);
|
|
223
|
+
}
|
|
224
|
+
const statedScore = scores.find((entry) => entry.vendor === stated) || null;
|
|
225
|
+
return {
|
|
226
|
+
vendor: stated,
|
|
227
|
+
profile: profileByVendor.get(stated) || null,
|
|
228
|
+
confidence: statedScore ? statedScore.score : 1,
|
|
229
|
+
source: 'user',
|
|
230
|
+
reason: 'user-stated',
|
|
231
|
+
evidence: `vendor stated by the user${statedScore ? `; fingerprint would score it ${statedScore.score}` : ''}`,
|
|
232
|
+
scores,
|
|
233
|
+
runnerUp,
|
|
234
|
+
nearMiss,
|
|
235
|
+
conflict: detectedVendor !== stated ? { stated, detected: detectedVendor } : null,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return {
|
|
240
|
+
vendor: detectedVendor,
|
|
241
|
+
profile: matched ? profileByVendor.get(winner.vendor) : null,
|
|
242
|
+
confidence: winner ? winner.score : 0,
|
|
243
|
+
source: matched ? 'fingerprint' : 'fallback',
|
|
244
|
+
reason,
|
|
245
|
+
evidence: winner ? evidenceLine(winner, runnerUp) : 'no vendor profiles available',
|
|
246
|
+
scores,
|
|
247
|
+
runnerUp,
|
|
248
|
+
nearMiss,
|
|
249
|
+
conflict: null,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// The two drift lists are scoped differently on purpose: `unmappedColumns` is
|
|
254
|
+
// about mapping coverage (anchors + columnMap), `missingExpectedColumns` is
|
|
255
|
+
// about format drift (anchors only — including every columnMap alias would
|
|
256
|
+
// make the list enormous and useless).
|
|
257
|
+
function diffProfile(headerColumns, profile) {
|
|
258
|
+
if (!profile) {
|
|
259
|
+
return { unmappedColumns: [...(headerColumns || [])], missingExpectedColumns: [] };
|
|
260
|
+
}
|
|
261
|
+
const aliases = aliasIndex(profile);
|
|
262
|
+
const anchors = profile.anchors || {};
|
|
263
|
+
const anchorNames = normalizedSet([...(anchors.required || []), ...(anchors.strong || [])]);
|
|
264
|
+
const header = normalizedSet(headerColumns);
|
|
265
|
+
|
|
266
|
+
const unmappedColumns = (headerColumns || []).filter((column) => {
|
|
267
|
+
const normalized = normalizeHeaderName(column);
|
|
268
|
+
return normalized && !anchorNames.has(normalized) && !aliases.has(normalized);
|
|
269
|
+
});
|
|
270
|
+
const missingExpectedColumns = [...(anchors.required || []), ...(anchors.strong || [])]
|
|
271
|
+
.filter((column) => !header.has(normalizeHeaderName(column)));
|
|
272
|
+
|
|
273
|
+
return { unmappedColumns, missingExpectedColumns };
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Advisory pre-fill for rp-mapper. Every column this does not cover still flows
|
|
277
|
+
// through discovery → mapper → user unchanged.
|
|
278
|
+
function prefillColumnMap(headerColumns, profile) {
|
|
279
|
+
if (!profile) {
|
|
280
|
+
return [];
|
|
281
|
+
}
|
|
282
|
+
const aliases = aliasIndex(profile);
|
|
283
|
+
const hints = [];
|
|
284
|
+
for (const column of headerColumns || []) {
|
|
285
|
+
const hit = aliases.get(normalizeHeaderName(column));
|
|
286
|
+
if (hit) {
|
|
287
|
+
hints.push({ column, wixTarget: hit.wixTarget, matchedAlias: hit.alias });
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return hints;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
module.exports = {
|
|
294
|
+
VENDORS_DIR,
|
|
295
|
+
BASE_REQUIRED,
|
|
296
|
+
STRONG_WEIGHT,
|
|
297
|
+
PARTIAL_FACTOR,
|
|
298
|
+
NEGATIVE_PENALTY,
|
|
299
|
+
MATCH_THRESHOLD,
|
|
300
|
+
MARGIN,
|
|
301
|
+
MIN_STRONG_HITS,
|
|
302
|
+
NEAR_MISS_FLOOR,
|
|
303
|
+
CUSTOM_VENDOR,
|
|
304
|
+
loadVendorProfiles,
|
|
305
|
+
validateProfile,
|
|
306
|
+
scoreProfile,
|
|
307
|
+
detectVendor,
|
|
308
|
+
diffProfile,
|
|
309
|
+
prefillColumnMap,
|
|
310
|
+
};
|