@wildo-ai/saas-website 1.1.1
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/LICENSE +34 -0
- package/dist/esm/.builder.pid +9 -0
- package/dist/esm/astro/blog-post-bridge.d.ts +324 -0
- package/dist/esm/astro/blog-post-bridge.d.ts.map +1 -0
- package/dist/esm/astro/blog-post-bridge.js +57 -0
- package/dist/esm/astro/blog-post-bridge.js.map +1 -0
- package/dist/esm/astro/blog-post-head.renderer.d.ts +129 -0
- package/dist/esm/astro/blog-post-head.renderer.d.ts.map +1 -0
- package/dist/esm/astro/blog-post-head.renderer.js +139 -0
- package/dist/esm/astro/blog-post-head.renderer.js.map +1 -0
- package/dist/esm/astro/bridge-runtime.d.ts +224 -0
- package/dist/esm/astro/bridge-runtime.d.ts.map +1 -0
- package/dist/esm/astro/bridge-runtime.js +30 -0
- package/dist/esm/astro/bridge-runtime.js.map +1 -0
- package/dist/esm/astro/collect-expected-label-keys.d.ts +65 -0
- package/dist/esm/astro/collect-expected-label-keys.d.ts.map +1 -0
- package/dist/esm/astro/collect-expected-label-keys.js +101 -0
- package/dist/esm/astro/collect-expected-label-keys.js.map +1 -0
- package/dist/esm/astro/headers-renderer.d.ts +32 -0
- package/dist/esm/astro/headers-renderer.d.ts.map +1 -0
- package/dist/esm/astro/headers-renderer.js +64 -0
- package/dist/esm/astro/headers-renderer.js.map +1 -0
- package/dist/esm/astro/i18n-routing.helper.d.ts +91 -0
- package/dist/esm/astro/i18n-routing.helper.d.ts.map +1 -0
- package/dist/esm/astro/i18n-routing.helper.js +23 -0
- package/dist/esm/astro/i18n-routing.helper.js.map +1 -0
- package/dist/esm/astro/internal/html-escape.d.ts +31 -0
- package/dist/esm/astro/internal/html-escape.d.ts.map +1 -0
- package/dist/esm/astro/internal/html-escape.js +40 -0
- package/dist/esm/astro/internal/html-escape.js.map +1 -0
- package/dist/esm/astro/label-pack-loader.d.ts +134 -0
- package/dist/esm/astro/label-pack-loader.d.ts.map +1 -0
- package/dist/esm/astro/label-pack-loader.js +298 -0
- package/dist/esm/astro/label-pack-loader.js.map +1 -0
- package/dist/esm/astro/llms-txt-server.d.ts +28 -0
- package/dist/esm/astro/llms-txt-server.d.ts.map +1 -0
- package/dist/esm/astro/llms-txt-server.js +33 -0
- package/dist/esm/astro/llms-txt-server.js.map +1 -0
- package/dist/esm/astro/pick-labels-for-page.d.ts +63 -0
- package/dist/esm/astro/pick-labels-for-page.d.ts.map +1 -0
- package/dist/esm/astro/pick-labels-for-page.js +73 -0
- package/dist/esm/astro/pick-labels-for-page.js.map +1 -0
- package/dist/esm/astro/robots-renderer.d.ts +85 -0
- package/dist/esm/astro/robots-renderer.d.ts.map +1 -0
- package/dist/esm/astro/robots-renderer.js +157 -0
- package/dist/esm/astro/robots-renderer.js.map +1 -0
- package/dist/esm/astro/sitemap-coverage.d.ts +101 -0
- package/dist/esm/astro/sitemap-coverage.d.ts.map +1 -0
- package/dist/esm/astro/sitemap-coverage.js +67 -0
- package/dist/esm/astro/sitemap-coverage.js.map +1 -0
- package/dist/esm/astro/structured-data.renderer.d.ts +21 -0
- package/dist/esm/astro/structured-data.renderer.d.ts.map +1 -0
- package/dist/esm/astro/structured-data.renderer.js +142 -0
- package/dist/esm/astro/structured-data.renderer.js.map +1 -0
- package/dist/esm/astro/website-page-head.renderer.d.ts +93 -0
- package/dist/esm/astro/website-page-head.renderer.d.ts.map +1 -0
- package/dist/esm/astro/website-page-head.renderer.js +184 -0
- package/dist/esm/astro/website-page-head.renderer.js.map +1 -0
- package/dist/esm/astro/website-page-runtime.helper.d.ts +112 -0
- package/dist/esm/astro/website-page-runtime.helper.d.ts.map +1 -0
- package/dist/esm/astro/website-page-runtime.helper.js +60 -0
- package/dist/esm/astro/website-page-runtime.helper.js.map +1 -0
- package/dist/esm/astro/website-site-context.d.ts +126 -0
- package/dist/esm/astro/website-site-context.d.ts.map +1 -0
- package/dist/esm/astro/website-site-context.js +37 -0
- package/dist/esm/astro/website-site-context.js.map +1 -0
- package/dist/esm/astro-island.d.ts +56 -0
- package/dist/esm/astro-island.d.ts.map +1 -0
- package/dist/esm/astro-island.js +61 -0
- package/dist/esm/astro-island.js.map +1 -0
- package/dist/esm/astro.d.ts +151 -0
- package/dist/esm/astro.d.ts.map +1 -0
- package/dist/esm/astro.js +151 -0
- package/dist/esm/astro.js.map +1 -0
- package/dist/esm/companion-exports.d.ts +38 -0
- package/dist/esm/companion-exports.d.ts.map +1 -0
- package/dist/esm/companion-exports.js +38 -0
- package/dist/esm/companion-exports.js.map +1 -0
- package/dist/esm/components/low-level/WebsiteButton.d.ts +73 -0
- package/dist/esm/components/low-level/WebsiteButton.d.ts.map +1 -0
- package/dist/esm/components/low-level/WebsiteButton.js +68 -0
- package/dist/esm/components/low-level/WebsiteButton.js.map +1 -0
- package/dist/esm/components/low-level/WebsiteHeading.d.ts +78 -0
- package/dist/esm/components/low-level/WebsiteHeading.d.ts.map +1 -0
- package/dist/esm/components/low-level/WebsiteHeading.js +41 -0
- package/dist/esm/components/low-level/WebsiteHeading.js.map +1 -0
- package/dist/esm/components/low-level/WebsiteImage.d.ts +73 -0
- package/dist/esm/components/low-level/WebsiteImage.d.ts.map +1 -0
- package/dist/esm/components/low-level/WebsiteImage.js +21 -0
- package/dist/esm/components/low-level/WebsiteImage.js.map +1 -0
- package/dist/esm/components/low-level/WebsiteInternalButton.d.ts +90 -0
- package/dist/esm/components/low-level/WebsiteInternalButton.d.ts.map +1 -0
- package/dist/esm/components/low-level/WebsiteInternalButton.js +47 -0
- package/dist/esm/components/low-level/WebsiteInternalButton.js.map +1 -0
- package/dist/esm/components/low-level/WebsiteInternalLink.d.ts +99 -0
- package/dist/esm/components/low-level/WebsiteInternalLink.d.ts.map +1 -0
- package/dist/esm/components/low-level/WebsiteInternalLink.js +68 -0
- package/dist/esm/components/low-level/WebsiteInternalLink.js.map +1 -0
- package/dist/esm/components/low-level/WebsiteLink.d.ts +50 -0
- package/dist/esm/components/low-level/WebsiteLink.d.ts.map +1 -0
- package/dist/esm/components/low-level/WebsiteLink.js +22 -0
- package/dist/esm/components/low-level/WebsiteLink.js.map +1 -0
- package/dist/esm/components/low-level/WebsiteText.d.ts +57 -0
- package/dist/esm/components/low-level/WebsiteText.d.ts.map +1 -0
- package/dist/esm/components/low-level/WebsiteText.js +57 -0
- package/dist/esm/components/low-level/WebsiteText.js.map +1 -0
- package/dist/esm/config/define-website-config.d.ts +83 -0
- package/dist/esm/config/define-website-config.d.ts.map +1 -0
- package/dist/esm/config/define-website-config.js +126 -0
- package/dist/esm/config/define-website-config.js.map +1 -0
- package/dist/esm/config/index.d.ts +38 -0
- package/dist/esm/config/index.d.ts.map +1 -0
- package/dist/esm/config/index.js +38 -0
- package/dist/esm/config/index.js.map +1 -0
- package/dist/esm/config/load-website-config.d.ts +136 -0
- package/dist/esm/config/load-website-config.d.ts.map +1 -0
- package/dist/esm/config/load-website-config.js +177 -0
- package/dist/esm/config/load-website-config.js.map +1 -0
- package/dist/esm/config/wildo-website-config.schemas.d.ts +251 -0
- package/dist/esm/config/wildo-website-config.schemas.d.ts.map +1 -0
- package/dist/esm/config/wildo-website-config.schemas.js +302 -0
- package/dist/esm/config/wildo-website-config.schemas.js.map +1 -0
- package/dist/esm/config-loader.d.ts +35 -0
- package/dist/esm/config-loader.d.ts.map +1 -0
- package/dist/esm/config-loader.js +35 -0
- package/dist/esm/config-loader.js.map +1 -0
- package/dist/esm/core/anonymous-session/InboundContactForm.d.ts +38 -0
- package/dist/esm/core/anonymous-session/InboundContactForm.d.ts.map +1 -0
- package/dist/esm/core/anonymous-session/InboundContactForm.js +77 -0
- package/dist/esm/core/anonymous-session/InboundContactForm.js.map +1 -0
- package/dist/esm/core/anonymous-session/inbound-contact-form.schema.d.ts +41 -0
- package/dist/esm/core/anonymous-session/inbound-contact-form.schema.d.ts.map +1 -0
- package/dist/esm/core/anonymous-session/inbound-contact-form.schema.js +58 -0
- package/dist/esm/core/anonymous-session/inbound-contact-form.schema.js.map +1 -0
- package/dist/esm/core/anonymous-session/website-anonymous-session-client.d.ts +81 -0
- package/dist/esm/core/anonymous-session/website-anonymous-session-client.d.ts.map +1 -0
- package/dist/esm/core/anonymous-session/website-anonymous-session-client.js +177 -0
- package/dist/esm/core/anonymous-session/website-anonymous-session-client.js.map +1 -0
- package/dist/esm/core/contexts/WebsitePageContext.d.ts +40 -0
- package/dist/esm/core/contexts/WebsitePageContext.d.ts.map +1 -0
- package/dist/esm/core/contexts/WebsitePageContext.js +8 -0
- package/dist/esm/core/contexts/WebsitePageContext.js.map +1 -0
- package/dist/esm/core/contexts/WebsiteRuntimeContext.d.ts +162 -0
- package/dist/esm/core/contexts/WebsiteRuntimeContext.d.ts.map +1 -0
- package/dist/esm/core/contexts/WebsiteRuntimeContext.js +22 -0
- package/dist/esm/core/contexts/WebsiteRuntimeContext.js.map +1 -0
- package/dist/esm/core/contexts/WebsiteSectionContext.d.ts +47 -0
- package/dist/esm/core/contexts/WebsiteSectionContext.d.ts.map +1 -0
- package/dist/esm/core/contexts/WebsiteSectionContext.js +8 -0
- package/dist/esm/core/contexts/WebsiteSectionContext.js.map +1 -0
- package/dist/esm/core/contexts/useWebsitePage.d.ts +13 -0
- package/dist/esm/core/contexts/useWebsitePage.d.ts.map +1 -0
- package/dist/esm/core/contexts/useWebsitePage.js +22 -0
- package/dist/esm/core/contexts/useWebsitePage.js.map +1 -0
- package/dist/esm/core/contexts/useWebsiteRuntime.d.ts +19 -0
- package/dist/esm/core/contexts/useWebsiteRuntime.d.ts.map +1 -0
- package/dist/esm/core/contexts/useWebsiteRuntime.js +28 -0
- package/dist/esm/core/contexts/useWebsiteRuntime.js.map +1 -0
- package/dist/esm/core/contexts/useWebsiteSection.d.ts +12 -0
- package/dist/esm/core/contexts/useWebsiteSection.d.ts.map +1 -0
- package/dist/esm/core/contexts/useWebsiteSection.js +22 -0
- package/dist/esm/core/contexts/useWebsiteSection.js.map +1 -0
- package/dist/esm/core/external-providers/frontend-provider-registry.website.d.ts +17 -0
- package/dist/esm/core/external-providers/frontend-provider-registry.website.d.ts.map +1 -0
- package/dist/esm/core/external-providers/frontend-provider-registry.website.js +23 -0
- package/dist/esm/core/external-providers/frontend-provider-registry.website.js.map +1 -0
- package/dist/esm/core/factories/define-website-page-manifest.d.ts +70 -0
- package/dist/esm/core/factories/define-website-page-manifest.d.ts.map +1 -0
- package/dist/esm/core/factories/define-website-page-manifest.js +51 -0
- package/dist/esm/core/factories/define-website-page-manifest.js.map +1 -0
- package/dist/esm/core/factories/define-website-section.d.ts +101 -0
- package/dist/esm/core/factories/define-website-section.d.ts.map +1 -0
- package/dist/esm/core/factories/define-website-section.js +71 -0
- package/dist/esm/core/factories/define-website-section.js.map +1 -0
- package/dist/esm/core/hooks/useWebsiteDesignTokens.d.ts +23 -0
- package/dist/esm/core/hooks/useWebsiteDesignTokens.d.ts.map +1 -0
- package/dist/esm/core/hooks/useWebsiteDesignTokens.js +25 -0
- package/dist/esm/core/hooks/useWebsiteDesignTokens.js.map +1 -0
- package/dist/esm/core/hooks/useWebsiteLabel.d.ts +68 -0
- package/dist/esm/core/hooks/useWebsiteLabel.d.ts.map +1 -0
- package/dist/esm/core/hooks/useWebsiteLabel.js +103 -0
- package/dist/esm/core/hooks/useWebsiteLabel.js.map +1 -0
- package/dist/esm/core/layouts/WebsitePageLayout.d.ts +87 -0
- package/dist/esm/core/layouts/WebsitePageLayout.d.ts.map +1 -0
- package/dist/esm/core/layouts/WebsitePageLayout.js +170 -0
- package/dist/esm/core/layouts/WebsitePageLayout.js.map +1 -0
- package/dist/esm/core/layouts/WebsiteSection.d.ts +91 -0
- package/dist/esm/core/layouts/WebsiteSection.d.ts.map +1 -0
- package/dist/esm/core/layouts/WebsiteSection.js +26 -0
- package/dist/esm/core/layouts/WebsiteSection.js.map +1 -0
- package/dist/esm/core/routing/internal-routing.utils.d.ts +65 -0
- package/dist/esm/core/routing/internal-routing.utils.d.ts.map +1 -0
- package/dist/esm/core/routing/internal-routing.utils.js +14 -0
- package/dist/esm/core/routing/internal-routing.utils.js.map +1 -0
- package/dist/esm/index.d.ts +129 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +129 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/mdx/BlogPost.d.ts +193 -0
- package/dist/esm/mdx/BlogPost.d.ts.map +1 -0
- package/dist/esm/mdx/BlogPost.js +161 -0
- package/dist/esm/mdx/BlogPost.js.map +1 -0
- package/dist/esm/mdx/blog-post-collection.config.d.ts +139 -0
- package/dist/esm/mdx/blog-post-collection.config.d.ts.map +1 -0
- package/dist/esm/mdx/blog-post-collection.config.js +27 -0
- package/dist/esm/mdx/blog-post-collection.config.js.map +1 -0
- package/dist/esm/mdx/blog-post-frontmatter-source.d.ts +12 -0
- package/dist/esm/mdx/blog-post-frontmatter-source.d.ts.map +1 -0
- package/dist/esm/mdx/blog-post-frontmatter-source.js +13 -0
- package/dist/esm/mdx/blog-post-frontmatter-source.js.map +1 -0
- package/dist/esm/mdx/index.d.ts +22 -0
- package/dist/esm/mdx/index.d.ts.map +1 -0
- package/dist/esm/mdx/index.js +22 -0
- package/dist/esm/mdx/index.js.map +1 -0
- package/dist/esm/mdx/website-mdx-provider.d.ts +90 -0
- package/dist/esm/mdx/website-mdx-provider.d.ts.map +1 -0
- package/dist/esm/mdx/website-mdx-provider.js +8 -0
- package/dist/esm/mdx/website-mdx-provider.js.map +1 -0
- package/dist/esm/mdx.d.ts +38 -0
- package/dist/esm/mdx.d.ts.map +1 -0
- package/dist/esm/mdx.js +38 -0
- package/dist/esm/mdx.js.map +1 -0
- package/dist/esm/schemas/blog/blog-post-frontmatter.shared.schemas.d.ts +75 -0
- package/dist/esm/schemas/blog/blog-post-frontmatter.shared.schemas.d.ts.map +1 -0
- package/dist/esm/schemas/blog/blog-post-frontmatter.shared.schemas.js +85 -0
- package/dist/esm/schemas/blog/blog-post-frontmatter.shared.schemas.js.map +1 -0
- package/dist/esm/schemas/design-tokens/website-design-tokens.shared.schemas.d.ts +120 -0
- package/dist/esm/schemas/design-tokens/website-design-tokens.shared.schemas.d.ts.map +1 -0
- package/dist/esm/schemas/design-tokens/website-design-tokens.shared.schemas.js +152 -0
- package/dist/esm/schemas/design-tokens/website-design-tokens.shared.schemas.js.map +1 -0
- package/dist/esm/schemas/label-keys/website-label-key.schemas.d.ts +73 -0
- package/dist/esm/schemas/label-keys/website-label-key.schemas.d.ts.map +1 -0
- package/dist/esm/schemas/label-keys/website-label-key.schemas.js +76 -0
- package/dist/esm/schemas/label-keys/website-label-key.schemas.js.map +1 -0
- package/dist/esm/schemas/manifests/website-page-manifest.shared.schemas.d.ts +209 -0
- package/dist/esm/schemas/manifests/website-page-manifest.shared.schemas.d.ts.map +1 -0
- package/dist/esm/schemas/manifests/website-page-manifest.shared.schemas.js +218 -0
- package/dist/esm/schemas/manifests/website-page-manifest.shared.schemas.js.map +1 -0
- package/dist/esm/schemas/manifests/website-root-config.shared.schemas.d.ts +431 -0
- package/dist/esm/schemas/manifests/website-root-config.shared.schemas.d.ts.map +1 -0
- package/dist/esm/schemas/manifests/website-root-config.shared.schemas.js +438 -0
- package/dist/esm/schemas/manifests/website-root-config.shared.schemas.js.map +1 -0
- package/dist/esm/schemas/refs/page-ref.schemas.d.ts +40 -0
- package/dist/esm/schemas/refs/page-ref.schemas.d.ts.map +1 -0
- package/dist/esm/schemas/refs/page-ref.schemas.js +43 -0
- package/dist/esm/schemas/refs/page-ref.schemas.js.map +1 -0
- package/dist/esm/schemas/refs/section-ref.schemas.d.ts +41 -0
- package/dist/esm/schemas/refs/section-ref.schemas.d.ts.map +1 -0
- package/dist/esm/schemas/refs/section-ref.schemas.js +44 -0
- package/dist/esm/schemas/refs/section-ref.schemas.js.map +1 -0
- package/dist/esm/schemas/sections/website-section-category.shared.d.ts +63 -0
- package/dist/esm/schemas/sections/website-section-category.shared.d.ts.map +1 -0
- package/dist/esm/schemas/sections/website-section-category.shared.js +64 -0
- package/dist/esm/schemas/sections/website-section-category.shared.js.map +1 -0
- package/dist/esm/schemas/sections/website-section-definition.shared.schemas.d.ts +114 -0
- package/dist/esm/schemas/sections/website-section-definition.shared.schemas.d.ts.map +1 -0
- package/dist/esm/schemas/sections/website-section-definition.shared.schemas.js +69 -0
- package/dist/esm/schemas/sections/website-section-definition.shared.schemas.js.map +1 -0
- package/dist/esm/schemas/structured-data/structured-data-reconciliation.shared.d.ts +100 -0
- package/dist/esm/schemas/structured-data/structured-data-reconciliation.shared.d.ts.map +1 -0
- package/dist/esm/schemas/structured-data/structured-data-reconciliation.shared.js +355 -0
- package/dist/esm/schemas/structured-data/structured-data-reconciliation.shared.js.map +1 -0
- package/dist/esm/schemas/structured-data/website-structured-data.shared.schemas.d.ts +58 -0
- package/dist/esm/schemas/structured-data/website-structured-data.shared.schemas.d.ts.map +1 -0
- package/dist/esm/schemas/structured-data/website-structured-data.shared.schemas.js +2 -0
- package/dist/esm/schemas/structured-data/website-structured-data.shared.schemas.js.map +1 -0
- package/dist/esm/schemas/validators/label-pack.validator.d.ts +144 -0
- package/dist/esm/schemas/validators/label-pack.validator.d.ts.map +1 -0
- package/dist/esm/schemas/validators/label-pack.validator.js +100 -0
- package/dist/esm/schemas/validators/label-pack.validator.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/package.json +143 -0
- package/src/__tests__/bundle-isolation.test.ts +607 -0
- package/src/astro/__tests__/blog-post-bridge.test.tsx +288 -0
- package/src/astro/__tests__/blog-post-head.renderer.test.ts +249 -0
- package/src/astro/__tests__/bridge-runtime.test.tsx +198 -0
- package/src/astro/__tests__/collect-expected-label-keys.test.ts +69 -0
- package/src/astro/__tests__/headers-renderer.test.ts +143 -0
- package/src/astro/__tests__/i18n-routing.helper.test.ts +116 -0
- package/src/astro/__tests__/label-pack-loader.test.ts +305 -0
- package/src/astro/__tests__/llms-txt-server.test.ts +127 -0
- package/src/astro/__tests__/pick-labels-for-page.test.ts +60 -0
- package/src/astro/__tests__/robots-renderer.test.ts +228 -0
- package/src/astro/__tests__/sitemap-coverage.test.ts +230 -0
- package/src/astro/__tests__/structured-data.renderer.test.ts +172 -0
- package/src/astro/__tests__/website-page-head.renderer.test.ts +424 -0
- package/src/astro/__tests__/website-page-runtime.helper.test.ts +157 -0
- package/src/astro/__tests__/website-site-context.test.ts +121 -0
- package/src/astro/blog-post-bridge.tsx +404 -0
- package/src/astro/blog-post-head.renderer.ts +293 -0
- package/src/astro/bridge-runtime.tsx +270 -0
- package/src/astro/collect-expected-label-keys.ts +113 -0
- package/src/astro/headers-renderer.ts +82 -0
- package/src/astro/i18n-routing.helper.ts +116 -0
- package/src/astro/internal/html-escape.ts +41 -0
- package/src/astro/label-pack-loader.ts +385 -0
- package/src/astro/llms-txt-server.ts +56 -0
- package/src/astro/pick-labels-for-page.ts +85 -0
- package/src/astro/robots-renderer.ts +171 -0
- package/src/astro/sitemap-coverage.ts +186 -0
- package/src/astro/structured-data.renderer.ts +171 -0
- package/src/astro/website-page-head.renderer.ts +279 -0
- package/src/astro/website-page-runtime.helper.ts +188 -0
- package/src/astro/website-site-context.ts +136 -0
- package/src/astro-island.ts +61 -0
- package/src/astro.ts +151 -0
- package/src/companion-exports.ts +38 -0
- package/src/components/low-level/WebsiteButton.tsx +118 -0
- package/src/components/low-level/WebsiteHeading.tsx +96 -0
- package/src/components/low-level/WebsiteImage.tsx +96 -0
- package/src/components/low-level/WebsiteInternalButton.tsx +172 -0
- package/src/components/low-level/WebsiteInternalLink.tsx +193 -0
- package/src/components/low-level/WebsiteLink.tsx +71 -0
- package/src/components/low-level/WebsiteText.tsx +75 -0
- package/src/components/low-level/__tests__/WebsiteInternalButton.test.tsx +169 -0
- package/src/components/low-level/__tests__/WebsiteInternalLink.test.tsx +202 -0
- package/src/components/low-level/__tests__/primitives.test.tsx +141 -0
- package/src/config/__tests__/define-website-config.test.ts +231 -0
- package/src/config/__tests__/load-website-config.test.ts +215 -0
- package/src/config/define-website-config.ts +134 -0
- package/src/config/index.ts +38 -0
- package/src/config/load-website-config.ts +229 -0
- package/src/config/wildo-website-config.schemas.ts +322 -0
- package/src/config-loader.ts +35 -0
- package/src/core/__tests__/WebsitePageLayout.test.tsx +184 -0
- package/src/core/__tests__/WebsiteSection.test.tsx +85 -0
- package/src/core/__tests__/contexts.test.tsx +133 -0
- package/src/core/__tests__/core-boundary.test.ts +85 -0
- package/src/core/__tests__/define-website-page-manifest.test.tsx +111 -0
- package/src/core/__tests__/define-website-section.test.tsx +89 -0
- package/src/core/__tests__/useWebsiteDesignTokens.test.tsx +41 -0
- package/src/core/__tests__/useWebsiteLabel.test.tsx +117 -0
- package/src/core/anonymous-session/InboundContactForm.tsx +157 -0
- package/src/core/anonymous-session/__tests__/inbound-contact-form.schema.test.ts +44 -0
- package/src/core/anonymous-session/inbound-contact-form.schema.ts +62 -0
- package/src/core/anonymous-session/website-anonymous-session-client.ts +194 -0
- package/src/core/contexts/WebsitePageContext.tsx +52 -0
- package/src/core/contexts/WebsiteRuntimeContext.tsx +175 -0
- package/src/core/contexts/WebsiteSectionContext.tsx +59 -0
- package/src/core/contexts/useWebsitePage.ts +28 -0
- package/src/core/contexts/useWebsiteRuntime.ts +34 -0
- package/src/core/contexts/useWebsiteSection.ts +28 -0
- package/src/core/external-providers/frontend-provider-registry.website.ts +62 -0
- package/src/core/factories/define-website-page-manifest.ts +102 -0
- package/src/core/factories/define-website-section.ts +128 -0
- package/src/core/hooks/useWebsiteDesignTokens.ts +26 -0
- package/src/core/hooks/useWebsiteLabel.ts +121 -0
- package/src/core/layouts/WebsitePageLayout.tsx +311 -0
- package/src/core/layouts/WebsiteSection.tsx +139 -0
- package/src/core/routing/__tests__/internal-routing.utils.test.ts +134 -0
- package/src/core/routing/internal-routing.utils.ts +77 -0
- package/src/index.ts +132 -0
- package/src/mdx/BlogPost.tsx +296 -0
- package/src/mdx/__tests__/BlogPost.test.tsx +218 -0
- package/src/mdx/__tests__/blog-post-collection.config.test.ts +127 -0
- package/src/mdx/__tests__/website-mdx-provider.test.tsx +82 -0
- package/src/mdx/blog-post-collection.config.ts +177 -0
- package/src/mdx/blog-post-frontmatter-source.ts +31 -0
- package/src/mdx/index.ts +39 -0
- package/src/mdx/website-mdx-provider.tsx +95 -0
- package/src/mdx.ts +38 -0
- package/src/schemas/__tests__/blog-frontmatter.test.ts +50 -0
- package/src/schemas/__tests__/companion-exports-react-free.test.ts +51 -0
- package/src/schemas/__tests__/design-tokens.test.ts +163 -0
- package/src/schemas/__tests__/label-key.test.ts +46 -0
- package/src/schemas/__tests__/label-pack-validator.test.ts +146 -0
- package/src/schemas/__tests__/page-manifest.test.ts +66 -0
- package/src/schemas/__tests__/refs.test.ts +37 -0
- package/src/schemas/__tests__/root-config.test.ts +292 -0
- package/src/schemas/__tests__/section-definition.test.ts +47 -0
- package/src/schemas/__tests__/structured-data-reconciliation.test.ts +543 -0
- package/src/schemas/blog/blog-post-frontmatter.shared.schemas.ts +111 -0
- package/src/schemas/design-tokens/website-design-tokens.shared.schemas.ts +166 -0
- package/src/schemas/label-keys/website-label-key.schemas.ts +88 -0
- package/src/schemas/manifests/website-page-manifest.shared.schemas.ts +266 -0
- package/src/schemas/manifests/website-root-config.shared.schemas.ts +504 -0
- package/src/schemas/refs/page-ref.schemas.ts +49 -0
- package/src/schemas/refs/section-ref.schemas.ts +50 -0
- package/src/schemas/sections/website-section-category.shared.ts +65 -0
- package/src/schemas/sections/website-section-definition.shared.schemas.ts +120 -0
- package/src/schemas/structured-data/structured-data-reconciliation.shared.ts +579 -0
- package/src/schemas/structured-data/website-structured-data.shared.schemas.ts +62 -0
- package/src/schemas/validators/label-pack.validator.ts +201 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { type BlogPostFrontmatter } from '../schemas/blog/blog-post-frontmatter.shared.schemas';
|
|
2
|
+
/**
|
|
3
|
+
* @wildo_source:part:start saas.website.blog.collection-config facet:layer:mdx facet:family:website
|
|
4
|
+
*
|
|
5
|
+
* Astro content-collection bridge for blog posts (Phase 7 D-3 = Path Z).
|
|
6
|
+
*
|
|
7
|
+
* # The Zod-version bridge problem
|
|
8
|
+
*
|
|
9
|
+
* Astro's `astro:content` ships its own bundled Zod (currently 3.x).
|
|
10
|
+
* Our `BlogPostFrontmatterSchema` is Zod 4 and uses Zod-4-only APIs
|
|
11
|
+
* (`z.iso.datetime`, `z.url(...)`, `.brand<>()`). The two cannot share
|
|
12
|
+
* a schema instance directly across the version boundary, and shimming
|
|
13
|
+
* a Zod 4 schema down to a Zod 3 schema would create either:
|
|
14
|
+
*
|
|
15
|
+
* - a hand-mirrored copy (Path X) — maintained in `src/content/config.ts`
|
|
16
|
+
* using Astro's `z`, with silent-drift risk every time a field is
|
|
17
|
+
* added/removed/refined; or
|
|
18
|
+
* - a runtime bridge package (Path C) — a non-trivial maintenance
|
|
19
|
+
* surface for a marginal gain.
|
|
20
|
+
*
|
|
21
|
+
* Path Z (this file) sidesteps the bridge entirely: the consumer's
|
|
22
|
+
* `src/content/config.ts` declares a `passthrough` collection schema
|
|
23
|
+
* that lets Astro accept any frontmatter shape; the engine then
|
|
24
|
+
* validates with the canonical Zod 4 schema at render time inside
|
|
25
|
+
* `<BlogPost>`. Astro's static site generator runs the page render
|
|
26
|
+
* during the build, so a malformed frontmatter still surfaces as a
|
|
27
|
+
* BUILD-TIME error (the `.parse()` call throws synchronously and Astro
|
|
28
|
+
* reports it with the page URL) — the only practical difference vs.
|
|
29
|
+
* Path X is the error-message stack location.
|
|
30
|
+
*
|
|
31
|
+
* # Why the engine ships an opaque shape (rather than the consumer
|
|
32
|
+
* importing the Astro `z` directly)
|
|
33
|
+
*
|
|
34
|
+
* Astro's content-collection API has churned across Astro 4 → 5
|
|
35
|
+
* (loaders moved from string-keyed `type` to a callable `loader`
|
|
36
|
+
* factory; the `glob()` loader's signature changed). Every consumer
|
|
37
|
+
* touching `defineCollection` directly inherits that churn; centralizing
|
|
38
|
+
* the wiring in the engine means the framework absorbs the upgrade
|
|
39
|
+
* cost in ONE place when Astro bumps a major.
|
|
40
|
+
*
|
|
41
|
+
* The shape returned here is `{ schema: <passthrough record> }`. The
|
|
42
|
+
* consumer spreads it into their `defineCollection` call:
|
|
43
|
+
*
|
|
44
|
+
* ```ts
|
|
45
|
+
* // examples/<app>/website/src/content/config.ts
|
|
46
|
+
* import { defineCollection, z } from 'astro:content';
|
|
47
|
+
* import { buildBlogPostCollectionConfig } from '@wildo-ai/saas-website/mdx';
|
|
48
|
+
*
|
|
49
|
+
* export const collections = {
|
|
50
|
+
* blog: defineCollection({
|
|
51
|
+
* type: 'content',
|
|
52
|
+
* ...buildBlogPostCollectionConfig({ astroZ: z }),
|
|
53
|
+
* }),
|
|
54
|
+
* };
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* The consumer passes Astro's own `z` in (because the engine cannot
|
|
58
|
+
* import `astro:content` — that virtual module only exists inside
|
|
59
|
+
* the Astro build context, never at the engine package's compile
|
|
60
|
+
* time, and importing it would also pull `astro` into the engine's
|
|
61
|
+
* walked closure which the bundle-isolation test forbids). The engine
|
|
62
|
+
* builds a passthrough `z.object({}).passthrough()` from the supplied
|
|
63
|
+
* factory and returns the schema slot.
|
|
64
|
+
*
|
|
65
|
+
* # `parseBlogPostFrontmatter`
|
|
66
|
+
*
|
|
67
|
+
* Companion render-time validator. Called at the top of `<BlogPost>`
|
|
68
|
+
* with the raw `entry.data` Astro hands the page; returns the
|
|
69
|
+
* branded, validated `BlogPostFrontmatter` (Zod 4) or throws with
|
|
70
|
+
* the standard Zod-4 issue formatting + a `[blog-post]` prefix that
|
|
71
|
+
* tells the SSG operator which file to fix.
|
|
72
|
+
*
|
|
73
|
+
* # Boundary
|
|
74
|
+
*
|
|
75
|
+
* This file is React-runtime-safe: it only imports the (also
|
|
76
|
+
* React-safe) `BlogPostFrontmatterSchema` from `schemas/blog/`. It
|
|
77
|
+
* ships into the React-island bundle via the `mdx.ts` barrel, which
|
|
78
|
+
* the bundle-isolation test walks as a dedicated entry. Helpers that
|
|
79
|
+
* parse raw MDX source live in `blog-post-frontmatter-source.ts` so the
|
|
80
|
+
* `yaml` package stays on the build-time/Node side of the boundary.
|
|
81
|
+
*/
|
|
82
|
+
/**
|
|
83
|
+
* Minimal contract for the Astro-side Zod factory we accept. Typed
|
|
84
|
+
* structurally (rather than imported from `astro:content`) so the
|
|
85
|
+
* engine package can compile/test without an Astro install. Astro's
|
|
86
|
+
* actual `z.object` returns a much richer Zod-3 schema; we narrow to
|
|
87
|
+
* just the `.passthrough()` call we make below.
|
|
88
|
+
*/
|
|
89
|
+
export interface AstroZodFactoryShape {
|
|
90
|
+
object: (shape: Record<string, never>) => {
|
|
91
|
+
passthrough: () => unknown;
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
export interface BuildBlogPostCollectionConfigOptions {
|
|
95
|
+
/**
|
|
96
|
+
* Astro's bundled `z` object — pass `import { z } from 'astro:content'`
|
|
97
|
+
* from the consumer-side `src/content/config.ts`. The engine cannot
|
|
98
|
+
* import `astro:content` itself (virtual module, only present inside
|
|
99
|
+
* the Astro build pipeline; would also bloat the bundle-isolation
|
|
100
|
+
* walked closure with the `astro` runtime).
|
|
101
|
+
*/
|
|
102
|
+
astroZ: AstroZodFactoryShape;
|
|
103
|
+
}
|
|
104
|
+
export interface BlogPostCollectionConfigShape {
|
|
105
|
+
/**
|
|
106
|
+
* The schema slot consumed by Astro's `defineCollection({...})`.
|
|
107
|
+
* A `passthrough` record (no field constraints at this layer) so
|
|
108
|
+
* Astro accepts any frontmatter; the strict Zod-4 validation runs
|
|
109
|
+
* at render time inside `<BlogPost>` via
|
|
110
|
+
* `parseBlogPostFrontmatter(...)`.
|
|
111
|
+
*/
|
|
112
|
+
schema: unknown;
|
|
113
|
+
}
|
|
114
|
+
export declare function buildBlogPostCollectionConfig(opts: BuildBlogPostCollectionConfigOptions): BlogPostCollectionConfigShape;
|
|
115
|
+
/**
|
|
116
|
+
* Strict Zod-4 validator for blog-post frontmatter. Called at the top
|
|
117
|
+
* of `<BlogPost>` rendering against `entry.data` (whatever Astro's
|
|
118
|
+
* passthrough collection schema accepted). Throws on validation
|
|
119
|
+
* failure with a `[blog-post]`-prefixed message that points to the
|
|
120
|
+
* offending file via the surrounding render call site.
|
|
121
|
+
*
|
|
122
|
+
* @param raw — the unvalidated frontmatter object Astro supplies
|
|
123
|
+
* (`entry.data` from `getEntry('blog', slug)` or `getCollection('blog')`).
|
|
124
|
+
* @param ctx — diagnostic context appended to the error message so
|
|
125
|
+
* the consumer can find the failing source file when SSG halts.
|
|
126
|
+
* Optional but recommended.
|
|
127
|
+
*/
|
|
128
|
+
export interface ParseBlogPostFrontmatterContext {
|
|
129
|
+
/**
|
|
130
|
+
* The MDX file's path or slug. Echoed into the error message when
|
|
131
|
+
* validation fails so the operator can grep for it. Astro typically
|
|
132
|
+
* gives consumers `entry.id` (the slug + extension) — passing it
|
|
133
|
+
* through here is enough for an actionable error.
|
|
134
|
+
*/
|
|
135
|
+
readonly source?: string;
|
|
136
|
+
}
|
|
137
|
+
export declare function parseBlogPostFrontmatter(raw: unknown, ctx?: ParseBlogPostFrontmatterContext): BlogPostFrontmatter;
|
|
138
|
+
/** @wildo_source:part:end saas.website.blog.collection-config */
|
|
139
|
+
//# sourceMappingURL=blog-post-collection.config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blog-post-collection.config.d.ts","sourceRoot":"","sources":["../../../../src/mdx/blog-post-collection.config.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,sDAAsD,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+EG;AAEH;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK;QACxC,WAAW,EAAE,MAAM,OAAO,CAAC;KAC5B,CAAC;CACH;AAED,MAAM,WAAW,oCAAoC;IACnD;;;;;;OAMG;IACH,MAAM,EAAE,oBAAoB,CAAC;CAC9B;AAED,MAAM,WAAW,6BAA6B;IAC5C;;;;;;OAMG;IACH,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,oCAAoC,GACzC,6BAA6B,CAK/B;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,+BAA+B;IAC9C;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,OAAO,EACZ,GAAG,GAAE,+BAAoC,GACxC,mBAAmB,CAkBrB;AACD,iEAAiE"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { formatZodIssues } from '@wildo-ai/saas-models/public-runtime';
|
|
2
|
+
import { BlogPostFrontmatterSchema, } from '../schemas/blog/blog-post-frontmatter.shared.schemas.js';
|
|
3
|
+
export function buildBlogPostCollectionConfig(opts) {
|
|
4
|
+
const { astroZ } = opts;
|
|
5
|
+
return {
|
|
6
|
+
schema: astroZ.object({}).passthrough(),
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export function parseBlogPostFrontmatter(raw, ctx = {}) {
|
|
10
|
+
const result = BlogPostFrontmatterSchema.safeParse(raw);
|
|
11
|
+
if (result.success) {
|
|
12
|
+
return result.data;
|
|
13
|
+
}
|
|
14
|
+
const sourceSuffix = ctx.source !== undefined ? ` (source="${ctx.source}")` : '';
|
|
15
|
+
/**
|
|
16
|
+
* Zod 4's `result.error.message` is the JSON-stringified `issues[]` array —
|
|
17
|
+
* long-form, it floods the Astro build log, and the path is what an operator
|
|
18
|
+
* needs to find the broken frontmatter field. `formatZodIssues` is the
|
|
19
|
+
* framework-canonical rendering (one `path: message` per entry); we only own
|
|
20
|
+
* the bullet prefix. Unbounded on purpose: every bad field in a post should
|
|
21
|
+
* be fixable from one build run.
|
|
22
|
+
*/
|
|
23
|
+
const issueLines = formatZodIssues(result.error.issues).map((entry) => ` - ${entry}`);
|
|
24
|
+
throw new Error(`[blog-post] Frontmatter failed BlogPostFrontmatterSchema validation${sourceSuffix}:\n${issueLines.join('\n')}`);
|
|
25
|
+
}
|
|
26
|
+
/** @wildo_source:part:end saas.website.blog.collection-config */
|
|
27
|
+
//# sourceMappingURL=blog-post-collection.config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blog-post-collection.config.js","sourceRoot":"","sources":["../../../../src/mdx/blog-post-collection.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EACL,yBAAyB,GAE1B,MAAM,sDAAsD,CAAC;AAsH9D,MAAM,UAAU,6BAA6B,CAC3C,IAA0C;IAE1C,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACxB,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE;KACxC,CAAC;AACJ,CAAC;AAyBD,MAAM,UAAU,wBAAwB,CACtC,GAAY,EACZ,MAAuC,EAAE;IAEzC,MAAM,MAAM,GAAG,yBAAyB,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IACxD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,MAAM,CAAC,IAAI,CAAC;IACrB,CAAC;IACD,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACjF;;;;;;;OAOG;IACH,MAAM,UAAU,GAAG,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,EAAE,CAAC,CAAC;IACvF,MAAM,IAAI,KAAK,CACb,sEAAsE,YAAY,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAChH,CAAC;AACJ,CAAC;AACD,iEAAiE","sourcesContent":["import { formatZodIssues } from '@wildo-ai/saas-models/public-runtime';\nimport {\n BlogPostFrontmatterSchema,\n type BlogPostFrontmatter,\n} from '../schemas/blog/blog-post-frontmatter.shared.schemas';\n\n/**\n * @wildo_source:part:start saas.website.blog.collection-config facet:layer:mdx facet:family:website\n *\n * Astro content-collection bridge for blog posts (Phase 7 D-3 = Path Z).\n *\n * # The Zod-version bridge problem\n *\n * Astro's `astro:content` ships its own bundled Zod (currently 3.x).\n * Our `BlogPostFrontmatterSchema` is Zod 4 and uses Zod-4-only APIs\n * (`z.iso.datetime`, `z.url(...)`, `.brand<>()`). The two cannot share\n * a schema instance directly across the version boundary, and shimming\n * a Zod 4 schema down to a Zod 3 schema would create either:\n *\n * - a hand-mirrored copy (Path X) — maintained in `src/content/config.ts`\n * using Astro's `z`, with silent-drift risk every time a field is\n * added/removed/refined; or\n * - a runtime bridge package (Path C) — a non-trivial maintenance\n * surface for a marginal gain.\n *\n * Path Z (this file) sidesteps the bridge entirely: the consumer's\n * `src/content/config.ts` declares a `passthrough` collection schema\n * that lets Astro accept any frontmatter shape; the engine then\n * validates with the canonical Zod 4 schema at render time inside\n * `<BlogPost>`. Astro's static site generator runs the page render\n * during the build, so a malformed frontmatter still surfaces as a\n * BUILD-TIME error (the `.parse()` call throws synchronously and Astro\n * reports it with the page URL) — the only practical difference vs.\n * Path X is the error-message stack location.\n *\n * # Why the engine ships an opaque shape (rather than the consumer\n * importing the Astro `z` directly)\n *\n * Astro's content-collection API has churned across Astro 4 → 5\n * (loaders moved from string-keyed `type` to a callable `loader`\n * factory; the `glob()` loader's signature changed). Every consumer\n * touching `defineCollection` directly inherits that churn; centralizing\n * the wiring in the engine means the framework absorbs the upgrade\n * cost in ONE place when Astro bumps a major.\n *\n * The shape returned here is `{ schema: <passthrough record> }`. The\n * consumer spreads it into their `defineCollection` call:\n *\n * ```ts\n * // examples/<app>/website/src/content/config.ts\n * import { defineCollection, z } from 'astro:content';\n * import { buildBlogPostCollectionConfig } from '@wildo-ai/saas-website/mdx';\n *\n * export const collections = {\n * blog: defineCollection({\n * type: 'content',\n * ...buildBlogPostCollectionConfig({ astroZ: z }),\n * }),\n * };\n * ```\n *\n * The consumer passes Astro's own `z` in (because the engine cannot\n * import `astro:content` — that virtual module only exists inside\n * the Astro build context, never at the engine package's compile\n * time, and importing it would also pull `astro` into the engine's\n * walked closure which the bundle-isolation test forbids). The engine\n * builds a passthrough `z.object({}).passthrough()` from the supplied\n * factory and returns the schema slot.\n *\n * # `parseBlogPostFrontmatter`\n *\n * Companion render-time validator. Called at the top of `<BlogPost>`\n * with the raw `entry.data` Astro hands the page; returns the\n * branded, validated `BlogPostFrontmatter` (Zod 4) or throws with\n * the standard Zod-4 issue formatting + a `[blog-post]` prefix that\n * tells the SSG operator which file to fix.\n *\n * # Boundary\n *\n * This file is React-runtime-safe: it only imports the (also\n * React-safe) `BlogPostFrontmatterSchema` from `schemas/blog/`. It\n * ships into the React-island bundle via the `mdx.ts` barrel, which\n * the bundle-isolation test walks as a dedicated entry. Helpers that\n * parse raw MDX source live in `blog-post-frontmatter-source.ts` so the\n * `yaml` package stays on the build-time/Node side of the boundary.\n */\n\n/**\n * Minimal contract for the Astro-side Zod factory we accept. Typed\n * structurally (rather than imported from `astro:content`) so the\n * engine package can compile/test without an Astro install. Astro's\n * actual `z.object` returns a much richer Zod-3 schema; we narrow to\n * just the `.passthrough()` call we make below.\n */\nexport interface AstroZodFactoryShape {\n object: (shape: Record<string, never>) => {\n passthrough: () => unknown;\n };\n}\n\nexport interface BuildBlogPostCollectionConfigOptions {\n /**\n * Astro's bundled `z` object — pass `import { z } from 'astro:content'`\n * from the consumer-side `src/content/config.ts`. The engine cannot\n * import `astro:content` itself (virtual module, only present inside\n * the Astro build pipeline; would also bloat the bundle-isolation\n * walked closure with the `astro` runtime).\n */\n astroZ: AstroZodFactoryShape;\n}\n\nexport interface BlogPostCollectionConfigShape {\n /**\n * The schema slot consumed by Astro's `defineCollection({...})`.\n * A `passthrough` record (no field constraints at this layer) so\n * Astro accepts any frontmatter; the strict Zod-4 validation runs\n * at render time inside `<BlogPost>` via\n * `parseBlogPostFrontmatter(...)`.\n */\n schema: unknown;\n}\n\nexport function buildBlogPostCollectionConfig(\n opts: BuildBlogPostCollectionConfigOptions,\n): BlogPostCollectionConfigShape {\n const { astroZ } = opts;\n return {\n schema: astroZ.object({}).passthrough(),\n };\n}\n\n/**\n * Strict Zod-4 validator for blog-post frontmatter. Called at the top\n * of `<BlogPost>` rendering against `entry.data` (whatever Astro's\n * passthrough collection schema accepted). Throws on validation\n * failure with a `[blog-post]`-prefixed message that points to the\n * offending file via the surrounding render call site.\n *\n * @param raw — the unvalidated frontmatter object Astro supplies\n * (`entry.data` from `getEntry('blog', slug)` or `getCollection('blog')`).\n * @param ctx — diagnostic context appended to the error message so\n * the consumer can find the failing source file when SSG halts.\n * Optional but recommended.\n */\nexport interface ParseBlogPostFrontmatterContext {\n /**\n * The MDX file's path or slug. Echoed into the error message when\n * validation fails so the operator can grep for it. Astro typically\n * gives consumers `entry.id` (the slug + extension) — passing it\n * through here is enough for an actionable error.\n */\n readonly source?: string;\n}\n\nexport function parseBlogPostFrontmatter(\n raw: unknown,\n ctx: ParseBlogPostFrontmatterContext = {},\n): BlogPostFrontmatter {\n const result = BlogPostFrontmatterSchema.safeParse(raw);\n if (result.success) {\n return result.data;\n }\n const sourceSuffix = ctx.source !== undefined ? ` (source=\"${ctx.source}\")` : '';\n /**\n * Zod 4's `result.error.message` is the JSON-stringified `issues[]` array —\n * long-form, it floods the Astro build log, and the path is what an operator\n * needs to find the broken frontmatter field. `formatZodIssues` is the\n * framework-canonical rendering (one `path: message` per entry); we only own\n * the bullet prefix. Unbounded on purpose: every bad field in a post should\n * be fixable from one build run.\n */\n const issueLines = formatZodIssues(result.error.issues).map((entry) => ` - ${entry}`);\n throw new Error(\n `[blog-post] Frontmatter failed BlogPostFrontmatterSchema validation${sourceSuffix}:\\n${issueLines.join('\\n')}`,\n );\n}\n/** @wildo_source:part:end saas.website.blog.collection-config */\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ParseBlogPostFrontmatterContext } from './blog-post-collection.config';
|
|
2
|
+
import type { BlogPostFrontmatter } from '../schemas/blog/blog-post-frontmatter.shared.schemas';
|
|
3
|
+
/**
|
|
4
|
+
* Build-time helper for code that reads raw MDX files from disk and
|
|
5
|
+
* needs the canonical Zod-4 blog frontmatter validation. This module is
|
|
6
|
+
* intentionally kept out of `@wildo-ai/saas-website/mdx`, because its
|
|
7
|
+
* `yaml` dependency belongs to the Node/build-time graph, not the
|
|
8
|
+
* React-island bundle walked by the D12 isolation test.
|
|
9
|
+
*/
|
|
10
|
+
export type ParseBlogPostFrontmatterFromMdxSourceContext = ParseBlogPostFrontmatterContext;
|
|
11
|
+
export declare function parseBlogPostFrontmatterFromMdxSource(source: string, ctx?: ParseBlogPostFrontmatterFromMdxSourceContext): BlogPostFrontmatter;
|
|
12
|
+
//# sourceMappingURL=blog-post-frontmatter-source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blog-post-frontmatter-source.d.ts","sourceRoot":"","sources":["../../../../src/mdx/blog-post-frontmatter-source.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,+BAA+B,EACrC,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sDAAsD,CAAC;AAEhG;;;;;;GAMG;AACH,MAAM,MAAM,4CAA4C,GAAG,+BAA+B,CAAC;AAE3F,wBAAgB,qCAAqC,CACnD,MAAM,EAAE,MAAM,EACd,GAAG,GAAE,4CAAiD,GACrD,mBAAmB,CAUrB"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { parse as parseYaml } from 'yaml';
|
|
2
|
+
import { parseBlogPostFrontmatter, } from './blog-post-collection.config.js';
|
|
3
|
+
export function parseBlogPostFrontmatterFromMdxSource(source, ctx = {}) {
|
|
4
|
+
const normalizedSource = source.replace(/\r\n/g, '\n');
|
|
5
|
+
const match = normalizedSource.match(/^---\n([\s\S]*?)\n---(?:\n|$)/);
|
|
6
|
+
if (!match) {
|
|
7
|
+
const sourceSuffix = ctx.source !== undefined ? ` (source="${ctx.source}")` : '';
|
|
8
|
+
throw new Error(`[blog-post] MDX file is missing YAML frontmatter${sourceSuffix}.`);
|
|
9
|
+
}
|
|
10
|
+
const rawFrontmatter = parseYaml(match[1]);
|
|
11
|
+
return parseBlogPostFrontmatter(rawFrontmatter, ctx);
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=blog-post-frontmatter-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blog-post-frontmatter-source.js","sourceRoot":"","sources":["../../../../src/mdx/blog-post-frontmatter-source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAE1C,OAAO,EACL,wBAAwB,GAEzB,MAAM,+BAA+B,CAAC;AAYvC,MAAM,UAAU,qCAAqC,CACnD,MAAc,EACd,MAAoD,EAAE;IAEtD,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACvD,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACtE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QACjF,MAAM,IAAI,KAAK,CAAC,mDAAmD,YAAY,GAAG,CAAC,CAAC;IACtF,CAAC;IAED,MAAM,cAAc,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,OAAO,wBAAwB,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;AACvD,CAAC","sourcesContent":["import { parse as parseYaml } from 'yaml';\n\nimport {\n parseBlogPostFrontmatter,\n type ParseBlogPostFrontmatterContext,\n} from './blog-post-collection.config';\nimport type { BlogPostFrontmatter } from '../schemas/blog/blog-post-frontmatter.shared.schemas';\n\n/**\n * Build-time helper for code that reads raw MDX files from disk and\n * needs the canonical Zod-4 blog frontmatter validation. This module is\n * intentionally kept out of `@wildo-ai/saas-website/mdx`, because its\n * `yaml` dependency belongs to the Node/build-time graph, not the\n * React-island bundle walked by the D12 isolation test.\n */\nexport type ParseBlogPostFrontmatterFromMdxSourceContext = ParseBlogPostFrontmatterContext;\n\nexport function parseBlogPostFrontmatterFromMdxSource(\n source: string,\n ctx: ParseBlogPostFrontmatterFromMdxSourceContext = {},\n): BlogPostFrontmatter {\n const normalizedSource = source.replace(/\\r\\n/g, '\\n');\n const match = normalizedSource.match(/^---\\n([\\s\\S]*?)\\n---(?:\\n|$)/);\n if (!match) {\n const sourceSuffix = ctx.source !== undefined ? ` (source=\"${ctx.source}\")` : '';\n throw new Error(`[blog-post] MDX file is missing YAML frontmatter${sourceSuffix}.`);\n }\n\n const rawFrontmatter = parseYaml(match[1]);\n return parseBlogPostFrontmatter(rawFrontmatter, ctx);\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sub-barrel for the marketing-blog MDX adapter (Phase 7). Re-exports
|
|
3
|
+
* the three engine surfaces consumers wire up:
|
|
4
|
+
*
|
|
5
|
+
* - `<BlogPost>` — the per-post page renderer that strict-validates
|
|
6
|
+
* frontmatter + composes `WebsitePageLayout` + `WebsiteMdxProvider`.
|
|
7
|
+
* - `<WebsiteMdxProvider>` — the `@mdx-js/react` boundary the
|
|
8
|
+
* framework owns so the upstream package is swap-safe.
|
|
9
|
+
* - `buildBlogPostCollectionConfig(...)` + `parseBlogPostFrontmatter(...)`
|
|
10
|
+
* — the Astro content-collection bridge (Path Z passthrough at the
|
|
11
|
+
* collection layer, strict Zod-4 validation at render time). Raw
|
|
12
|
+
* MDX-source parsing is exported separately from `./mdx-source` so
|
|
13
|
+
* `yaml` stays out of the React-island graph.
|
|
14
|
+
*
|
|
15
|
+
* Re-exported through the top-level `mdx.ts` barrel so the public
|
|
16
|
+
* import surface is `'@wildo-ai/saas-website/mdx'` (matching the
|
|
17
|
+
* `astro.ts` / `astro-island.ts` naming pattern).
|
|
18
|
+
*/
|
|
19
|
+
export { BlogPost, BLOG_POST_PAGE_REF, type BlogPostProps, type BlogPostMdxComponents, type BlogPostMdxComponent, } from './BlogPost';
|
|
20
|
+
export { buildBlogPostCollectionConfig, parseBlogPostFrontmatter, type AstroZodFactoryShape, type BuildBlogPostCollectionConfigOptions, type BlogPostCollectionConfigShape, type ParseBlogPostFrontmatterContext, } from './blog-post-collection.config';
|
|
21
|
+
export { WebsiteMdxProvider, type WebsiteMdxComponentsMap, type WebsiteMdxProviderProps, } from './website-mdx-provider';
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mdx/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACL,QAAQ,EACR,kBAAkB,EAClB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,GAC1B,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,6BAA6B,EAC7B,wBAAwB,EACxB,KAAK,oBAAoB,EACzB,KAAK,oCAAoC,EACzC,KAAK,6BAA6B,EAClC,KAAK,+BAA+B,GACrC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,kBAAkB,EAClB,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,GAC7B,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sub-barrel for the marketing-blog MDX adapter (Phase 7). Re-exports
|
|
3
|
+
* the three engine surfaces consumers wire up:
|
|
4
|
+
*
|
|
5
|
+
* - `<BlogPost>` — the per-post page renderer that strict-validates
|
|
6
|
+
* frontmatter + composes `WebsitePageLayout` + `WebsiteMdxProvider`.
|
|
7
|
+
* - `<WebsiteMdxProvider>` — the `@mdx-js/react` boundary the
|
|
8
|
+
* framework owns so the upstream package is swap-safe.
|
|
9
|
+
* - `buildBlogPostCollectionConfig(...)` + `parseBlogPostFrontmatter(...)`
|
|
10
|
+
* — the Astro content-collection bridge (Path Z passthrough at the
|
|
11
|
+
* collection layer, strict Zod-4 validation at render time). Raw
|
|
12
|
+
* MDX-source parsing is exported separately from `./mdx-source` so
|
|
13
|
+
* `yaml` stays out of the React-island graph.
|
|
14
|
+
*
|
|
15
|
+
* Re-exported through the top-level `mdx.ts` barrel so the public
|
|
16
|
+
* import surface is `'@wildo-ai/saas-website/mdx'` (matching the
|
|
17
|
+
* `astro.ts` / `astro-island.ts` naming pattern).
|
|
18
|
+
*/
|
|
19
|
+
export { BlogPost, BLOG_POST_PAGE_REF, } from './BlogPost.js';
|
|
20
|
+
export { buildBlogPostCollectionConfig, parseBlogPostFrontmatter, } from './blog-post-collection.config.js';
|
|
21
|
+
export { WebsiteMdxProvider, } from './website-mdx-provider.js';
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/mdx/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACL,QAAQ,EACR,kBAAkB,GAInB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,6BAA6B,EAC7B,wBAAwB,GAKzB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,kBAAkB,GAGnB,MAAM,wBAAwB,CAAC","sourcesContent":["/**\n * Sub-barrel for the marketing-blog MDX adapter (Phase 7). Re-exports\n * the three engine surfaces consumers wire up:\n *\n * - `<BlogPost>` — the per-post page renderer that strict-validates\n * frontmatter + composes `WebsitePageLayout` + `WebsiteMdxProvider`.\n * - `<WebsiteMdxProvider>` — the `@mdx-js/react` boundary the\n * framework owns so the upstream package is swap-safe.\n * - `buildBlogPostCollectionConfig(...)` + `parseBlogPostFrontmatter(...)`\n * — the Astro content-collection bridge (Path Z passthrough at the\n * collection layer, strict Zod-4 validation at render time). Raw\n * MDX-source parsing is exported separately from `./mdx-source` so\n * `yaml` stays out of the React-island graph.\n *\n * Re-exported through the top-level `mdx.ts` barrel so the public\n * import surface is `'@wildo-ai/saas-website/mdx'` (matching the\n * `astro.ts` / `astro-island.ts` naming pattern).\n */\n\nexport {\n BlogPost,\n BLOG_POST_PAGE_REF,\n type BlogPostProps,\n type BlogPostMdxComponents,\n type BlogPostMdxComponent,\n} from './BlogPost';\nexport {\n buildBlogPostCollectionConfig,\n parseBlogPostFrontmatter,\n type AstroZodFactoryShape,\n type BuildBlogPostCollectionConfigOptions,\n type BlogPostCollectionConfigShape,\n type ParseBlogPostFrontmatterContext,\n} from './blog-post-collection.config';\nexport {\n WebsiteMdxProvider,\n type WebsiteMdxComponentsMap,\n type WebsiteMdxProviderProps,\n} from './website-mdx-provider';\n"]}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { ComponentType, ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* @wildo_source:part:start saas.website.blog.mdx-provider facet:layer:mdx facet:family:website
|
|
4
|
+
*
|
|
5
|
+
* `WebsiteMdxProvider` — thin wrapper around `@mdx-js/react`'s
|
|
6
|
+
* `MDXProvider` that scopes a consumer-supplied `components` map for
|
|
7
|
+
* the entire MDX subtree it wraps.
|
|
8
|
+
*
|
|
9
|
+
* # Why a framework wrapper at all (vs. consumers using `MDXProvider` directly)
|
|
10
|
+
*
|
|
11
|
+
* Three application-facing reasons:
|
|
12
|
+
*
|
|
13
|
+
* 1. **Single API surface for embedded business sections.** The framework
|
|
14
|
+
* owns the provider boundary so consumers
|
|
15
|
+
* never directly import from `@mdx-js/react` — they ship a single
|
|
16
|
+
* `mdxComponents` object literal and the framework picks the
|
|
17
|
+
* provider implementation. If `@mdx-js/react` ever splits its
|
|
18
|
+
* package or changes its provider semantics (it has shipped
|
|
19
|
+
* breaking changes between major versions before), the swap
|
|
20
|
+
* lands in this file with zero consumer churn.
|
|
21
|
+
* 2. **Bundle-isolation discipline.** `@mdx-js/react` is browser-safe
|
|
22
|
+
* but heavy (`mdx/types.js`, `react-context` propagation). Walling
|
|
23
|
+
* it behind a single re-export keeps the import surface auditable
|
|
24
|
+
* through the package's client-bundle boundary: the `mdx` public entry is
|
|
25
|
+
* checked separately and lists `@mdx-js/react` exactly once.
|
|
26
|
+
* 3. **`disableParentContext: false` (default) is the right default.**
|
|
27
|
+
* MDX 3 lets a nested `MDXProvider` inherit components from the
|
|
28
|
+
* parent provider, which is what we want when the per-blog-post
|
|
29
|
+
* provider sits inside a site-wide MDX provider used by landing-page
|
|
30
|
+
* islands.
|
|
31
|
+
* Pinning the option here makes the framework's posture explicit;
|
|
32
|
+
* a future change documents itself as a breaking framework decision
|
|
33
|
+
* rather than a silent `@mdx-js/react` default flip.
|
|
34
|
+
*
|
|
35
|
+
* # The `components` map shape
|
|
36
|
+
*
|
|
37
|
+
* The map is `Record<string, ComponentType<any>>` — every key is the
|
|
38
|
+
* tag name an MDX file uses (`<CTASection ref="post-cta" />` resolves
|
|
39
|
+
* via the `CTASection` key). Values are React components the consumer
|
|
40
|
+
* authored under their own `src/sections/blog.sections.tsx` and
|
|
41
|
+
* wrapped in `<WebsiteSection sectionRef={…} category={…}>` so the
|
|
42
|
+
* label-key context is established before the section's
|
|
43
|
+
* `useWebsiteLabel(slot)` calls fire. The framework does NOT inspect
|
|
44
|
+
* the shape — discipline lives in the consumer's section registry
|
|
45
|
+
* + the label-pack validation boundary (which proves the locale pack covers
|
|
46
|
+
* each section's expected keys).
|
|
47
|
+
*
|
|
48
|
+
* # Why a `ComponentType<any>` value type and not a stricter generic
|
|
49
|
+
*
|
|
50
|
+
* MDX components receive their own props (children, plus whatever the
|
|
51
|
+
* MDX author writes inline as JSX attributes). The type system cannot
|
|
52
|
+
* narrow this through the provider boundary because the MDX compiler
|
|
53
|
+
* does the routing at compile time. `ComponentType<any>` is the
|
|
54
|
+
* convention `@mdx-js/react` itself uses (`MDXComponents` in
|
|
55
|
+
* `mdx/types.js`) — staying compatible with the upstream type avoids
|
|
56
|
+
* a wrap/unwrap dance at every consumer call site.
|
|
57
|
+
*
|
|
58
|
+
* # Bundle boundary
|
|
59
|
+
*
|
|
60
|
+
* Ships into the React-island bundle (consumed transitively from
|
|
61
|
+
* `BlogPost.tsx` which itself sits behind the consumer's per-page
|
|
62
|
+
* bridge file). MUST stay clear of `node:*` and SSR-tier specifiers
|
|
63
|
+
* — the bundle-isolation test walks `mdx.ts` as one of its entries.
|
|
64
|
+
*/
|
|
65
|
+
export interface WebsiteMdxComponentsMap {
|
|
66
|
+
/**
|
|
67
|
+
* Tag-name → component map. The MDX compiler resolves each
|
|
68
|
+
* `<TagName />` in a blog post's body against this object.
|
|
69
|
+
*/
|
|
70
|
+
readonly [tagName: string]: ComponentType<any>;
|
|
71
|
+
}
|
|
72
|
+
export interface WebsiteMdxProviderProps {
|
|
73
|
+
/**
|
|
74
|
+
* Consumer-supplied component overrides. Keys are MDX tag names;
|
|
75
|
+
* values are the React components those tags resolve to.
|
|
76
|
+
*/
|
|
77
|
+
components: WebsiteMdxComponentsMap;
|
|
78
|
+
/**
|
|
79
|
+
* MDX subtree (typically the compiled `<MdxBody/>` from a content
|
|
80
|
+
* collection entry). May render any number of provider-scoped
|
|
81
|
+
* components.
|
|
82
|
+
*/
|
|
83
|
+
children: ReactNode;
|
|
84
|
+
}
|
|
85
|
+
export declare function WebsiteMdxProvider(props: WebsiteMdxProviderProps): ReactNode;
|
|
86
|
+
export declare namespace WebsiteMdxProvider {
|
|
87
|
+
var displayName: string;
|
|
88
|
+
}
|
|
89
|
+
/** @wildo_source:part:end saas.website.blog.mdx-provider */
|
|
90
|
+
//# sourceMappingURL=website-mdx-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"website-mdx-provider.d.ts","sourceRoot":"","sources":["../../../../src/mdx/website-mdx-provider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAItD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,UAAU,EAAE,uBAAuB,CAAC;IACpC;;;;OAIG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,SAAS,CAG5E;yBAHe,kBAAkB;;;AAKlC,4DAA4D"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { MDXProvider } from '@mdx-js/react';
|
|
3
|
+
export function WebsiteMdxProvider(props) {
|
|
4
|
+
const { components, children } = props;
|
|
5
|
+
return _jsx(MDXProvider, { components: components, children: children });
|
|
6
|
+
}
|
|
7
|
+
WebsiteMdxProvider.displayName = 'WebsiteMdxProvider';
|
|
8
|
+
//# sourceMappingURL=website-mdx-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"website-mdx-provider.js","sourceRoot":"","sources":["../../../../src/mdx/website-mdx-provider.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAuF5C,MAAM,UAAU,kBAAkB,CAAC,KAA8B;IAC/D,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IACvC,OAAO,KAAC,WAAW,IAAC,UAAU,EAAE,UAAU,YAAG,QAAQ,GAAe,CAAC;AACvE,CAAC;AACD,kBAAkB,CAAC,WAAW,GAAG,oBAAoB,CAAC","sourcesContent":["import type { ComponentType, ReactNode } from 'react';\n\nimport { MDXProvider } from '@mdx-js/react';\n\n/**\n * @wildo_source:part:start saas.website.blog.mdx-provider facet:layer:mdx facet:family:website\n *\n * `WebsiteMdxProvider` — thin wrapper around `@mdx-js/react`'s\n * `MDXProvider` that scopes a consumer-supplied `components` map for\n * the entire MDX subtree it wraps.\n *\n * # Why a framework wrapper at all (vs. consumers using `MDXProvider` directly)\n *\n * Three application-facing reasons:\n *\n * 1. **Single API surface for embedded business sections.** The framework\n * owns the provider boundary so consumers\n * never directly import from `@mdx-js/react` — they ship a single\n * `mdxComponents` object literal and the framework picks the\n * provider implementation. If `@mdx-js/react` ever splits its\n * package or changes its provider semantics (it has shipped\n * breaking changes between major versions before), the swap\n * lands in this file with zero consumer churn.\n * 2. **Bundle-isolation discipline.** `@mdx-js/react` is browser-safe\n * but heavy (`mdx/types.js`, `react-context` propagation). Walling\n * it behind a single re-export keeps the import surface auditable\n * through the package's client-bundle boundary: the `mdx` public entry is\n * checked separately and lists `@mdx-js/react` exactly once.\n * 3. **`disableParentContext: false` (default) is the right default.**\n * MDX 3 lets a nested `MDXProvider` inherit components from the\n * parent provider, which is what we want when the per-blog-post\n * provider sits inside a site-wide MDX provider used by landing-page\n * islands.\n * Pinning the option here makes the framework's posture explicit;\n * a future change documents itself as a breaking framework decision\n * rather than a silent `@mdx-js/react` default flip.\n *\n * # The `components` map shape\n *\n * The map is `Record<string, ComponentType<any>>` — every key is the\n * tag name an MDX file uses (`<CTASection ref=\"post-cta\" />` resolves\n * via the `CTASection` key). Values are React components the consumer\n * authored under their own `src/sections/blog.sections.tsx` and\n * wrapped in `<WebsiteSection sectionRef={…} category={…}>` so the\n * label-key context is established before the section's\n * `useWebsiteLabel(slot)` calls fire. The framework does NOT inspect\n * the shape — discipline lives in the consumer's section registry\n * + the label-pack validation boundary (which proves the locale pack covers\n * each section's expected keys).\n *\n * # Why a `ComponentType<any>` value type and not a stricter generic\n *\n * MDX components receive their own props (children, plus whatever the\n * MDX author writes inline as JSX attributes). The type system cannot\n * narrow this through the provider boundary because the MDX compiler\n * does the routing at compile time. `ComponentType<any>` is the\n * convention `@mdx-js/react` itself uses (`MDXComponents` in\n * `mdx/types.js`) — staying compatible with the upstream type avoids\n * a wrap/unwrap dance at every consumer call site.\n *\n * # Bundle boundary\n *\n * Ships into the React-island bundle (consumed transitively from\n * `BlogPost.tsx` which itself sits behind the consumer's per-page\n * bridge file). MUST stay clear of `node:*` and SSR-tier specifiers\n * — the bundle-isolation test walks `mdx.ts` as one of its entries.\n */\nexport interface WebsiteMdxComponentsMap {\n /**\n * Tag-name → component map. The MDX compiler resolves each\n * `<TagName />` in a blog post's body against this object.\n */\n readonly [tagName: string]: ComponentType<any>;\n}\n\nexport interface WebsiteMdxProviderProps {\n /**\n * Consumer-supplied component overrides. Keys are MDX tag names;\n * values are the React components those tags resolve to.\n */\n components: WebsiteMdxComponentsMap;\n /**\n * MDX subtree (typically the compiled `<MdxBody/>` from a content\n * collection entry). May render any number of provider-scoped\n * components.\n */\n children: ReactNode;\n}\n\nexport function WebsiteMdxProvider(props: WebsiteMdxProviderProps): ReactNode {\n const { components, children } = props;\n return <MDXProvider components={components}>{children}</MDXProvider>;\n}\nWebsiteMdxProvider.displayName = 'WebsiteMdxProvider';\n/** @wildo_source:part:end saas.website.blog.mdx-provider */\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Top-level barrel for the marketing-blog MDX adapter (Phase 7).
|
|
3
|
+
*
|
|
4
|
+
* # Why a dedicated subpath instead of folding into the root barrel
|
|
5
|
+
*
|
|
6
|
+
* `@wildo-ai/saas-website/mdx` ships into the React-island bundle
|
|
7
|
+
* (consumed transitively from a consumer's per-post `.astro` page
|
|
8
|
+
* which imports `<BlogPost>` and renders it client-side). The
|
|
9
|
+
* `@mdx-js/react` runtime adds non-trivial weight to the closure;
|
|
10
|
+
* isolating the entry behind a dedicated subpath:
|
|
11
|
+
*
|
|
12
|
+
* - keeps `index.ts` (the Node + React companion-runtime entry) free
|
|
13
|
+
* of MDX runtime dependencies for sites that ship landing-page-only
|
|
14
|
+
* marketing surfaces;
|
|
15
|
+
* - lets the bundle-isolation test walk this entry independently
|
|
16
|
+
* (see `engine/saas-website/src/__tests__/bundle-isolation.test.ts`
|
|
17
|
+
* `ENTRY_FILES` list) so an accidental `node:fs` import inside
|
|
18
|
+
* `BlogPost.tsx` regresses against the React-bundle constraint
|
|
19
|
+
* without polluting the other entries' allow-lists.
|
|
20
|
+
*
|
|
21
|
+
* Pattern mirrors `astro.ts` / `astro-island.ts` / `config-loader.ts`:
|
|
22
|
+
* one purpose, one barrel, one bundle-isolation entry.
|
|
23
|
+
*/
|
|
24
|
+
export * from './mdx/index';
|
|
25
|
+
/**
|
|
26
|
+
* The blog adapter's per-locale bridge factory
|
|
27
|
+
* (`createWebsiteBlogPostBridgeIsland`). Lives in `astro/` beside
|
|
28
|
+
* `bridge-runtime.tsx` (same closure-over-deps pattern) but is exported
|
|
29
|
+
* from THIS entry — not `astro-island.ts` — because it hard-imports
|
|
30
|
+
* `./mdx/BlogPost`, whose `@mdx-js/react` peer is optional. Exporting it
|
|
31
|
+
* from the mandatory per-page bridge entry made the optional peer a
|
|
32
|
+
* de-facto install requirement for every non-blog site (Vite resolves the
|
|
33
|
+
* whole `export *` graph before tree-shaking). Here, only sites that opt
|
|
34
|
+
* into the blog adapter — and therefore install `@astrojs/mdx` +
|
|
35
|
+
* `@mdx-js/react` — ever resolve it.
|
|
36
|
+
*/
|
|
37
|
+
export * from './astro/blog-post-bridge';
|
|
38
|
+
//# sourceMappingURL=mdx.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mdx.d.ts","sourceRoot":"","sources":["../../../src/mdx.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,cAAc,aAAa,CAAC;AAC5B;;;;;;;;;;;GAWG;AACH,cAAc,0BAA0B,CAAC"}
|
package/dist/esm/mdx.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Top-level barrel for the marketing-blog MDX adapter (Phase 7).
|
|
3
|
+
*
|
|
4
|
+
* # Why a dedicated subpath instead of folding into the root barrel
|
|
5
|
+
*
|
|
6
|
+
* `@wildo-ai/saas-website/mdx` ships into the React-island bundle
|
|
7
|
+
* (consumed transitively from a consumer's per-post `.astro` page
|
|
8
|
+
* which imports `<BlogPost>` and renders it client-side). The
|
|
9
|
+
* `@mdx-js/react` runtime adds non-trivial weight to the closure;
|
|
10
|
+
* isolating the entry behind a dedicated subpath:
|
|
11
|
+
*
|
|
12
|
+
* - keeps `index.ts` (the Node + React companion-runtime entry) free
|
|
13
|
+
* of MDX runtime dependencies for sites that ship landing-page-only
|
|
14
|
+
* marketing surfaces;
|
|
15
|
+
* - lets the bundle-isolation test walk this entry independently
|
|
16
|
+
* (see `engine/saas-website/src/__tests__/bundle-isolation.test.ts`
|
|
17
|
+
* `ENTRY_FILES` list) so an accidental `node:fs` import inside
|
|
18
|
+
* `BlogPost.tsx` regresses against the React-bundle constraint
|
|
19
|
+
* without polluting the other entries' allow-lists.
|
|
20
|
+
*
|
|
21
|
+
* Pattern mirrors `astro.ts` / `astro-island.ts` / `config-loader.ts`:
|
|
22
|
+
* one purpose, one barrel, one bundle-isolation entry.
|
|
23
|
+
*/
|
|
24
|
+
export * from './mdx/index.js';
|
|
25
|
+
/**
|
|
26
|
+
* The blog adapter's per-locale bridge factory
|
|
27
|
+
* (`createWebsiteBlogPostBridgeIsland`). Lives in `astro/` beside
|
|
28
|
+
* `bridge-runtime.tsx` (same closure-over-deps pattern) but is exported
|
|
29
|
+
* from THIS entry — not `astro-island.ts` — because it hard-imports
|
|
30
|
+
* `./mdx/BlogPost`, whose `@mdx-js/react` peer is optional. Exporting it
|
|
31
|
+
* from the mandatory per-page bridge entry made the optional peer a
|
|
32
|
+
* de-facto install requirement for every non-blog site (Vite resolves the
|
|
33
|
+
* whole `export *` graph before tree-shaking). Here, only sites that opt
|
|
34
|
+
* into the blog adapter — and therefore install `@astrojs/mdx` +
|
|
35
|
+
* `@mdx-js/react` — ever resolve it.
|
|
36
|
+
*/
|
|
37
|
+
export * from './astro/blog-post-bridge.js';
|
|
38
|
+
//# sourceMappingURL=mdx.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mdx.js","sourceRoot":"","sources":["../../../src/mdx.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,cAAc,aAAa,CAAC;AAC5B;;;;;;;;;;;GAWG;AACH,cAAc,0BAA0B,CAAC","sourcesContent":["/**\n * Top-level barrel for the marketing-blog MDX adapter (Phase 7).\n *\n * # Why a dedicated subpath instead of folding into the root barrel\n *\n * `@wildo-ai/saas-website/mdx` ships into the React-island bundle\n * (consumed transitively from a consumer's per-post `.astro` page\n * which imports `<BlogPost>` and renders it client-side). The\n * `@mdx-js/react` runtime adds non-trivial weight to the closure;\n * isolating the entry behind a dedicated subpath:\n *\n * - keeps `index.ts` (the Node + React companion-runtime entry) free\n * of MDX runtime dependencies for sites that ship landing-page-only\n * marketing surfaces;\n * - lets the bundle-isolation test walk this entry independently\n * (see `engine/saas-website/src/__tests__/bundle-isolation.test.ts`\n * `ENTRY_FILES` list) so an accidental `node:fs` import inside\n * `BlogPost.tsx` regresses against the React-bundle constraint\n * without polluting the other entries' allow-lists.\n *\n * Pattern mirrors `astro.ts` / `astro-island.ts` / `config-loader.ts`:\n * one purpose, one barrel, one bundle-isolation entry.\n */\n\nexport * from './mdx/index';\n/**\n * The blog adapter's per-locale bridge factory\n * (`createWebsiteBlogPostBridgeIsland`). Lives in `astro/` beside\n * `bridge-runtime.tsx` (same closure-over-deps pattern) but is exported\n * from THIS entry — not `astro-island.ts` — because it hard-imports\n * `./mdx/BlogPost`, whose `@mdx-js/react` peer is optional. Exporting it\n * from the mandatory per-page bridge entry made the optional peer a\n * de-facto install requirement for every non-blog site (Vite resolves the\n * whole `export *` graph before tree-shaking). Here, only sites that opt\n * into the blog adapter — and therefore install `@astrojs/mdx` +\n * `@mdx-js/react` — ever resolve it.\n */\nexport * from './astro/blog-post-bridge';\n"]}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { AvailableLanguage } from '@wildo-ai/saas-models/public-runtime';
|
|
3
|
+
/**
|
|
4
|
+
* @wildo_source:part:start saas.website.blog.frontmatter facet:layer:shared facet:family:website
|
|
5
|
+
*
|
|
6
|
+
* `BlogPostFrontmatter` — the YAML frontmatter contract every blog
|
|
7
|
+
* post MDX file under `examples/<app>/website/src/content/blog/<locale>/`
|
|
8
|
+
* MUST satisfy.
|
|
9
|
+
*
|
|
10
|
+
* **Q16=B context**: blogs are authored as full per-locale MDX files
|
|
11
|
+
* (one MDX per (slug, locale) pair), NOT as label-pack-keyed content.
|
|
12
|
+
* The frontmatter therefore carries strings directly (`title`,
|
|
13
|
+
* `summary`) rather than label keys — there is no shared
|
|
14
|
+
* label-pack-driven authoring surface for blog content. This is
|
|
15
|
+
* intentional: blog copy is long-form and locale-divergent; forcing
|
|
16
|
+
* it through a structural label-pack would either inflate the pack
|
|
17
|
+
* or fragment the prose.
|
|
18
|
+
*
|
|
19
|
+
* **Field rationale**:
|
|
20
|
+
*
|
|
21
|
+
* - `title` — REQUIRED. Renders into `<title>`, `og:title`, and the
|
|
22
|
+
* in-page H1. Authored as a direct string, deliberately.
|
|
23
|
+
* - `summary` — REQUIRED. Renders into `<meta name="description">`,
|
|
24
|
+
* `og:description`, and listing-card descriptions. Direct string.
|
|
25
|
+
* - `slug` — REQUIRED. URL slug (lowercase kebab-case). Brand prevents
|
|
26
|
+
* accidental swap with `WebsitePageRef` (same shape, different role).
|
|
27
|
+
* - `locale` — REQUIRED. The post's locale. Drives the URL prefix
|
|
28
|
+
* (`/<locale>/blog/<slug>`) and `<html lang>`. Cross-locale
|
|
29
|
+
* correspondence is established by sharing the `slug` across
|
|
30
|
+
* per-locale MDX files (e.g. `en/why-context.md` and
|
|
31
|
+
* `fr/why-context.md` are the same post in two locales).
|
|
32
|
+
* - `publishedAt` — REQUIRED. ISO-8601 date-time string. Renders into
|
|
33
|
+
* `og:article:published_time` and the listing-card date label.
|
|
34
|
+
* Stored as string (not `z.coerce.date`) because YAML frontmatter
|
|
35
|
+
* parsers preserve the original string and the SEO emitters need
|
|
36
|
+
* the original ISO formatting (no Date.toISOString() round-trip
|
|
37
|
+
* loss).
|
|
38
|
+
* - `authorRef` — REQUIRED. Identifier of the author resolved by the
|
|
39
|
+
* consumer's author registry (typically a `src/content/authors/<ref>.ts`
|
|
40
|
+
* file). Brand keeps it distinct from page/section refs.
|
|
41
|
+
* - `tags` — REQUIRED, possibly empty. Lowercase kebab-case tag
|
|
42
|
+
* identifiers. Drives `og:article:tag` and the listing-page facets.
|
|
43
|
+
* - `coverImageUrl` — OPTIONAL. CDN URL for the blog post hero image
|
|
44
|
+
* and `og:image`.
|
|
45
|
+
*
|
|
46
|
+
* **Why a separate file from the page-manifest**: a blog post is NOT
|
|
47
|
+
* a `WebsitePageManifest` (no React `pageComponent` to mount — the
|
|
48
|
+
* MDX file IS the content). The Astro adapter emits one MDX route
|
|
49
|
+
* per post via `content collections`, with `BlogPostFrontmatter`
|
|
50
|
+
* driving the route generation and the SEO emission.
|
|
51
|
+
*/
|
|
52
|
+
declare const _BlogPostSlugSchema: z.core.$ZodBranded<z.ZodString, "BlogPostSlug", "out">;
|
|
53
|
+
export declare const BlogPostSlugSchema: typeof _BlogPostSlugSchema;
|
|
54
|
+
export type BlogPostSlug = z.infer<typeof _BlogPostSlugSchema>;
|
|
55
|
+
declare const _BlogAuthorRefSchema: z.core.$ZodBranded<z.ZodString, "BlogAuthorRef", "out">;
|
|
56
|
+
export declare const BlogAuthorRefSchema: typeof _BlogAuthorRefSchema;
|
|
57
|
+
export type BlogAuthorRef = z.infer<typeof _BlogAuthorRefSchema>;
|
|
58
|
+
declare const _BlogPostTagSchema: z.core.$ZodBranded<z.ZodString, "BlogPostTag", "out">;
|
|
59
|
+
export declare const BlogPostTagSchema: typeof _BlogPostTagSchema;
|
|
60
|
+
export type BlogPostTag = z.infer<typeof _BlogPostTagSchema>;
|
|
61
|
+
declare const _BlogPostFrontmatterSchema: z.ZodObject<{
|
|
62
|
+
title: z.ZodString;
|
|
63
|
+
summary: z.ZodString;
|
|
64
|
+
slug: z.core.$ZodBranded<z.ZodString, "BlogPostSlug", "out">;
|
|
65
|
+
locale: z.ZodEnum<typeof AvailableLanguage>;
|
|
66
|
+
publishedAt: z.ZodISODateTime;
|
|
67
|
+
authorRef: z.core.$ZodBranded<z.ZodString, "BlogAuthorRef", "out">;
|
|
68
|
+
tags: z.ZodArray<z.core.$ZodBranded<z.ZodString, "BlogPostTag", "out">>;
|
|
69
|
+
coverImageUrl: z.ZodOptional<z.ZodURL>;
|
|
70
|
+
}, z.core.$strip>;
|
|
71
|
+
export declare const BlogPostFrontmatterSchema: typeof _BlogPostFrontmatterSchema;
|
|
72
|
+
export type BlogPostFrontmatter = z.infer<typeof _BlogPostFrontmatterSchema>;
|
|
73
|
+
export {};
|
|
74
|
+
/** @wildo_source:part:end saas.website.blog.frontmatter */
|
|
75
|
+
//# sourceMappingURL=blog-post-frontmatter.shared.schemas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blog-post-frontmatter.shared.schemas.d.ts","sourceRoot":"","sources":["../../../../../src/schemas/blog/blog-post-frontmatter.shared.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,QAAA,MAAM,mBAAmB,wDAQC,CAAC;AAE3B,eAAO,MAAM,kBAAkB,EAAE,OAAO,mBAAyC,CAAC;AAElF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAE/D,QAAA,MAAM,oBAAoB,yDAQC,CAAC;AAE5B,eAAO,MAAM,mBAAmB,EAAE,OAAO,oBAA2C,CAAC;AAErF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAEjE,QAAA,MAAM,kBAAkB,uDAQC,CAAC;AAE1B,eAAO,MAAM,iBAAiB,EAAE,OAAO,kBAAuC,CAAC;AAE/E,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE7D,QAAA,MAAM,0BAA0B;;;;;;;;;iBAS9B,CAAC;AAEH,eAAO,MAAM,yBAAyB,EAAE,OAAO,0BACnB,CAAC;AAE7B,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;;AAC7E,2DAA2D"}
|