@wildo-ai/saas-website 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (383) hide show
  1. package/LICENSE +34 -0
  2. package/dist/esm/.builder.pid +9 -0
  3. package/dist/esm/astro/blog-post-bridge.d.ts +324 -0
  4. package/dist/esm/astro/blog-post-bridge.d.ts.map +1 -0
  5. package/dist/esm/astro/blog-post-bridge.js +57 -0
  6. package/dist/esm/astro/blog-post-bridge.js.map +1 -0
  7. package/dist/esm/astro/blog-post-head.renderer.d.ts +129 -0
  8. package/dist/esm/astro/blog-post-head.renderer.d.ts.map +1 -0
  9. package/dist/esm/astro/blog-post-head.renderer.js +139 -0
  10. package/dist/esm/astro/blog-post-head.renderer.js.map +1 -0
  11. package/dist/esm/astro/bridge-runtime.d.ts +224 -0
  12. package/dist/esm/astro/bridge-runtime.d.ts.map +1 -0
  13. package/dist/esm/astro/bridge-runtime.js +30 -0
  14. package/dist/esm/astro/bridge-runtime.js.map +1 -0
  15. package/dist/esm/astro/collect-expected-label-keys.d.ts +65 -0
  16. package/dist/esm/astro/collect-expected-label-keys.d.ts.map +1 -0
  17. package/dist/esm/astro/collect-expected-label-keys.js +101 -0
  18. package/dist/esm/astro/collect-expected-label-keys.js.map +1 -0
  19. package/dist/esm/astro/headers-renderer.d.ts +32 -0
  20. package/dist/esm/astro/headers-renderer.d.ts.map +1 -0
  21. package/dist/esm/astro/headers-renderer.js +64 -0
  22. package/dist/esm/astro/headers-renderer.js.map +1 -0
  23. package/dist/esm/astro/i18n-routing.helper.d.ts +91 -0
  24. package/dist/esm/astro/i18n-routing.helper.d.ts.map +1 -0
  25. package/dist/esm/astro/i18n-routing.helper.js +23 -0
  26. package/dist/esm/astro/i18n-routing.helper.js.map +1 -0
  27. package/dist/esm/astro/internal/html-escape.d.ts +31 -0
  28. package/dist/esm/astro/internal/html-escape.d.ts.map +1 -0
  29. package/dist/esm/astro/internal/html-escape.js +40 -0
  30. package/dist/esm/astro/internal/html-escape.js.map +1 -0
  31. package/dist/esm/astro/label-pack-loader.d.ts +134 -0
  32. package/dist/esm/astro/label-pack-loader.d.ts.map +1 -0
  33. package/dist/esm/astro/label-pack-loader.js +298 -0
  34. package/dist/esm/astro/label-pack-loader.js.map +1 -0
  35. package/dist/esm/astro/llms-txt-server.d.ts +28 -0
  36. package/dist/esm/astro/llms-txt-server.d.ts.map +1 -0
  37. package/dist/esm/astro/llms-txt-server.js +33 -0
  38. package/dist/esm/astro/llms-txt-server.js.map +1 -0
  39. package/dist/esm/astro/pick-labels-for-page.d.ts +63 -0
  40. package/dist/esm/astro/pick-labels-for-page.d.ts.map +1 -0
  41. package/dist/esm/astro/pick-labels-for-page.js +73 -0
  42. package/dist/esm/astro/pick-labels-for-page.js.map +1 -0
  43. package/dist/esm/astro/robots-renderer.d.ts +85 -0
  44. package/dist/esm/astro/robots-renderer.d.ts.map +1 -0
  45. package/dist/esm/astro/robots-renderer.js +157 -0
  46. package/dist/esm/astro/robots-renderer.js.map +1 -0
  47. package/dist/esm/astro/sitemap-coverage.d.ts +101 -0
  48. package/dist/esm/astro/sitemap-coverage.d.ts.map +1 -0
  49. package/dist/esm/astro/sitemap-coverage.js +67 -0
  50. package/dist/esm/astro/sitemap-coverage.js.map +1 -0
  51. package/dist/esm/astro/structured-data.renderer.d.ts +21 -0
  52. package/dist/esm/astro/structured-data.renderer.d.ts.map +1 -0
  53. package/dist/esm/astro/structured-data.renderer.js +142 -0
  54. package/dist/esm/astro/structured-data.renderer.js.map +1 -0
  55. package/dist/esm/astro/website-page-head.renderer.d.ts +93 -0
  56. package/dist/esm/astro/website-page-head.renderer.d.ts.map +1 -0
  57. package/dist/esm/astro/website-page-head.renderer.js +184 -0
  58. package/dist/esm/astro/website-page-head.renderer.js.map +1 -0
  59. package/dist/esm/astro/website-page-runtime.helper.d.ts +112 -0
  60. package/dist/esm/astro/website-page-runtime.helper.d.ts.map +1 -0
  61. package/dist/esm/astro/website-page-runtime.helper.js +60 -0
  62. package/dist/esm/astro/website-page-runtime.helper.js.map +1 -0
  63. package/dist/esm/astro/website-site-context.d.ts +126 -0
  64. package/dist/esm/astro/website-site-context.d.ts.map +1 -0
  65. package/dist/esm/astro/website-site-context.js +37 -0
  66. package/dist/esm/astro/website-site-context.js.map +1 -0
  67. package/dist/esm/astro-island.d.ts +56 -0
  68. package/dist/esm/astro-island.d.ts.map +1 -0
  69. package/dist/esm/astro-island.js +61 -0
  70. package/dist/esm/astro-island.js.map +1 -0
  71. package/dist/esm/astro.d.ts +151 -0
  72. package/dist/esm/astro.d.ts.map +1 -0
  73. package/dist/esm/astro.js +151 -0
  74. package/dist/esm/astro.js.map +1 -0
  75. package/dist/esm/companion-exports.d.ts +38 -0
  76. package/dist/esm/companion-exports.d.ts.map +1 -0
  77. package/dist/esm/companion-exports.js +38 -0
  78. package/dist/esm/companion-exports.js.map +1 -0
  79. package/dist/esm/components/low-level/WebsiteButton.d.ts +73 -0
  80. package/dist/esm/components/low-level/WebsiteButton.d.ts.map +1 -0
  81. package/dist/esm/components/low-level/WebsiteButton.js +68 -0
  82. package/dist/esm/components/low-level/WebsiteButton.js.map +1 -0
  83. package/dist/esm/components/low-level/WebsiteHeading.d.ts +78 -0
  84. package/dist/esm/components/low-level/WebsiteHeading.d.ts.map +1 -0
  85. package/dist/esm/components/low-level/WebsiteHeading.js +41 -0
  86. package/dist/esm/components/low-level/WebsiteHeading.js.map +1 -0
  87. package/dist/esm/components/low-level/WebsiteImage.d.ts +73 -0
  88. package/dist/esm/components/low-level/WebsiteImage.d.ts.map +1 -0
  89. package/dist/esm/components/low-level/WebsiteImage.js +21 -0
  90. package/dist/esm/components/low-level/WebsiteImage.js.map +1 -0
  91. package/dist/esm/components/low-level/WebsiteInternalButton.d.ts +90 -0
  92. package/dist/esm/components/low-level/WebsiteInternalButton.d.ts.map +1 -0
  93. package/dist/esm/components/low-level/WebsiteInternalButton.js +47 -0
  94. package/dist/esm/components/low-level/WebsiteInternalButton.js.map +1 -0
  95. package/dist/esm/components/low-level/WebsiteInternalLink.d.ts +99 -0
  96. package/dist/esm/components/low-level/WebsiteInternalLink.d.ts.map +1 -0
  97. package/dist/esm/components/low-level/WebsiteInternalLink.js +68 -0
  98. package/dist/esm/components/low-level/WebsiteInternalLink.js.map +1 -0
  99. package/dist/esm/components/low-level/WebsiteLink.d.ts +50 -0
  100. package/dist/esm/components/low-level/WebsiteLink.d.ts.map +1 -0
  101. package/dist/esm/components/low-level/WebsiteLink.js +22 -0
  102. package/dist/esm/components/low-level/WebsiteLink.js.map +1 -0
  103. package/dist/esm/components/low-level/WebsiteText.d.ts +57 -0
  104. package/dist/esm/components/low-level/WebsiteText.d.ts.map +1 -0
  105. package/dist/esm/components/low-level/WebsiteText.js +57 -0
  106. package/dist/esm/components/low-level/WebsiteText.js.map +1 -0
  107. package/dist/esm/config/define-website-config.d.ts +83 -0
  108. package/dist/esm/config/define-website-config.d.ts.map +1 -0
  109. package/dist/esm/config/define-website-config.js +126 -0
  110. package/dist/esm/config/define-website-config.js.map +1 -0
  111. package/dist/esm/config/index.d.ts +38 -0
  112. package/dist/esm/config/index.d.ts.map +1 -0
  113. package/dist/esm/config/index.js +38 -0
  114. package/dist/esm/config/index.js.map +1 -0
  115. package/dist/esm/config/load-website-config.d.ts +136 -0
  116. package/dist/esm/config/load-website-config.d.ts.map +1 -0
  117. package/dist/esm/config/load-website-config.js +177 -0
  118. package/dist/esm/config/load-website-config.js.map +1 -0
  119. package/dist/esm/config/wildo-website-config.schemas.d.ts +251 -0
  120. package/dist/esm/config/wildo-website-config.schemas.d.ts.map +1 -0
  121. package/dist/esm/config/wildo-website-config.schemas.js +302 -0
  122. package/dist/esm/config/wildo-website-config.schemas.js.map +1 -0
  123. package/dist/esm/config-loader.d.ts +35 -0
  124. package/dist/esm/config-loader.d.ts.map +1 -0
  125. package/dist/esm/config-loader.js +35 -0
  126. package/dist/esm/config-loader.js.map +1 -0
  127. package/dist/esm/core/anonymous-session/InboundContactForm.d.ts +38 -0
  128. package/dist/esm/core/anonymous-session/InboundContactForm.d.ts.map +1 -0
  129. package/dist/esm/core/anonymous-session/InboundContactForm.js +77 -0
  130. package/dist/esm/core/anonymous-session/InboundContactForm.js.map +1 -0
  131. package/dist/esm/core/anonymous-session/inbound-contact-form.schema.d.ts +41 -0
  132. package/dist/esm/core/anonymous-session/inbound-contact-form.schema.d.ts.map +1 -0
  133. package/dist/esm/core/anonymous-session/inbound-contact-form.schema.js +58 -0
  134. package/dist/esm/core/anonymous-session/inbound-contact-form.schema.js.map +1 -0
  135. package/dist/esm/core/anonymous-session/website-anonymous-session-client.d.ts +81 -0
  136. package/dist/esm/core/anonymous-session/website-anonymous-session-client.d.ts.map +1 -0
  137. package/dist/esm/core/anonymous-session/website-anonymous-session-client.js +177 -0
  138. package/dist/esm/core/anonymous-session/website-anonymous-session-client.js.map +1 -0
  139. package/dist/esm/core/contexts/WebsitePageContext.d.ts +40 -0
  140. package/dist/esm/core/contexts/WebsitePageContext.d.ts.map +1 -0
  141. package/dist/esm/core/contexts/WebsitePageContext.js +8 -0
  142. package/dist/esm/core/contexts/WebsitePageContext.js.map +1 -0
  143. package/dist/esm/core/contexts/WebsiteRuntimeContext.d.ts +162 -0
  144. package/dist/esm/core/contexts/WebsiteRuntimeContext.d.ts.map +1 -0
  145. package/dist/esm/core/contexts/WebsiteRuntimeContext.js +22 -0
  146. package/dist/esm/core/contexts/WebsiteRuntimeContext.js.map +1 -0
  147. package/dist/esm/core/contexts/WebsiteSectionContext.d.ts +47 -0
  148. package/dist/esm/core/contexts/WebsiteSectionContext.d.ts.map +1 -0
  149. package/dist/esm/core/contexts/WebsiteSectionContext.js +8 -0
  150. package/dist/esm/core/contexts/WebsiteSectionContext.js.map +1 -0
  151. package/dist/esm/core/contexts/useWebsitePage.d.ts +13 -0
  152. package/dist/esm/core/contexts/useWebsitePage.d.ts.map +1 -0
  153. package/dist/esm/core/contexts/useWebsitePage.js +22 -0
  154. package/dist/esm/core/contexts/useWebsitePage.js.map +1 -0
  155. package/dist/esm/core/contexts/useWebsiteRuntime.d.ts +19 -0
  156. package/dist/esm/core/contexts/useWebsiteRuntime.d.ts.map +1 -0
  157. package/dist/esm/core/contexts/useWebsiteRuntime.js +28 -0
  158. package/dist/esm/core/contexts/useWebsiteRuntime.js.map +1 -0
  159. package/dist/esm/core/contexts/useWebsiteSection.d.ts +12 -0
  160. package/dist/esm/core/contexts/useWebsiteSection.d.ts.map +1 -0
  161. package/dist/esm/core/contexts/useWebsiteSection.js +22 -0
  162. package/dist/esm/core/contexts/useWebsiteSection.js.map +1 -0
  163. package/dist/esm/core/external-providers/frontend-provider-registry.website.d.ts +17 -0
  164. package/dist/esm/core/external-providers/frontend-provider-registry.website.d.ts.map +1 -0
  165. package/dist/esm/core/external-providers/frontend-provider-registry.website.js +23 -0
  166. package/dist/esm/core/external-providers/frontend-provider-registry.website.js.map +1 -0
  167. package/dist/esm/core/factories/define-website-page-manifest.d.ts +70 -0
  168. package/dist/esm/core/factories/define-website-page-manifest.d.ts.map +1 -0
  169. package/dist/esm/core/factories/define-website-page-manifest.js +51 -0
  170. package/dist/esm/core/factories/define-website-page-manifest.js.map +1 -0
  171. package/dist/esm/core/factories/define-website-section.d.ts +101 -0
  172. package/dist/esm/core/factories/define-website-section.d.ts.map +1 -0
  173. package/dist/esm/core/factories/define-website-section.js +71 -0
  174. package/dist/esm/core/factories/define-website-section.js.map +1 -0
  175. package/dist/esm/core/hooks/useWebsiteDesignTokens.d.ts +23 -0
  176. package/dist/esm/core/hooks/useWebsiteDesignTokens.d.ts.map +1 -0
  177. package/dist/esm/core/hooks/useWebsiteDesignTokens.js +25 -0
  178. package/dist/esm/core/hooks/useWebsiteDesignTokens.js.map +1 -0
  179. package/dist/esm/core/hooks/useWebsiteLabel.d.ts +68 -0
  180. package/dist/esm/core/hooks/useWebsiteLabel.d.ts.map +1 -0
  181. package/dist/esm/core/hooks/useWebsiteLabel.js +103 -0
  182. package/dist/esm/core/hooks/useWebsiteLabel.js.map +1 -0
  183. package/dist/esm/core/layouts/WebsitePageLayout.d.ts +87 -0
  184. package/dist/esm/core/layouts/WebsitePageLayout.d.ts.map +1 -0
  185. package/dist/esm/core/layouts/WebsitePageLayout.js +170 -0
  186. package/dist/esm/core/layouts/WebsitePageLayout.js.map +1 -0
  187. package/dist/esm/core/layouts/WebsiteSection.d.ts +91 -0
  188. package/dist/esm/core/layouts/WebsiteSection.d.ts.map +1 -0
  189. package/dist/esm/core/layouts/WebsiteSection.js +26 -0
  190. package/dist/esm/core/layouts/WebsiteSection.js.map +1 -0
  191. package/dist/esm/core/routing/internal-routing.utils.d.ts +65 -0
  192. package/dist/esm/core/routing/internal-routing.utils.d.ts.map +1 -0
  193. package/dist/esm/core/routing/internal-routing.utils.js +14 -0
  194. package/dist/esm/core/routing/internal-routing.utils.js.map +1 -0
  195. package/dist/esm/index.d.ts +129 -0
  196. package/dist/esm/index.d.ts.map +1 -0
  197. package/dist/esm/index.js +129 -0
  198. package/dist/esm/index.js.map +1 -0
  199. package/dist/esm/mdx/BlogPost.d.ts +193 -0
  200. package/dist/esm/mdx/BlogPost.d.ts.map +1 -0
  201. package/dist/esm/mdx/BlogPost.js +161 -0
  202. package/dist/esm/mdx/BlogPost.js.map +1 -0
  203. package/dist/esm/mdx/blog-post-collection.config.d.ts +139 -0
  204. package/dist/esm/mdx/blog-post-collection.config.d.ts.map +1 -0
  205. package/dist/esm/mdx/blog-post-collection.config.js +27 -0
  206. package/dist/esm/mdx/blog-post-collection.config.js.map +1 -0
  207. package/dist/esm/mdx/blog-post-frontmatter-source.d.ts +12 -0
  208. package/dist/esm/mdx/blog-post-frontmatter-source.d.ts.map +1 -0
  209. package/dist/esm/mdx/blog-post-frontmatter-source.js +13 -0
  210. package/dist/esm/mdx/blog-post-frontmatter-source.js.map +1 -0
  211. package/dist/esm/mdx/index.d.ts +22 -0
  212. package/dist/esm/mdx/index.d.ts.map +1 -0
  213. package/dist/esm/mdx/index.js +22 -0
  214. package/dist/esm/mdx/index.js.map +1 -0
  215. package/dist/esm/mdx/website-mdx-provider.d.ts +90 -0
  216. package/dist/esm/mdx/website-mdx-provider.d.ts.map +1 -0
  217. package/dist/esm/mdx/website-mdx-provider.js +8 -0
  218. package/dist/esm/mdx/website-mdx-provider.js.map +1 -0
  219. package/dist/esm/mdx.d.ts +38 -0
  220. package/dist/esm/mdx.d.ts.map +1 -0
  221. package/dist/esm/mdx.js +38 -0
  222. package/dist/esm/mdx.js.map +1 -0
  223. package/dist/esm/schemas/blog/blog-post-frontmatter.shared.schemas.d.ts +75 -0
  224. package/dist/esm/schemas/blog/blog-post-frontmatter.shared.schemas.d.ts.map +1 -0
  225. package/dist/esm/schemas/blog/blog-post-frontmatter.shared.schemas.js +85 -0
  226. package/dist/esm/schemas/blog/blog-post-frontmatter.shared.schemas.js.map +1 -0
  227. package/dist/esm/schemas/design-tokens/website-design-tokens.shared.schemas.d.ts +120 -0
  228. package/dist/esm/schemas/design-tokens/website-design-tokens.shared.schemas.d.ts.map +1 -0
  229. package/dist/esm/schemas/design-tokens/website-design-tokens.shared.schemas.js +152 -0
  230. package/dist/esm/schemas/design-tokens/website-design-tokens.shared.schemas.js.map +1 -0
  231. package/dist/esm/schemas/label-keys/website-label-key.schemas.d.ts +73 -0
  232. package/dist/esm/schemas/label-keys/website-label-key.schemas.d.ts.map +1 -0
  233. package/dist/esm/schemas/label-keys/website-label-key.schemas.js +76 -0
  234. package/dist/esm/schemas/label-keys/website-label-key.schemas.js.map +1 -0
  235. package/dist/esm/schemas/manifests/website-page-manifest.shared.schemas.d.ts +209 -0
  236. package/dist/esm/schemas/manifests/website-page-manifest.shared.schemas.d.ts.map +1 -0
  237. package/dist/esm/schemas/manifests/website-page-manifest.shared.schemas.js +218 -0
  238. package/dist/esm/schemas/manifests/website-page-manifest.shared.schemas.js.map +1 -0
  239. package/dist/esm/schemas/manifests/website-root-config.shared.schemas.d.ts +431 -0
  240. package/dist/esm/schemas/manifests/website-root-config.shared.schemas.d.ts.map +1 -0
  241. package/dist/esm/schemas/manifests/website-root-config.shared.schemas.js +438 -0
  242. package/dist/esm/schemas/manifests/website-root-config.shared.schemas.js.map +1 -0
  243. package/dist/esm/schemas/refs/page-ref.schemas.d.ts +40 -0
  244. package/dist/esm/schemas/refs/page-ref.schemas.d.ts.map +1 -0
  245. package/dist/esm/schemas/refs/page-ref.schemas.js +43 -0
  246. package/dist/esm/schemas/refs/page-ref.schemas.js.map +1 -0
  247. package/dist/esm/schemas/refs/section-ref.schemas.d.ts +41 -0
  248. package/dist/esm/schemas/refs/section-ref.schemas.d.ts.map +1 -0
  249. package/dist/esm/schemas/refs/section-ref.schemas.js +44 -0
  250. package/dist/esm/schemas/refs/section-ref.schemas.js.map +1 -0
  251. package/dist/esm/schemas/sections/website-section-category.shared.d.ts +63 -0
  252. package/dist/esm/schemas/sections/website-section-category.shared.d.ts.map +1 -0
  253. package/dist/esm/schemas/sections/website-section-category.shared.js +64 -0
  254. package/dist/esm/schemas/sections/website-section-category.shared.js.map +1 -0
  255. package/dist/esm/schemas/sections/website-section-definition.shared.schemas.d.ts +114 -0
  256. package/dist/esm/schemas/sections/website-section-definition.shared.schemas.d.ts.map +1 -0
  257. package/dist/esm/schemas/sections/website-section-definition.shared.schemas.js +69 -0
  258. package/dist/esm/schemas/sections/website-section-definition.shared.schemas.js.map +1 -0
  259. package/dist/esm/schemas/structured-data/structured-data-reconciliation.shared.d.ts +100 -0
  260. package/dist/esm/schemas/structured-data/structured-data-reconciliation.shared.d.ts.map +1 -0
  261. package/dist/esm/schemas/structured-data/structured-data-reconciliation.shared.js +355 -0
  262. package/dist/esm/schemas/structured-data/structured-data-reconciliation.shared.js.map +1 -0
  263. package/dist/esm/schemas/structured-data/website-structured-data.shared.schemas.d.ts +58 -0
  264. package/dist/esm/schemas/structured-data/website-structured-data.shared.schemas.d.ts.map +1 -0
  265. package/dist/esm/schemas/structured-data/website-structured-data.shared.schemas.js +2 -0
  266. package/dist/esm/schemas/structured-data/website-structured-data.shared.schemas.js.map +1 -0
  267. package/dist/esm/schemas/validators/label-pack.validator.d.ts +144 -0
  268. package/dist/esm/schemas/validators/label-pack.validator.d.ts.map +1 -0
  269. package/dist/esm/schemas/validators/label-pack.validator.js +100 -0
  270. package/dist/esm/schemas/validators/label-pack.validator.js.map +1 -0
  271. package/dist/tsconfig.build.tsbuildinfo +1 -0
  272. package/package.json +143 -0
  273. package/src/__tests__/bundle-isolation.test.ts +607 -0
  274. package/src/astro/__tests__/blog-post-bridge.test.tsx +288 -0
  275. package/src/astro/__tests__/blog-post-head.renderer.test.ts +249 -0
  276. package/src/astro/__tests__/bridge-runtime.test.tsx +198 -0
  277. package/src/astro/__tests__/collect-expected-label-keys.test.ts +69 -0
  278. package/src/astro/__tests__/headers-renderer.test.ts +143 -0
  279. package/src/astro/__tests__/i18n-routing.helper.test.ts +116 -0
  280. package/src/astro/__tests__/label-pack-loader.test.ts +305 -0
  281. package/src/astro/__tests__/llms-txt-server.test.ts +127 -0
  282. package/src/astro/__tests__/pick-labels-for-page.test.ts +60 -0
  283. package/src/astro/__tests__/robots-renderer.test.ts +228 -0
  284. package/src/astro/__tests__/sitemap-coverage.test.ts +230 -0
  285. package/src/astro/__tests__/structured-data.renderer.test.ts +172 -0
  286. package/src/astro/__tests__/website-page-head.renderer.test.ts +424 -0
  287. package/src/astro/__tests__/website-page-runtime.helper.test.ts +157 -0
  288. package/src/astro/__tests__/website-site-context.test.ts +121 -0
  289. package/src/astro/blog-post-bridge.tsx +404 -0
  290. package/src/astro/blog-post-head.renderer.ts +293 -0
  291. package/src/astro/bridge-runtime.tsx +270 -0
  292. package/src/astro/collect-expected-label-keys.ts +113 -0
  293. package/src/astro/headers-renderer.ts +82 -0
  294. package/src/astro/i18n-routing.helper.ts +116 -0
  295. package/src/astro/internal/html-escape.ts +41 -0
  296. package/src/astro/label-pack-loader.ts +385 -0
  297. package/src/astro/llms-txt-server.ts +56 -0
  298. package/src/astro/pick-labels-for-page.ts +85 -0
  299. package/src/astro/robots-renderer.ts +171 -0
  300. package/src/astro/sitemap-coverage.ts +186 -0
  301. package/src/astro/structured-data.renderer.ts +171 -0
  302. package/src/astro/website-page-head.renderer.ts +279 -0
  303. package/src/astro/website-page-runtime.helper.ts +188 -0
  304. package/src/astro/website-site-context.ts +136 -0
  305. package/src/astro-island.ts +61 -0
  306. package/src/astro.ts +151 -0
  307. package/src/companion-exports.ts +38 -0
  308. package/src/components/low-level/WebsiteButton.tsx +118 -0
  309. package/src/components/low-level/WebsiteHeading.tsx +96 -0
  310. package/src/components/low-level/WebsiteImage.tsx +96 -0
  311. package/src/components/low-level/WebsiteInternalButton.tsx +172 -0
  312. package/src/components/low-level/WebsiteInternalLink.tsx +193 -0
  313. package/src/components/low-level/WebsiteLink.tsx +71 -0
  314. package/src/components/low-level/WebsiteText.tsx +75 -0
  315. package/src/components/low-level/__tests__/WebsiteInternalButton.test.tsx +169 -0
  316. package/src/components/low-level/__tests__/WebsiteInternalLink.test.tsx +202 -0
  317. package/src/components/low-level/__tests__/primitives.test.tsx +141 -0
  318. package/src/config/__tests__/define-website-config.test.ts +231 -0
  319. package/src/config/__tests__/load-website-config.test.ts +215 -0
  320. package/src/config/define-website-config.ts +134 -0
  321. package/src/config/index.ts +38 -0
  322. package/src/config/load-website-config.ts +229 -0
  323. package/src/config/wildo-website-config.schemas.ts +322 -0
  324. package/src/config-loader.ts +35 -0
  325. package/src/core/__tests__/WebsitePageLayout.test.tsx +184 -0
  326. package/src/core/__tests__/WebsiteSection.test.tsx +85 -0
  327. package/src/core/__tests__/contexts.test.tsx +133 -0
  328. package/src/core/__tests__/core-boundary.test.ts +85 -0
  329. package/src/core/__tests__/define-website-page-manifest.test.tsx +111 -0
  330. package/src/core/__tests__/define-website-section.test.tsx +89 -0
  331. package/src/core/__tests__/useWebsiteDesignTokens.test.tsx +41 -0
  332. package/src/core/__tests__/useWebsiteLabel.test.tsx +117 -0
  333. package/src/core/anonymous-session/InboundContactForm.tsx +157 -0
  334. package/src/core/anonymous-session/__tests__/inbound-contact-form.schema.test.ts +44 -0
  335. package/src/core/anonymous-session/inbound-contact-form.schema.ts +62 -0
  336. package/src/core/anonymous-session/website-anonymous-session-client.ts +194 -0
  337. package/src/core/contexts/WebsitePageContext.tsx +52 -0
  338. package/src/core/contexts/WebsiteRuntimeContext.tsx +175 -0
  339. package/src/core/contexts/WebsiteSectionContext.tsx +59 -0
  340. package/src/core/contexts/useWebsitePage.ts +28 -0
  341. package/src/core/contexts/useWebsiteRuntime.ts +34 -0
  342. package/src/core/contexts/useWebsiteSection.ts +28 -0
  343. package/src/core/external-providers/frontend-provider-registry.website.ts +62 -0
  344. package/src/core/factories/define-website-page-manifest.ts +102 -0
  345. package/src/core/factories/define-website-section.ts +128 -0
  346. package/src/core/hooks/useWebsiteDesignTokens.ts +26 -0
  347. package/src/core/hooks/useWebsiteLabel.ts +121 -0
  348. package/src/core/layouts/WebsitePageLayout.tsx +311 -0
  349. package/src/core/layouts/WebsiteSection.tsx +139 -0
  350. package/src/core/routing/__tests__/internal-routing.utils.test.ts +134 -0
  351. package/src/core/routing/internal-routing.utils.ts +77 -0
  352. package/src/index.ts +132 -0
  353. package/src/mdx/BlogPost.tsx +296 -0
  354. package/src/mdx/__tests__/BlogPost.test.tsx +218 -0
  355. package/src/mdx/__tests__/blog-post-collection.config.test.ts +127 -0
  356. package/src/mdx/__tests__/website-mdx-provider.test.tsx +82 -0
  357. package/src/mdx/blog-post-collection.config.ts +177 -0
  358. package/src/mdx/blog-post-frontmatter-source.ts +31 -0
  359. package/src/mdx/index.ts +39 -0
  360. package/src/mdx/website-mdx-provider.tsx +95 -0
  361. package/src/mdx.ts +38 -0
  362. package/src/schemas/__tests__/blog-frontmatter.test.ts +50 -0
  363. package/src/schemas/__tests__/companion-exports-react-free.test.ts +51 -0
  364. package/src/schemas/__tests__/design-tokens.test.ts +163 -0
  365. package/src/schemas/__tests__/label-key.test.ts +46 -0
  366. package/src/schemas/__tests__/label-pack-validator.test.ts +146 -0
  367. package/src/schemas/__tests__/page-manifest.test.ts +66 -0
  368. package/src/schemas/__tests__/refs.test.ts +37 -0
  369. package/src/schemas/__tests__/root-config.test.ts +292 -0
  370. package/src/schemas/__tests__/section-definition.test.ts +47 -0
  371. package/src/schemas/__tests__/structured-data-reconciliation.test.ts +543 -0
  372. package/src/schemas/blog/blog-post-frontmatter.shared.schemas.ts +111 -0
  373. package/src/schemas/design-tokens/website-design-tokens.shared.schemas.ts +166 -0
  374. package/src/schemas/label-keys/website-label-key.schemas.ts +88 -0
  375. package/src/schemas/manifests/website-page-manifest.shared.schemas.ts +266 -0
  376. package/src/schemas/manifests/website-root-config.shared.schemas.ts +504 -0
  377. package/src/schemas/refs/page-ref.schemas.ts +49 -0
  378. package/src/schemas/refs/section-ref.schemas.ts +50 -0
  379. package/src/schemas/sections/website-section-category.shared.ts +65 -0
  380. package/src/schemas/sections/website-section-definition.shared.schemas.ts +120 -0
  381. package/src/schemas/structured-data/structured-data-reconciliation.shared.ts +579 -0
  382. package/src/schemas/structured-data/website-structured-data.shared.schemas.ts +62 -0
  383. package/src/schemas/validators/label-pack.validator.ts +201 -0
