@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,54 @@
|
|
|
1
|
+
// Category landing page — resolves the URL slug to a category (getCategoryBySlug → null on miss),
|
|
2
|
+
// then lists that category's posts via queryPostsByCategory (same { posts, nextCursor } shape as the
|
|
3
|
+
// feed, so paging is identical). Displays the category by .label; cover from category.coverImage.url
|
|
4
|
+
// (a DIFFERENT path from the post cover). Styled with base44 design tokens (shadcn Tailwind classes).
|
|
5
|
+
import { useEffect, useState } from "react";
|
|
6
|
+
import { useParams } from "react-router-dom";
|
|
7
|
+
import { getCategoryBySlug, queryPostsByCategory } from "@/rest/wix-blog";
|
|
8
|
+
import PostGrid from "@/components/PostGrid";
|
|
9
|
+
|
|
10
|
+
export default function CategoryPage() {
|
|
11
|
+
const { slug } = useParams();
|
|
12
|
+
const [category, setCategory] = useState(undefined); // undefined=loading, null=not found
|
|
13
|
+
const [posts, setPosts] = useState(null);
|
|
14
|
+
const [cursor, setCursor] = useState(null);
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
setCategory(undefined); setPosts(null); setCursor(null);
|
|
18
|
+
getCategoryBySlug(slug).then((c) => {
|
|
19
|
+
setCategory(c);
|
|
20
|
+
if (!c) return;
|
|
21
|
+
queryPostsByCategory(c.id, { limit: 20 }).then(({ posts, nextCursor }) => { setPosts(posts); setCursor(nextCursor); });
|
|
22
|
+
});
|
|
23
|
+
}, [slug]);
|
|
24
|
+
|
|
25
|
+
const loadMore = () =>
|
|
26
|
+
queryPostsByCategory(category.id, { limit: 20, cursor }).then(({ posts: more, nextCursor }) => {
|
|
27
|
+
setPosts((p) => [...(p || []), ...more]);
|
|
28
|
+
setCursor(nextCursor);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
if (category === null) return <Centered>Category not found.</Centered>;
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<main className="max-w-[1100px] mx-auto p-4">
|
|
35
|
+
<h1 className="font-display mb-1">{category?.label || "…"}</h1>
|
|
36
|
+
{category?.description && (
|
|
37
|
+
<p className="text-muted-foreground mb-4">{category.description}</p>
|
|
38
|
+
)}
|
|
39
|
+
{posts === null
|
|
40
|
+
? <p className="text-muted-foreground">Loading…</p>
|
|
41
|
+
: <PostGrid posts={posts} empty="No posts in this category yet." />}
|
|
42
|
+
{cursor && (
|
|
43
|
+
<div className="text-center mt-8">
|
|
44
|
+
<button onClick={loadMore}
|
|
45
|
+
className="py-3 px-6 cursor-pointer text-[15px] font-semibold bg-primary text-primary-foreground border-none rounded-sm">Load more</button>
|
|
46
|
+
</div>
|
|
47
|
+
)}
|
|
48
|
+
</main>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function Centered({ children }) {
|
|
53
|
+
return <div className="p-12 text-center text-muted-foreground">{children}</div>;
|
|
54
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Post detail — thin view over usePostDetail (all logic lives in the hook). Renders the cover, meta,
|
|
2
|
+
// category/tag chips, and the plain-text body as paragraphs. For a faithful render of embeds/images/
|
|
3
|
+
// formatting, render `d.post.richContent` with a Ricos renderer (see INSTRUCTIONS "Extending").
|
|
4
|
+
// Styled with base44 design tokens (shadcn Tailwind classes).
|
|
5
|
+
import { useParams } from "react-router-dom";
|
|
6
|
+
import { usePostDetail } from "@/hooks/usePostDetail";
|
|
7
|
+
import PostChips from "@/components/PostChips";
|
|
8
|
+
|
|
9
|
+
function coverImage(post) {
|
|
10
|
+
const url = post?.media?.wixMedia?.image?.url;
|
|
11
|
+
return url ? (url.startsWith("//") ? `https:${url}` : url) : null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function formatDate(iso) {
|
|
15
|
+
if (!iso) return null;
|
|
16
|
+
try { return new Date(iso).toLocaleDateString(undefined, { year: "numeric", month: "short", day: "numeric" }); }
|
|
17
|
+
catch { return null; }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default function PostDetail() {
|
|
21
|
+
const { slug } = useParams();
|
|
22
|
+
const d = usePostDetail(slug);
|
|
23
|
+
|
|
24
|
+
if (d.notFound) return <Centered>Post not found.</Centered>;
|
|
25
|
+
if (!d.post) return <Centered>Loading…</Centered>;
|
|
26
|
+
|
|
27
|
+
const image = coverImage(d.post);
|
|
28
|
+
const date = formatDate(d.post.firstPublishedDate);
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<main className="max-w-[1100px] mx-auto p-4">
|
|
32
|
+
<article className="max-w-[72ch] mx-auto">
|
|
33
|
+
<h1 className="font-display m-0 mb-2 leading-[1.2]">{d.post.title}</h1>
|
|
34
|
+
<div className="flex gap-2 items-center text-muted-foreground text-[13px] mb-4">
|
|
35
|
+
{date && <span>{date}</span>}
|
|
36
|
+
{date && d.post.minutesToRead ? <span aria-hidden="true">·</span> : null}
|
|
37
|
+
{d.post.minutesToRead ? <span>{d.post.minutesToRead} min read</span> : null}
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
{image && (
|
|
41
|
+
<div className="rounded-lg overflow-hidden mb-6">
|
|
42
|
+
<img src={image} alt={d.post.media?.wixMedia?.image?.altText || d.post.title}
|
|
43
|
+
className="w-full h-auto block" />
|
|
44
|
+
</div>
|
|
45
|
+
)}
|
|
46
|
+
|
|
47
|
+
<div className="text-foreground leading-[1.7] text-[17px]">
|
|
48
|
+
{d.paragraphs.map((para, i) => (
|
|
49
|
+
<p key={i} className="m-0 mb-4">{para}</p>
|
|
50
|
+
))}
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
{(d.cats.length || d.tags.length) ? (
|
|
54
|
+
<div className="mt-8 pt-4 border-t border-border">
|
|
55
|
+
<PostChips post={d.post} />
|
|
56
|
+
</div>
|
|
57
|
+
) : null}
|
|
58
|
+
</article>
|
|
59
|
+
</main>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function Centered({ children }) {
|
|
64
|
+
return <div className="p-12 text-center text-muted-foreground">{children}</div>;
|
|
65
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Tag landing page — resolves the URL slug to a tag (getTagBySlug → null on miss), then lists that
|
|
2
|
+
// tag's posts via queryPostsByTag (same { posts, nextCursor } shape as the feed). Displays the tag by
|
|
3
|
+
// .label (per-tag count is publishedPostCount). Styled with base44 design tokens (shadcn Tailwind classes).
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
|
+
import { useParams } from "react-router-dom";
|
|
6
|
+
import { getTagBySlug, queryPostsByTag } from "@/rest/wix-blog";
|
|
7
|
+
import PostGrid from "@/components/PostGrid";
|
|
8
|
+
|
|
9
|
+
export default function TagPage() {
|
|
10
|
+
const { slug } = useParams();
|
|
11
|
+
const [tag, setTag] = useState(undefined); // undefined=loading, null=not found
|
|
12
|
+
const [posts, setPosts] = useState(null);
|
|
13
|
+
const [cursor, setCursor] = useState(null);
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
setTag(undefined); setPosts(null); setCursor(null);
|
|
17
|
+
getTagBySlug(slug).then((t) => {
|
|
18
|
+
setTag(t);
|
|
19
|
+
if (!t) return;
|
|
20
|
+
queryPostsByTag(t.id, { limit: 20 }).then(({ posts, nextCursor }) => { setPosts(posts); setCursor(nextCursor); });
|
|
21
|
+
});
|
|
22
|
+
}, [slug]);
|
|
23
|
+
|
|
24
|
+
const loadMore = () =>
|
|
25
|
+
queryPostsByTag(tag.id, { limit: 20, cursor }).then(({ posts: more, nextCursor }) => {
|
|
26
|
+
setPosts((p) => [...(p || []), ...more]);
|
|
27
|
+
setCursor(nextCursor);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
if (tag === null) return <Centered>Tag not found.</Centered>;
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<main className="max-w-[1100px] mx-auto p-4">
|
|
34
|
+
<h1 className="font-display mb-4">#{tag?.label || "…"}</h1>
|
|
35
|
+
{posts === null
|
|
36
|
+
? <p className="text-muted-foreground">Loading…</p>
|
|
37
|
+
: <PostGrid posts={posts} empty="No posts with this tag yet." />}
|
|
38
|
+
{cursor && (
|
|
39
|
+
<div className="text-center mt-8">
|
|
40
|
+
<button onClick={loadMore}
|
|
41
|
+
className="py-3 px-6 cursor-pointer text-[15px] font-semibold bg-primary text-primary-foreground border-none rounded-sm">Load more</button>
|
|
42
|
+
</div>
|
|
43
|
+
)}
|
|
44
|
+
</main>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function Centered({ children }) {
|
|
49
|
+
return <div className="p-12 text-center text-muted-foreground">{children}</div>;
|
|
50
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Blog — seeding
|
|
2
|
+
|
|
3
|
+
Seed a Wix Blog (Blog V3) by **calling `seed-blog.js`** — don't hand-write the REST calls. It's
|
|
4
|
+
a build-time module (run via `exec_tool`, not shipped in the app) that abstracts every Wix Blog
|
|
5
|
+
seed operation. `require` it and call the functions with plain data.
|
|
6
|
+
|
|
7
|
+
> **NOT yet live-verified — transcribed from `setup-blog.md`.** Endpoints/fields mirror the recipe
|
|
8
|
+
> exactly; if a call returns an unexpected shape, use the **`wix-docs`** skill (never guess).
|
|
9
|
+
|
|
10
|
+
**DEFAULT — one call.** `setupBlog(ctx, plan)` runs the whole flow (memberId → categories/tags →
|
|
11
|
+
posts → covers), keeping every id in memory. Pass category/tag **names** and it resolves them to
|
|
12
|
+
ids internally; a post's `coverImageUrl` is a plain image url that the module imports into Wix Media
|
|
13
|
+
for you (Blog binds the cover by the Wix Media file id, not a url).
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
// build-time exec_tool
|
|
17
|
+
const { accessToken } = await base44.asServiceRole.connectors.getConnection("wix"); // Base44 (generic: use $TOKEN)
|
|
18
|
+
const fs = require("fs");
|
|
19
|
+
// exec_tool's require can return EMPTY exports for these build-time modules — load the file itself:
|
|
20
|
+
const seed = (() => { const m = { exports: {} };
|
|
21
|
+
new Function("module", "exports", "require", fs.readFileSync("/app/.agents/skills/wix-vibe-headless/references/blog/seed/seed-blog.js", "utf8"))(m, m.exports, require);
|
|
22
|
+
return m.exports; })();
|
|
23
|
+
const ctx = { token: accessToken, siteId: WIX_METASITE_ID };
|
|
24
|
+
|
|
25
|
+
const result = await seed.setupBlog(ctx, {
|
|
26
|
+
categories: ["Recipes", "Brewing"], // optional — names, resolved to ids internally
|
|
27
|
+
posts: [
|
|
28
|
+
{ title: "How We Roast Our Beans", category: "Recipes", tags: ["coffee"],
|
|
29
|
+
content: [
|
|
30
|
+
{ type: "heading", text: "From farm to cup", level: 2 },
|
|
31
|
+
{ type: "paragraph", text: "Every batch starts with beans from a single estate." },
|
|
32
|
+
{ type: "quote", text: "Great coffee is grown, not made." },
|
|
33
|
+
],
|
|
34
|
+
// cover is optional and attached IN this one call. Pass a plain url — the module imports it to
|
|
35
|
+
// Wix Media for you (Blog binds the cover by file id). Use the FINAL https://media.base44.com/...
|
|
36
|
+
// url from the COMPLETED generate_image (it runs in the background while you build — wait for
|
|
37
|
+
// it), never a still-generating /__generating__/<id>.png placeholder.
|
|
38
|
+
coverImageUrl: "https://media.base44.com/…",
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
});
|
|
42
|
+
// → { posts:[{id,index,success}], categories:[{id,name}], tags:[{id,name}], coversAttached }
|
|
43
|
+
// check each posts[].success (bulk returns 200 even on partial failure).
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Seeding is additive — never delete or overwrite existing content.** Don't clean up, don't remove
|
|
47
|
+
"sample" data, don't reset. Just add.
|
|
48
|
+
|
|
49
|
+
## Escape hatch — individual functions
|
|
50
|
+
Reach for the functions below only when the one-call `setupBlog` doesn't fit (custom ordering,
|
|
51
|
+
reusing existing ids). `setupBlog` is built from them, in this order:
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
const memberId = await seed.getAuthorMemberId(ctx); // STEP 1 — required for every post create
|
|
55
|
+
|
|
56
|
+
// STEP 3 (optional): only if the request groups posts (e.g. "Recipes and Brewing sections")
|
|
57
|
+
const cats = await seed.createCategories(ctx, ["Recipes", "Brewing"]);
|
|
58
|
+
|
|
59
|
+
// STEP 2: bulk for postCount >= 2, single endpoint for 1 — handled inside. content = plain blocks.
|
|
60
|
+
const posts = await seed.createPosts(ctx, [
|
|
61
|
+
{ title: "How We Roast Our Beans", categoryIds: [cats[0].id], content: [
|
|
62
|
+
{ type: "heading", text: "From farm to cup", level: 2 },
|
|
63
|
+
{ type: "paragraph", text: "Every batch starts with beans from a single estate." },
|
|
64
|
+
{ type: "quote", text: "Great coffee is grown, not made." },
|
|
65
|
+
] },
|
|
66
|
+
]); // → [{ id, index, success }] — check each .success (bulk returns 200 even on partial failure)
|
|
67
|
+
|
|
68
|
+
// optional — import each url to Wix Media (blog binds by file id), then attach covers (PATCH + re-publish)
|
|
69
|
+
const files = await Promise.all(imageUrls.map((u) => seed.importImage(ctx, u))); // → [{ id, url }]
|
|
70
|
+
await seed.attachPostCovers(ctx, posts.map((p, i) => ({ postId: p.id, fileId: files[i].id })));
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Functions
|
|
74
|
+
| fn | does |
|
|
75
|
+
|---|---|
|
|
76
|
+
| `setupBlog(ctx, plan)` | **DEFAULT** — one call: memberId → categories/tags → posts → covers; names resolved to ids internally → `{posts,categories,tags,coversAttached}` |
|
|
77
|
+
| `getAuthorMemberId(ctx)` | STEP 1 — fetch a real member id for author attribution (throws if none) |
|
|
78
|
+
| `createPosts(ctx, posts, { memberId })` | STEP 2 — auto single-vs-bulk create, published → `[{id,index,success}]` |
|
|
79
|
+
| `createCategories(ctx, names)` | STEP 3 — sequential creates → `[{id,name}]` (feed into `post.categoryIds`) |
|
|
80
|
+
| `createTags(ctx, names)` | STEP 3 — sequential creates → `[{id,name}]` (feed into `post.tagIds`) |
|
|
81
|
+
| `importImage(ctx, url)` | import an external url into Wix Media → `{id,url}` (file id + wixstatic url); blog binds the cover by this file id |
|
|
82
|
+
| `attachPostCovers(ctx, [{postId,fileId}])` | optional — PATCH cover (`displayed+custom+wixMedia.image.id`) + re-publish; `fileId` MUST be a Wix Media file id from `importImage` |
|
|
83
|
+
|
|
84
|
+
`content` blocks: `{type:"heading",text,level?}` · `{type:"paragraph",text}` · `{type:"quote",text}` ·
|
|
85
|
+
`{type:"bulleted"|"ordered",items:[…]}`. For node types the recipe doesn't cover (code, images),
|
|
86
|
+
pass a pre-built Ricos `richContent` on the post instead. `setupBlog` **installs the Wix Blog app
|
|
87
|
+
first** (`installBlogApp`, idempotent), so seeding works even if the site doesn't have it yet.
|
|
88
|
+
|
|
89
|
+
## Reference
|
|
90
|
+
If a call returns a shape you didn't expect, or you need an operation this module doesn't cover,
|
|
91
|
+
use the **`wix-docs`** skill to search + read the live Wix Blog API reference — never guess. The
|
|
92
|
+
authoritative source recipe is `wix-headless/references/inline-recipes/setup-blog.md`.
|
|
93
|
+
|
|
94
|
+
Read a method's page before writing its call: it carries the exact body shape, the required
|
|
95
|
+
permission scope, and the response envelope.
|
|
96
|
+
- Install a Wix app onto the site: https://dev.wix.com/docs/api-reference/business-management/app-installation/app-installation/install-app.md
|
|
97
|
+
- Import an image into Wix Media: https://dev.wix.com/docs/api-reference/assets/media/media-manager/files/import-file.md
|
|
98
|
+
- Bulk Create Draft Posts: https://dev.wix.com/docs/api-reference/business-solutions/blog/draft-posts/bulk-create-draft-posts.md
|
|
99
|
+
- Create Draft Post: https://dev.wix.com/docs/api-reference/business-solutions/blog/draft-posts/create-draft-post.md
|
|
100
|
+
- Publish Draft Post: https://dev.wix.com/docs/api-reference/business-solutions/blog/draft-posts/publish-draft-post.md
|
|
101
|
+
- Create Category: https://dev.wix.com/docs/api-reference/business-solutions/blog/category/create-category.md
|
|
102
|
+
- Create Tag: https://dev.wix.com/docs/api-reference/business-solutions/blog/tags/create-tag.md
|
|
103
|
+
- Create Member (post authors): https://dev.wix.com/docs/api-reference/crm/members-contacts/members/member-management/members/create-member.md
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
// Blog seed helpers — run at BUILD TIME via exec_tool (NOT shipped in the app).
|
|
2
|
+
// The agent requires this and calls the functions with plain data; all Wix Blog V3
|
|
3
|
+
// request/response mechanics (the required author memberId, single-vs-bulk endpoint switch,
|
|
4
|
+
// the flat-per-item bulk shape, Ricos richContent nesting, sequential category/tag creates,
|
|
5
|
+
// the cover-image PATCH + re-publish) live here, once.
|
|
6
|
+
//
|
|
7
|
+
// Usage (build-time exec_tool):
|
|
8
|
+
// const { accessToken } = await base44.asServiceRole.connectors.getConnection("wix"); // Base44
|
|
9
|
+
// const seed = require("/app/.agents/skills/wix-vibe-headless/references/blog/seed/seed-blog.js");
|
|
10
|
+
// const ctx = { token: accessToken, siteId: WIX_METASITE_ID };
|
|
11
|
+
// const memberId = await seed.getAuthorMemberId(ctx); // STEP 1 — required for every post
|
|
12
|
+
// const cats = await seed.createCategories(ctx, ["Recipes", "Brewing"]); // STEP 3 — only if the brief groups posts
|
|
13
|
+
// const posts = await seed.createPosts(ctx, [
|
|
14
|
+
// { title: "How We Roast Our Beans", categoryIds: [cats[0].id], content: [
|
|
15
|
+
// { type: "heading", text: "From farm to cup", level: 2 },
|
|
16
|
+
// { type: "paragraph", text: "Every batch starts with beans from a single estate." },
|
|
17
|
+
// { type: "quote", text: "Great coffee is grown, not made." },
|
|
18
|
+
// ] },
|
|
19
|
+
// ], { memberId });
|
|
20
|
+
// // optional — import each image url to Wix Media (blog binds by file id), then attach covers + re-publish
|
|
21
|
+
// const files = await Promise.all(imageUrls.map((u) => seed.importImage(ctx, u))); // → [{ id, url }]
|
|
22
|
+
// await seed.attachPostCovers(ctx, posts.map((p, i) => ({ postId: p.id, fileId: files[i].id })));
|
|
23
|
+
//
|
|
24
|
+
// Live-verified end-to-end (members author, categories, posts single+bulk, tags, covers, idempotent
|
|
25
|
+
// re-runs). If any call ever fails with a shape the caller didn't expect, fall back to the wix-docs
|
|
26
|
+
// skill (search + read the live Wix Blog API reference) — never guess. Source recipe:
|
|
27
|
+
// wix-headless/references/inline-recipes/setup-blog.md.
|
|
28
|
+
|
|
29
|
+
const API = "https://www.wixapis.com";
|
|
30
|
+
const BLOG_APP_ID = "14bcded7-0066-7c35-14d7-466cb3f09103"; // installBlogApp installs this before seeding
|
|
31
|
+
|
|
32
|
+
async function req(ctx, path, { method = "POST", body } = {}) {
|
|
33
|
+
const res = await fetch(API + path, {
|
|
34
|
+
method,
|
|
35
|
+
headers: {
|
|
36
|
+
Authorization: `Bearer ${ctx.token}`,
|
|
37
|
+
"wix-site-id": ctx.siteId,
|
|
38
|
+
"Content-Type": "application/json",
|
|
39
|
+
},
|
|
40
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
41
|
+
});
|
|
42
|
+
const json = await res.json().catch(() => ({}));
|
|
43
|
+
if (!res.ok) throw new Error(`${method} ${path} -> ${res.status}: ${JSON.stringify(json).slice(0, 400)}`);
|
|
44
|
+
return json;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ---- Ricos richContent builder (per recipe § "CRITICAL RICOS NESTING") ----
|
|
48
|
+
// A post's `content` is a list of plain block descriptors; this builds the Ricos node tree.
|
|
49
|
+
// Rules baked in: TEXT is always a leaf inside a container; BLOCKQUOTE / LIST_ITEM wrap a
|
|
50
|
+
// PARAGRAPH; BULLETED_LIST / ORDERED_LIST wrap LIST_ITEM -> PARAGRAPH -> TEXT; every container
|
|
51
|
+
// node gets a unique id, TEXT leaves use id "". Supported block types: heading, paragraph,
|
|
52
|
+
// quote, bulleted, ordered. For node types the recipe doesn't spell out (CODE_BLOCK, IMAGE, …)
|
|
53
|
+
// pass a pre-built `richContent` on the post instead and it's used verbatim (see fall-back below).
|
|
54
|
+
const mkText = (text) => ({ type: "TEXT", id: "", nodes: [], textData: { text: text || "", decorations: [] } });
|
|
55
|
+
const mkParagraph = (id, text) => ({ type: "PARAGRAPH", id, nodes: [mkText(text)], paragraphData: {} });
|
|
56
|
+
|
|
57
|
+
function mkRichContent(blocks = [], postIdx = 0) {
|
|
58
|
+
let n = 0;
|
|
59
|
+
const id = () => `p${postIdx}-n${n++}`;
|
|
60
|
+
const nodes = [];
|
|
61
|
+
for (const b of blocks) {
|
|
62
|
+
switch (b.type) {
|
|
63
|
+
case "heading":
|
|
64
|
+
nodes.push({ type: "HEADING", id: id(), nodes: [mkText(b.text)], headingData: { level: b.level ?? 2 } });
|
|
65
|
+
break;
|
|
66
|
+
case "quote":
|
|
67
|
+
// BLOCKQUOTE wraps a PARAGRAPH, per recipe
|
|
68
|
+
nodes.push({ type: "BLOCKQUOTE", id: id(), nodes: [mkParagraph(id(), b.text)], blockquoteData: { indentation: 1 } });
|
|
69
|
+
break;
|
|
70
|
+
case "bulleted":
|
|
71
|
+
case "ordered": {
|
|
72
|
+
// LIST -> LIST_ITEM -> PARAGRAPH -> TEXT, per recipe
|
|
73
|
+
const listType = b.type === "bulleted" ? "BULLETED_LIST" : "ORDERED_LIST";
|
|
74
|
+
nodes.push({
|
|
75
|
+
type: listType, id: id(),
|
|
76
|
+
nodes: (b.items ?? []).map((item) => ({ type: "LIST_ITEM", id: id(), nodes: [mkParagraph(id(), item)] })),
|
|
77
|
+
});
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
case "paragraph":
|
|
81
|
+
default:
|
|
82
|
+
nodes.push(mkParagraph(id(), b.text));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return { nodes };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// One post's plain data -> a flat Blog V3 draft-post object.
|
|
89
|
+
// `content` (block list) is turned into Ricos richContent unless a pre-built `richContent` is given.
|
|
90
|
+
// media is omitted here — covers are a separate pass (attachPostCovers), optional (a separate covers pass). Per recipe.
|
|
91
|
+
function buildPost(p, i, memberId) {
|
|
92
|
+
return {
|
|
93
|
+
title: p.title,
|
|
94
|
+
memberId,
|
|
95
|
+
richContent: p.richContent ?? mkRichContent(p.content, i),
|
|
96
|
+
...(p.categoryIds ? { categoryIds: p.categoryIds } : {}),
|
|
97
|
+
...(p.tagIds ? { tagIds: p.tagIds } : {}),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ---- exported operations ----
|
|
102
|
+
|
|
103
|
+
// STEP 1: fetch a real author memberId (required — every post create needs it; a fabricated id
|
|
104
|
+
// fails with "memberIds ... do not exist"). Returns members[0].id; throws loudly if none exist.
|
|
105
|
+
async function getAuthorMemberId(ctx) {
|
|
106
|
+
const r = await req(ctx, "/members/v1/members?fieldsets=PUBLIC&paging.limit=1", { method: "GET" });
|
|
107
|
+
const id = r.members?.[0]?.id;
|
|
108
|
+
if (!id) throw new Error(`No site member found for author attribution: ${JSON.stringify(r).slice(0, 400)}`);
|
|
109
|
+
return id;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* STEP 2: create posts, published (publish:true so they go live immediately).
|
|
114
|
+
* Auto-selects the endpoint per recipe: single-post endpoint for exactly one post (nested
|
|
115
|
+
* `{ draftPost }` envelope), the bulk endpoint for >= 2 (flat per-item objects, NOT wrapped).
|
|
116
|
+
* @param posts [{ title, content: [blocks] | richContent?, categoryIds?, tagIds? }]
|
|
117
|
+
* content blocks: { type:"heading", text, level? } | { type:"paragraph", text }
|
|
118
|
+
* | { type:"quote", text } | { type:"bulleted"|"ordered", items:[text,...] }.
|
|
119
|
+
* Pass a pre-built Ricos `richContent` instead of `content` for node types not covered here.
|
|
120
|
+
* @param opts { memberId } memberId from getAuthorMemberId — required; publish defaults to true.
|
|
121
|
+
* @returns [{ id, index, success }] (id is the draftPostId; feeds attachPostCovers)
|
|
122
|
+
*/
|
|
123
|
+
async function createPosts(ctx, posts, { memberId, publish = true } = {}) {
|
|
124
|
+
if (!memberId) throw new Error("createPosts requires opts.memberId (see getAuthorMemberId)");
|
|
125
|
+
if (posts.length === 1) {
|
|
126
|
+
// single-post endpoint uses the nested { draftPost } envelope
|
|
127
|
+
const r = await req(ctx, "/blog/v3/draft-posts", { body: { draftPost: buildPost(posts[0], 0, memberId), publish } });
|
|
128
|
+
return [{ id: r.draftPost?.id, index: 0, success: !!r.draftPost?.id }];
|
|
129
|
+
}
|
|
130
|
+
// bulk endpoint: `bulk` is a path segment BETWEEN v3 and draft-posts; each item is FLAT (no draftPost wrapper)
|
|
131
|
+
const r = await req(ctx, "/blog/v3/bulk/draft-posts/create", {
|
|
132
|
+
body: { draftPosts: posts.map((p, i) => buildPost(p, i, memberId)), publish },
|
|
133
|
+
});
|
|
134
|
+
// Bulk returns 200 even on partial failure — read per-item results[].itemMetadata.success.
|
|
135
|
+
return (r.results ?? []).map((x) => ({
|
|
136
|
+
id: x.itemMetadata?.id, index: x.itemMetadata?.originalIndex, success: !!x.itemMetadata?.success,
|
|
137
|
+
}));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
141
|
+
|
|
142
|
+
// Existing label -> id, straight from the query (the source of truth for what actually persisted).
|
|
143
|
+
async function labelIdMap(ctx, kind) {
|
|
144
|
+
const path = kind === "categories" ? "/blog/v3/categories/query" : "/v3/tags/query";
|
|
145
|
+
const r = await req(ctx, path, { body: { query: { paging: { limit: 100 } } } });
|
|
146
|
+
return new Map((r[kind] ?? []).map((x) => [x.label, x.id]));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Create category/tag labels resiliently. TWO hazards this absorbs:
|
|
150
|
+
// 1. Fresh-install provisioning window — for a few seconds after the Blog app is installed, per-item
|
|
151
|
+
// category/tag creates return 200 with an id but DON'T persist (last-write-wins; the id is a lie).
|
|
152
|
+
// Posts (bulk) are unaffected. So we never trust the create response — we re-query and treat what
|
|
153
|
+
// the query returns as truth, re-creating anything still missing until it sticks (store warms in ~s).
|
|
154
|
+
// 2. Idempotency — an already-present label (e.g. a partial-failure re-run) is skipped, not re-created.
|
|
155
|
+
// Category bodies are NESTED (`{ category: { label } }`); tag bodies are FLAT (`{ label }`) — a
|
|
156
|
+
// `{ tag: { label } }` body sends an empty top-level label and 400s. Returns [{ id, name }].
|
|
157
|
+
async function ensureLabels(ctx, kind, createPath, mkBody, names) {
|
|
158
|
+
let map = await labelIdMap(ctx, kind);
|
|
159
|
+
for (let attempt = 0; attempt < 8; attempt++) {
|
|
160
|
+
const missing = names.filter((n) => !map.has(n));
|
|
161
|
+
if (!missing.length) break;
|
|
162
|
+
if (attempt) await sleep(1500); // backoff only between retries — happy path pays nothing
|
|
163
|
+
for (const name of missing) {
|
|
164
|
+
try { await req(ctx, createPath, { body: mkBody(name) }); }
|
|
165
|
+
catch (e) { if (!String(e.message).includes("-> 409")) throw e; } // 409 = raced, already there
|
|
166
|
+
}
|
|
167
|
+
map = await labelIdMap(ctx, kind);
|
|
168
|
+
}
|
|
169
|
+
return names.map((name) => ({ id: map.get(name), name }));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// STEP 3 (optional — only if the request groups posts): create categories. No bulk endpoint.
|
|
173
|
+
async function createCategories(ctx, names) {
|
|
174
|
+
return ensureLabels(ctx, "categories", "/blog/v3/categories", (name) => ({ category: { label: name } }), names);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// STEP 3 (optional): create tags. Feed the returned ids into post.tagIds.
|
|
178
|
+
async function createTags(ctx, names) {
|
|
179
|
+
return ensureLabels(ctx, "tags", "/blog/v3/tags", (name) => ({ label: name }), names);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Import an external image URL into Wix Media → { id, url }. Blog binds the cover by the Wix Media
|
|
183
|
+
// file **id**, NOT a url — an external url (e.g. a base44 generate_image result) MUST be imported
|
|
184
|
+
// first; the raw url renders nothing. id = wixstatic file id, url = the permanent wixstatic url.
|
|
185
|
+
async function importImage(ctx, url, displayName = "image.png") {
|
|
186
|
+
const r = await req(ctx, "/site-media/v1/files/import", { body: { url, mimeType: "image/png", displayName } });
|
|
187
|
+
const f = r.file || r;
|
|
188
|
+
if (!f?.id) throw new Error(`import-file returned no file id: ${JSON.stringify(r).slice(0, 200)}`);
|
|
189
|
+
return { id: f.id, url: f.url };
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Attach images step (optional). covers: [{ postId, fileId }] where fileId is the WixMedia
|
|
193
|
+
// file.id from importImage (Blog binds the cover by id, not url). Per post:
|
|
194
|
+
// PATCH /blog/v3/draft-posts/{id} (NOT POST …/{id}/update — that 404s for a single post),
|
|
195
|
+
// setting media.displayed:true + media.custom:true + wixMedia.image.id (id ALONE is a silent no-op),
|
|
196
|
+
// then re-publish (the PATCH sets hasUnpublishedChanges, so the live post stays cover-less until republish).
|
|
197
|
+
// Image failures never block the run — skip a failed cover, leave the post text-only.
|
|
198
|
+
async function attachPostCovers(ctx, covers) {
|
|
199
|
+
for (const { postId, fileId } of covers) {
|
|
200
|
+
try {
|
|
201
|
+
await req(ctx, `/blog/v3/draft-posts/${postId}`, {
|
|
202
|
+
method: "PATCH",
|
|
203
|
+
body: { draftPost: { media: { displayed: true, custom: true, wixMedia: { image: { id: fileId } } } } },
|
|
204
|
+
});
|
|
205
|
+
await req(ctx, `/blog/v3/draft-posts/${postId}/publish`, { method: "POST" });
|
|
206
|
+
} catch (e) {
|
|
207
|
+
console.warn(`cover attach skipped for post ${postId}: ${e.message}`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* DEFAULT one-call path — seed a whole blog in ONE exec call. Resolves the author memberId and
|
|
214
|
+
* category/tag names → ids internally and keeps every id in memory, so nothing is hand-threaded
|
|
215
|
+
* across exec calls. Order: memberId → categories/tags → posts (with resolved ids) → covers.
|
|
216
|
+
* @param plan {
|
|
217
|
+
* posts: [{ title, content?|richContent?, category?|categories?(name|names), tags?(names), coverImageUrl? }],
|
|
218
|
+
* categories?: [name], // pre-create categories even if no post references them
|
|
219
|
+
* tags?: [name],
|
|
220
|
+
* }
|
|
221
|
+
* category/categories/tags are display NAMES (resolved to ids here); coverImageUrl is a plain image
|
|
222
|
+
* url — imported to Wix Media here — and a cover is attached only for posts that provide one.
|
|
223
|
+
* @returns { posts:[{id,index,success}], categories:[{id,name}], tags:[{id,name}], coversAttached }
|
|
224
|
+
*/
|
|
225
|
+
// Install the Wix Blog app before seeding — base44 sites aren't guaranteed to have it (no separate
|
|
226
|
+
// Setup step here, unlike the wix-headless recipe). Idempotent: re-installing returns 200.
|
|
227
|
+
async function installBlogApp(ctx) {
|
|
228
|
+
return req(ctx, "/apps-installer-service/v1/app-instance/install", { body: {
|
|
229
|
+
tenant: { tenantType: "SITE", id: ctx.siteId },
|
|
230
|
+
appInstance: { appDefId: BLOG_APP_ID, enabled: true },
|
|
231
|
+
} });
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async function setupBlog(ctx, { posts = [], categories = [], tags = [] } = {}) {
|
|
235
|
+
await installBlogApp(ctx);
|
|
236
|
+
await sleep(3000); // let a fresh Blog install settle so the first category/tag writes stick (see ensureLabels);
|
|
237
|
+
// correctness is still guaranteed by ensureLabels' verify-retry — this just cuts the retries.
|
|
238
|
+
const memberId = await getAuthorMemberId(ctx);
|
|
239
|
+
const catNames = [...new Set([...categories, ...posts.flatMap((p) => [].concat(p.category ?? [], p.categories ?? []))])];
|
|
240
|
+
const tagNames = [...new Set([...tags, ...posts.flatMap((p) => [].concat(p.tags ?? []))])];
|
|
241
|
+
const cats = catNames.length ? await createCategories(ctx, catNames) : [];
|
|
242
|
+
const tgs = tagNames.length ? await createTags(ctx, tagNames) : [];
|
|
243
|
+
const catId = new Map(cats.map((c) => [c.name, c.id]));
|
|
244
|
+
const tagId = new Map(tgs.map((t) => [t.name, t.id]));
|
|
245
|
+
const created = await createPosts(ctx, posts.map((p) => {
|
|
246
|
+
const cn = [].concat(p.category ?? [], p.categories ?? []);
|
|
247
|
+
const tn = [].concat(p.tags ?? []);
|
|
248
|
+
return {
|
|
249
|
+
...p,
|
|
250
|
+
...(cn.length ? { categoryIds: cn.map((n) => catId.get(n)).filter(Boolean) } : {}),
|
|
251
|
+
...(tn.length ? { tagIds: tn.map((n) => tagId.get(n)).filter(Boolean) } : {}),
|
|
252
|
+
};
|
|
253
|
+
}), { memberId });
|
|
254
|
+
const covers = [];
|
|
255
|
+
for (let i = 0; i < created.length; i++) {
|
|
256
|
+
const url = posts[i]?.coverImageUrl;
|
|
257
|
+
if (!created[i]?.id || !url) continue;
|
|
258
|
+
try {
|
|
259
|
+
const file = await importImage(ctx, url, `post-${i}.png`); // → Wix Media file id
|
|
260
|
+
covers.push({ postId: created[i].id, fileId: file.id });
|
|
261
|
+
} catch { /* never block on image failure — leave the post cover-less */ }
|
|
262
|
+
}
|
|
263
|
+
if (covers.length) await attachPostCovers(ctx, covers);
|
|
264
|
+
return { posts: created, categories: cats, tags: tgs, coversAttached: covers.length };
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
module.exports = {
|
|
268
|
+
setupBlog, installBlogApp,
|
|
269
|
+
getAuthorMemberId, createPosts, createCategories, createTags, importImage, attachPostCovers,
|
|
270
|
+
};
|