@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,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Author helper for `wildo.website.config.ts` files.
|
|
3
|
+
*
|
|
4
|
+
* `defineWebsiteConfig({...})` mirrors the `defineSaasConfig` /
|
|
5
|
+
* `defineInfraEnvConfig` helpers from `@wildo-ai/platform-config-lib`
|
|
6
|
+
* and `defineTechnicalDocConfig` from `@wildo-ai/saas-technical-doc`:
|
|
7
|
+
* it wraps `WildoMarketingWebsiteConfigSchema.parse(...)` with full
|
|
8
|
+
* IDE autocompletion on the input shape, and emits a parse-time
|
|
9
|
+
* stderr warning for any authored field that has no runtime
|
|
10
|
+
* consumer yet.
|
|
11
|
+
*
|
|
12
|
+
* # `@unimplemented` channel — current state
|
|
13
|
+
*
|
|
14
|
+
* The warner has ZERO branches today because every OPTIONAL field that
|
|
15
|
+
* exists is already wired (`csp?` now flows through the website-local
|
|
16
|
+
* CSP sync step) and the only unwired field left is `appOrigin`, which
|
|
17
|
+
* is REQUIRED. After the seam-collapse (`saas-website-seam-collapse.md`
|
|
18
|
+
* — SHIPPED), the routing/origin fields (`publicOrigin`,
|
|
19
|
+
* `defaultLocale`, `locales`) are consumed directly by every Astro
|
|
20
|
+
* engine helper via `WebsiteSiteContext`, so they are no longer
|
|
21
|
+
* candidates for a "deferred wiring" warning either. The
|
|
22
|
+
* `@unimplemented` warner is for fields that are parsed-but-unused AND
|
|
23
|
+
* opt-in — firing on every Astro build for a required field would drown
|
|
24
|
+
* the dev console.
|
|
25
|
+
*
|
|
26
|
+
* Two valid futures will trigger adding warner branches:
|
|
27
|
+
* 1. A future optional field lands (e.g. `seo?.{title,description}`,
|
|
28
|
+
* `structuredData?.organization`) whose runtime wiring ships
|
|
29
|
+
* in a later PR — that would get
|
|
30
|
+
* `if (config.seo !== undefined) warn('seo', ...)` until the
|
|
31
|
+
* renderer reads it.
|
|
32
|
+
* 2. A required field temporarily loses its consumer (e.g. a
|
|
33
|
+
* large refactor splits the SEO renderer into two PRs); the
|
|
34
|
+
* branch fires unconditionally for the duration.
|
|
35
|
+
*
|
|
36
|
+
* The scaffold is kept (and the no-warning contract is pinned by
|
|
37
|
+
* the test suite) so the moment either case lands, the warning
|
|
38
|
+
* channel is one branch addition away — matching the
|
|
39
|
+
* `defineTechnicalDocConfig` shape exactly so future authors
|
|
40
|
+
* grepping for `@unimplemented` find a uniform pattern.
|
|
41
|
+
*
|
|
42
|
+
* Why we don't reuse `platform-config-lib`'s
|
|
43
|
+
* `createUnimplementedFieldWarner`:
|
|
44
|
+
*
|
|
45
|
+
* `platform-config-lib` is the platform-level boundary; this engine
|
|
46
|
+
* package is downstream of it for everything else. Importing the
|
|
47
|
+
* warner from `platform-config-lib` would invert the dependency
|
|
48
|
+
* direction (engine → platform-config), creating the same architectural
|
|
49
|
+
* defect Step 7.5 set out to fix. The warning format is small and
|
|
50
|
+
* stable enough to inline here — kept structurally similar to the
|
|
51
|
+
* platform-config-lib warner so readers grepping for `@unimplemented`
|
|
52
|
+
* still find both surfaces.
|
|
53
|
+
*/
|
|
54
|
+
import { WildoMarketingWebsiteConfigSchema, } from './wildo-website-config.schemas.js';
|
|
55
|
+
/**
|
|
56
|
+
* Define a per-service marketing-website config. Provides full IDE
|
|
57
|
+
* autocompletion on the input shape, runs Zod validation (fail-closed
|
|
58
|
+
* on typos / unknown keys / out-of-range values / cross-field
|
|
59
|
+
* invariants like `defaultLocale ∈ locales`), and emits parse-time
|
|
60
|
+
* `@unimplemented` warnings for fields that are authored but have no
|
|
61
|
+
* runtime consumer yet.
|
|
62
|
+
*
|
|
63
|
+
* Throws on validation failure — same contract as `defineSaasConfig`
|
|
64
|
+
* and `defineTechnicalDocConfig`.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* import { AvailableLanguage } from '@wildo-ai/saas-models/public-runtime';
|
|
69
|
+
* import { defineWebsiteConfig } from '@wildo-ai/saas-website';
|
|
70
|
+
*
|
|
71
|
+
* export default defineWebsiteConfig({
|
|
72
|
+
* publicOrigin: 'https://wonder-todos.example.com',
|
|
73
|
+
* appOrigin: 'https://app.wonder-todos.example.com',
|
|
74
|
+
* defaultLocale: AvailableLanguage.EN,
|
|
75
|
+
* locales: [
|
|
76
|
+
* { locale: AvailableLanguage.EN, path: 'en' },
|
|
77
|
+
* { locale: AvailableLanguage.FR, path: 'fr' },
|
|
78
|
+
* ],
|
|
79
|
+
* });
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export function defineWebsiteConfig(config) {
|
|
83
|
+
const parsed = WildoMarketingWebsiteConfigSchema.parse(config);
|
|
84
|
+
emitUnimplementedRuntimeWarnings(parsed);
|
|
85
|
+
return parsed;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Emit `@unimplemented` parse-time warnings for every authored
|
|
89
|
+
* OPTIONAL field on `WildoMarketingWebsiteConfig` that is parsed
|
|
90
|
+
* but has no runtime consumer yet.
|
|
91
|
+
*
|
|
92
|
+
* Branches today: ZERO. The one OPTIONAL field that exists (`csp?`) is
|
|
93
|
+
* fully wired through the website-local CSP sync/build path, while the
|
|
94
|
+
* only field that still lacks a runtime consumer (`appOrigin`) is
|
|
95
|
+
* REQUIRED. After the seam-collapse (`saas-website-seam-collapse.md` —
|
|
96
|
+
* SHIPPED) the routing/origin fields are consumed directly by every
|
|
97
|
+
* Astro engine helper via `WebsiteSiteContext`. Required-but-unwired
|
|
98
|
+
* fields cannot reasonably fire on every parse — that's a
|
|
99
|
+
* deferred-wiring surface tracked in the schema header, not an
|
|
100
|
+
* `@unimplemented` warner concern.
|
|
101
|
+
*
|
|
102
|
+
* The function exists as a structural mirror of
|
|
103
|
+
* `defineTechnicalDocConfig.emitUnimplementedRuntimeWarnings` so
|
|
104
|
+
* readers grepping for `emitUnimplementedRuntimeWarnings` find a
|
|
105
|
+
* uniform pattern across every `defineXxxConfig` helper.
|
|
106
|
+
*
|
|
107
|
+
* # Adding a branch (recipe)
|
|
108
|
+
*
|
|
109
|
+
* When the first OPTIONAL `@unimplemented` field lands (most
|
|
110
|
+
* likely candidate: `seo?.{title,description}`), add the warner
|
|
111
|
+
* machinery here: a `seen` set + a
|
|
112
|
+
* `warn(fieldPath, sliceId)` helper that formats as
|
|
113
|
+
* `[wildo-website-config] @unimplemented field '...'` and writes
|
|
114
|
+
* to `process.stderr`, then the matching `if (config.<field> !==
|
|
115
|
+
* undefined)` branch. Copy the exact shape from
|
|
116
|
+
* `define-tech-doc-config.ts > emitUnimplementedRuntimeWarnings`
|
|
117
|
+
* to keep the message format identical across helpers. The test
|
|
118
|
+
* suite pins the zero-warnings contract — flip its expectation in
|
|
119
|
+
* the same commit.
|
|
120
|
+
*/
|
|
121
|
+
function emitUnimplementedRuntimeWarnings(_config) {
|
|
122
|
+
// Intentional no-op — see function JSDoc for why a no-op is the
|
|
123
|
+
// correct shape today (optional fields are either fully wired or
|
|
124
|
+
// absent) and the recipe for adding the first branch.
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=define-website-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-website-config.js","sourceRoot":"","sources":["../../../../src/config/define-website-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,OAAO,EACL,iCAAiC,GAGlC,MAAM,gCAAgC,CAAC;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAAwC;IAExC,MAAM,MAAM,GAAG,iCAAiC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/D,gCAAgC,CAAC,MAAM,CAAC,CAAC;IACzC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,SAAS,gCAAgC,CAAC,OAAoC;IAC5E,gEAAgE;IAChE,iEAAiE;IACjE,sDAAsD;AACxD,CAAC","sourcesContent":["/**\n * @fileoverview Author helper for `wildo.website.config.ts` files.\n *\n * `defineWebsiteConfig({...})` mirrors the `defineSaasConfig` /\n * `defineInfraEnvConfig` helpers from `@wildo-ai/platform-config-lib`\n * and `defineTechnicalDocConfig` from `@wildo-ai/saas-technical-doc`:\n * it wraps `WildoMarketingWebsiteConfigSchema.parse(...)` with full\n * IDE autocompletion on the input shape, and emits a parse-time\n * stderr warning for any authored field that has no runtime\n * consumer yet.\n *\n * # `@unimplemented` channel — current state\n *\n * The warner has ZERO branches today because every OPTIONAL field that\n * exists is already wired (`csp?` now flows through the website-local\n * CSP sync step) and the only unwired field left is `appOrigin`, which\n * is REQUIRED. After the seam-collapse (`saas-website-seam-collapse.md`\n * — SHIPPED), the routing/origin fields (`publicOrigin`,\n * `defaultLocale`, `locales`) are consumed directly by every Astro\n * engine helper via `WebsiteSiteContext`, so they are no longer\n * candidates for a \"deferred wiring\" warning either. The\n * `@unimplemented` warner is for fields that are parsed-but-unused AND\n * opt-in — firing on every Astro build for a required field would drown\n * the dev console.\n *\n * Two valid futures will trigger adding warner branches:\n * 1. A future optional field lands (e.g. `seo?.{title,description}`,\n * `structuredData?.organization`) whose runtime wiring ships\n * in a later PR — that would get\n * `if (config.seo !== undefined) warn('seo', ...)` until the\n * renderer reads it.\n * 2. A required field temporarily loses its consumer (e.g. a\n * large refactor splits the SEO renderer into two PRs); the\n * branch fires unconditionally for the duration.\n *\n * The scaffold is kept (and the no-warning contract is pinned by\n * the test suite) so the moment either case lands, the warning\n * channel is one branch addition away — matching the\n * `defineTechnicalDocConfig` shape exactly so future authors\n * grepping for `@unimplemented` find a uniform pattern.\n *\n * Why we don't reuse `platform-config-lib`'s\n * `createUnimplementedFieldWarner`:\n *\n * `platform-config-lib` is the platform-level boundary; this engine\n * package is downstream of it for everything else. Importing the\n * warner from `platform-config-lib` would invert the dependency\n * direction (engine → platform-config), creating the same architectural\n * defect Step 7.5 set out to fix. The warning format is small and\n * stable enough to inline here — kept structurally similar to the\n * platform-config-lib warner so readers grepping for `@unimplemented`\n * still find both surfaces.\n */\n\nimport {\n WildoMarketingWebsiteConfigSchema,\n type WildoMarketingWebsiteConfig,\n type WildoMarketingWebsiteConfigInput,\n} from './wildo-website-config.schemas';\n\n/**\n * Define a per-service marketing-website config. Provides full IDE\n * autocompletion on the input shape, runs Zod validation (fail-closed\n * on typos / unknown keys / out-of-range values / cross-field\n * invariants like `defaultLocale ∈ locales`), and emits parse-time\n * `@unimplemented` warnings for fields that are authored but have no\n * runtime consumer yet.\n *\n * Throws on validation failure — same contract as `defineSaasConfig`\n * and `defineTechnicalDocConfig`.\n *\n * @example\n * ```ts\n * import { AvailableLanguage } from '@wildo-ai/saas-models/public-runtime';\n * import { defineWebsiteConfig } from '@wildo-ai/saas-website';\n *\n * export default defineWebsiteConfig({\n * publicOrigin: 'https://wonder-todos.example.com',\n * appOrigin: 'https://app.wonder-todos.example.com',\n * defaultLocale: AvailableLanguage.EN,\n * locales: [\n * { locale: AvailableLanguage.EN, path: 'en' },\n * { locale: AvailableLanguage.FR, path: 'fr' },\n * ],\n * });\n * ```\n */\nexport function defineWebsiteConfig(\n config: WildoMarketingWebsiteConfigInput,\n): WildoMarketingWebsiteConfig {\n const parsed = WildoMarketingWebsiteConfigSchema.parse(config);\n emitUnimplementedRuntimeWarnings(parsed);\n return parsed;\n}\n\n/**\n * Emit `@unimplemented` parse-time warnings for every authored\n * OPTIONAL field on `WildoMarketingWebsiteConfig` that is parsed\n * but has no runtime consumer yet.\n *\n * Branches today: ZERO. The one OPTIONAL field that exists (`csp?`) is\n * fully wired through the website-local CSP sync/build path, while the\n * only field that still lacks a runtime consumer (`appOrigin`) is\n * REQUIRED. After the seam-collapse (`saas-website-seam-collapse.md` —\n * SHIPPED) the routing/origin fields are consumed directly by every\n * Astro engine helper via `WebsiteSiteContext`. Required-but-unwired\n * fields cannot reasonably fire on every parse — that's a\n * deferred-wiring surface tracked in the schema header, not an\n * `@unimplemented` warner concern.\n *\n * The function exists as a structural mirror of\n * `defineTechnicalDocConfig.emitUnimplementedRuntimeWarnings` so\n * readers grepping for `emitUnimplementedRuntimeWarnings` find a\n * uniform pattern across every `defineXxxConfig` helper.\n *\n * # Adding a branch (recipe)\n *\n * When the first OPTIONAL `@unimplemented` field lands (most\n * likely candidate: `seo?.{title,description}`), add the warner\n * machinery here: a `seen` set + a\n * `warn(fieldPath, sliceId)` helper that formats as\n * `[wildo-website-config] @unimplemented field '...'` and writes\n * to `process.stderr`, then the matching `if (config.<field> !==\n * undefined)` branch. Copy the exact shape from\n * `define-tech-doc-config.ts > emitUnimplementedRuntimeWarnings`\n * to keep the message format identical across helpers. The test\n * suite pins the zero-warnings contract — flip its expectation in\n * the same commit.\n */\nfunction emitUnimplementedRuntimeWarnings(_config: WildoMarketingWebsiteConfig): void {\n // Intentional no-op — see function JSDoc for why a no-op is the\n // correct shape today (optional fields are either fully wired or\n // absent) and the recipe for adding the first branch.\n}\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@wildo-ai/saas-website` — config surface.
|
|
3
|
+
*
|
|
4
|
+
* Per-service `wildo.website.config.ts` schema + `defineWebsiteConfig`
|
|
5
|
+
* helper. Co-located with the engine package that owns the marketing-
|
|
6
|
+
* site primitives so a new SEO field / locale-pack id ships in a
|
|
7
|
+
* single PR with no cross-package allow-list to keep in sync (see
|
|
8
|
+
* `wildo-website-config.schemas.ts` JSDoc for the architectural
|
|
9
|
+
* rationale behind moving this out of `platform-config-lib` —
|
|
10
|
+
* `saas-website-slice.md` Step 7.5 mirrors the
|
|
11
|
+
* `saas-technical-doc.md` Step 7.5 fix).
|
|
12
|
+
*
|
|
13
|
+
* @wildo-boundary
|
|
14
|
+
* This sub-tree is split intentionally:
|
|
15
|
+
*
|
|
16
|
+
* - `wildo-website-config.schemas.ts` — Zod-only, no Node-only
|
|
17
|
+
* imports, no `process.*` references. Safe to bundle anywhere.
|
|
18
|
+
* - `define-website-config.ts` — uses `process.stderr.write` for
|
|
19
|
+
* the (currently empty) `@unimplemented` warner. Bundle-safe in
|
|
20
|
+
* practice (the global `process` is polyfilled by every modern
|
|
21
|
+
* bundler and the warner has no `node:*` bare specifier), so it
|
|
22
|
+
* can ship through the root barrel alongside the schema.
|
|
23
|
+
* - `load-website-config.ts` — Node-only. Imports `loadConfig` +
|
|
24
|
+
* `AppFrontendType` from `@wildo-ai/platform-config-lib` and
|
|
25
|
+
* `node:fs` / `node:path`. Re-exported via the dedicated
|
|
26
|
+
* package subpath `./config-loader` (NOT from this barrel) so
|
|
27
|
+
* the React-island closure stays free of Node-only specifiers
|
|
28
|
+
* (enforced by `__tests__/bundle-isolation.test.ts`).
|
|
29
|
+
*
|
|
30
|
+
* Consumers:
|
|
31
|
+
* - Author per-service config: `import { defineWebsiteConfig }`
|
|
32
|
+
* from `'@wildo-ai/saas-website'`.
|
|
33
|
+
* - Load per-service config from a Node-side build / dev pipeline:
|
|
34
|
+
* `import { loadWebsiteConfig }` from `'@wildo-ai/saas-website/config-loader'`.
|
|
35
|
+
*/
|
|
36
|
+
export * from './define-website-config';
|
|
37
|
+
export * from './wildo-website-config.schemas';
|
|
38
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,cAAc,yBAAyB,CAAC;AACxC,cAAc,gCAAgC,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@wildo-ai/saas-website` — config surface.
|
|
3
|
+
*
|
|
4
|
+
* Per-service `wildo.website.config.ts` schema + `defineWebsiteConfig`
|
|
5
|
+
* helper. Co-located with the engine package that owns the marketing-
|
|
6
|
+
* site primitives so a new SEO field / locale-pack id ships in a
|
|
7
|
+
* single PR with no cross-package allow-list to keep in sync (see
|
|
8
|
+
* `wildo-website-config.schemas.ts` JSDoc for the architectural
|
|
9
|
+
* rationale behind moving this out of `platform-config-lib` —
|
|
10
|
+
* `saas-website-slice.md` Step 7.5 mirrors the
|
|
11
|
+
* `saas-technical-doc.md` Step 7.5 fix).
|
|
12
|
+
*
|
|
13
|
+
* @wildo-boundary
|
|
14
|
+
* This sub-tree is split intentionally:
|
|
15
|
+
*
|
|
16
|
+
* - `wildo-website-config.schemas.ts` — Zod-only, no Node-only
|
|
17
|
+
* imports, no `process.*` references. Safe to bundle anywhere.
|
|
18
|
+
* - `define-website-config.ts` — uses `process.stderr.write` for
|
|
19
|
+
* the (currently empty) `@unimplemented` warner. Bundle-safe in
|
|
20
|
+
* practice (the global `process` is polyfilled by every modern
|
|
21
|
+
* bundler and the warner has no `node:*` bare specifier), so it
|
|
22
|
+
* can ship through the root barrel alongside the schema.
|
|
23
|
+
* - `load-website-config.ts` — Node-only. Imports `loadConfig` +
|
|
24
|
+
* `AppFrontendType` from `@wildo-ai/platform-config-lib` and
|
|
25
|
+
* `node:fs` / `node:path`. Re-exported via the dedicated
|
|
26
|
+
* package subpath `./config-loader` (NOT from this barrel) so
|
|
27
|
+
* the React-island closure stays free of Node-only specifiers
|
|
28
|
+
* (enforced by `__tests__/bundle-isolation.test.ts`).
|
|
29
|
+
*
|
|
30
|
+
* Consumers:
|
|
31
|
+
* - Author per-service config: `import { defineWebsiteConfig }`
|
|
32
|
+
* from `'@wildo-ai/saas-website'`.
|
|
33
|
+
* - Load per-service config from a Node-side build / dev pipeline:
|
|
34
|
+
* `import { loadWebsiteConfig }` from `'@wildo-ai/saas-website/config-loader'`.
|
|
35
|
+
*/
|
|
36
|
+
export * from './define-website-config.js';
|
|
37
|
+
export * from './wildo-website-config.schemas.js';
|
|
38
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,cAAc,yBAAyB,CAAC;AACxC,cAAc,gCAAgC,CAAC","sourcesContent":["/**\n * `@wildo-ai/saas-website` — config surface.\n *\n * Per-service `wildo.website.config.ts` schema + `defineWebsiteConfig`\n * helper. Co-located with the engine package that owns the marketing-\n * site primitives so a new SEO field / locale-pack id ships in a\n * single PR with no cross-package allow-list to keep in sync (see\n * `wildo-website-config.schemas.ts` JSDoc for the architectural\n * rationale behind moving this out of `platform-config-lib` —\n * `saas-website-slice.md` Step 7.5 mirrors the\n * `saas-technical-doc.md` Step 7.5 fix).\n *\n * @wildo-boundary\n * This sub-tree is split intentionally:\n *\n * - `wildo-website-config.schemas.ts` — Zod-only, no Node-only\n * imports, no `process.*` references. Safe to bundle anywhere.\n * - `define-website-config.ts` — uses `process.stderr.write` for\n * the (currently empty) `@unimplemented` warner. Bundle-safe in\n * practice (the global `process` is polyfilled by every modern\n * bundler and the warner has no `node:*` bare specifier), so it\n * can ship through the root barrel alongside the schema.\n * - `load-website-config.ts` — Node-only. Imports `loadConfig` +\n * `AppFrontendType` from `@wildo-ai/platform-config-lib` and\n * `node:fs` / `node:path`. Re-exported via the dedicated\n * package subpath `./config-loader` (NOT from this barrel) so\n * the React-island closure stays free of Node-only specifiers\n * (enforced by `__tests__/bundle-isolation.test.ts`).\n *\n * Consumers:\n * - Author per-service config: `import { defineWebsiteConfig }`\n * from `'@wildo-ai/saas-website'`.\n * - Load per-service config from a Node-side build / dev pipeline:\n * `import { loadWebsiteConfig }` from `'@wildo-ai/saas-website/config-loader'`.\n */\n\nexport * from './define-website-config';\nexport * from './wildo-website-config.schemas';\n"]}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Per-service `wildo.website.config.ts` loader.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the `loadTechnicalDocConfig()` shape used by
|
|
5
|
+
* `platform/factory/wildo-dev-companion/src/technical-doc/services/technical-doc.companion.service.ts`
|
|
6
|
+
* (see `saas-technical-doc.md` Step 7.5). Discovers the unique
|
|
7
|
+
* `frontendType: STATIC_WEBSITE` service in the SaaS config, joins
|
|
8
|
+
* `<saasRoot>/<service.path>/wildo.website.config.ts`, and loads it
|
|
9
|
+
* via the jiti-backed `loadConfig` from `@wildo-ai/platform-config-lib`.
|
|
10
|
+
*
|
|
11
|
+
* The actual Zod validation runs INSIDE `defineWebsiteConfig` (which
|
|
12
|
+
* the per-service config file invokes via
|
|
13
|
+
* `export default defineWebsiteConfig({...})`), so by the time
|
|
14
|
+
* `loadConfig` returns we already hold a parsed
|
|
15
|
+
* `WildoMarketingWebsiteConfig`.
|
|
16
|
+
*
|
|
17
|
+
* @wildo-boundary
|
|
18
|
+
* This module is **Node-only**. It imports `loadConfig` and
|
|
19
|
+
* `AppFrontendType` from `@wildo-ai/platform-config-lib`, which
|
|
20
|
+
* transitively pulls `jiti`, `node:fs`, `node:path`, `node:crypto`,
|
|
21
|
+
* and other Node-only API surface. It MUST NOT be imported from
|
|
22
|
+
* any browser-bundled entry of this engine package — specifically
|
|
23
|
+
* NOT from `index.ts`, `companion-exports.ts`, or `astro-island.ts`.
|
|
24
|
+
* The dedicated `./config-loader` package subpath exists precisely
|
|
25
|
+
* to keep this surface OUT of the React-island bundle (enforced by
|
|
26
|
+
* `__tests__/bundle-isolation.test.ts`).
|
|
27
|
+
*
|
|
28
|
+
* The Astro build's `astro.config.ts` (a Node-side file by
|
|
29
|
+
* construction) is the canonical caller. A future companion
|
|
30
|
+
* subprocess that audits the marketing surface would also call
|
|
31
|
+
* from here. Browser bundles MUST NOT.
|
|
32
|
+
*/
|
|
33
|
+
import type { WildoSaasConfig } from '@wildo-ai/platform-config-lib';
|
|
34
|
+
import type { WildoMarketingWebsiteConfig } from './wildo-website-config.schemas';
|
|
35
|
+
/**
|
|
36
|
+
* Conventional file name for the per-service marketing-website
|
|
37
|
+
* configuration (Step 7.5 refactor — `saas-website-slice.md` /
|
|
38
|
+
* `saas-technical-doc.md` Step 7.5 mirror). Authored at the website
|
|
39
|
+
* service root next to `package.json` / `astro.config.ts`.
|
|
40
|
+
*
|
|
41
|
+
* Discovery is "by convention, not by configuration":
|
|
42
|
+
*
|
|
43
|
+
* - The loader locates this file by walking the `services` entry
|
|
44
|
+
* whose `frontendType === STATIC_WEBSITE` and joining
|
|
45
|
+
* `<saasRoot>/<service.path>/`. The saas-config schema's
|
|
46
|
+
* `superRefine` already enforces "at most one STATIC_WEBSITE
|
|
47
|
+
* service per app", so the lookup is deterministic — apps can
|
|
48
|
+
* name the website service anything (`'website'`, `'marketing'`,
|
|
49
|
+
* `'site'`).
|
|
50
|
+
*
|
|
51
|
+
* - File presence is the enable signal — there is NO `enabled`
|
|
52
|
+
* field on `WildoMarketingWebsiteConfigSchema`. A STATIC_WEBSITE
|
|
53
|
+
* service without this file is treated as a misconfiguration
|
|
54
|
+
* and the loader throws (rather than silently shipping an Astro
|
|
55
|
+
* build with no `i18n` routing / no canonical origin).
|
|
56
|
+
*/
|
|
57
|
+
export declare const PER_SERVICE_WEBSITE_CONFIG_FILE_NAME = "wildo.website.config.ts";
|
|
58
|
+
/**
|
|
59
|
+
* Test helper — pre-populate the loader's memoization slot for a
|
|
60
|
+
* given absolute config path. Mirrors the
|
|
61
|
+
* `cachedTechnicalDocConfig` pre-population trick used by
|
|
62
|
+
* `technical-doc.publish-openapi.service.test.ts` so the loader's
|
|
63
|
+
* downstream consumers can be exercised in tests without writing a
|
|
64
|
+
* `.ts` file to disk + invoking jiti.
|
|
65
|
+
*
|
|
66
|
+
* Production callers MUST NOT use this helper.
|
|
67
|
+
*/
|
|
68
|
+
export declare function primeWebsiteConfigCache(absoluteConfigPath: string, config: WildoMarketingWebsiteConfig): void;
|
|
69
|
+
/**
|
|
70
|
+
* Test helper — clear every cached entry. Use in `beforeEach`/`afterEach`
|
|
71
|
+
* to prevent test cross-contamination.
|
|
72
|
+
*/
|
|
73
|
+
export declare function clearWebsiteConfigCache(): void;
|
|
74
|
+
/**
|
|
75
|
+
* Arguments for {@link loadWebsiteConfig}. Kept as a structured shape
|
|
76
|
+
* (rather than positional `loadWebsiteConfig(saasRoot, saasConfig)`)
|
|
77
|
+
* so that future per-call options (e.g. an explicit `serviceKey`
|
|
78
|
+
* override for multi-website apps the day the singleton invariant
|
|
79
|
+
* relaxes) slot in without breaking callers.
|
|
80
|
+
*/
|
|
81
|
+
export interface LoadWebsiteConfigArgs {
|
|
82
|
+
/**
|
|
83
|
+
* Absolute path to the SaaS app root — the directory holding
|
|
84
|
+
* `wildo.saas.config.ts`. Used to resolve `<saasRoot>/<service.path>/`
|
|
85
|
+
* for the website service folder.
|
|
86
|
+
*/
|
|
87
|
+
saasRoot: string;
|
|
88
|
+
/**
|
|
89
|
+
* The already-parsed SaaS config (load once via
|
|
90
|
+
* `loadConfig<WildoSaasConfig>(...)` upstream and pass it down here
|
|
91
|
+
* — re-parsing per call would invoke jiti twice for one logical
|
|
92
|
+
* load).
|
|
93
|
+
*/
|
|
94
|
+
saasConfig: WildoSaasConfig;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Discover and load the per-service marketing-website config.
|
|
98
|
+
*
|
|
99
|
+
* Resolution algorithm (mirrors
|
|
100
|
+
* `TechnicalDocCompanionService.loadTechnicalDocConfig`):
|
|
101
|
+
*
|
|
102
|
+
* 1. Find the unique service in `saasConfig.services` whose
|
|
103
|
+
* `frontendType === STATIC_WEBSITE`. The saas-config
|
|
104
|
+
* `superRefine` guarantees there is at most one — if there is
|
|
105
|
+
* none, throw with the misconfiguration message.
|
|
106
|
+
* 2. Resolve `<saasRoot>/<service.path>/wildo.website.config.ts`.
|
|
107
|
+
* 3. If the file does not exist, throw (file presence IS the
|
|
108
|
+
* enable signal — a STATIC_WEBSITE service without this file
|
|
109
|
+
* is broken).
|
|
110
|
+
* 4. Check the memoization slot keyed on the absolute path; return
|
|
111
|
+
* the cached value if present.
|
|
112
|
+
* 5. Call `loadConfig<WildoMarketingWebsiteConfig>(absolutePath)`.
|
|
113
|
+
* jiti evaluates the file, which invokes `defineWebsiteConfig`,
|
|
114
|
+
* which invokes `WildoMarketingWebsiteConfigSchema.parse` and
|
|
115
|
+
* emits any `@unimplemented` warnings. The returned object is
|
|
116
|
+
* already-validated — we trust the in-file `defineWebsiteConfig`
|
|
117
|
+
* contract here (mirrors the technical-doc loader pattern in
|
|
118
|
+
* `TechnicalDocCompanionService.loadTechnicalDocConfig`, which
|
|
119
|
+
* also does NOT re-parse). A file that hand-rolls the default
|
|
120
|
+
* export without going through `defineWebsiteConfig` would
|
|
121
|
+
* surface as a downstream type mismatch — acceptable given the
|
|
122
|
+
* authoring contract is explicit and grep-discoverable.
|
|
123
|
+
* 6. Memoize and return.
|
|
124
|
+
*
|
|
125
|
+
* @throws Error with a `[wildo-website-config]` prefix if no
|
|
126
|
+
* STATIC_WEBSITE service is declared, the per-service config
|
|
127
|
+
* file is missing, or the file's default export does not
|
|
128
|
+
* pass `WildoMarketingWebsiteConfigSchema`. The loader
|
|
129
|
+
* intentionally throws plain `Error`s rather than building a
|
|
130
|
+
* `WildoBackendError` so it stays usable from the Astro
|
|
131
|
+
* build pipeline (which has no DI container) — the companion
|
|
132
|
+
* can wrap with `errorBuilder` at the call site if needed
|
|
133
|
+
* (mirrors how `loadConfig` itself throws plain `Error`).
|
|
134
|
+
*/
|
|
135
|
+
export declare function loadWebsiteConfig(args: LoadWebsiteConfigArgs): Promise<WildoMarketingWebsiteConfig>;
|
|
136
|
+
//# sourceMappingURL=load-website-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-website-config.d.ts","sourceRoot":"","sources":["../../../../src/config/load-website-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAC;AAElF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,oCAAoC,4BAA4B,CAAC;AAkB9E;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,kBAAkB,EAAE,MAAM,EAC1B,MAAM,EAAE,2BAA2B,GAClC,IAAI,CAEN;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,UAAU,EAAE,eAAe,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,2BAA2B,CAAC,CA4DtC"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Per-service `wildo.website.config.ts` loader.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the `loadTechnicalDocConfig()` shape used by
|
|
5
|
+
* `platform/factory/wildo-dev-companion/src/technical-doc/services/technical-doc.companion.service.ts`
|
|
6
|
+
* (see `saas-technical-doc.md` Step 7.5). Discovers the unique
|
|
7
|
+
* `frontendType: STATIC_WEBSITE` service in the SaaS config, joins
|
|
8
|
+
* `<saasRoot>/<service.path>/wildo.website.config.ts`, and loads it
|
|
9
|
+
* via the jiti-backed `loadConfig` from `@wildo-ai/platform-config-lib`.
|
|
10
|
+
*
|
|
11
|
+
* The actual Zod validation runs INSIDE `defineWebsiteConfig` (which
|
|
12
|
+
* the per-service config file invokes via
|
|
13
|
+
* `export default defineWebsiteConfig({...})`), so by the time
|
|
14
|
+
* `loadConfig` returns we already hold a parsed
|
|
15
|
+
* `WildoMarketingWebsiteConfig`.
|
|
16
|
+
*
|
|
17
|
+
* @wildo-boundary
|
|
18
|
+
* This module is **Node-only**. It imports `loadConfig` and
|
|
19
|
+
* `AppFrontendType` from `@wildo-ai/platform-config-lib`, which
|
|
20
|
+
* transitively pulls `jiti`, `node:fs`, `node:path`, `node:crypto`,
|
|
21
|
+
* and other Node-only API surface. It MUST NOT be imported from
|
|
22
|
+
* any browser-bundled entry of this engine package — specifically
|
|
23
|
+
* NOT from `index.ts`, `companion-exports.ts`, or `astro-island.ts`.
|
|
24
|
+
* The dedicated `./config-loader` package subpath exists precisely
|
|
25
|
+
* to keep this surface OUT of the React-island bundle (enforced by
|
|
26
|
+
* `__tests__/bundle-isolation.test.ts`).
|
|
27
|
+
*
|
|
28
|
+
* The Astro build's `astro.config.ts` (a Node-side file by
|
|
29
|
+
* construction) is the canonical caller. A future companion
|
|
30
|
+
* subprocess that audits the marketing surface would also call
|
|
31
|
+
* from here. Browser bundles MUST NOT.
|
|
32
|
+
*/
|
|
33
|
+
import { existsSync } from 'node:fs';
|
|
34
|
+
import { resolve as resolvePath } from 'node:path';
|
|
35
|
+
import { AppFrontendType, loadConfig } from '@wildo-ai/platform-config-lib';
|
|
36
|
+
/**
|
|
37
|
+
* Conventional file name for the per-service marketing-website
|
|
38
|
+
* configuration (Step 7.5 refactor — `saas-website-slice.md` /
|
|
39
|
+
* `saas-technical-doc.md` Step 7.5 mirror). Authored at the website
|
|
40
|
+
* service root next to `package.json` / `astro.config.ts`.
|
|
41
|
+
*
|
|
42
|
+
* Discovery is "by convention, not by configuration":
|
|
43
|
+
*
|
|
44
|
+
* - The loader locates this file by walking the `services` entry
|
|
45
|
+
* whose `frontendType === STATIC_WEBSITE` and joining
|
|
46
|
+
* `<saasRoot>/<service.path>/`. The saas-config schema's
|
|
47
|
+
* `superRefine` already enforces "at most one STATIC_WEBSITE
|
|
48
|
+
* service per app", so the lookup is deterministic — apps can
|
|
49
|
+
* name the website service anything (`'website'`, `'marketing'`,
|
|
50
|
+
* `'site'`).
|
|
51
|
+
*
|
|
52
|
+
* - File presence is the enable signal — there is NO `enabled`
|
|
53
|
+
* field on `WildoMarketingWebsiteConfigSchema`. A STATIC_WEBSITE
|
|
54
|
+
* service without this file is treated as a misconfiguration
|
|
55
|
+
* and the loader throws (rather than silently shipping an Astro
|
|
56
|
+
* build with no `i18n` routing / no canonical origin).
|
|
57
|
+
*/
|
|
58
|
+
export const PER_SERVICE_WEBSITE_CONFIG_FILE_NAME = 'wildo.website.config.ts';
|
|
59
|
+
/**
|
|
60
|
+
* Memoization slot scoped to the loader module. Keyed by absolute
|
|
61
|
+
* config file path so multiple SaaS configs evaluated in the same
|
|
62
|
+
* process (rare in production — possible in tests) do not collide.
|
|
63
|
+
*
|
|
64
|
+
* Lifetime: the loader is invoked from the Astro build / dev-server
|
|
65
|
+
* pipeline, both of which restart the Node process on every dev-stack
|
|
66
|
+
* reload (the watcher that picks up changes to `wildo.website.config.ts`
|
|
67
|
+
* is the same watcher that reboots the build). A stale entry here
|
|
68
|
+
* therefore cannot outlive a config edit.
|
|
69
|
+
*
|
|
70
|
+
* Tests can pre-populate a known path via {@link primeWebsiteConfigCache}
|
|
71
|
+
* to skip the jiti round-trip when exercising downstream consumers.
|
|
72
|
+
*/
|
|
73
|
+
const WEBSITE_CONFIG_CACHE = new Map();
|
|
74
|
+
/**
|
|
75
|
+
* Test helper — pre-populate the loader's memoization slot for a
|
|
76
|
+
* given absolute config path. Mirrors the
|
|
77
|
+
* `cachedTechnicalDocConfig` pre-population trick used by
|
|
78
|
+
* `technical-doc.publish-openapi.service.test.ts` so the loader's
|
|
79
|
+
* downstream consumers can be exercised in tests without writing a
|
|
80
|
+
* `.ts` file to disk + invoking jiti.
|
|
81
|
+
*
|
|
82
|
+
* Production callers MUST NOT use this helper.
|
|
83
|
+
*/
|
|
84
|
+
export function primeWebsiteConfigCache(absoluteConfigPath, config) {
|
|
85
|
+
WEBSITE_CONFIG_CACHE.set(resolvePath(absoluteConfigPath), config);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Test helper — clear every cached entry. Use in `beforeEach`/`afterEach`
|
|
89
|
+
* to prevent test cross-contamination.
|
|
90
|
+
*/
|
|
91
|
+
export function clearWebsiteConfigCache() {
|
|
92
|
+
WEBSITE_CONFIG_CACHE.clear();
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Discover and load the per-service marketing-website config.
|
|
96
|
+
*
|
|
97
|
+
* Resolution algorithm (mirrors
|
|
98
|
+
* `TechnicalDocCompanionService.loadTechnicalDocConfig`):
|
|
99
|
+
*
|
|
100
|
+
* 1. Find the unique service in `saasConfig.services` whose
|
|
101
|
+
* `frontendType === STATIC_WEBSITE`. The saas-config
|
|
102
|
+
* `superRefine` guarantees there is at most one — if there is
|
|
103
|
+
* none, throw with the misconfiguration message.
|
|
104
|
+
* 2. Resolve `<saasRoot>/<service.path>/wildo.website.config.ts`.
|
|
105
|
+
* 3. If the file does not exist, throw (file presence IS the
|
|
106
|
+
* enable signal — a STATIC_WEBSITE service without this file
|
|
107
|
+
* is broken).
|
|
108
|
+
* 4. Check the memoization slot keyed on the absolute path; return
|
|
109
|
+
* the cached value if present.
|
|
110
|
+
* 5. Call `loadConfig<WildoMarketingWebsiteConfig>(absolutePath)`.
|
|
111
|
+
* jiti evaluates the file, which invokes `defineWebsiteConfig`,
|
|
112
|
+
* which invokes `WildoMarketingWebsiteConfigSchema.parse` and
|
|
113
|
+
* emits any `@unimplemented` warnings. The returned object is
|
|
114
|
+
* already-validated — we trust the in-file `defineWebsiteConfig`
|
|
115
|
+
* contract here (mirrors the technical-doc loader pattern in
|
|
116
|
+
* `TechnicalDocCompanionService.loadTechnicalDocConfig`, which
|
|
117
|
+
* also does NOT re-parse). A file that hand-rolls the default
|
|
118
|
+
* export without going through `defineWebsiteConfig` would
|
|
119
|
+
* surface as a downstream type mismatch — acceptable given the
|
|
120
|
+
* authoring contract is explicit and grep-discoverable.
|
|
121
|
+
* 6. Memoize and return.
|
|
122
|
+
*
|
|
123
|
+
* @throws Error with a `[wildo-website-config]` prefix if no
|
|
124
|
+
* STATIC_WEBSITE service is declared, the per-service config
|
|
125
|
+
* file is missing, or the file's default export does not
|
|
126
|
+
* pass `WildoMarketingWebsiteConfigSchema`. The loader
|
|
127
|
+
* intentionally throws plain `Error`s rather than building a
|
|
128
|
+
* `WildoBackendError` so it stays usable from the Astro
|
|
129
|
+
* build pipeline (which has no DI container) — the companion
|
|
130
|
+
* can wrap with `errorBuilder` at the call site if needed
|
|
131
|
+
* (mirrors how `loadConfig` itself throws plain `Error`).
|
|
132
|
+
*/
|
|
133
|
+
export async function loadWebsiteConfig(args) {
|
|
134
|
+
const { saasRoot, saasConfig } = args;
|
|
135
|
+
const websiteServiceEntry = Object.entries(saasConfig.services).find(([, service]) => service.frontendType === AppFrontendType.STATIC_WEBSITE);
|
|
136
|
+
if (!websiteServiceEntry) {
|
|
137
|
+
throw new Error('[wildo-website-config] No frontend service with `frontendType: STATIC_WEBSITE` is declared in '
|
|
138
|
+
+ 'wildo.saas.config.ts. The marketing-website Astro build / loader requires an authored '
|
|
139
|
+
+ 'STATIC_WEBSITE service because that service folder owns the per-service '
|
|
140
|
+
+ '`wildo.website.config.ts` (publicOrigin, appOrigin, defaultLocale, locales). '
|
|
141
|
+
+ 'Add a STATIC_WEBSITE service in wildo.saas.config.ts and ship the per-service '
|
|
142
|
+
+ 'config file under it.');
|
|
143
|
+
}
|
|
144
|
+
const [websiteServiceKey, websiteService] = websiteServiceEntry;
|
|
145
|
+
const websiteConfigPath = resolvePath(saasRoot, websiteService.path, PER_SERVICE_WEBSITE_CONFIG_FILE_NAME);
|
|
146
|
+
const cached = WEBSITE_CONFIG_CACHE.get(websiteConfigPath);
|
|
147
|
+
if (cached !== undefined) {
|
|
148
|
+
return cached;
|
|
149
|
+
}
|
|
150
|
+
if (!existsSync(websiteConfigPath)) {
|
|
151
|
+
throw new Error(`[wildo-website-config] STATIC_WEBSITE service '${websiteServiceKey}' is declared in `
|
|
152
|
+
+ `wildo.saas.config.ts but the required per-service config file `
|
|
153
|
+
+ `'${PER_SERVICE_WEBSITE_CONFIG_FILE_NAME}' is missing under `
|
|
154
|
+
+ `'${websiteService.path}/'. File presence IS the enable signal `
|
|
155
|
+
+ '(saas-website-slice.md / saas-technical-doc.md Step 7.5 — the legacy '
|
|
156
|
+
+ '`marketingWebsite` block on wildo.saas.config.ts was dropped in favor of '
|
|
157
|
+
+ 'a per-service file). Create '
|
|
158
|
+
+ `'${websiteConfigPath}' with `
|
|
159
|
+
+ '`export default defineWebsiteConfig({ ... })` from `@wildo-ai/saas-website`.');
|
|
160
|
+
}
|
|
161
|
+
let loaded;
|
|
162
|
+
try {
|
|
163
|
+
loaded = await loadConfig(websiteConfigPath);
|
|
164
|
+
}
|
|
165
|
+
catch (e) {
|
|
166
|
+
const cause = e instanceof Error ? e.message : String(e);
|
|
167
|
+
throw new Error(`[wildo-website-config] Failed to load per-service marketing-website config at `
|
|
168
|
+
+ `${websiteConfigPath}. The file MUST do `
|
|
169
|
+
+ '`export default defineWebsiteConfig({...})` and pass '
|
|
170
|
+
+ 'WildoMarketingWebsiteConfigSchema (`z.strictObject` — unknown keys reject; '
|
|
171
|
+
+ '`defaultLocale` must appear in `locales`). '
|
|
172
|
+
+ `Cause: ${cause}`);
|
|
173
|
+
}
|
|
174
|
+
WEBSITE_CONFIG_CACHE.set(websiteConfigPath, loaded);
|
|
175
|
+
return loaded;
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=load-website-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-website-config.js","sourceRoot":"","sources":["../../../../src/config/load-website-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAI5E;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,oCAAoC,GAAG,yBAAyB,CAAC;AAE9E;;;;;;;;;;;;;GAaG;AACH,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAAuC,CAAC;AAE5E;;;;;;;;;GASG;AACH,MAAM,UAAU,uBAAuB,CACrC,kBAA0B,EAC1B,MAAmC;IAEnC,oBAAoB,CAAC,GAAG,CAAC,WAAW,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC,CAAC;AACpE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB;IACrC,oBAAoB,CAAC,KAAK,EAAE,CAAC;AAC/B,CAAC;AAyBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAA2B;IAE3B,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;IAEtC,MAAM,mBAAmB,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,IAAI,CAClE,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,YAAY,KAAK,eAAe,CAAC,cAAc,CACzE,CAAC;IACF,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,gGAAgG;cAC5F,wFAAwF;cACxF,0EAA0E;cAC1E,+EAA+E;cAC/E,gFAAgF;cAChF,uBAAuB,CAC5B,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,iBAAiB,EAAE,cAAc,CAAC,GAAG,mBAAmB,CAAC;IAChE,MAAM,iBAAiB,GAAG,WAAW,CACnC,QAAQ,EACR,cAAc,CAAC,IAAI,EACnB,oCAAoC,CACrC,CAAC;IAEF,MAAM,MAAM,GAAG,oBAAoB,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAC3D,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CACb,kDAAkD,iBAAiB,mBAAmB;cAClF,gEAAgE;cAChE,IAAI,oCAAoC,qBAAqB;cAC7D,IAAI,cAAc,CAAC,IAAI,yCAAyC;cAChE,uEAAuE;cACvE,2EAA2E;cAC3E,8BAA8B;cAC9B,IAAI,iBAAiB,SAAS;cAC9B,8EAA8E,CACnF,CAAC;IACJ,CAAC;IAED,IAAI,MAAmC,CAAC;IACxC,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,UAAU,CAA8B,iBAAiB,CAAC,CAAC;IAC5E,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,KAAK,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACzD,MAAM,IAAI,KAAK,CACb,gFAAgF;cAC5E,GAAG,iBAAiB,qBAAqB;cACzC,uDAAuD;cACvD,6EAA6E;cAC7E,6CAA6C;cAC7C,UAAU,KAAK,EAAE,CACtB,CAAC;IACJ,CAAC;IAED,oBAAoB,CAAC,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;IACpD,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["/**\n * @fileoverview Per-service `wildo.website.config.ts` loader.\n *\n * Mirrors the `loadTechnicalDocConfig()` shape used by\n * `platform/factory/wildo-dev-companion/src/technical-doc/services/technical-doc.companion.service.ts`\n * (see `saas-technical-doc.md` Step 7.5). Discovers the unique\n * `frontendType: STATIC_WEBSITE` service in the SaaS config, joins\n * `<saasRoot>/<service.path>/wildo.website.config.ts`, and loads it\n * via the jiti-backed `loadConfig` from `@wildo-ai/platform-config-lib`.\n *\n * The actual Zod validation runs INSIDE `defineWebsiteConfig` (which\n * the per-service config file invokes via\n * `export default defineWebsiteConfig({...})`), so by the time\n * `loadConfig` returns we already hold a parsed\n * `WildoMarketingWebsiteConfig`.\n *\n * @wildo-boundary\n * This module is **Node-only**. It imports `loadConfig` and\n * `AppFrontendType` from `@wildo-ai/platform-config-lib`, which\n * transitively pulls `jiti`, `node:fs`, `node:path`, `node:crypto`,\n * and other Node-only API surface. It MUST NOT be imported from\n * any browser-bundled entry of this engine package — specifically\n * NOT from `index.ts`, `companion-exports.ts`, or `astro-island.ts`.\n * The dedicated `./config-loader` package subpath exists precisely\n * to keep this surface OUT of the React-island bundle (enforced by\n * `__tests__/bundle-isolation.test.ts`).\n *\n * The Astro build's `astro.config.ts` (a Node-side file by\n * construction) is the canonical caller. A future companion\n * subprocess that audits the marketing surface would also call\n * from here. Browser bundles MUST NOT.\n */\n\nimport { existsSync } from 'node:fs';\nimport { resolve as resolvePath } from 'node:path';\nimport { AppFrontendType, loadConfig } from '@wildo-ai/platform-config-lib';\nimport type { WildoSaasConfig } from '@wildo-ai/platform-config-lib';\nimport type { WildoMarketingWebsiteConfig } from './wildo-website-config.schemas';\n\n/**\n * Conventional file name for the per-service marketing-website\n * configuration (Step 7.5 refactor — `saas-website-slice.md` /\n * `saas-technical-doc.md` Step 7.5 mirror). Authored at the website\n * service root next to `package.json` / `astro.config.ts`.\n *\n * Discovery is \"by convention, not by configuration\":\n *\n * - The loader locates this file by walking the `services` entry\n * whose `frontendType === STATIC_WEBSITE` and joining\n * `<saasRoot>/<service.path>/`. The saas-config schema's\n * `superRefine` already enforces \"at most one STATIC_WEBSITE\n * service per app\", so the lookup is deterministic — apps can\n * name the website service anything (`'website'`, `'marketing'`,\n * `'site'`).\n *\n * - File presence is the enable signal — there is NO `enabled`\n * field on `WildoMarketingWebsiteConfigSchema`. A STATIC_WEBSITE\n * service without this file is treated as a misconfiguration\n * and the loader throws (rather than silently shipping an Astro\n * build with no `i18n` routing / no canonical origin).\n */\nexport const PER_SERVICE_WEBSITE_CONFIG_FILE_NAME = 'wildo.website.config.ts';\n\n/**\n * Memoization slot scoped to the loader module. Keyed by absolute\n * config file path so multiple SaaS configs evaluated in the same\n * process (rare in production — possible in tests) do not collide.\n *\n * Lifetime: the loader is invoked from the Astro build / dev-server\n * pipeline, both of which restart the Node process on every dev-stack\n * reload (the watcher that picks up changes to `wildo.website.config.ts`\n * is the same watcher that reboots the build). A stale entry here\n * therefore cannot outlive a config edit.\n *\n * Tests can pre-populate a known path via {@link primeWebsiteConfigCache}\n * to skip the jiti round-trip when exercising downstream consumers.\n */\nconst WEBSITE_CONFIG_CACHE = new Map<string, WildoMarketingWebsiteConfig>();\n\n/**\n * Test helper — pre-populate the loader's memoization slot for a\n * given absolute config path. Mirrors the\n * `cachedTechnicalDocConfig` pre-population trick used by\n * `technical-doc.publish-openapi.service.test.ts` so the loader's\n * downstream consumers can be exercised in tests without writing a\n * `.ts` file to disk + invoking jiti.\n *\n * Production callers MUST NOT use this helper.\n */\nexport function primeWebsiteConfigCache(\n absoluteConfigPath: string,\n config: WildoMarketingWebsiteConfig,\n): void {\n WEBSITE_CONFIG_CACHE.set(resolvePath(absoluteConfigPath), config);\n}\n\n/**\n * Test helper — clear every cached entry. Use in `beforeEach`/`afterEach`\n * to prevent test cross-contamination.\n */\nexport function clearWebsiteConfigCache(): void {\n WEBSITE_CONFIG_CACHE.clear();\n}\n\n/**\n * Arguments for {@link loadWebsiteConfig}. Kept as a structured shape\n * (rather than positional `loadWebsiteConfig(saasRoot, saasConfig)`)\n * so that future per-call options (e.g. an explicit `serviceKey`\n * override for multi-website apps the day the singleton invariant\n * relaxes) slot in without breaking callers.\n */\nexport interface LoadWebsiteConfigArgs {\n /**\n * Absolute path to the SaaS app root — the directory holding\n * `wildo.saas.config.ts`. Used to resolve `<saasRoot>/<service.path>/`\n * for the website service folder.\n */\n saasRoot: string;\n /**\n * The already-parsed SaaS config (load once via\n * `loadConfig<WildoSaasConfig>(...)` upstream and pass it down here\n * — re-parsing per call would invoke jiti twice for one logical\n * load).\n */\n saasConfig: WildoSaasConfig;\n}\n\n/**\n * Discover and load the per-service marketing-website config.\n *\n * Resolution algorithm (mirrors\n * `TechnicalDocCompanionService.loadTechnicalDocConfig`):\n *\n * 1. Find the unique service in `saasConfig.services` whose\n * `frontendType === STATIC_WEBSITE`. The saas-config\n * `superRefine` guarantees there is at most one — if there is\n * none, throw with the misconfiguration message.\n * 2. Resolve `<saasRoot>/<service.path>/wildo.website.config.ts`.\n * 3. If the file does not exist, throw (file presence IS the\n * enable signal — a STATIC_WEBSITE service without this file\n * is broken).\n * 4. Check the memoization slot keyed on the absolute path; return\n * the cached value if present.\n * 5. Call `loadConfig<WildoMarketingWebsiteConfig>(absolutePath)`.\n * jiti evaluates the file, which invokes `defineWebsiteConfig`,\n * which invokes `WildoMarketingWebsiteConfigSchema.parse` and\n * emits any `@unimplemented` warnings. The returned object is\n * already-validated — we trust the in-file `defineWebsiteConfig`\n * contract here (mirrors the technical-doc loader pattern in\n * `TechnicalDocCompanionService.loadTechnicalDocConfig`, which\n * also does NOT re-parse). A file that hand-rolls the default\n * export without going through `defineWebsiteConfig` would\n * surface as a downstream type mismatch — acceptable given the\n * authoring contract is explicit and grep-discoverable.\n * 6. Memoize and return.\n *\n * @throws Error with a `[wildo-website-config]` prefix if no\n * STATIC_WEBSITE service is declared, the per-service config\n * file is missing, or the file's default export does not\n * pass `WildoMarketingWebsiteConfigSchema`. The loader\n * intentionally throws plain `Error`s rather than building a\n * `WildoBackendError` so it stays usable from the Astro\n * build pipeline (which has no DI container) — the companion\n * can wrap with `errorBuilder` at the call site if needed\n * (mirrors how `loadConfig` itself throws plain `Error`).\n */\nexport async function loadWebsiteConfig(\n args: LoadWebsiteConfigArgs,\n): Promise<WildoMarketingWebsiteConfig> {\n const { saasRoot, saasConfig } = args;\n\n const websiteServiceEntry = Object.entries(saasConfig.services).find(\n ([, service]) => service.frontendType === AppFrontendType.STATIC_WEBSITE,\n );\n if (!websiteServiceEntry) {\n throw new Error(\n '[wildo-website-config] No frontend service with `frontendType: STATIC_WEBSITE` is declared in '\n + 'wildo.saas.config.ts. The marketing-website Astro build / loader requires an authored '\n + 'STATIC_WEBSITE service because that service folder owns the per-service '\n + '`wildo.website.config.ts` (publicOrigin, appOrigin, defaultLocale, locales). '\n + 'Add a STATIC_WEBSITE service in wildo.saas.config.ts and ship the per-service '\n + 'config file under it.',\n );\n }\n\n const [websiteServiceKey, websiteService] = websiteServiceEntry;\n const websiteConfigPath = resolvePath(\n saasRoot,\n websiteService.path,\n PER_SERVICE_WEBSITE_CONFIG_FILE_NAME,\n );\n\n const cached = WEBSITE_CONFIG_CACHE.get(websiteConfigPath);\n if (cached !== undefined) {\n return cached;\n }\n\n if (!existsSync(websiteConfigPath)) {\n throw new Error(\n `[wildo-website-config] STATIC_WEBSITE service '${websiteServiceKey}' is declared in `\n + `wildo.saas.config.ts but the required per-service config file `\n + `'${PER_SERVICE_WEBSITE_CONFIG_FILE_NAME}' is missing under `\n + `'${websiteService.path}/'. File presence IS the enable signal `\n + '(saas-website-slice.md / saas-technical-doc.md Step 7.5 — the legacy '\n + '`marketingWebsite` block on wildo.saas.config.ts was dropped in favor of '\n + 'a per-service file). Create '\n + `'${websiteConfigPath}' with `\n + '`export default defineWebsiteConfig({ ... })` from `@wildo-ai/saas-website`.',\n );\n }\n\n let loaded: WildoMarketingWebsiteConfig;\n try {\n loaded = await loadConfig<WildoMarketingWebsiteConfig>(websiteConfigPath);\n } catch (e) {\n const cause = e instanceof Error ? e.message : String(e);\n throw new Error(\n `[wildo-website-config] Failed to load per-service marketing-website config at `\n + `${websiteConfigPath}. The file MUST do `\n + '`export default defineWebsiteConfig({...})` and pass '\n + 'WildoMarketingWebsiteConfigSchema (`z.strictObject` — unknown keys reject; '\n + '`defaultLocale` must appear in `locales`). '\n + `Cause: ${cause}`,\n );\n }\n\n WEBSITE_CONFIG_CACHE.set(websiteConfigPath, loaded);\n return loaded;\n}\n"]}
|