@wildo-ai/saas-website 1.1.5 → 1.1.7
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/dist/esm/astro/blog-post-bridge.d.ts +9 -0
- package/dist/esm/astro/blog-post-bridge.d.ts.map +1 -1
- package/dist/esm/astro/blog-post-bridge.js +10 -5
- package/dist/esm/astro/blog-post-bridge.js.map +1 -1
- package/dist/esm/astro/blog-post-head.renderer.d.ts.map +1 -1
- package/dist/esm/astro/bridge-runtime.d.ts +25 -6
- package/dist/esm/astro/bridge-runtime.d.ts.map +1 -1
- package/dist/esm/astro/bridge-runtime.js +10 -6
- package/dist/esm/astro/bridge-runtime.js.map +1 -1
- package/dist/esm/astro/collect-expected-label-keys.d.ts.map +1 -1
- package/dist/esm/astro/headers-renderer.d.ts.map +1 -1
- package/dist/esm/astro/i18n-routing.helper.d.ts.map +1 -1
- package/dist/esm/astro/label-pack-loader.d.ts +4 -4
- package/dist/esm/astro/label-pack-loader.d.ts.map +1 -1
- package/dist/esm/astro/label-pack-loader.js +9 -4
- package/dist/esm/astro/label-pack-loader.js.map +1 -1
- package/dist/esm/astro/llms-txt-server.d.ts.map +1 -1
- package/dist/esm/astro/pick-labels-for-page.d.ts.map +1 -1
- package/dist/esm/astro/robots-renderer.d.ts +9 -8
- package/dist/esm/astro/robots-renderer.d.ts.map +1 -1
- package/dist/esm/astro/robots-renderer.js +15 -15
- package/dist/esm/astro/robots-renderer.js.map +1 -1
- package/dist/esm/astro/sitemap-coverage.d.ts.map +1 -1
- package/dist/esm/astro/structured-data.renderer.d.ts.map +1 -1
- package/dist/esm/astro/website-page-head.renderer.d.ts +1 -1
- package/dist/esm/astro/website-page-head.renderer.d.ts.map +1 -1
- package/dist/esm/astro/website-page-head.renderer.js +2 -1
- package/dist/esm/astro/website-page-head.renderer.js.map +1 -1
- package/dist/esm/astro/website-page-runtime.helper.d.ts.map +1 -1
- package/dist/esm/astro/website-site-context.d.ts +5 -2
- package/dist/esm/astro/website-site-context.d.ts.map +1 -1
- package/dist/esm/astro/website-site-context.js.map +1 -1
- package/dist/esm/astro-island.d.ts.map +1 -1
- package/dist/esm/astro.d.ts.map +1 -1
- package/dist/esm/companion-exports.d.ts +8 -15
- package/dist/esm/companion-exports.d.ts.map +1 -1
- package/dist/esm/companion-exports.js +8 -15
- package/dist/esm/companion-exports.js.map +1 -1
- package/dist/esm/components/low-level/WebsiteInternalButton.d.ts.map +1 -1
- package/dist/esm/components/low-level/WebsiteInternalLink.d.ts.map +1 -1
- package/dist/esm/config/define-website-config.d.ts +3 -2
- package/dist/esm/config/define-website-config.d.ts.map +1 -1
- package/dist/esm/config/define-website-config.js +10 -10
- package/dist/esm/config/define-website-config.js.map +1 -1
- package/dist/esm/config/index.d.ts.map +1 -1
- package/dist/esm/config/load-website-config.d.ts +6 -0
- package/dist/esm/config/load-website-config.d.ts.map +1 -1
- package/dist/esm/config/load-website-config.js +18 -9
- package/dist/esm/config/load-website-config.js.map +1 -1
- package/dist/esm/config/load-website-pricing-catalog.d.ts +13 -0
- package/dist/esm/config/load-website-pricing-catalog.d.ts.map +1 -0
- package/dist/esm/config/load-website-pricing-catalog.js +34 -0
- package/dist/esm/config/load-website-pricing-catalog.js.map +1 -0
- package/dist/esm/config/load-website-site-context.d.ts +53 -0
- package/dist/esm/config/load-website-site-context.d.ts.map +1 -0
- package/dist/esm/config/load-website-site-context.js +98 -0
- package/dist/esm/config/load-website-site-context.js.map +1 -0
- package/dist/esm/config/wildo-website-config.schemas.d.ts.map +1 -1
- package/dist/esm/config-loader.d.ts +2 -0
- package/dist/esm/config-loader.d.ts.map +1 -1
- package/dist/esm/config-loader.js +2 -0
- package/dist/esm/config-loader.js.map +1 -1
- package/dist/esm/core/anonymous-session/InboundContactForm.d.ts +26 -6
- package/dist/esm/core/anonymous-session/InboundContactForm.d.ts.map +1 -1
- package/dist/esm/core/anonymous-session/InboundContactForm.js +51 -33
- package/dist/esm/core/anonymous-session/InboundContactForm.js.map +1 -1
- package/dist/esm/core/anonymous-session/inbound-contact-form.schema.d.ts +11 -0
- package/dist/esm/core/anonymous-session/inbound-contact-form.schema.d.ts.map +1 -1
- package/dist/esm/core/anonymous-session/inbound-contact-form.schema.js +15 -4
- package/dist/esm/core/anonymous-session/inbound-contact-form.schema.js.map +1 -1
- package/dist/esm/core/anonymous-session/website-anonymous-session-client.d.ts +14 -2
- package/dist/esm/core/anonymous-session/website-anonymous-session-client.d.ts.map +1 -1
- package/dist/esm/core/anonymous-session/website-anonymous-session-client.js +34 -4
- package/dist/esm/core/anonymous-session/website-anonymous-session-client.js.map +1 -1
- package/dist/esm/core/anonymous-session/website-submission-challenge.d.ts +36 -0
- package/dist/esm/core/anonymous-session/website-submission-challenge.d.ts.map +1 -0
- package/dist/esm/core/anonymous-session/website-submission-challenge.js +69 -0
- package/dist/esm/core/anonymous-session/website-submission-challenge.js.map +1 -0
- package/dist/esm/core/consent/WebsiteConsentBanner.d.ts.map +1 -1
- package/dist/esm/core/consent/WebsiteConsentBanner.js +11 -10
- package/dist/esm/core/consent/WebsiteConsentBanner.js.map +1 -1
- package/dist/esm/core/consent/WebsiteConsentContext.d.ts.map +1 -1
- package/dist/esm/core/consent/WebsiteConsentGate.d.ts.map +1 -1
- package/dist/esm/core/consent/useWebsiteConsent.d.ts.map +1 -1
- package/dist/esm/core/consent/website-consent-storage.d.ts.map +1 -1
- package/dist/esm/core/contexts/WebsitePageContext.d.ts.map +1 -1
- package/dist/esm/core/contexts/WebsiteRuntimeContext.d.ts +25 -5
- package/dist/esm/core/contexts/WebsiteRuntimeContext.d.ts.map +1 -1
- package/dist/esm/core/contexts/WebsiteRuntimeContext.js.map +1 -1
- package/dist/esm/core/contexts/WebsiteSectionContext.d.ts.map +1 -1
- package/dist/esm/core/contexts/useWebsitePage.d.ts.map +1 -1
- package/dist/esm/core/contexts/useWebsiteRuntime.d.ts +18 -0
- package/dist/esm/core/contexts/useWebsiteRuntime.d.ts.map +1 -1
- package/dist/esm/core/contexts/useWebsiteRuntime.js +28 -2
- package/dist/esm/core/contexts/useWebsiteRuntime.js.map +1 -1
- package/dist/esm/core/contexts/useWebsiteSection.d.ts.map +1 -1
- package/dist/esm/core/external-providers/WebsiteProviderComponent.d.ts +57 -0
- package/dist/esm/core/external-providers/WebsiteProviderComponent.d.ts.map +1 -0
- package/dist/esm/core/external-providers/WebsiteProviderComponent.js +56 -0
- package/dist/esm/core/external-providers/WebsiteProviderComponent.js.map +1 -0
- package/dist/esm/core/external-providers/frontend-provider-registry.website.d.ts.map +1 -1
- package/dist/esm/core/external-providers/provider-component-registry.website.d.ts +63 -0
- package/dist/esm/core/external-providers/provider-component-registry.website.d.ts.map +1 -0
- package/dist/esm/core/external-providers/provider-component-registry.website.js +68 -0
- package/dist/esm/core/external-providers/provider-component-registry.website.js.map +1 -0
- package/dist/esm/core/external-providers/useWebsiteProviderComponent.d.ts +36 -0
- package/dist/esm/core/external-providers/useWebsiteProviderComponent.d.ts.map +1 -0
- package/dist/esm/core/external-providers/useWebsiteProviderComponent.js +59 -0
- package/dist/esm/core/external-providers/useWebsiteProviderComponent.js.map +1 -0
- package/dist/esm/core/external-providers/useWebsiteProviderScripts.d.ts +15 -5
- package/dist/esm/core/external-providers/useWebsiteProviderScripts.d.ts.map +1 -1
- package/dist/esm/core/external-providers/useWebsiteProviderScripts.js +39 -24
- package/dist/esm/core/external-providers/useWebsiteProviderScripts.js.map +1 -1
- package/dist/esm/core/external-providers/website-provider-sdk-activations.d.ts +11 -0
- package/dist/esm/core/external-providers/website-provider-sdk-activations.d.ts.map +1 -0
- package/dist/esm/core/external-providers/website-provider-sdk-activations.js +14 -0
- package/dist/esm/core/external-providers/website-provider-sdk-activations.js.map +1 -0
- package/dist/esm/core/factories/define-website-page-manifest.d.ts.map +1 -1
- package/dist/esm/core/factories/define-website-section.d.ts +3 -3
- package/dist/esm/core/factories/define-website-section.d.ts.map +1 -1
- package/dist/esm/core/factories/define-website-section.js +3 -3
- package/dist/esm/core/factories/define-website-section.js.map +1 -1
- package/dist/esm/core/hooks/useWebsiteDesignTokens.d.ts.map +1 -1
- package/dist/esm/core/hooks/useWebsiteLabel.d.ts.map +1 -1
- package/dist/esm/core/layouts/WebsitePageLayout.d.ts.map +1 -1
- package/dist/esm/core/layouts/WebsitePageLayout.js +10 -7
- package/dist/esm/core/layouts/WebsitePageLayout.js.map +1 -1
- package/dist/esm/core/layouts/WebsiteSection.d.ts.map +1 -1
- package/dist/esm/core/routing/internal-routing.utils.d.ts.map +1 -1
- package/dist/esm/index.d.ts +30 -65
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +30 -65
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/mdx/BlogPost.d.ts.map +1 -1
- package/dist/esm/mdx/blog-post-collection.config.d.ts.map +1 -1
- package/dist/esm/mdx/blog-post-frontmatter-source.d.ts.map +1 -1
- package/dist/esm/mdx/index.d.ts.map +1 -1
- package/dist/esm/mdx.d.ts.map +1 -1
- package/dist/esm/schemas/blog/blog-post-frontmatter.shared.schemas.d.ts.map +1 -1
- package/dist/esm/schemas/design-tokens/website-design-tokens.shared.schemas.d.ts +35 -6
- package/dist/esm/schemas/design-tokens/website-design-tokens.shared.schemas.d.ts.map +1 -1
- package/dist/esm/schemas/design-tokens/website-design-tokens.shared.schemas.js +39 -5
- package/dist/esm/schemas/design-tokens/website-design-tokens.shared.schemas.js.map +1 -1
- package/dist/esm/schemas/label-keys/website-consent-label-keys.schemas.d.ts.map +1 -1
- package/dist/esm/schemas/label-keys/website-label-key.schemas.d.ts.map +1 -1
- package/dist/esm/schemas/label-keys/website-provider-component-label-keys.schemas.d.ts +32 -0
- package/dist/esm/schemas/label-keys/website-provider-component-label-keys.schemas.d.ts.map +1 -0
- package/dist/esm/schemas/label-keys/website-provider-component-label-keys.schemas.js +36 -0
- package/dist/esm/schemas/label-keys/website-provider-component-label-keys.schemas.js.map +1 -0
- package/dist/esm/schemas/manifests/website-page-manifest.shared.schemas.d.ts.map +1 -1
- package/dist/esm/schemas/manifests/website-root-config.shared.schemas.d.ts +9 -8
- package/dist/esm/schemas/manifests/website-root-config.shared.schemas.d.ts.map +1 -1
- package/dist/esm/schemas/manifests/website-root-config.shared.schemas.js +8 -7
- package/dist/esm/schemas/manifests/website-root-config.shared.schemas.js.map +1 -1
- package/dist/esm/schemas/refs/page-ref.schemas.d.ts.map +1 -1
- package/dist/esm/schemas/refs/section-ref.schemas.d.ts.map +1 -1
- package/dist/esm/schemas/sections/website-section-category.shared.d.ts.map +1 -1
- package/dist/esm/schemas/sections/website-section-definition.shared.schemas.d.ts +14 -7
- package/dist/esm/schemas/sections/website-section-definition.shared.schemas.d.ts.map +1 -1
- package/dist/esm/schemas/sections/website-section-definition.shared.schemas.js +14 -7
- package/dist/esm/schemas/sections/website-section-definition.shared.schemas.js.map +1 -1
- package/dist/esm/schemas/structured-data/pricing-offer-structured-data.shared.d.ts +57 -0
- package/dist/esm/schemas/structured-data/pricing-offer-structured-data.shared.d.ts.map +1 -0
- package/dist/esm/schemas/structured-data/pricing-offer-structured-data.shared.js +76 -0
- package/dist/esm/schemas/structured-data/pricing-offer-structured-data.shared.js.map +1 -0
- package/dist/esm/schemas/structured-data/structured-data-reconciliation.shared.d.ts +23 -0
- package/dist/esm/schemas/structured-data/structured-data-reconciliation.shared.d.ts.map +1 -1
- package/dist/esm/schemas/structured-data/structured-data-reconciliation.shared.js +20 -2
- package/dist/esm/schemas/structured-data/structured-data-reconciliation.shared.js.map +1 -1
- package/dist/esm/schemas/structured-data/website-structured-data.shared.schemas.d.ts +7 -5
- package/dist/esm/schemas/structured-data/website-structured-data.shared.schemas.d.ts.map +1 -1
- package/dist/esm/schemas/structured-data/website-structured-data.shared.schemas.js.map +1 -1
- package/dist/esm/schemas/validators/label-pack.validator.d.ts.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/src/__tests__/bundle-isolation.test.ts +19 -22
- package/src/astro/__tests__/blog-post-bridge.test.tsx +18 -2
- package/src/astro/__tests__/bridge-runtime.test.tsx +21 -3
- package/src/astro/__tests__/label-pack-loader.test.ts +7 -4
- package/src/astro/blog-post-bridge.tsx +19 -5
- package/src/astro/bridge-runtime.tsx +35 -11
- package/src/astro/label-pack-loader.ts +8 -4
- package/src/astro/robots-renderer.ts +15 -15
- package/src/astro/website-page-head.renderer.ts +2 -2
- package/src/astro/website-site-context.ts +5 -2
- package/src/companion-exports.ts +8 -15
- package/src/config/__tests__/website-build-origins.test.ts +52 -0
- package/src/config/define-website-config.ts +10 -10
- package/src/config/load-website-config.ts +25 -14
- package/src/config/load-website-pricing-catalog.ts +52 -0
- package/src/config/load-website-site-context.ts +145 -0
- package/src/config-loader.ts +2 -0
- package/src/core/__tests__/contexts.test.tsx +20 -1
- package/src/core/__tests__/website-consent.test.tsx +2 -1
- package/src/core/anonymous-session/InboundContactForm.tsx +100 -45
- package/src/core/anonymous-session/__tests__/InboundContactForm.labels.test.tsx +108 -0
- package/src/core/anonymous-session/__tests__/InboundContactForm.submission-challenge.test.tsx +139 -0
- package/src/core/anonymous-session/inbound-contact-form.schema.ts +16 -4
- package/src/core/anonymous-session/website-anonymous-session-client.ts +39 -4
- package/src/core/anonymous-session/website-submission-challenge.ts +99 -0
- package/src/core/consent/WebsiteConsentBanner.tsx +11 -10
- package/src/core/contexts/WebsiteRuntimeContext.tsx +25 -5
- package/src/core/contexts/useWebsiteRuntime.ts +33 -2
- package/src/core/external-providers/WebsiteProviderComponent.tsx +153 -0
- package/src/core/external-providers/__tests__/frontend-provider-registry.website.test.ts +4 -0
- package/src/core/external-providers/__tests__/website-provider-component.test.tsx +238 -0
- package/src/core/external-providers/__tests__/website-provider-sdks.test.tsx +72 -0
- package/src/core/external-providers/provider-component-registry.website.ts +115 -0
- package/src/core/external-providers/useWebsiteProviderComponent.ts +76 -0
- package/src/core/external-providers/useWebsiteProviderScripts.ts +56 -37
- package/src/core/external-providers/website-provider-sdk-activations.ts +23 -0
- package/src/core/factories/define-website-section.ts +3 -3
- package/src/core/layouts/WebsitePageLayout.tsx +11 -6
- package/src/index.ts +31 -65
- package/src/schemas/__tests__/design-token-css-property.test.ts +72 -0
- package/src/schemas/__tests__/pricing-offer-structured-data.test.ts +122 -0
- package/src/schemas/__tests__/structured-data-reconciliation.test.ts +35 -0
- package/src/schemas/design-tokens/website-design-tokens.shared.schemas.ts +45 -5
- package/src/schemas/label-keys/__tests__/scaffolded-consent-label-pack.parity.test.ts +12 -0
- package/src/schemas/label-keys/website-provider-component-label-keys.schemas.ts +40 -0
- package/src/schemas/manifests/website-root-config.shared.schemas.ts +10 -9
- package/src/schemas/sections/website-section-definition.shared.schemas.ts +14 -7
- package/src/schemas/structured-data/pricing-offer-structured-data.shared.ts +144 -0
- package/src/schemas/structured-data/structured-data-reconciliation.shared.ts +46 -1
- package/src/schemas/structured-data/website-structured-data.shared.schemas.ts +7 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WebsiteInternalButton.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"WebsiteInternalButton.d.ts","sourceRoot":"","sources":["../../../../src/components/low-level/WebsiteInternalButton.tsx"],"names":[],"mappings":"AAAA,OAAc,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAOlE,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EAC1B,MAAM,iBAAiB,CAAC;AAmBzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgEG;AACH,MAAM,WAAW,0BAA0B;IACzC;;;;;;OAMG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,OAAO,EACP,IAAI,EACJ,SAAS,EACT,KAAK,EACL,EAAE,EACF,SAAS,EACT,QAAQ,GACT,EAAE,0BAA0B,GAAG,SAAS,CA+CxC;yBAxDe,qBAAqB;;;AA0DrC,qEAAqE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WebsiteInternalLink.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"WebsiteInternalLink.d.ts","sourceRoot":"","sources":["../../../../src/components/low-level/WebsiteInternalLink.tsx"],"names":[],"mappings":"AAAA,OAAc,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AASlE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwEG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;;;;OAMG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAqCD,wBAAgB,mBAAmB,CAAC,EAClC,SAAS,EACT,SAAS,EACT,KAAK,EACL,EAAE,EACF,SAAS,EACT,QAAQ,GACT,EAAE,wBAAwB,GAAG,SAAS,CA8CtC;yBArDe,mBAAmB;;;AAuDnC,mEAAmE"}
|
|
@@ -13,8 +13,9 @@
|
|
|
13
13
|
*
|
|
14
14
|
* The warner has ZERO branches today because every OPTIONAL field that
|
|
15
15
|
* exists is already wired (`csp?` now flows through the website-local
|
|
16
|
-
* CSP sync step) and
|
|
17
|
-
*
|
|
16
|
+
* CSP sync step), and every REQUIRED field has a runtime consumer too —
|
|
17
|
+
* `appOrigin` reaches every CTA through `WebsiteRuntimeContext.appOrigin`,
|
|
18
|
+
* settled per build by `loadWebsiteSiteContext`. After the seam-collapse (`saas-website-seam-collapse.md`
|
|
18
19
|
* — SHIPPED), the routing/origin fields (`publicOrigin`,
|
|
19
20
|
* `defaultLocale`, `locales`) are consumed directly by every Astro
|
|
20
21
|
* engine helper via `WebsiteSiteContext`, so they are no longer
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define-website-config.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"define-website-config.d.ts","sourceRoot":"","sources":["../../../src/config/define-website-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAEH,OAAO,EAEL,KAAK,2BAA2B,EAChC,KAAK,gCAAgC,EACtC,MAAM,gCAAgC,CAAC;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,gCAAgC,GACvC,2BAA2B,CAI7B"}
|
|
@@ -13,8 +13,9 @@
|
|
|
13
13
|
*
|
|
14
14
|
* The warner has ZERO branches today because every OPTIONAL field that
|
|
15
15
|
* exists is already wired (`csp?` now flows through the website-local
|
|
16
|
-
* CSP sync step) and
|
|
17
|
-
*
|
|
16
|
+
* CSP sync step), and every REQUIRED field has a runtime consumer too —
|
|
17
|
+
* `appOrigin` reaches every CTA through `WebsiteRuntimeContext.appOrigin`,
|
|
18
|
+
* settled per build by `loadWebsiteSiteContext`. After the seam-collapse (`saas-website-seam-collapse.md`
|
|
18
19
|
* — SHIPPED), the routing/origin fields (`publicOrigin`,
|
|
19
20
|
* `defaultLocale`, `locales`) are consumed directly by every Astro
|
|
20
21
|
* engine helper via `WebsiteSiteContext`, so they are no longer
|
|
@@ -90,14 +91,13 @@ export function defineWebsiteConfig(config) {
|
|
|
90
91
|
* but has no runtime consumer yet.
|
|
91
92
|
*
|
|
92
93
|
* Branches today: ZERO. The one OPTIONAL field that exists (`csp?`) is
|
|
93
|
-
* fully wired through the website-local CSP sync/build path
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
* `@unimplemented` warner concern.
|
|
94
|
+
* fully wired through the website-local CSP sync/build path. After the
|
|
95
|
+
* seam-collapse (`saas-website-seam-collapse.md` — SHIPPED) the
|
|
96
|
+
* routing/origin fields are consumed directly by every Astro engine
|
|
97
|
+
* helper via `WebsiteSiteContext`, and `appOrigin` / `apiOrigin` are
|
|
98
|
+
* settled per build by `loadWebsiteSiteContext` and read by every page.
|
|
99
|
+
* A required field could never fire this warner anyway — it would fire
|
|
100
|
+
* on every parse.
|
|
101
101
|
*
|
|
102
102
|
* The function exists as a structural mirror of
|
|
103
103
|
* `defineTechnicalDocConfig.emitUnimplementedRuntimeWarnings` so
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define-website-config.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"define-website-config.js","sourceRoot":"","sources":["../../../src/config/define-website-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;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 every REQUIRED field has a runtime consumer too —\n * `appOrigin` reaches every CTA through `WebsiteRuntimeContext.appOrigin`,\n * settled per build by `loadWebsiteSiteContext`. 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. After the\n * seam-collapse (`saas-website-seam-collapse.md` — SHIPPED) the\n * routing/origin fields are consumed directly by every Astro engine\n * helper via `WebsiteSiteContext`, and `appOrigin` / `apiOrigin` are\n * settled per build by `loadWebsiteSiteContext` and read by every page.\n * A required field could never fire this warner anyway — it would fire\n * on every parse.\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"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["
|
|
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"}
|
|
@@ -93,6 +93,12 @@ export interface LoadWebsiteConfigArgs {
|
|
|
93
93
|
*/
|
|
94
94
|
saasConfig: WildoSaasConfig;
|
|
95
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* The application's one `STATIC_WEBSITE` service, as `[serviceKey, service]`.
|
|
98
|
+
* Throws when none is declared: the service folder is what owns
|
|
99
|
+
* `wildo.website.config.ts`, so a website build without one has nothing to load.
|
|
100
|
+
*/
|
|
101
|
+
export declare function resolveStaticWebsiteServiceEntry(saasConfig: WildoSaasConfig): [string, WildoSaasConfig['services'][string]];
|
|
96
102
|
/**
|
|
97
103
|
* Discover and load the per-service marketing-website config.
|
|
98
104
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load-website-config.d.ts","sourceRoot":"","sources":["
|
|
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;AAGlF;;;;;;;;;;;;;;;;;;;;;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;;;;GAIG;AACH,wBAAgB,gCAAgC,CAC9C,UAAU,EAAE,eAAe,GAC1B,CAAC,MAAM,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAe/C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,2BAA2B,CAAC,CA+CtC"}
|
|
@@ -92,6 +92,23 @@ export function primeWebsiteConfigCache(absoluteConfigPath, config) {
|
|
|
92
92
|
export function clearWebsiteConfigCache() {
|
|
93
93
|
WEBSITE_CONFIG_CACHE.clear();
|
|
94
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* The application's one `STATIC_WEBSITE` service, as `[serviceKey, service]`.
|
|
97
|
+
* Throws when none is declared: the service folder is what owns
|
|
98
|
+
* `wildo.website.config.ts`, so a website build without one has nothing to load.
|
|
99
|
+
*/
|
|
100
|
+
export function resolveStaticWebsiteServiceEntry(saasConfig) {
|
|
101
|
+
const websiteServiceEntry = Object.entries(saasConfig.services).find(([, service]) => service.frontendType === AppFrontendType.STATIC_WEBSITE);
|
|
102
|
+
if (!websiteServiceEntry) {
|
|
103
|
+
throw new Error('[wildo-website-config] No frontend service with `frontendType: STATIC_WEBSITE` is declared in '
|
|
104
|
+
+ 'wildo.saas.config.ts. The marketing-website Astro build / loader requires an authored '
|
|
105
|
+
+ 'STATIC_WEBSITE service because that service folder owns the per-service '
|
|
106
|
+
+ '`wildo.website.config.ts` (publicOrigin, appOrigin, defaultLocale, locales). '
|
|
107
|
+
+ 'Add a STATIC_WEBSITE service in wildo.saas.config.ts and ship the per-service '
|
|
108
|
+
+ 'config file under it.');
|
|
109
|
+
}
|
|
110
|
+
return websiteServiceEntry;
|
|
111
|
+
}
|
|
95
112
|
/**
|
|
96
113
|
* Discover and load the per-service marketing-website config.
|
|
97
114
|
*
|
|
@@ -133,15 +150,7 @@ export function clearWebsiteConfigCache() {
|
|
|
133
150
|
*/
|
|
134
151
|
export async function loadWebsiteConfig(args) {
|
|
135
152
|
const { saasRoot, saasConfig } = args;
|
|
136
|
-
const websiteServiceEntry =
|
|
137
|
-
if (!websiteServiceEntry) {
|
|
138
|
-
throw new Error('[wildo-website-config] No frontend service with `frontendType: STATIC_WEBSITE` is declared in '
|
|
139
|
-
+ 'wildo.saas.config.ts. The marketing-website Astro build / loader requires an authored '
|
|
140
|
-
+ 'STATIC_WEBSITE service because that service folder owns the per-service '
|
|
141
|
-
+ '`wildo.website.config.ts` (publicOrigin, appOrigin, defaultLocale, locales). '
|
|
142
|
-
+ 'Add a STATIC_WEBSITE service in wildo.saas.config.ts and ship the per-service '
|
|
143
|
-
+ 'config file under it.');
|
|
144
|
-
}
|
|
153
|
+
const websiteServiceEntry = resolveStaticWebsiteServiceEntry(saasConfig);
|
|
145
154
|
const [websiteServiceKey, websiteService] = websiteServiceEntry;
|
|
146
155
|
const websiteConfigPath = resolvePath(saasRoot, websiteService.path, PER_SERVICE_WEBSITE_CONFIG_FILE_NAME);
|
|
147
156
|
const cached = WEBSITE_CONFIG_CACHE.get(websiteConfigPath);
|
|
@@ -1 +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,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E;;;;;;;;;;;;;;;;;;;;;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,mBAAmB,CAAC,CAAC,CAAC,CAAC;QACrC,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\nimport { describeThrownValue } from '@wildo-ai/saas-models/public-runtime';\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 = describeThrownValue(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"]}
|
|
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,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E;;;;;;;;;;;;;;;;;;;;;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;;;;GAIG;AACH,MAAM,UAAU,gCAAgC,CAC9C,UAA2B;IAE3B,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;IACD,OAAO,mBAAmB,CAAC;AAC7B,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAA2B;IAE3B,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;IACtC,MAAM,mBAAmB,GAAG,gCAAgC,CAAC,UAAU,CAAC,CAAC;IAEzE,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,mBAAmB,CAAC,CAAC,CAAC,CAAC;QACrC,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\nimport { describeThrownValue } from '@wildo-ai/saas-models/public-runtime';\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 * The application's one `STATIC_WEBSITE` service, as `[serviceKey, service]`.\n * Throws when none is declared: the service folder is what owns\n * `wildo.website.config.ts`, so a website build without one has nothing to load.\n */\nexport function resolveStaticWebsiteServiceEntry(\n saasConfig: WildoSaasConfig,\n): [string, WildoSaasConfig['services'][string]] {\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 return websiteServiceEntry;\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 const websiteServiceEntry = resolveStaticWebsiteServiceEntry(saasConfig);\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 = describeThrownValue(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"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PublicPricingCatalog } from '@wildo-ai/saas-models/public-runtime';
|
|
2
|
+
export interface LoadWebsitePricingCatalogInput {
|
|
3
|
+
/** Where to start the walk up to `wildo.saas.config.ts`. Defaults to the working directory. */
|
|
4
|
+
readonly cwd?: string | undefined;
|
|
5
|
+
/**
|
|
6
|
+
* Keep only plans this scope may subscribe to (a `ResourcePrimaryScope` wire value, e.g.
|
|
7
|
+
* `'organizations'`). Omit when the catalogue sells to one audience.
|
|
8
|
+
*/
|
|
9
|
+
readonly targetScope?: string | undefined;
|
|
10
|
+
}
|
|
11
|
+
export declare function loadWebsitePricingCatalog(input?: LoadWebsitePricingCatalogInput): Promise<PublicPricingCatalog>;
|
|
12
|
+
/** @wildo_source:part:end saas.website.config.pricing-catalog-loader */
|
|
13
|
+
//# sourceMappingURL=load-website-pricing-catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-website-pricing-catalog.d.ts","sourceRoot":"","sources":["../../../src/config/load-website-pricing-catalog.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAEjF,MAAM,WAAW,8BAA8B;IAC7C,+FAA+F;IAC/F,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3C;AAED,wBAAsB,yBAAyB,CAAC,KAAK,GAAE,8BAAmC,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAczH;AACD,wEAAwE"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @wildo_source:part:start saas.website.config.pricing-catalog-loader facet:layer:astro facet:family:website facet:audience:app-developer
|
|
3
|
+
*
|
|
4
|
+
* `loadWebsitePricingCatalog` — the application's public pricing catalogue, for a website's pricing
|
|
5
|
+
* page (#1835). Call it in the page's `.astro` frontmatter, pass the result to the bridge island as
|
|
6
|
+
* `pricingCatalog`, and read it in the section with `useWebsitePricingCatalog()`; build the page's
|
|
7
|
+
* `AggregateOffer` from the same value with `buildWebsitePricingOfferStructuredData`.
|
|
8
|
+
*
|
|
9
|
+
* It walks up to `wildo.saas.config.ts` the way `loadWebsiteSiteContext` does, and reads the billing
|
|
10
|
+
* catalogue the backend sells from — the `productDefinitions` of the application's shared modules —
|
|
11
|
+
* through `loadApplicationPublicPricingCatalog`, from SOURCE, so a website image that builds only the
|
|
12
|
+
* website still sees the current catalogue.
|
|
13
|
+
*
|
|
14
|
+
* Separate from `loadWebsiteSiteContext` on purpose: loading the shared graph costs seconds, and only a
|
|
15
|
+
* pricing page needs it. Every other page's build stays as fast as it was.
|
|
16
|
+
*
|
|
17
|
+
* **Node-only.** Lives on the `/config-loader` subpath; it must never reach a React-island bundle.
|
|
18
|
+
*/
|
|
19
|
+
import { loadApplicationPublicPricingCatalog, loadConfig, resolveWorkspaceScope, } from '@wildo-ai/platform-config-lib';
|
|
20
|
+
export async function loadWebsitePricingCatalog(input = {}) {
|
|
21
|
+
const workspaceScope = resolveWorkspaceScope(input.cwd);
|
|
22
|
+
if (workspaceScope.saasRoot === null || workspaceScope.saasConfigPath === null) {
|
|
23
|
+
throw new Error(`[saas-website] No wildo.saas.config.ts found walking up from ${input.cwd ?? process.cwd()}. `
|
|
24
|
+
+ 'Run astro from inside the application workspace.');
|
|
25
|
+
}
|
|
26
|
+
const saasConfig = await loadConfig(workspaceScope.saasConfigPath);
|
|
27
|
+
return loadApplicationPublicPricingCatalog({
|
|
28
|
+
saasRoot: workspaceScope.saasRoot,
|
|
29
|
+
saasConfig,
|
|
30
|
+
...(input.targetScope === undefined ? {} : { targetScope: input.targetScope }),
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/** @wildo_source:part:end saas.website.config.pricing-catalog-loader */
|
|
34
|
+
//# sourceMappingURL=load-website-pricing-catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-website-pricing-catalog.js","sourceRoot":"","sources":["../../../src/config/load-website-pricing-catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EACL,mCAAmC,EACnC,UAAU,EACV,qBAAqB,GAEtB,MAAM,+BAA+B,CAAC;AAavC,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,QAAwC,EAAE;IACxF,MAAM,cAAc,GAAG,qBAAqB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACxD,IAAI,cAAc,CAAC,QAAQ,KAAK,IAAI,IAAI,cAAc,CAAC,cAAc,KAAK,IAAI,EAAE,CAAC;QAC/E,MAAM,IAAI,KAAK,CACb,gEAAgE,KAAK,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,IAAI;cAC1F,kDAAkD,CACvD,CAAC;IACJ,CAAC;IACD,MAAM,UAAU,GAAG,MAAM,UAAU,CAAkB,cAAc,CAAC,cAAc,CAAC,CAAC;IACpF,OAAO,mCAAmC,CAAC;QACzC,QAAQ,EAAE,cAAc,CAAC,QAAQ;QACjC,UAAU;QACV,GAAG,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;KAC/E,CAAC,CAAC;AACL,CAAC;AACD,wEAAwE","sourcesContent":["/**\n * @wildo_source:part:start saas.website.config.pricing-catalog-loader facet:layer:astro facet:family:website facet:audience:app-developer\n *\n * `loadWebsitePricingCatalog` — the application's public pricing catalogue, for a website's pricing\n * page (#1835). Call it in the page's `.astro` frontmatter, pass the result to the bridge island as\n * `pricingCatalog`, and read it in the section with `useWebsitePricingCatalog()`; build the page's\n * `AggregateOffer` from the same value with `buildWebsitePricingOfferStructuredData`.\n *\n * It walks up to `wildo.saas.config.ts` the way `loadWebsiteSiteContext` does, and reads the billing\n * catalogue the backend sells from — the `productDefinitions` of the application's shared modules —\n * through `loadApplicationPublicPricingCatalog`, from SOURCE, so a website image that builds only the\n * website still sees the current catalogue.\n *\n * Separate from `loadWebsiteSiteContext` on purpose: loading the shared graph costs seconds, and only a\n * pricing page needs it. Every other page's build stays as fast as it was.\n *\n * **Node-only.** Lives on the `/config-loader` subpath; it must never reach a React-island bundle.\n */\nimport {\n loadApplicationPublicPricingCatalog,\n loadConfig,\n resolveWorkspaceScope,\n type WildoSaasConfig,\n} from '@wildo-ai/platform-config-lib';\nimport type { PublicPricingCatalog } from '@wildo-ai/saas-models/public-runtime';\n\nexport interface LoadWebsitePricingCatalogInput {\n /** Where to start the walk up to `wildo.saas.config.ts`. Defaults to the working directory. */\n readonly cwd?: string | undefined;\n /**\n * Keep only plans this scope may subscribe to (a `ResourcePrimaryScope` wire value, e.g.\n * `'organizations'`). Omit when the catalogue sells to one audience.\n */\n readonly targetScope?: string | undefined;\n}\n\nexport async function loadWebsitePricingCatalog(input: LoadWebsitePricingCatalogInput = {}): Promise<PublicPricingCatalog> {\n const workspaceScope = resolveWorkspaceScope(input.cwd);\n if (workspaceScope.saasRoot === null || workspaceScope.saasConfigPath === null) {\n throw new Error(\n `[saas-website] No wildo.saas.config.ts found walking up from ${input.cwd ?? process.cwd()}. `\n + 'Run astro from inside the application workspace.',\n );\n }\n const saasConfig = await loadConfig<WildoSaasConfig>(workspaceScope.saasConfigPath);\n return loadApplicationPublicPricingCatalog({\n saasRoot: workspaceScope.saasRoot,\n saasConfig,\n ...(input.targetScope === undefined ? {} : { targetScope: input.targetScope }),\n });\n}\n/** @wildo_source:part:end saas.website.config.pricing-catalog-loader */\n"]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { type LocalhostApplicationOrigins } from '@wildo-ai/platform-config-lib';
|
|
2
|
+
import { type WebsiteSiteContext } from '../astro/website-site-context';
|
|
3
|
+
import type { WebsiteRootConfig } from '../schemas/manifests/website-root-config.shared.schemas';
|
|
4
|
+
import type { WildoMarketingWebsiteConfig } from './wildo-website-config.schemas';
|
|
5
|
+
/** Explicit per-build origin overrides — what a deploy build passes as build arguments. */
|
|
6
|
+
export interface WebsiteOriginOverrides {
|
|
7
|
+
/** `PUBLIC_APP_ORIGIN`: this environment's product origin, derived by the deploy workflow. */
|
|
8
|
+
readonly appOrigin?: string | undefined;
|
|
9
|
+
/** `PUBLIC_API_ORIGIN`: this environment's API origin. */
|
|
10
|
+
readonly apiOrigin?: string | undefined;
|
|
11
|
+
}
|
|
12
|
+
export interface ResolveWebsiteBuildOriginsInput {
|
|
13
|
+
/** The authored `wildo.website.config.ts` — the production default. */
|
|
14
|
+
readonly websiteConfig: WildoMarketingWebsiteConfig;
|
|
15
|
+
/** `true` under `astro dev`. */
|
|
16
|
+
readonly isDevelopment: boolean;
|
|
17
|
+
/** Where the product and API run locally, from the app's own declared ports. */
|
|
18
|
+
readonly localOrigins: LocalhostApplicationOrigins;
|
|
19
|
+
/** Explicit overrides, which win over everything. */
|
|
20
|
+
readonly overrides: WebsiteOriginOverrides;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The `websiteConfig` this BUILD serves, with `appOrigin` and `apiOrigin` settled.
|
|
24
|
+
*
|
|
25
|
+
* Precedence, per origin:
|
|
26
|
+
*
|
|
27
|
+
* 1. an explicit override (`PUBLIC_APP_ORIGIN` / `PUBLIC_API_ORIGIN`) — the deploy
|
|
28
|
+
* workflow derives these per environment, so a staging build links into staging;
|
|
29
|
+
* 2. under `astro dev`, the locally running product / API, from the ports the
|
|
30
|
+
* application declares — so a CTA reaches the process `wildo local dev` started;
|
|
31
|
+
* 3. the value authored in `wildo.website.config.ts`.
|
|
32
|
+
*
|
|
33
|
+
* The result replaces the two fields in `websiteConfig` rather than living beside
|
|
34
|
+
* it, because every page already forwards `websiteConfig.appOrigin` /
|
|
35
|
+
* `websiteConfig.apiOrigin` into its island: a second field would be a second
|
|
36
|
+
* source that pages could read instead. `websiteConfig` in a site context is
|
|
37
|
+
* therefore "the config as it applies to this build", which the config file was
|
|
38
|
+
* already half-way to being — it reads `PUBLIC_APP_ORIGIN` itself.
|
|
39
|
+
*/
|
|
40
|
+
export declare function resolveWebsiteBuildOrigins(input: ResolveWebsiteBuildOriginsInput): WildoMarketingWebsiteConfig;
|
|
41
|
+
export interface LoadWebsiteSiteContextInput {
|
|
42
|
+
/** The workspace's `WEBSITE_ROOT_CONFIG`. */
|
|
43
|
+
readonly rootConfig: WebsiteRootConfig;
|
|
44
|
+
/** Pass `import.meta.env?.DEV === true` (optional chaining: `astro.config.ts` evaluates the caller before Vite's env exists). */
|
|
45
|
+
readonly isDevelopment: boolean;
|
|
46
|
+
/** Where to start the walk up to `wildo.saas.config.ts`. Defaults to the working directory. */
|
|
47
|
+
readonly cwd?: string | undefined;
|
|
48
|
+
/** Defaults to `PUBLIC_APP_ORIGIN` / `PUBLIC_API_ORIGIN` from the process environment. */
|
|
49
|
+
readonly overrides?: WebsiteOriginOverrides | undefined;
|
|
50
|
+
}
|
|
51
|
+
export declare function loadWebsiteSiteContext(input: LoadWebsiteSiteContextInput): Promise<WebsiteSiteContext>;
|
|
52
|
+
/** @wildo_source:part:end saas.website.config.site-context-loader */
|
|
53
|
+
//# sourceMappingURL=load-website-site-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-website-site-context.d.ts","sourceRoot":"","sources":["../../../src/config/load-website-site-context.ts"],"names":[],"mappings":"AA0CA,OAAO,EAML,KAAK,2BAA2B,EAEjC,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAA6B,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yDAAyD,CAAC;AAEjG,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAC;AAElF,2FAA2F;AAC3F,MAAM,WAAW,sBAAsB;IACrC,8FAA8F;IAC9F,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC;AAED,MAAM,WAAW,+BAA+B;IAC9C,uEAAuE;IACvE,QAAQ,CAAC,aAAa,EAAE,2BAA2B,CAAC;IACpD,gCAAgC;IAChC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,gFAAgF;IAChF,QAAQ,CAAC,YAAY,EAAE,2BAA2B,CAAC;IACnD,qDAAqD;IACrD,QAAQ,CAAC,SAAS,EAAE,sBAAsB,CAAC;CAC5C;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,+BAA+B,GAAG,2BAA2B,CAO9G;AAED,MAAM,WAAW,2BAA2B;IAC1C,6CAA6C;IAC7C,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAC;IACvC,iIAAiI;IACjI,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,+FAA+F;IAC/F,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,0FAA0F;IAC1F,QAAQ,CAAC,SAAS,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAAC;CACzD;AAED,wBAAsB,sBAAsB,CAAC,KAAK,EAAE,2BAA2B,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA6B5G;AACD,qEAAqE"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @wildo_source:part:start saas.website.config.site-context-loader facet:layer:astro facet:family:website facet:audience:app-developer
|
|
3
|
+
*
|
|
4
|
+
* `loadWebsiteSiteContext` — the ONE way a website workspace builds its
|
|
5
|
+
* `WebsiteSiteContext`. Called once, from the workspace's
|
|
6
|
+
* `src/website-site-context.ts`:
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { loadWebsiteSiteContext } from '@wildo-ai/saas-website/config-loader';
|
|
10
|
+
* import { WEBSITE_ROOT_CONFIG } from './website-root.config.js';
|
|
11
|
+
*
|
|
12
|
+
* export const WEBSITE_SITE_CONTEXT = await loadWebsiteSiteContext({
|
|
13
|
+
* rootConfig: WEBSITE_ROOT_CONFIG,
|
|
14
|
+
* isDevelopment: import.meta.env?.DEV === true,
|
|
15
|
+
* });
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* It walks up from the working directory to `wildo.saas.config.ts`, finds the
|
|
19
|
+
* application's single `STATIC_WEBSITE` service, loads that service's
|
|
20
|
+
* `wildo.website.config.ts` and its materialized provider block, and settles the
|
|
21
|
+
* two origins the site reaches the product through (see
|
|
22
|
+
* {@link resolveWebsiteBuildOrigins}).
|
|
23
|
+
*
|
|
24
|
+
* **Why the engine owns this.** Every website workspace used to carry its own
|
|
25
|
+
* copy of this lookup — the scaffolded ones and the hand-written ones alike —
|
|
26
|
+
* and each copy hardcoded its local API port while the app origin had no local
|
|
27
|
+
* form at all. The result: under `astro dev`, every "Start free" CTA pointed at a
|
|
28
|
+
* production-shaped host that resolves to nothing. One loader means one rule.
|
|
29
|
+
*
|
|
30
|
+
* **Why it walks up from the working directory, never from `import.meta.url`.**
|
|
31
|
+
* Astro's prerender pass bundles the calling module into `dist/.prerender/chunks/…`,
|
|
32
|
+
* where a `new URL('../..', import.meta.url)` anchor resolves to `dist/` rather than
|
|
33
|
+
* the application root — every prerendered route then failed with "Config file not
|
|
34
|
+
* found: …/website/dist/wildo.saas.config.ts", while `astro dev` hid it by serving
|
|
35
|
+
* from `src/`. Every `astro dev` / `astro build` runs with the website package (or
|
|
36
|
+
* an ancestor) as its working directory, which is inside the application either way.
|
|
37
|
+
*
|
|
38
|
+
* **Node-only.** Lives on the `/config-loader` subpath with the other loaders; it
|
|
39
|
+
* must never reach a React-island bundle.
|
|
40
|
+
*/
|
|
41
|
+
import { resolve as resolvePath } from 'node:path';
|
|
42
|
+
import { loadConfig, loadMaterializedFrontendProviders, resolveFrontendServicesArtifactPath, resolveLocalhostApplicationOrigins, resolveWorkspaceScope, } from '@wildo-ai/platform-config-lib';
|
|
43
|
+
import { composeWebsiteSiteContext } from '../astro/website-site-context.js';
|
|
44
|
+
import { loadWebsiteConfig, resolveStaticWebsiteServiceEntry } from './load-website-config.js';
|
|
45
|
+
/**
|
|
46
|
+
* The `websiteConfig` this BUILD serves, with `appOrigin` and `apiOrigin` settled.
|
|
47
|
+
*
|
|
48
|
+
* Precedence, per origin:
|
|
49
|
+
*
|
|
50
|
+
* 1. an explicit override (`PUBLIC_APP_ORIGIN` / `PUBLIC_API_ORIGIN`) — the deploy
|
|
51
|
+
* workflow derives these per environment, so a staging build links into staging;
|
|
52
|
+
* 2. under `astro dev`, the locally running product / API, from the ports the
|
|
53
|
+
* application declares — so a CTA reaches the process `wildo local dev` started;
|
|
54
|
+
* 3. the value authored in `wildo.website.config.ts`.
|
|
55
|
+
*
|
|
56
|
+
* The result replaces the two fields in `websiteConfig` rather than living beside
|
|
57
|
+
* it, because every page already forwards `websiteConfig.appOrigin` /
|
|
58
|
+
* `websiteConfig.apiOrigin` into its island: a second field would be a second
|
|
59
|
+
* source that pages could read instead. `websiteConfig` in a site context is
|
|
60
|
+
* therefore "the config as it applies to this build", which the config file was
|
|
61
|
+
* already half-way to being — it reads `PUBLIC_APP_ORIGIN` itself.
|
|
62
|
+
*/
|
|
63
|
+
export function resolveWebsiteBuildOrigins(input) {
|
|
64
|
+
const { websiteConfig, isDevelopment, localOrigins, overrides } = input;
|
|
65
|
+
const settle = (override, local, authored) => override || (isDevelopment ? local : undefined) || authored;
|
|
66
|
+
const appOrigin = settle(overrides.appOrigin, localOrigins.app, websiteConfig.appOrigin) ?? websiteConfig.appOrigin;
|
|
67
|
+
const apiOrigin = settle(overrides.apiOrigin, localOrigins.api, websiteConfig.apiOrigin);
|
|
68
|
+
return { ...websiteConfig, appOrigin, ...(apiOrigin === undefined ? {} : { apiOrigin }) };
|
|
69
|
+
}
|
|
70
|
+
export async function loadWebsiteSiteContext(input) {
|
|
71
|
+
const workspaceScope = resolveWorkspaceScope(input.cwd);
|
|
72
|
+
if (workspaceScope.saasRoot === null || workspaceScope.saasConfigPath === null) {
|
|
73
|
+
throw new Error(`[saas-website] No wildo.saas.config.ts found walking up from ${input.cwd ?? process.cwd()}. `
|
|
74
|
+
+ 'Run astro from inside the application workspace.');
|
|
75
|
+
}
|
|
76
|
+
const saasRoot = workspaceScope.saasRoot;
|
|
77
|
+
const saasConfig = await loadConfig(workspaceScope.saasConfigPath);
|
|
78
|
+
const [websiteServiceKey] = resolveStaticWebsiteServiceEntry(saasConfig);
|
|
79
|
+
const websiteConfig = await loadWebsiteConfig({ saasRoot, saasConfig });
|
|
80
|
+
return composeWebsiteSiteContext({
|
|
81
|
+
rootConfig: input.rootConfig,
|
|
82
|
+
websiteConfig: resolveWebsiteBuildOrigins({
|
|
83
|
+
websiteConfig,
|
|
84
|
+
isDevelopment: input.isDevelopment,
|
|
85
|
+
localOrigins: resolveLocalhostApplicationOrigins(saasConfig.services),
|
|
86
|
+
overrides: input.overrides ?? {
|
|
87
|
+
appOrigin: process.env.PUBLIC_APP_ORIGIN,
|
|
88
|
+
apiOrigin: process.env.PUBLIC_API_ORIGIN,
|
|
89
|
+
},
|
|
90
|
+
}),
|
|
91
|
+
frontendProviders: loadMaterializedFrontendProviders({
|
|
92
|
+
artifactPath: resolveFrontendServicesArtifactPath(resolvePath(saasRoot)),
|
|
93
|
+
serviceKey: websiteServiceKey,
|
|
94
|
+
}),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/** @wildo_source:part:end saas.website.config.site-context-loader */
|
|
98
|
+
//# sourceMappingURL=load-website-site-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-website-site-context.js","sourceRoot":"","sources":["../../../src/config/load-website-site-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;AAEnD,OAAO,EACL,UAAU,EACV,iCAAiC,EACjC,mCAAmC,EACnC,kCAAkC,EAClC,qBAAqB,GAGtB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAE,yBAAyB,EAA2B,MAAM,+BAA+B,CAAC;AAEnG,OAAO,EAAE,iBAAiB,EAAE,gCAAgC,EAAE,MAAM,uBAAuB,CAAC;AAsB5F;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,0BAA0B,CAAC,KAAsC;IAC/E,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IACxE,MAAM,MAAM,GAAG,CAAC,QAA4B,EAAE,KAAyB,EAAE,QAA4B,EAAsB,EAAE,CAC3H,QAAQ,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,QAAQ,CAAC;IAC9D,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,EAAE,aAAa,CAAC,SAAS,CAAC,IAAI,aAAa,CAAC,SAAS,CAAC;IACpH,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IACzF,OAAO,EAAE,GAAG,aAAa,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;AAC5F,CAAC;AAaD,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,KAAkC;IAC7E,MAAM,cAAc,GAAG,qBAAqB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACxD,IAAI,cAAc,CAAC,QAAQ,KAAK,IAAI,IAAI,cAAc,CAAC,cAAc,KAAK,IAAI,EAAE,CAAC;QAC/E,MAAM,IAAI,KAAK,CACb,gEAAgE,KAAK,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,IAAI;cAC1F,kDAAkD,CACvD,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC;IACzC,MAAM,UAAU,GAAG,MAAM,UAAU,CAAkB,cAAc,CAAC,cAAc,CAAC,CAAC;IACpF,MAAM,CAAC,iBAAiB,CAAC,GAAG,gCAAgC,CAAC,UAAU,CAAC,CAAC;IACzE,MAAM,aAAa,GAAG,MAAM,iBAAiB,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;IAExE,OAAO,yBAAyB,CAAC;QAC/B,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,aAAa,EAAE,0BAA0B,CAAC;YACxC,aAAa;YACb,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,YAAY,EAAE,kCAAkC,CAAC,UAAU,CAAC,QAAQ,CAAC;YACrE,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI;gBAC5B,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB;gBACxC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB;aACzC;SACF,CAAC;QACF,iBAAiB,EAAE,iCAAiC,CAAC;YACnD,YAAY,EAAE,mCAAmC,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;YACxE,UAAU,EAAE,iBAAiB;SAC9B,CAAC;KACH,CAAC,CAAC;AACL,CAAC;AACD,qEAAqE","sourcesContent":["/**\n * @wildo_source:part:start saas.website.config.site-context-loader facet:layer:astro facet:family:website facet:audience:app-developer\n *\n * `loadWebsiteSiteContext` — the ONE way a website workspace builds its\n * `WebsiteSiteContext`. Called once, from the workspace's\n * `src/website-site-context.ts`:\n *\n * ```ts\n * import { loadWebsiteSiteContext } from '@wildo-ai/saas-website/config-loader';\n * import { WEBSITE_ROOT_CONFIG } from './website-root.config';\n *\n * export const WEBSITE_SITE_CONTEXT = await loadWebsiteSiteContext({\n * rootConfig: WEBSITE_ROOT_CONFIG,\n * isDevelopment: import.meta.env?.DEV === true,\n * });\n * ```\n *\n * It walks up from the working directory to `wildo.saas.config.ts`, finds the\n * application's single `STATIC_WEBSITE` service, loads that service's\n * `wildo.website.config.ts` and its materialized provider block, and settles the\n * two origins the site reaches the product through (see\n * {@link resolveWebsiteBuildOrigins}).\n *\n * **Why the engine owns this.** Every website workspace used to carry its own\n * copy of this lookup — the scaffolded ones and the hand-written ones alike —\n * and each copy hardcoded its local API port while the app origin had no local\n * form at all. The result: under `astro dev`, every \"Start free\" CTA pointed at a\n * production-shaped host that resolves to nothing. One loader means one rule.\n *\n * **Why it walks up from the working directory, never from `import.meta.url`.**\n * Astro's prerender pass bundles the calling module into `dist/.prerender/chunks/…`,\n * where a `new URL('../..', import.meta.url)` anchor resolves to `dist/` rather than\n * the application root — every prerendered route then failed with \"Config file not\n * found: …/website/dist/wildo.saas.config.ts\", while `astro dev` hid it by serving\n * from `src/`. Every `astro dev` / `astro build` runs with the website package (or\n * an ancestor) as its working directory, which is inside the application either way.\n *\n * **Node-only.** Lives on the `/config-loader` subpath with the other loaders; it\n * must never reach a React-island bundle.\n */\nimport { resolve as resolvePath } from 'node:path';\n\nimport {\n loadConfig,\n loadMaterializedFrontendProviders,\n resolveFrontendServicesArtifactPath,\n resolveLocalhostApplicationOrigins,\n resolveWorkspaceScope,\n type LocalhostApplicationOrigins,\n type WildoSaasConfig,\n} from '@wildo-ai/platform-config-lib';\n\nimport { composeWebsiteSiteContext, type WebsiteSiteContext } from '../astro/website-site-context';\nimport type { WebsiteRootConfig } from '../schemas/manifests/website-root-config.shared.schemas';\nimport { loadWebsiteConfig, resolveStaticWebsiteServiceEntry } from './load-website-config';\nimport type { WildoMarketingWebsiteConfig } from './wildo-website-config.schemas';\n\n/** Explicit per-build origin overrides — what a deploy build passes as build arguments. */\nexport interface WebsiteOriginOverrides {\n /** `PUBLIC_APP_ORIGIN`: this environment's product origin, derived by the deploy workflow. */\n readonly appOrigin?: string | undefined;\n /** `PUBLIC_API_ORIGIN`: this environment's API origin. */\n readonly apiOrigin?: string | undefined;\n}\n\nexport interface ResolveWebsiteBuildOriginsInput {\n /** The authored `wildo.website.config.ts` — the production default. */\n readonly websiteConfig: WildoMarketingWebsiteConfig;\n /** `true` under `astro dev`. */\n readonly isDevelopment: boolean;\n /** Where the product and API run locally, from the app's own declared ports. */\n readonly localOrigins: LocalhostApplicationOrigins;\n /** Explicit overrides, which win over everything. */\n readonly overrides: WebsiteOriginOverrides;\n}\n\n/**\n * The `websiteConfig` this BUILD serves, with `appOrigin` and `apiOrigin` settled.\n *\n * Precedence, per origin:\n *\n * 1. an explicit override (`PUBLIC_APP_ORIGIN` / `PUBLIC_API_ORIGIN`) — the deploy\n * workflow derives these per environment, so a staging build links into staging;\n * 2. under `astro dev`, the locally running product / API, from the ports the\n * application declares — so a CTA reaches the process `wildo local dev` started;\n * 3. the value authored in `wildo.website.config.ts`.\n *\n * The result replaces the two fields in `websiteConfig` rather than living beside\n * it, because every page already forwards `websiteConfig.appOrigin` /\n * `websiteConfig.apiOrigin` into its island: a second field would be a second\n * source that pages could read instead. `websiteConfig` in a site context is\n * therefore \"the config as it applies to this build\", which the config file was\n * already half-way to being — it reads `PUBLIC_APP_ORIGIN` itself.\n */\nexport function resolveWebsiteBuildOrigins(input: ResolveWebsiteBuildOriginsInput): WildoMarketingWebsiteConfig {\n const { websiteConfig, isDevelopment, localOrigins, overrides } = input;\n const settle = (override: string | undefined, local: string | undefined, authored: string | undefined): string | undefined =>\n override || (isDevelopment ? local : undefined) || authored;\n const appOrigin = settle(overrides.appOrigin, localOrigins.app, websiteConfig.appOrigin) ?? websiteConfig.appOrigin;\n const apiOrigin = settle(overrides.apiOrigin, localOrigins.api, websiteConfig.apiOrigin);\n return { ...websiteConfig, appOrigin, ...(apiOrigin === undefined ? {} : { apiOrigin }) };\n}\n\nexport interface LoadWebsiteSiteContextInput {\n /** The workspace's `WEBSITE_ROOT_CONFIG`. */\n readonly rootConfig: WebsiteRootConfig;\n /** Pass `import.meta.env?.DEV === true` (optional chaining: `astro.config.ts` evaluates the caller before Vite's env exists). */\n readonly isDevelopment: boolean;\n /** Where to start the walk up to `wildo.saas.config.ts`. Defaults to the working directory. */\n readonly cwd?: string | undefined;\n /** Defaults to `PUBLIC_APP_ORIGIN` / `PUBLIC_API_ORIGIN` from the process environment. */\n readonly overrides?: WebsiteOriginOverrides | undefined;\n}\n\nexport async function loadWebsiteSiteContext(input: LoadWebsiteSiteContextInput): Promise<WebsiteSiteContext> {\n const workspaceScope = resolveWorkspaceScope(input.cwd);\n if (workspaceScope.saasRoot === null || workspaceScope.saasConfigPath === null) {\n throw new Error(\n `[saas-website] No wildo.saas.config.ts found walking up from ${input.cwd ?? process.cwd()}. `\n + 'Run astro from inside the application workspace.',\n );\n }\n const saasRoot = workspaceScope.saasRoot;\n const saasConfig = await loadConfig<WildoSaasConfig>(workspaceScope.saasConfigPath);\n const [websiteServiceKey] = resolveStaticWebsiteServiceEntry(saasConfig);\n const websiteConfig = await loadWebsiteConfig({ saasRoot, saasConfig });\n\n return composeWebsiteSiteContext({\n rootConfig: input.rootConfig,\n websiteConfig: resolveWebsiteBuildOrigins({\n websiteConfig,\n isDevelopment: input.isDevelopment,\n localOrigins: resolveLocalhostApplicationOrigins(saasConfig.services),\n overrides: input.overrides ?? {\n appOrigin: process.env.PUBLIC_APP_ORIGIN,\n apiOrigin: process.env.PUBLIC_API_ORIGIN,\n },\n }),\n frontendProviders: loadMaterializedFrontendProviders({\n artifactPath: resolveFrontendServicesArtifactPath(resolvePath(saasRoot)),\n serviceKey: websiteServiceKey,\n }),\n });\n}\n/** @wildo_source:part:end saas.website.config.site-context-loader */\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wildo-website-config.schemas.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"wildo-website-config.schemas.d.ts","sourceRoot":"","sources":["../../../src/config/wildo-website-config.schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsHG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,oDAAoD,CAAC;AAEvF;;;;;;;;;GASG;AACH,eAAO,MAAM,yBAAyB;;;kBASpC,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,iCAAiC;IAE1C;;;;;;;;;;OAUG;;IASH;;;;;;;;;;;;;;;;;;;OAmBG;;IAGH;;;;;;;;;;;;;;;;;;;;;;OAsBG;;IAWH;;;;;OAKG;;;;;;;;IAGH;;;;;;;;;OASG;;IAGH;;;;;;;;;OASG;;;;;kBAqDH,CAAC;AACL,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iCAAiC,CAAC,CAAC;AAC5F,MAAM,MAAM,gCAAgC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iCAAiC,CAAC,CAAC;AACjG,wDAAwD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/config-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,cAAc,8BAA8B,CAAC;AAC7C,cAAc,oCAAoC,CAAC;AACnD,cAAc,uCAAuC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-loader.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../src/config-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,cAAc,8BAA8B,CAAC;AAC7C,cAAc,oCAAoC,CAAC;AACnD,cAAc,uCAAuC,CAAC","sourcesContent":["/**\n * @wildo-package @wildo-ai/saas-website (Node-only config-loader entry)\n *\n * Dedicated subpath for the per-service `wildo.website.config.ts`\n * loader (`saas-website-slice.md` Step 7.5 — mirrors the\n * `saas-technical-doc.md` Step 7.5 ship). Consumers:\n *\n * - `examples/wonder-todos/website/astro.config.ts` — wires the\n * loader into the Astro build's `i18n` config.\n * - Future companion subprocesses that introspect the marketing\n * surface (locale coverage audits, SEO-link sanity checks).\n *\n * @wildo-boundary\n * This entry is on the **Node-only** side of the bundle boundary.\n * It re-exports `loadWebsiteConfig` (which transitively pulls\n * `loadConfig` from `@wildo-ai/platform-config-lib` — jiti-backed,\n * uses `node:fs` / `node:path` / `node:crypto`) and is therefore\n * carved into its own package subpath so it cannot leak into the\n * browser-side React-island bundle.\n *\n * Enforced by `engine/saas-website/src/__tests__/bundle-isolation.test.ts`:\n * - This file IS in `ENTRY_FILES` (so the closure walker covers it).\n * - `@wildo-ai/platform-config-lib` is in `ALLOWED_BARE_SPECIFIERS`\n * AND `SSR_ONLY_BARE_SPECIFIERS`, which together prove the\n * specifier reaches the closure ONLY through this entry — never\n * through `index.ts`, `companion-exports.ts`, or `astro-island.ts`.\n *\n * Re-exporting `loadWebsiteConfig` from `index.ts` would (a) drag\n * `@wildo-ai/platform-config-lib`'s heavy graph into the marketing-\n * site browser bundle and (b) trip the SSR-tier negative test\n * above — both fail-loud signals that this subpath separation\n * exists for a reason.\n */\n\nexport * from './config/load-website-config';\nexport * from './config/load-website-site-context';\nexport * from './config/load-website-pricing-catalog';\n"]}
|
|
@@ -8,12 +8,26 @@
|
|
|
8
8
|
* the anonymous session (init header) and the backend stamps the lead's `anonymousUserId`
|
|
9
9
|
* so it can later transpose to the visitor's account on signup/login.
|
|
10
10
|
*
|
|
11
|
-
* Labels are injected
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* Labels are injected rather than read from the website runtime context, so the component stays framework-light and
|
|
12
|
+
* unit-testable; the section wrapper passes the strings it resolved through `useWebsiteLabel`. EVERY label is required
|
|
13
|
+
* and the form carries no words of its own (#1986): a fallback would be English in every locale and would hide the
|
|
14
|
+
* missing label, while a required prop makes an omission a type error in the section, and a key the pack does not
|
|
15
|
+
* carry reaches the page as the key itself — which is what `useWebsiteLabel` returns, so somebody authors it.
|
|
16
|
+
*
|
|
17
|
+
* Submission challenge (#1735): when the application protects the form with a captcha, each submission carries an
|
|
18
|
+
* answer — the consented vendor's token when its browser part runs on the page, otherwise the engine's proof of work,
|
|
19
|
+
* which needs no consent (see `website-submission-challenge.ts`). Nothing for the visitor to click or read: both are
|
|
20
|
+
* invisible, so the form stays operable by keyboard and screen reader exactly as before. A vendor token the backend
|
|
21
|
+
* refuses is retried once with the proof of work; a refusal that survives that shows `challengeRefusedMessage`.
|
|
14
22
|
*/
|
|
15
23
|
import React from "react";
|
|
16
24
|
import type { WebsiteAnonymousSessionClient } from "./website-anonymous-session-client";
|
|
25
|
+
import { type WebsiteSubmissionChallengeSource } from "./website-submission-challenge";
|
|
26
|
+
/**
|
|
27
|
+
* Every word the form shows. All required (#1986): the section resolves each through `useWebsiteLabel` and lists its
|
|
28
|
+
* key in `expectedLabelKeys`, so a missing label is a type error in the section or a visible key on the page, never a
|
|
29
|
+
* silent English substitute.
|
|
30
|
+
*/
|
|
17
31
|
export interface InboundContactFormLabels {
|
|
18
32
|
emailLabel: string;
|
|
19
33
|
firstNameLabel: string;
|
|
@@ -25,14 +39,20 @@ export interface InboundContactFormLabels {
|
|
|
25
39
|
submittingLabel: string;
|
|
26
40
|
successMessage: string;
|
|
27
41
|
errorMessage: string;
|
|
42
|
+
/** The anti-spam check did not pass, even with the proof of work (#1735). */
|
|
43
|
+
challengeRefusedMessage: string;
|
|
44
|
+
/** Shown beside the email field when what was typed is not an email address (#1986). */
|
|
45
|
+
invalidEmailMessage: string;
|
|
28
46
|
}
|
|
29
47
|
export interface InboundContactFormProps {
|
|
30
48
|
/** The anonymous-session client (constructed by the section wiring from site config). */
|
|
31
49
|
client: WebsiteAnonymousSessionClient;
|
|
32
|
-
/**
|
|
33
|
-
labels
|
|
50
|
+
/** The section's i18n-resolved labels — every one of them (#1986). */
|
|
51
|
+
labels: InboundContactFormLabels;
|
|
34
52
|
/** Optional callback fired after a successful submission (e.g. analytics). */
|
|
35
53
|
onSubmitted?: () => void;
|
|
54
|
+
/** The page's captcha, for a form rendered outside a page layout (tests). Defaults to the page's own. */
|
|
55
|
+
challengeSource?: WebsiteSubmissionChallengeSource;
|
|
36
56
|
}
|
|
37
|
-
export declare function InboundContactForm({ client, labels, onSubmitted }: InboundContactFormProps): React.ReactElement;
|
|
57
|
+
export declare function InboundContactForm({ client, labels, onSubmitted, challengeSource }: InboundContactFormProps): React.ReactElement;
|
|
38
58
|
//# sourceMappingURL=InboundContactForm.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InboundContactForm.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"InboundContactForm.d.ts","sourceRoot":"","sources":["../../../../src/core/anonymous-session/InboundContactForm.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAgC,MAAM,OAAO,CAAC;AASrD,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AACxF,OAAO,EAIL,KAAK,gCAAgC,EACtC,MAAM,gCAAgC,CAAC;AAExC;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,qBAAqB,EAAE,MAAM,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,uBAAuB,EAAE,MAAM,CAAC;IAChC,wFAAwF;IACxF,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAID,MAAM,WAAW,uBAAuB;IACtC,yFAAyF;IACzF,MAAM,EAAE,6BAA6B,CAAC;IACtC,sEAAsE;IACtE,MAAM,EAAE,wBAAwB,CAAC;IACjC,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,yGAAyG;IACzG,eAAe,CAAC,EAAE,gCAAgC,CAAC;CACpD;AAUD,wBAAgB,kBAAkB,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,eAAe,EAAE,EAAE,uBAAuB,GAAG,KAAK,CAAC,YAAY,CAgIhI"}
|