@@ -0,0 +1,209 @@
1
+ import type { ComponentType } from 'react';
2
+ import { z } from 'zod';
3
+ /**
4
+ * @wildo_source:part:start saas.website.page-manifest.meta-label-keys facet:layer:shared facet:family:website
5
+ *
6
+ * `WebsitePageMetaLabelKeys` — the i18n keys the Astro adapter (Phase 5)
7
+ * resolves at static-build time to populate `<title>` / `<meta>` /
8
+ * Open Graph tags for the page.
9
+ *
10
+ * - `titleKey` — REQUIRED. Renders into `<title>` AND `og:title`. The
11
+ * manifest commits to declaring this key in every locale's label
12
+ * pack; the validator surfaces missing entries at build start.
13
+ * - `descriptionKey` — REQUIRED. Renders into `<meta name="description">`,
14
+ * `og:description`, and `twitter:description`. Same per-locale
15
+ * commitment.
16
+ * - `ogImageUrl` — OPTIONAL. Static URL (typically a per-locale CDN
17
+ * path) for `og:image` / `twitter:image`. Not a label key because
18
+ * marketing teams overwhelmingly ship one localized asset URL per
19
+ * page rather than authoring image URLs in label packs. When
20
+ * per-locale images are needed, the consumer supplies a function
21
+ * in their site-root config that resolves locale → URL (Phase 5).
22
+ *
23
+ * **Why these three only**: the JSON-LD / canonical / `hreflang` /
24
+ * robots tags are NOT label-key-driven — they are derived
25
+ * mechanically from the manifest (`routePath`), the root config
26
+ * (`locales`, `defaultLocale`), and the section-level
27
+ * `getStructuredData()` hooks. Mixing them into the meta-label-keys
28
+ * shape would conflate human-authored copy with structural metadata.
29
+ */
30
+ declare const _WebsitePageMetaLabelKeysSchema: z.ZodObject<{
31
+ titleKey: z.core.$ZodBranded<z.ZodString, "WebsiteLabelKey", "out">;
32
+ descriptionKey: z.core.$ZodBranded<z.ZodString, "WebsiteLabelKey", "out">;
33
+ ogImageUrl: z.ZodOptional<z.ZodURL>;
34
+ }, z.core.$strip>;
35
+ export declare const WebsitePageMetaLabelKeysSchema: typeof _WebsitePageMetaLabelKeysSchema;
36
+ export type WebsitePageMetaLabelKeys = z.infer<typeof _WebsitePageMetaLabelKeysSchema>;
37
+ /** @wildo_source:part:end saas.website.page-manifest.meta-label-keys */
38
+ /**
39
+ * @wildo_source:part:start saas.website.page-manifest.route-path facet:layer:shared facet:family:website
40
+ *
41
+ * `WebsitePageRoutePath` — the URL path the page mounts at (locale
42
+ * prefix stripped).
43
+ *
44
+ * **Format**:
45
+ * - MUST start with `/`
46
+ * - MAY be the root (`'/'`) for the landing page
47
+ * - segments are lowercase kebab-case
48
+ * - parameter segments use Astro's `[param]` convention
49
+ * (e.g. `'/blog/[slug]'`, `'/case-studies/[slug]'`)
50
+ *
51
+ * The Astro adapter (Phase 5) prepends the locale prefix
52
+ * (`/en`, `/fr`, …) when generating routes. The manifest stores the
53
+ * locale-neutral path because the same `pageComponent` renders for
54
+ * every locale.
55
+ *
56
+ * **Brand**: prevents accidental cross-talk with absolute URLs
57
+ * (`https://…`), with locale-prefixed paths (`/en/pricing`), and with
58
+ * arbitrary string props in the manifest factory.
59
+ */
60
+ declare const _WebsitePageRoutePathSchema: z.core.$ZodBranded<z.ZodString, "WebsitePageRoutePath", "out">;
61
+ export declare const WebsitePageRoutePathSchema: typeof _WebsitePageRoutePathSchema;
62
+ export type WebsitePageRoutePath = z.infer<typeof _WebsitePageRoutePathSchema>;
63
+ /** @wildo_source:part:end saas.website.page-manifest.route-path */
64
+ /**
65
+ * @wildo_source:part:start saas.website.page-manifest.schema facet:layer:shared facet:family:website
66
+ *
67
+ * `WebsitePageManifest` — the registration-time descriptor for one
68
+ * marketing-site page.
69
+ *
70
+ * **Authoring path**: each page-impl module exports both a
71
+ * `<PageName>Page` React component AND a `<PAGE_NAME>_PAGE_MANIFEST`
72
+ * literal. The manifest is collected into `WebsiteRootConfig.pageManifests[]`;
73
+ * the Astro page file (`src/pages/<page>.astro`) imports the manifest
74
+ * and hands it to `<WebsitePageBridge manifest={…}>` (Phase 5).
75
+ *
76
+ * **Field-by-field rationale** (semantic-weight discipline):
77
+ *
78
+ * - `ref` — the page's structural identity. Used for label-key
79
+ * derivation (`website.<ref>.<sectionRef>.<slot>`), for
80
+ * cross-page navigation lookup, and as the manifest registry key.
81
+ * - `routePath` — the locale-neutral URL path. Decoupled from `ref`
82
+ * because the same page (e.g. `ref: 'pricing'`) may mount at a
83
+ * localized path (`/tarifs` in French) — the locale-aware path
84
+ * resolution is a Phase 5 concern; this field is the canonical
85
+ * English-language path.
86
+ * - `pageComponent` — the React component the bridge renders inside
87
+ * `<WebsitePageContext value={{ pageRef: ref }}>`. Type relaxed to
88
+ * `unknown` at the schema layer for the same reasons as
89
+ * `WebsiteSectionDefinition.Component`; the manifest factory
90
+ * (`defineWebsitePageManifest`, Phase 2) preserves precise typing
91
+ * at the consumer call site.
92
+ * - `sectionRefs` — the contractual list of section refs the page
93
+ * declares. Used by the label-pack validator to cross-reference
94
+ * `expectedLabelKeys` collected from each section against the
95
+ * page's commitment. **Order matters** for the validator's
96
+ * diagnostic output (sections are reported in declaration order)
97
+ * but does NOT control render order — render order is whatever the
98
+ * `pageComponent` JSX lays out.
99
+ * - `metaLabelKeys` — see `WebsitePageMetaLabelKeysSchema`.
100
+ * - `hydration` — opt-in flag. `'lazy'` (default) corresponds to
101
+ * `client:idle` in the Astro adapter (deferred hydration); `'eager'`
102
+ * corresponds to `client:load` (immediate hydration). The page
103
+ * author flips this to `'eager'` only when the page hosts
104
+ * above-the-fold interactive sections (e.g. a contact form).
105
+ *
106
+ * **Important — informational, NOT auto-wired**: Astro's
107
+ * `client:*` directives MUST resolve to a literal token at compile
108
+ * time (the Astro compiler reads the directive from the JSX source
109
+ * to decide which hydration helper to bundle); a runtime-computed
110
+ * value will not work. The framework therefore CANNOT translate
111
+ * this field into the directive on the consumer's behalf — the
112
+ * manifest field is the single source of truth a consumer's
113
+ * per-page `.astro` template should USE to pick the matching
114
+ * `client:idle` / `client:load` directive by hand. Keeping the two
115
+ * in lock-step is a discipline obligation; the audit CLI (Phase 7)
116
+ * will surface a drift warning when a page's hydration field does
117
+ * not match the directive in its `.astro` file.
118
+ *
119
+ * **Refinements**:
120
+ * - `sectionRefs` MUST contain unique values. Duplicates indicate
121
+ * either a copy-paste bug (two sections pointing at the same
122
+ * label-key root) or an intent to share a label-key root that
123
+ * the framework rejects to keep the per-page validation
124
+ * unambiguous (consumers who need a shared label-key root
125
+ * across two distinct sections should pull the shared content
126
+ * to the page level via `WebsiteRootConfig`-level globals,
127
+ * Phase 2.5).
128
+ */
129
+ export declare enum WebsitePageHydrationStrategy {
130
+ /** `client:idle` in the Astro adapter (deferred hydration). */
131
+ LAZY = "lazy",
132
+ /** `client:load` in the Astro adapter (immediate hydration). */
133
+ EAGER = "eager"
134
+ }
135
+ export declare const WebsitePageHydrationStrategySchema: z.ZodEnum<typeof WebsitePageHydrationStrategy>;
136
+ /**
137
+ * @wildo_source:part:start saas.website.page-manifest.seo facet:layer:shared facet:family:website
138
+ *
139
+ * `WebsitePageSeoConfig` — per-page SEO/AEO/GEO knobs.
140
+ *
141
+ * The marketing-site default is to be FULLY discoverable by every
142
+ * crawler (search engines AND AI training crawlers). This block holds
143
+ * the per-page opt-out levers that flip a page out of that default.
144
+ *
145
+ * **Field rationale**:
146
+ *
147
+ * - `noaiOptOut?` — when `true`, the page emits
148
+ * `<meta name="robots" content="noai, noimageai">` AND a sibling
149
+ * `_headers` file entry signalling `X-Robots-Tag: noai, noimageai`
150
+ * for crawlers that don't honor in-document meta. ONE knob drives
151
+ * BOTH channels (`headers-renderer.ts` reads the same flag) — the
152
+ * framework owns the dual emission so consumers can't accidentally
153
+ * set one and forget the other.
154
+ *
155
+ * **Why default-IN to AI training (D-AG3)**: the marketing-site
156
+ * default is `false` (consent to AI training). Marketing pages
157
+ * benefit from AI-engine citation; opting out is a per-page
158
+ * editorial decision (typically pricing pages — to avoid stale
159
+ * price training; or legal/internal pages — to avoid free-text
160
+ * reproduction of contractual language). Per-blog-post opt-out
161
+ * would mirror this knob on a sibling blog-post manifest schema
162
+ * if that need materializes.
163
+ */
164
+ declare const _WebsitePageSeoConfigSchema: z.ZodObject<{
165
+ noaiOptOut: z.ZodOptional<z.ZodBoolean>;
166
+ }, z.core.$strip>;
167
+ export declare const WebsitePageSeoConfigSchema: typeof _WebsitePageSeoConfigSchema;
168
+ export type WebsitePageSeoConfig = z.infer<typeof _WebsitePageSeoConfigSchema>;
169
+ /** @wildo_source:part:end saas.website.page-manifest.seo */
170
+ declare const _WebsitePageManifestSchema: z.ZodObject<{
171
+ ref: z.core.$ZodBranded<z.ZodString, "WebsitePageRef", "out">;
172
+ routePath: z.core.$ZodBranded<z.ZodString, "WebsitePageRoutePath", "out">;
173
+ pageComponent: z.ZodUnknown;
174
+ sectionRefs: z.ZodArray<z.core.$ZodBranded<z.ZodString, "WebsiteSectionRef", "out">>;
175
+ metaLabelKeys: z.ZodObject<{
176
+ titleKey: z.core.$ZodBranded<z.ZodString, "WebsiteLabelKey", "out">;
177
+ descriptionKey: z.core.$ZodBranded<z.ZodString, "WebsiteLabelKey", "out">;
178
+ ogImageUrl: z.ZodOptional<z.ZodURL>;
179
+ }, z.core.$strip>;
180
+ hydration: z.ZodOptional<z.ZodEnum<typeof WebsitePageHydrationStrategy>>;
181
+ seo: z.ZodOptional<z.ZodObject<{
182
+ noaiOptOut: z.ZodOptional<z.ZodBoolean>;
183
+ }, z.core.$strip>>;
184
+ }, z.core.$strip>;
185
+ export declare const WebsitePageManifestSchema: typeof _WebsitePageManifestSchema;
186
+ /**
187
+ * Runtime shape of `WebsitePageManifest`.
188
+ *
189
+ * **Why `ComponentType<any>` and NOT `ComponentType<unknown>`** —
190
+ * same variance reasoning as `WebsiteSectionDefinition.Component`:
191
+ * `ComponentType<TProps>` is CONTRAVARIANT in `TProps`, so a
192
+ * narrower `TypedWebsitePageManifest<TProps>` (returned by
193
+ * `defineWebsitePageManifest<TProps>`) was not assignable to a
194
+ * `WebsitePageManifest` typed with `ComponentType<unknown>`. That
195
+ * blocked every consumer call-site that passed a typed manifest to
196
+ * helpers / registries / validators expecting the bare type
197
+ * (root config's `pageManifests[]`, the Astro adapter's
198
+ * `loadWebsitePageRuntime`, and the head-renderer). Using `any`
199
+ * matches the React-canonical pattern for heterogeneous component
200
+ * containers and reflects the runtime contract: the framework only
201
+ * RENDERS these components — it never constructs ad-hoc props for
202
+ * them; the consumer's JSX call site supplies the precise props.
203
+ */
204
+ export interface WebsitePageManifest extends z.infer<typeof _WebsitePageManifestSchema> {
205
+ pageComponent: ComponentType<any>;
206
+ }
207
+ export {};
208
+ /** @wildo_source:part:end saas.website.page-manifest.schema */
209
+ //# sourceMappingURL=website-page-manifest.shared.schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"website-page-manifest.shared.schemas.d.ts","sourceRoot":"","sources":["../../../../../src/schemas/manifests/website-page-manifest.shared.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,QAAA,MAAM,+BAA+B;;;;iBAInC,CAAC;AAEH,eAAO,MAAM,8BAA8B,EAAE,OAAO,+BACnB,CAAC;AAElC,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC;AACvF,wEAAwE;AAExE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,QAAA,MAAM,2BAA2B,gEAWC,CAAC;AAEnC,eAAO,MAAM,0BAA0B,EAAE,OAAO,2BACnB,CAAC;AAE9B,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAC/E,mEAAmE;AAEnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgEG;AACH,oBAAY,4BAA4B;IACtC,+DAA+D;IAC/D,IAAI,SAAS;IACb,gEAAgE;IAChE,KAAK,UAAU;CAChB;AAED,eAAO,MAAM,kCAAkC,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,4BAA4B,CACxD,CAAC;AAEvC;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,QAAA,MAAM,2BAA2B;;iBAE/B,CAAC;AAEH,eAAO,MAAM,0BAA0B,EAAE,OAAO,2BACnB,CAAC;AAE9B,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAC/E,4DAA4D;AAE5D,QAAA,MAAM,0BAA0B;;;;;;;;;;;;;;iBAuC5B,CAAC;AAEL,eAAO,MAAM,yBAAyB,EAAE,OAAO,0BACnB,CAAC;AAE7B;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,mBAAoB,SAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC;IACrF,aAAa,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;CACnC;;AACD,+DAA+D"}
@@ -0,0 +1,218 @@
1
+ import { z } from 'zod';
2
+ import { WebsiteLabelKeySchema } from '../label-keys/website-label-key.schemas.js';
3
+ import { WebsitePageRefSchema } from '../refs/page-ref.schemas.js';
4
+ import { WebsiteSectionRefSchema } from '../refs/section-ref.schemas.js';
5
+ /**
6
+ * @wildo_source:part:start saas.website.page-manifest.meta-label-keys facet:layer:shared facet:family:website
7
+ *
8
+ * `WebsitePageMetaLabelKeys` — the i18n keys the Astro adapter (Phase 5)
9
+ * resolves at static-build time to populate `<title>` / `<meta>` /
10
+ * Open Graph tags for the page.
11
+ *
12
+ * - `titleKey` — REQUIRED. Renders into `<title>` AND `og:title`. The
13
+ * manifest commits to declaring this key in every locale's label
14
+ * pack; the validator surfaces missing entries at build start.
15
+ * - `descriptionKey` — REQUIRED. Renders into `<meta name="description">`,
16
+ * `og:description`, and `twitter:description`. Same per-locale
17
+ * commitment.
18
+ * - `ogImageUrl` — OPTIONAL. Static URL (typically a per-locale CDN
19
+ * path) for `og:image` / `twitter:image`. Not a label key because
20
+ * marketing teams overwhelmingly ship one localized asset URL per
21
+ * page rather than authoring image URLs in label packs. When
22
+ * per-locale images are needed, the consumer supplies a function
23
+ * in their site-root config that resolves locale → URL (Phase 5).
24
+ *
25
+ * **Why these three only**: the JSON-LD / canonical / `hreflang` /
26
+ * robots tags are NOT label-key-driven — they are derived
27
+ * mechanically from the manifest (`routePath`), the root config
28
+ * (`locales`, `defaultLocale`), and the section-level
29
+ * `getStructuredData()` hooks. Mixing them into the meta-label-keys
30
+ * shape would conflate human-authored copy with structural metadata.
31
+ */
32
+ const _WebsitePageMetaLabelKeysSchema = z.object({
33
+ titleKey: WebsiteLabelKeySchema,
34
+ descriptionKey: WebsiteLabelKeySchema,
35
+ ogImageUrl: z.url({ error: 'ogImageUrl must be a valid URL' }).optional(),
36
+ });
37
+ export const WebsitePageMetaLabelKeysSchema = _WebsitePageMetaLabelKeysSchema;
38
+ /** @wildo_source:part:end saas.website.page-manifest.meta-label-keys */
39
+ /**
40
+ * @wildo_source:part:start saas.website.page-manifest.route-path facet:layer:shared facet:family:website
41
+ *
42
+ * `WebsitePageRoutePath` — the URL path the page mounts at (locale
43
+ * prefix stripped).
44
+ *
45
+ * **Format**:
46
+ * - MUST start with `/`
47
+ * - MAY be the root (`'/'`) for the landing page
48
+ * - segments are lowercase kebab-case
49
+ * - parameter segments use Astro's `[param]` convention
50
+ * (e.g. `'/blog/[slug]'`, `'/case-studies/[slug]'`)
51
+ *
52
+ * The Astro adapter (Phase 5) prepends the locale prefix
53
+ * (`/en`, `/fr`, …) when generating routes. The manifest stores the
54
+ * locale-neutral path because the same `pageComponent` renders for
55
+ * every locale.
56
+ *
57
+ * **Brand**: prevents accidental cross-talk with absolute URLs
58
+ * (`https://…`), with locale-prefixed paths (`/en/pricing`), and with
59
+ * arbitrary string props in the manifest factory.
60
+ */
61
+ const _WebsitePageRoutePathSchema = z
62
+ .string()
63
+ .min(1, { error: 'routePath must not be empty' })
64
+ .max(256, { error: 'routePath must be at most 256 characters' })
65
+ .regex(/^\/(?:[a-z0-9][a-z0-9-]*(?:\/[a-z0-9-]+|\/\[[a-z][a-zA-Z0-9]*\])*)?\/?$/, {
66
+ error: 'routePath must start with `/`, use lowercase kebab-case segments, and may include Astro `[param]` segments (e.g. "/", "/pricing", "/blog/[slug]")',
67
+ })
68
+ .brand();
69
+ export const WebsitePageRoutePathSchema = _WebsitePageRoutePathSchema;
70
+ /** @wildo_source:part:end saas.website.page-manifest.route-path */
71
+ /**
72
+ * @wildo_source:part:start saas.website.page-manifest.schema facet:layer:shared facet:family:website
73
+ *
74
+ * `WebsitePageManifest` — the registration-time descriptor for one
75
+ * marketing-site page.
76
+ *
77
+ * **Authoring path**: each page-impl module exports both a
78
+ * `<PageName>Page` React component AND a `<PAGE_NAME>_PAGE_MANIFEST`
79
+ * literal. The manifest is collected into `WebsiteRootConfig.pageManifests[]`;
80
+ * the Astro page file (`src/pages/<page>.astro`) imports the manifest
81
+ * and hands it to `<WebsitePageBridge manifest={…}>` (Phase 5).
82
+ *
83
+ * **Field-by-field rationale** (semantic-weight discipline):
84
+ *
85
+ * - `ref` — the page's structural identity. Used for label-key
86
+ * derivation (`website.<ref>.<sectionRef>.<slot>`), for
87
+ * cross-page navigation lookup, and as the manifest registry key.
88
+ * - `routePath` — the locale-neutral URL path. Decoupled from `ref`
89
+ * because the same page (e.g. `ref: 'pricing'`) may mount at a
90
+ * localized path (`/tarifs` in French) — the locale-aware path
91
+ * resolution is a Phase 5 concern; this field is the canonical
92
+ * English-language path.
93
+ * - `pageComponent` — the React component the bridge renders inside
94
+ * `<WebsitePageContext value={{ pageRef: ref }}>`. Type relaxed to
95
+ * `unknown` at the schema layer for the same reasons as
96
+ * `WebsiteSectionDefinition.Component`; the manifest factory
97
+ * (`defineWebsitePageManifest`, Phase 2) preserves precise typing
98
+ * at the consumer call site.
99
+ * - `sectionRefs` — the contractual list of section refs the page
100
+ * declares. Used by the label-pack validator to cross-reference
101
+ * `expectedLabelKeys` collected from each section against the
102
+ * page's commitment. **Order matters** for the validator's
103
+ * diagnostic output (sections are reported in declaration order)
104
+ * but does NOT control render order — render order is whatever the
105
+ * `pageComponent` JSX lays out.
106
+ * - `metaLabelKeys` — see `WebsitePageMetaLabelKeysSchema`.
107
+ * - `hydration` — opt-in flag. `'lazy'` (default) corresponds to
108
+ * `client:idle` in the Astro adapter (deferred hydration); `'eager'`
109
+ * corresponds to `client:load` (immediate hydration). The page
110
+ * author flips this to `'eager'` only when the page hosts
111
+ * above-the-fold interactive sections (e.g. a contact form).
112
+ *
113
+ * **Important — informational, NOT auto-wired**: Astro's
114
+ * `client:*` directives MUST resolve to a literal token at compile
115
+ * time (the Astro compiler reads the directive from the JSX source
116
+ * to decide which hydration helper to bundle); a runtime-computed
117
+ * value will not work. The framework therefore CANNOT translate
118
+ * this field into the directive on the consumer's behalf — the
119
+ * manifest field is the single source of truth a consumer's
120
+ * per-page `.astro` template should USE to pick the matching
121
+ * `client:idle` / `client:load` directive by hand. Keeping the two
122
+ * in lock-step is a discipline obligation; the audit CLI (Phase 7)
123
+ * will surface a drift warning when a page's hydration field does
124
+ * not match the directive in its `.astro` file.
125
+ *
126
+ * **Refinements**:
127
+ * - `sectionRefs` MUST contain unique values. Duplicates indicate
128
+ * either a copy-paste bug (two sections pointing at the same
129
+ * label-key root) or an intent to share a label-key root that
130
+ * the framework rejects to keep the per-page validation
131
+ * unambiguous (consumers who need a shared label-key root
132
+ * across two distinct sections should pull the shared content
133
+ * to the page level via `WebsiteRootConfig`-level globals,
134
+ * Phase 2.5).
135
+ */
136
+ export var WebsitePageHydrationStrategy;
137
+ (function (WebsitePageHydrationStrategy) {
138
+ /** `client:idle` in the Astro adapter (deferred hydration). */
139
+ WebsitePageHydrationStrategy["LAZY"] = "lazy";
140
+ /** `client:load` in the Astro adapter (immediate hydration). */
141
+ WebsitePageHydrationStrategy["EAGER"] = "eager";
142
+ })(WebsitePageHydrationStrategy || (WebsitePageHydrationStrategy = {}));
143
+ export const WebsitePageHydrationStrategySchema = z.enum(WebsitePageHydrationStrategy);
144
+ /**
145
+ * @wildo_source:part:start saas.website.page-manifest.seo facet:layer:shared facet:family:website
146
+ *
147
+ * `WebsitePageSeoConfig` — per-page SEO/AEO/GEO knobs.
148
+ *
149
+ * The marketing-site default is to be FULLY discoverable by every
150
+ * crawler (search engines AND AI training crawlers). This block holds
151
+ * the per-page opt-out levers that flip a page out of that default.
152
+ *
153
+ * **Field rationale**:
154
+ *
155
+ * - `noaiOptOut?` — when `true`, the page emits
156
+ * `<meta name="robots" content="noai, noimageai">` AND a sibling
157
+ * `_headers` file entry signalling `X-Robots-Tag: noai, noimageai`
158
+ * for crawlers that don't honor in-document meta. ONE knob drives
159
+ * BOTH channels (`headers-renderer.ts` reads the same flag) — the
160
+ * framework owns the dual emission so consumers can't accidentally
161
+ * set one and forget the other.
162
+ *
163
+ * **Why default-IN to AI training (D-AG3)**: the marketing-site
164
+ * default is `false` (consent to AI training). Marketing pages
165
+ * benefit from AI-engine citation; opting out is a per-page
166
+ * editorial decision (typically pricing pages — to avoid stale
167
+ * price training; or legal/internal pages — to avoid free-text
168
+ * reproduction of contractual language). Per-blog-post opt-out
169
+ * would mirror this knob on a sibling blog-post manifest schema
170
+ * if that need materializes.
171
+ */
172
+ const _WebsitePageSeoConfigSchema = z.object({
173
+ noaiOptOut: z.boolean().optional(),
174
+ });
175
+ export const WebsitePageSeoConfigSchema = _WebsitePageSeoConfigSchema;
176
+ /** @wildo_source:part:end saas.website.page-manifest.seo */
177
+ const _WebsitePageManifestSchema = z
178
+ .object({
179
+ ref: WebsitePageRefSchema,
180
+ routePath: _WebsitePageRoutePathSchema,
181
+ pageComponent: z.unknown(),
182
+ sectionRefs: z.array(WebsiteSectionRefSchema).min(1, {
183
+ error: 'A page manifest must declare at least one sectionRef',
184
+ }),
185
+ metaLabelKeys: _WebsitePageMetaLabelKeysSchema,
186
+ hydration: WebsitePageHydrationStrategySchema.optional(),
187
+ seo: _WebsitePageSeoConfigSchema.optional(),
188
+ })
189
+ .superRefine((manifest, ctx) => {
190
+ const seen = new Set();
191
+ for (const [index, sectionRef] of manifest.sectionRefs.entries()) {
192
+ const key = sectionRef;
193
+ if (seen.has(key)) {
194
+ ctx.addIssue({
195
+ code: 'custom',
196
+ path: ['sectionRefs', index],
197
+ message: `Duplicate sectionRef "${key}" in page manifest "${manifest.ref}"`,
198
+ });
199
+ }
200
+ seen.add(key);
201
+ }
202
+ const expectedPagePrefix = `website.${manifest.ref}.`;
203
+ for (const [field, key] of [
204
+ ['titleKey', manifest.metaLabelKeys.titleKey],
205
+ ['descriptionKey', manifest.metaLabelKeys.descriptionKey],
206
+ ]) {
207
+ if (!key.startsWith(expectedPagePrefix)) {
208
+ ctx.addIssue({
209
+ code: 'custom',
210
+ path: ['metaLabelKeys', field],
211
+ message: `metaLabelKeys.${field} ("${key}") must be rooted under the page ref "${manifest.ref}" (expected prefix "${expectedPagePrefix}")`,
212
+ });
213
+ }
214
+ }
215
+ });
216
+ export const WebsitePageManifestSchema = _WebsitePageManifestSchema;
217
+ /** @wildo_source:part:end saas.website.page-manifest.schema */
218
+ //# sourceMappingURL=website-page-manifest.shared.schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"website-page-manifest.shared.schemas.js","sourceRoot":"","sources":["../../../../../src/schemas/manifests/website-page-manifest.shared.schemas.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ComponentType } from 'react';\nimport { z } from 'zod';\n\nimport { WebsiteLabelKeySchema } from '../label-keys/website-label-key.schemas';\nimport { WebsitePageRefSchema } from '../refs/page-ref.schemas';\nimport { WebsiteSectionRefSchema } from '../refs/section-ref.schemas';\n\n/**\n * @wildo_source:part:start saas.website.page-manifest.meta-label-keys facet:layer:shared facet:family:website\n *\n * `WebsitePageMetaLabelKeys` — the i18n keys the Astro adapter (Phase 5)\n * resolves at static-build time to populate `<title>` / `<meta>` /\n * Open Graph tags for the page.\n *\n * - `titleKey` — REQUIRED. Renders into `<title>` AND `og:title`. The\n * manifest commits to declaring this key in every locale's label\n * pack; the validator surfaces missing entries at build start.\n * - `descriptionKey` — REQUIRED. Renders into `<meta name=\"description\">`,\n * `og:description`, and `twitter:description`. Same per-locale\n * commitment.\n * - `ogImageUrl` — OPTIONAL. Static URL (typically a per-locale CDN\n * path) for `og:image` / `twitter:image`. Not a label key because\n * marketing teams overwhelmingly ship one localized asset URL per\n * page rather than authoring image URLs in label packs. When\n * per-locale images are needed, the consumer supplies a function\n * in their site-root config that resolves locale → URL (Phase 5).\n *\n * **Why these three only**: the JSON-LD / canonical / `hreflang` /\n * robots tags are NOT label-key-driven — they are derived\n * mechanically from the manifest (`routePath`), the root config\n * (`locales`, `defaultLocale`), and the section-level\n * `getStructuredData()` hooks. Mixing them into the meta-label-keys\n * shape would conflate human-authored copy with structural metadata.\n */\nconst _WebsitePageMetaLabelKeysSchema = z.object({\n titleKey: WebsiteLabelKeySchema,\n descriptionKey: WebsiteLabelKeySchema,\n ogImageUrl: z.url({ error: 'ogImageUrl must be a valid URL' }).optional(),\n});\n\nexport const WebsitePageMetaLabelKeysSchema: typeof _WebsitePageMetaLabelKeysSchema =\n _WebsitePageMetaLabelKeysSchema;\n\nexport type WebsitePageMetaLabelKeys = z.infer<typeof _WebsitePageMetaLabelKeysSchema>;\n/** @wildo_source:part:end saas.website.page-manifest.meta-label-keys */\n\n/**\n * @wildo_source:part:start saas.website.page-manifest.route-path facet:layer:shared facet:family:website\n *\n * `WebsitePageRoutePath` — the URL path the page mounts at (locale\n * prefix stripped).\n *\n * **Format**:\n * - MUST start with `/`\n * - MAY be the root (`'/'`) for the landing page\n * - segments are lowercase kebab-case\n * - parameter segments use Astro's `[param]` convention\n * (e.g. `'/blog/[slug]'`, `'/case-studies/[slug]'`)\n *\n * The Astro adapter (Phase 5) prepends the locale prefix\n * (`/en`, `/fr`, …) when generating routes. The manifest stores the\n * locale-neutral path because the same `pageComponent` renders for\n * every locale.\n *\n * **Brand**: prevents accidental cross-talk with absolute URLs\n * (`https://…`), with locale-prefixed paths (`/en/pricing`), and with\n * arbitrary string props in the manifest factory.\n */\nconst _WebsitePageRoutePathSchema = z\n .string()\n .min(1, { error: 'routePath must not be empty' })\n .max(256, { error: 'routePath must be at most 256 characters' })\n .regex(\n /^\\/(?:[a-z0-9][a-z0-9-]*(?:\\/[a-z0-9-]+|\\/\\[[a-z][a-zA-Z0-9]*\\])*)?\\/?$/,\n {\n error:\n 'routePath must start with `/`, use lowercase kebab-case segments, and may include Astro `[param]` segments (e.g. \"/\", \"/pricing\", \"/blog/[slug]\")',\n },\n )\n .brand<'WebsitePageRoutePath'>();\n\nexport const WebsitePageRoutePathSchema: typeof _WebsitePageRoutePathSchema =\n _WebsitePageRoutePathSchema;\n\nexport type WebsitePageRoutePath = z.infer<typeof _WebsitePageRoutePathSchema>;\n/** @wildo_source:part:end saas.website.page-manifest.route-path */\n\n/**\n * @wildo_source:part:start saas.website.page-manifest.schema facet:layer:shared facet:family:website\n *\n * `WebsitePageManifest` — the registration-time descriptor for one\n * marketing-site page.\n *\n * **Authoring path**: each page-impl module exports both a\n * `<PageName>Page` React component AND a `<PAGE_NAME>_PAGE_MANIFEST`\n * literal. The manifest is collected into `WebsiteRootConfig.pageManifests[]`;\n * the Astro page file (`src/pages/<page>.astro`) imports the manifest\n * and hands it to `<WebsitePageBridge manifest={…}>` (Phase 5).\n *\n * **Field-by-field rationale** (semantic-weight discipline):\n *\n * - `ref` — the page's structural identity. Used for label-key\n * derivation (`website.<ref>.<sectionRef>.<slot>`), for\n * cross-page navigation lookup, and as the manifest registry key.\n * - `routePath` — the locale-neutral URL path. Decoupled from `ref`\n * because the same page (e.g. `ref: 'pricing'`) may mount at a\n * localized path (`/tarifs` in French) — the locale-aware path\n * resolution is a Phase 5 concern; this field is the canonical\n * English-language path.\n * - `pageComponent` — the React component the bridge renders inside\n * `<WebsitePageContext value={{ pageRef: ref }}>`. Type relaxed to\n * `unknown` at the schema layer for the same reasons as\n * `WebsiteSectionDefinition.Component`; the manifest factory\n * (`defineWebsitePageManifest`, Phase 2) preserves precise typing\n * at the consumer call site.\n * - `sectionRefs` — the contractual list of section refs the page\n * declares. Used by the label-pack validator to cross-reference\n * `expectedLabelKeys` collected from each section against the\n * page's commitment. **Order matters** for the validator's\n * diagnostic output (sections are reported in declaration order)\n * but does NOT control render order — render order is whatever the\n * `pageComponent` JSX lays out.\n * - `metaLabelKeys` — see `WebsitePageMetaLabelKeysSchema`.\n * - `hydration` — opt-in flag. `'lazy'` (default) corresponds to\n * `client:idle` in the Astro adapter (deferred hydration); `'eager'`\n * corresponds to `client:load` (immediate hydration). The page\n * author flips this to `'eager'` only when the page hosts\n * above-the-fold interactive sections (e.g. a contact form).\n *\n * **Important — informational, NOT auto-wired**: Astro's\n * `client:*` directives MUST resolve to a literal token at compile\n * time (the Astro compiler reads the directive from the JSX source\n * to decide which hydration helper to bundle); a runtime-computed\n * value will not work. The framework therefore CANNOT translate\n * this field into the directive on the consumer's behalf — the\n * manifest field is the single source of truth a consumer's\n * per-page `.astro` template should USE to pick the matching\n * `client:idle` / `client:load` directive by hand. Keeping the two\n * in lock-step is a discipline obligation; the audit CLI (Phase 7)\n * will surface a drift warning when a page's hydration field does\n * not match the directive in its `.astro` file.\n *\n * **Refinements**:\n * - `sectionRefs` MUST contain unique values. Duplicates indicate\n * either a copy-paste bug (two sections pointing at the same\n * label-key root) or an intent to share a label-key root that\n * the framework rejects to keep the per-page validation\n * unambiguous (consumers who need a shared label-key root\n * across two distinct sections should pull the shared content\n * to the page level via `WebsiteRootConfig`-level globals,\n * Phase 2.5).\n */\nexport enum WebsitePageHydrationStrategy {\n /** `client:idle` in the Astro adapter (deferred hydration). */\n LAZY = 'lazy',\n /** `client:load` in the Astro adapter (immediate hydration). */\n EAGER = 'eager',\n}\n\nexport const WebsitePageHydrationStrategySchema: z.ZodEnum<typeof WebsitePageHydrationStrategy> =\n z.enum(WebsitePageHydrationStrategy);\n\n/**\n * @wildo_source:part:start saas.website.page-manifest.seo facet:layer:shared facet:family:website\n *\n * `WebsitePageSeoConfig` — per-page SEO/AEO/GEO knobs.\n *\n * The marketing-site default is to be FULLY discoverable by every\n * crawler (search engines AND AI training crawlers). This block holds\n * the per-page opt-out levers that flip a page out of that default.\n *\n * **Field rationale**:\n *\n * - `noaiOptOut?` — when `true`, the page emits\n * `<meta name=\"robots\" content=\"noai, noimageai\">` AND a sibling\n * `_headers` file entry signalling `X-Robots-Tag: noai, noimageai`\n * for crawlers that don't honor in-document meta. ONE knob drives\n * BOTH channels (`headers-renderer.ts` reads the same flag) — the\n * framework owns the dual emission so consumers can't accidentally\n * set one and forget the other.\n *\n * **Why default-IN to AI training (D-AG3)**: the marketing-site\n * default is `false` (consent to AI training). Marketing pages\n * benefit from AI-engine citation; opting out is a per-page\n * editorial decision (typically pricing pages — to avoid stale\n * price training; or legal/internal pages — to avoid free-text\n * reproduction of contractual language). Per-blog-post opt-out\n * would mirror this knob on a sibling blog-post manifest schema\n * if that need materializes.\n */\nconst _WebsitePageSeoConfigSchema = z.object({\n noaiOptOut: z.boolean().optional(),\n});\n\nexport const WebsitePageSeoConfigSchema: typeof _WebsitePageSeoConfigSchema =\n _WebsitePageSeoConfigSchema;\n\nexport type WebsitePageSeoConfig = z.infer<typeof _WebsitePageSeoConfigSchema>;\n/** @wildo_source:part:end saas.website.page-manifest.seo */\n\nconst _WebsitePageManifestSchema = z\n .object({\n ref: WebsitePageRefSchema,\n routePath: _WebsitePageRoutePathSchema,\n pageComponent: z.unknown(),\n sectionRefs: z.array(WebsiteSectionRefSchema).min(1, {\n error: 'A page manifest must declare at least one sectionRef',\n }),\n metaLabelKeys: _WebsitePageMetaLabelKeysSchema,\n hydration: WebsitePageHydrationStrategySchema.optional(),\n seo: _WebsitePageSeoConfigSchema.optional(),\n })\n .superRefine((manifest, ctx) => {\n const seen = new Set<string>();\n for (const [index, sectionRef] of manifest.sectionRefs.entries()) {\n const key = sectionRef as unknown as string;\n if (seen.has(key)) {\n ctx.addIssue({\n code: 'custom',\n path: ['sectionRefs', index],\n message: `Duplicate sectionRef \"${key}\" in page manifest \"${manifest.ref as unknown as string}\"`,\n });\n }\n seen.add(key);\n }\n\n const expectedPagePrefix = `website.${manifest.ref as unknown as string}.`;\n for (const [field, key] of [\n ['titleKey', manifest.metaLabelKeys.titleKey] as const,\n ['descriptionKey', manifest.metaLabelKeys.descriptionKey] as const,\n ]) {\n if (!(key as unknown as string).startsWith(expectedPagePrefix)) {\n ctx.addIssue({\n code: 'custom',\n path: ['metaLabelKeys', field],\n message: `metaLabelKeys.${field} (\"${key as unknown as string}\") must be rooted under the page ref \"${manifest.ref as unknown as string}\" (expected prefix \"${expectedPagePrefix}\")`,\n });\n }\n }\n });\n\nexport const WebsitePageManifestSchema: typeof _WebsitePageManifestSchema =\n _WebsitePageManifestSchema;\n\n/**\n * Runtime shape of `WebsitePageManifest`.\n *\n * **Why `ComponentType<any>` and NOT `ComponentType<unknown>`** —\n * same variance reasoning as `WebsiteSectionDefinition.Component`:\n * `ComponentType<TProps>` is CONTRAVARIANT in `TProps`, so a\n * narrower `TypedWebsitePageManifest<TProps>` (returned by\n * `defineWebsitePageManifest<TProps>`) was not assignable to a\n * `WebsitePageManifest` typed with `ComponentType<unknown>`. That\n * blocked every consumer call-site that passed a typed manifest to\n * helpers / registries / validators expecting the bare type\n * (root config's `pageManifests[]`, the Astro adapter's\n * `loadWebsitePageRuntime`, and the head-renderer). Using `any`\n * matches the React-canonical pattern for heterogeneous component\n * containers and reflects the runtime contract: the framework only\n * RENDERS these components — it never constructs ad-hoc props for\n * them; the consumer's JSX call site supplies the precise props.\n */\nexport interface WebsitePageManifest extends z.infer<typeof _WebsitePageManifestSchema> {\n pageComponent: ComponentType<any>;\n}\n/** @wildo_source:part:end saas.website.page-manifest.schema */\n"]}