@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,438 @@
1
+ import { z } from 'zod';
2
+ import { WebsiteDesignTokensSchema } from '../design-tokens/website-design-tokens.shared.schemas.js';
3
+ import { WebsiteLabelKeySchema } from '../label-keys/website-label-key.schemas.js';
4
+ import { WebsitePageManifestSchema, } from './website-page-manifest.shared.schemas.js';
5
+ /**
6
+ * @wildo_source:part:start saas.website.seo.sitemap-config facet:layer:shared facet:family:website
7
+ *
8
+ * `WebsiteSitemapConfig` — site-wide sitemap policy block.
9
+ *
10
+ * Materialized at build time by `@astrojs/sitemap` (the official
11
+ * Astro plugin) when the consumer wires it into `astro.config.ts`
12
+ * (see `website-seo-aeo-geo` SKILL). The framework owns the
13
+ * **schema** (so config + enforcement live in lock-step with the
14
+ * page registry) but the framework does NOT own the runtime
15
+ * generator — `@astrojs/sitemap` already covers per-page
16
+ * `lastmod` / `changefreq` / `priority` + i18n `xhtml:link
17
+ * hreflang` annotations natively, and re-implementing that surface
18
+ * inside the engine would duplicate well-trodden Astro tooling for
19
+ * zero added value.
20
+ *
21
+ * # Field rationale
22
+ *
23
+ * **Why `enabled` defaults to `true`**:
24
+ * - Marketing sites that want to ship public pages overwhelmingly
25
+ * also want them in `sitemap.xml` (search engines treat its
26
+ * absence as a discoverability signal). The opt-OUT shape avoids
27
+ * a silent regression where a consumer ships pages that crawlers
28
+ * never index because they forgot to flip a flag.
29
+ * - The escape hatch (`enabled: false`) covers staging deployments
30
+ * and the rare per-app decision to suppress sitemap emission
31
+ * entirely (e.g. a private beta surface routed under a
32
+ * `noindex` policy).
33
+ *
34
+ * **Why `changefreq` / `priority` are OPTIONAL** (no defaults):
35
+ * - Both fields are non-binding hints — Google explicitly
36
+ * ignores `priority` and treats `changefreq` as a soft signal.
37
+ * Forcing the consumer to pick a value would either invite
38
+ * superstitious authoring (`priority: 1.0` on every page) or
39
+ * bury the field's actual ergonomic shape (per-page overrides
40
+ * via `WebsitePageManifest.seo` — deferred until a real
41
+ * consumer requests it).
42
+ * - Unset values are simply omitted from the emitted `<url>`
43
+ * entries; `@astrojs/sitemap` handles that automatically.
44
+ *
45
+ * **Validation**:
46
+ * - `priority` is `z.number().min(0).max(1)` — outside the spec
47
+ * range would silently break crawler ingestion.
48
+ * - `changefreq` is the union of the seven values the sitemap
49
+ * spec defines; arbitrary strings would be silently dropped by
50
+ * compliant crawlers.
51
+ */
52
+ const _WebsiteSitemapConfigSchema = z.object({
53
+ enabled: z.boolean().default(true),
54
+ changefreq: z
55
+ .enum(['always', 'hourly', 'daily', 'weekly', 'monthly', 'yearly', 'never'])
56
+ .optional(),
57
+ priority: z
58
+ .number()
59
+ .min(0, { error: 'WebsiteSitemapConfig.priority must be between 0 and 1' })
60
+ .max(1, { error: 'WebsiteSitemapConfig.priority must be between 0 and 1' })
61
+ .optional(),
62
+ });
63
+ export const WebsiteSitemapConfigSchema = _WebsiteSitemapConfigSchema;
64
+ /** @wildo_source:part:end saas.website.seo.sitemap-config */
65
+ /**
66
+ * @wildo_source:part:start saas.website.seo.robots-config facet:layer:shared facet:family:website
67
+ *
68
+ * `WebsiteRobotsConfig` — site-wide `robots.txt` policy block.
69
+ *
70
+ * Materialized at request time by `renderRobotsTxt(siteContext)`
71
+ * from `@wildo-ai/saas-website/astro` (consumer wires a thin
72
+ * `src/pages/robots.txt.ts` Astro endpoint that returns the helper's
73
+ * output). Scoped to the SITE-WIDE policy surface — per-page
74
+ * `noindex` is a separate concern that lands on
75
+ * `WebsitePageManifest.seo` once a real consumer requests it (today
76
+ * the site-wide `disallow[]` covers staging-environment exclusion of
77
+ * specific path prefixes, the dominant real-world use case).
78
+ *
79
+ * # Field rationale
80
+ *
81
+ * **Why `policy` defaults to `'index'`**:
82
+ * - The default for a public marketing site is "let crawlers in";
83
+ * `'noindex'` is the deliberate exception (staging environments,
84
+ * beta surfaces, sites still under construction). The opt-OUT
85
+ * shape mirrors `WebsiteSitemapConfig.enabled` for consistency.
86
+ * - `'noindex'` emits a `User-agent: *\nDisallow: /` block — the
87
+ * standard "tell every well-behaved crawler to stay away"
88
+ * primitive.
89
+ *
90
+ * **Why `disallow[]` is a path-prefix list (not a regex)**:
91
+ * - The `robots.txt` spec only supports literal path prefixes
92
+ * with `*` / `$` wildcards; Disallow is NOT a regex surface.
93
+ * Typing it as `string[]` (validated to start with `/`) keeps
94
+ * the contract honest and lets consumers paste from their CDN
95
+ * allowlists without translation.
96
+ *
97
+ * **Why `allowedCrawlers` and `disallowedCrawlers` are mutually
98
+ * exclusive**:
99
+ * - The two fields are two halves of the SAME AI-crawler policy
100
+ * decision. `allowedCrawlers` is the deny-by-default shape
101
+ * (only the named bots may crawl); `disallowedCrawlers` is the
102
+ * allow-by-default shape (every bot except the named ones may
103
+ * crawl). Mixing both would emit a contradictory `robots.txt`
104
+ * (a bot in both lists would receive conflicting directives).
105
+ * A `superRefine` enforces the mutual-exclusion invariant at
106
+ * parse time so the build fails fast.
107
+ *
108
+ * **Validation**:
109
+ * - `disallow[]` entries must start with `/` (sitemap path-prefix
110
+ * spec) — anything else would silently match nothing.
111
+ * - `allowedCrawlers` / `disallowedCrawlers` entries must be
112
+ * non-empty strings (a blank User-agent token would emit
113
+ * `User-agent: ` which compliant crawlers ignore — silent
114
+ * misconfig).
115
+ * - `superRefine` rejects the combined-list anti-pattern.
116
+ */
117
+ const _WebsiteRobotsConfigSchema = z
118
+ .object({
119
+ policy: z.enum(['index', 'noindex']).default('index'),
120
+ disallow: z
121
+ .array(z
122
+ .string()
123
+ .min(1)
124
+ .refine((path) => path.startsWith('/'), {
125
+ error: 'WebsiteRobotsConfig.disallow[] entries must start with "/"',
126
+ }))
127
+ .optional(),
128
+ /**
129
+ * Deny-by-default AI-crawler allowlist. When set, the emitted
130
+ * `robots.txt` lists each named bot under its own
131
+ * `User-agent: <bot>\nAllow: /` block, then closes with a
132
+ * catch-all `User-agent: *\nDisallow: /`. Mutually exclusive
133
+ * with `disallowedCrawlers` (see `superRefine` below).
134
+ */
135
+ allowedCrawlers: z.array(z.string().min(1)).optional(),
136
+ /**
137
+ * Allow-by-default AI-crawler denylist. When set, the emitted
138
+ * `robots.txt` lists each named bot under its own
139
+ * `User-agent: <bot>\nDisallow: /` block. Mutually exclusive
140
+ * with `allowedCrawlers` (see `superRefine` below).
141
+ */
142
+ disallowedCrawlers: z.array(z.string().min(1)).optional(),
143
+ })
144
+ .superRefine((value, ctx) => {
145
+ if (value.allowedCrawlers !== undefined && value.disallowedCrawlers !== undefined) {
146
+ ctx.addIssue({
147
+ code: 'custom',
148
+ path: ['allowedCrawlers'],
149
+ message: 'WebsiteRobotsConfig.allowedCrawlers and disallowedCrawlers are mutually exclusive — pick one policy direction (deny-by-default vs allow-by-default).',
150
+ });
151
+ }
152
+ });
153
+ export const WebsiteRobotsConfigSchema = _WebsiteRobotsConfigSchema;
154
+ /** @wildo_source:part:end saas.website.seo.robots-config */
155
+ /**
156
+ * @wildo_source:part:start saas.website.seo.llms-txt-config facet:layer:shared facet:family:website
157
+ *
158
+ * `WebsiteLlmsTxtConfig` — site-wide `llms.txt` publication policy.
159
+ *
160
+ * The framework owns only the SERVING surface; the CONTENT remains
161
+ * hand-authored in `src/content/llms.txt`. This block therefore needs
162
+ * exactly one knob:
163
+ *
164
+ * - `enabled?: boolean`
165
+ * - `true` → publish when the file exists
166
+ * - `false` → suppress publication even if the file exists
167
+ * - `undefined` → auto-detect (`readLlmsTxtBody` publishes when the
168
+ * file exists, returns `null` when absent)
169
+ *
170
+ * Keeping the "auto-detect when undefined" convention in the HELPER
171
+ * (not as a schema default) is deliberate: schema defaults are static,
172
+ * while file presence is runtime/build-time state.
173
+ */
174
+ const _WebsiteLlmsTxtConfigSchema = z.object({
175
+ enabled: z.boolean().optional(),
176
+ });
177
+ export const WebsiteLlmsTxtConfigSchema = _WebsiteLlmsTxtConfigSchema;
178
+ /** @wildo_source:part:end saas.website.seo.llms-txt-config */
179
+ /**
180
+ * @wildo_source:part:start saas.website.root-config.seo facet:layer:shared facet:family:website
181
+ *
182
+ * `WebsiteSeoConfig` — site-wide SEO/social-graph configuration
183
+ * AUTHORED ON THE ROOT CONFIG.
184
+ *
185
+ * # Scope
186
+ *
187
+ * The public marketing-site origin belongs only in the per-service
188
+ * `wildo.website.config.ts` declaration. Keep it out of this site-level SEO
189
+ * block so the origin and localized routing have one source of truth.
190
+ *
191
+ * What stays on this block: site-level branding + hero-image
192
+ * fallbacks that are co-authored with chrome labels and page
193
+ * manifests respectively, NOT with the URL/i18n routing surface.
194
+ *
195
+ * # Field rationale
196
+ *
197
+ * **Why `siteName` is REQUIRED**:
198
+ * - `og:site_name` is the brand label social platforms render
199
+ * above the page title in shared previews. Without it, every
200
+ * LinkedIn / Facebook / Slack preview shows the bare title with
201
+ * no brand context.
202
+ * - It is also the recommended `application-name` meta tag value
203
+ * and a useful default for JSON-LD `Organization.name` schema
204
+ * when the application ships structured data.
205
+ *
206
+ * **Why `defaultOgImageUrl` is OPTIONAL**:
207
+ * - Each page's `WebsitePageManifest.metaLabelKeys.ogImageUrl`
208
+ * takes precedence; the site-level default is a fallback for
209
+ * pages that did not commit to a hero image.
210
+ * - Marketing surfaces shipping no OG images at all (acceptable
211
+ * for a placeholder build) should not be forced to author one.
212
+ *
213
+ * **Why `sitemap?` and `robots?` are OPTIONAL** (with sensible
214
+ * defaults inside each sub-schema):
215
+ * - The marketing-site default ships a public surface — every
216
+ * page indexable, no AI-crawler restrictions, no per-path
217
+ * disallow. Forcing every consumer to author both blocks just
218
+ * to land in that default state would pollute the call site.
219
+ * - Omitting either block at the call site is equivalent to
220
+ * authoring `{}` — `WebsiteSitemapConfig.enabled` defaults to
221
+ * `true`, `WebsiteRobotsConfig.policy` defaults to `'index'`.
222
+ * The per-block field rationale lives on each sub-schema.
223
+ * - `llmsTxt?` is similarly optional, but with a different default
224
+ * mechanic: omitting the block means "auto-detect from file
225
+ * presence" rather than "use a static schema default". The helper
226
+ * `readLlmsTxtBody(...)` publishes when `src/content/llms.txt`
227
+ * exists and returns `null` otherwise.
228
+ *
229
+ * **Validation**:
230
+ * - `siteName` is `z.string().min(1)` — empty strings would emit
231
+ * `<meta property="og:site_name" content="" />` which social
232
+ * platforms render as a blank line.
233
+ * - `defaultOgImageUrl` (when present) is `z.url()`.
234
+ * - `sitemap` / `robots` validation lives on the sub-schemas.
235
+ */
236
+ const _WebsiteSeoConfigSchema = z
237
+ .object({
238
+ siteName: z
239
+ .string()
240
+ .min(1, { error: 'WebsiteSeoConfig.siteName must be a non-empty string' }),
241
+ defaultOgImageUrl: z
242
+ .url({ error: 'WebsiteSeoConfig.defaultOgImageUrl must be a fully-qualified URL' })
243
+ .optional(),
244
+ /**
245
+ * Sitemap policy block. Optional — omitting it is equivalent to
246
+ * `{ enabled: true }` (the marketing-site default). See
247
+ * `WebsiteSitemapConfigSchema` for field-by-field rationale.
248
+ */
249
+ sitemap: _WebsiteSitemapConfigSchema.optional(),
250
+ /**
251
+ * Robots.txt policy block. Optional — omitting it is equivalent
252
+ * to `{ policy: 'index' }` (the marketing-site default). See
253
+ * `WebsiteRobotsConfigSchema` for field-by-field rationale.
254
+ */
255
+ robots: _WebsiteRobotsConfigSchema.optional(),
256
+ /**
257
+ * `llms.txt` publication policy. Optional — omitting it means
258
+ * "auto-detect from file presence". See
259
+ * `WebsiteLlmsTxtConfigSchema` for the serving contract.
260
+ */
261
+ llmsTxt: _WebsiteLlmsTxtConfigSchema.optional(),
262
+ });
263
+ export const WebsiteSeoConfigSchema = _WebsiteSeoConfigSchema;
264
+ /** @wildo_source:part:end saas.website.root-config.seo */
265
+ /**
266
+ * @wildo_source:part:start saas.website.root-config.navigation facet:layer:shared facet:family:website
267
+ *
268
+ * `WebsiteNavigationConfig` — site-wide header/footer slot bindings.
269
+ *
270
+ * The framework intentionally ships no concrete header or footer. The
271
+ * application authors both as React components, registers them once here, and
272
+ * the page layout renders the site-wide chrome around every page.
273
+ *
274
+ * Both fields are typed as `unknown` at the schema layer with the
275
+ * `WebsiteNavigationConfig` interface narrowing them to
276
+ * `ComponentType<unknown>` — same rationale as
277
+ * `WebsiteSectionDefinition.Component` and `WebsitePageManifest.pageComponent`.
278
+ */
279
+ const _WebsiteNavigationConfigSchema = z.object({
280
+ headerComponent: z.unknown(),
281
+ footerComponent: z.unknown(),
282
+ });
283
+ export const WebsiteNavigationConfigSchema = _WebsiteNavigationConfigSchema;
284
+ /** @wildo_source:part:end saas.website.root-config.navigation */
285
+ /**
286
+ * @wildo_source:part:start saas.website.root-config.schema facet:layer:shared facet:family:website
287
+ *
288
+ * `WebsiteRootConfig` — the site-level configuration consumed by:
289
+ * - the Astro adapter to drive i18n routing, page mounting,
290
+ * and design-token CSS emission,
291
+ * - the website audit command to validate label-pack
292
+ * coverage and SEO structured-data conformance,
293
+ * - the runtime `<WebsitePageLayout>` to render navigation
294
+ * and apply design tokens.
295
+ *
296
+ * **Authoring convention**: each marketing-site service exports a single
297
+ * `WEBSITE_ROOT_CONFIG: WebsiteRootConfig` from `src/website-root.config.ts`.
298
+ * The Astro adapter and the audit command
299
+ * both consume this canonical entry point; there is exactly one site
300
+ * config per marketing site (no per-page or per-section overrides at
301
+ * this level — overrides flow through the L0/L1/L1.5 component
302
+ * registration hierarchy described in D6).
303
+ *
304
+ * # Scope
305
+ *
306
+ * This block carries site-level chrome and registry data only. Per-locale
307
+ * routing (`locales` / `defaultLocale`) and the public origin belong in the
308
+ * per-service `wildo.website.config.ts` declaration, avoiding duplicated
309
+ * configuration that could diverge during site generation.
310
+ *
311
+ * **Field-by-field rationale**:
312
+ *
313
+ * - `pageManifests` — the registry of every page on the site. Indexed
314
+ * downstream by `manifest.ref`. Refs MUST be unique (refinement
315
+ * below).
316
+ * - `designTokens` — see `WebsiteDesignTokensSchema`.
317
+ * - `navigation` — see `WebsiteNavigationConfigSchema`.
318
+ * - `chromeLabelKeys` — OPTIONAL. The set of fully-composed label keys
319
+ * the site-wide chrome (header / footer / any global slot the
320
+ * consumer renders outside a section context) reads via
321
+ * `useWebsiteLabelByKey(...)`. Declared here, NOT in section
322
+ * `expectedLabelKeys`, because chrome is rendered outside the
323
+ * page+section context — `useWebsiteLabel(slot)` is structurally
324
+ * unavailable to it. Threading these through the label-pack
325
+ * validator (a) silences the always-on "orphaned chrome key" build
326
+ * warnings and (b) lets the build fail fast when a chrome key is
327
+ * missing from a locale pack, the same way section keys do.
328
+ * Defaults to an empty array; sites with no chrome label reads
329
+ * may omit the field entirely.
330
+ * - `seo` — site-level branding + hero-image fallback (see
331
+ * `WebsiteSeoConfigSchema`). The marketing-site origin USED to live
332
+ * here as `seo.siteOrigin`; it now lives only on
333
+ * `WildoMarketingWebsiteConfig.publicOrigin`.
334
+ * - `skipToMainContentLabelKey` — see field JSDoc below.
335
+ *
336
+ * **Refinements**:
337
+ * - `pageManifests[].ref` uniqueness — the registry is keyed by ref;
338
+ * duplicates would silently overwrite each other in the lookup
339
+ * table the bridge uses for cross-page links.
340
+ * - `pageManifests[].routePath` uniqueness — two pages cannot mount
341
+ * at the same path (Astro would error at build time, but we
342
+ * surface it earlier here with a clearer diagnostic).
343
+ * - `chromeLabelKeys` uniqueness — duplicates indicate copy-paste
344
+ * bugs at the consumer's call site; surface them here.
345
+ */
346
+ const _WebsiteRootConfigSchema = z
347
+ .object({
348
+ pageManifests: z.array(WebsitePageManifestSchema).min(1, {
349
+ error: 'WebsiteRootConfig must declare at least one page manifest',
350
+ }),
351
+ designTokens: WebsiteDesignTokensSchema,
352
+ navigation: _WebsiteNavigationConfigSchema,
353
+ chromeLabelKeys: z.array(WebsiteLabelKeySchema).default([]),
354
+ /**
355
+ * Site-level branding + hero-image fallback used by the Astro
356
+ * head renderer to compose `<meta property="og:site_name">` and
357
+ * the per-page OG image fallback. The marketing-site origin
358
+ * (`siteOrigin`) USED to live here; it was moved to
359
+ * `WildoMarketingWebsiteConfig.publicOrigin` in the seam-collapse
360
+ * (single source of truth for "what's the origin this site is
361
+ * reachable at").
362
+ */
363
+ seo: _WebsiteSeoConfigSchema,
364
+ /**
365
+ * Label key the framework reads to render the "Skip to main
366
+ * content" link as the first focusable element on every page
367
+ * Required because:
368
+ * - Skip-to-main is a baseline keyboard-accessibility
369
+ * affordance — WCAG 2.1 §2.4.1 "Bypass Blocks" (Level A)
370
+ * mandates it. A marketing-site framework that omits it
371
+ * fails AA for the entire surface; making the contract
372
+ * opt-in invites that regression on every new consumer.
373
+ * - The text is announced verbatim by assistive tech, so it
374
+ * MUST be localized — a hardcoded English fallback would
375
+ * speak "Skip to main content" to French users. Forcing the
376
+ * key through the label-pack validation surface means the
377
+ * dev server fails fast when the consumer forgets to add
378
+ * the entry to a locale pack.
379
+ * - The framework (NOT the consumer's chrome) owns rendering
380
+ * the skip link because the chrome is itself the obstacle
381
+ * the link bypasses — a chrome-side implementation would
382
+ * either be inside the chrome (impossible to focus before
383
+ * the chrome) or above it (creating a structural surface
384
+ * the framework needs anyway).
385
+ *
386
+ * The key MUST also be present in `chromeLabelKeys` (the
387
+ * label-pack validator silences "orphaned" warnings off
388
+ * `chromeLabelKeys`) — the framework adds it automatically via
389
+ * the `superRefine` pass below so consumers cannot forget.
390
+ */
391
+ skipToMainContentLabelKey: WebsiteLabelKeySchema,
392
+ })
393
+ .superRefine((config, ctx) => {
394
+ const seenRefs = new Set();
395
+ const seenRoutePaths = new Set();
396
+ for (const [index, manifest] of config.pageManifests.entries()) {
397
+ const refKey = manifest.ref;
398
+ if (seenRefs.has(refKey)) {
399
+ ctx.addIssue({
400
+ code: 'custom',
401
+ path: ['pageManifests', index, 'ref'],
402
+ message: `Duplicate page ref "${refKey}" in WebsiteRootConfig.pageManifests`,
403
+ });
404
+ }
405
+ seenRefs.add(refKey);
406
+ const routeKey = manifest.routePath;
407
+ if (seenRoutePaths.has(routeKey)) {
408
+ ctx.addIssue({
409
+ code: 'custom',
410
+ path: ['pageManifests', index, 'routePath'],
411
+ message: `Duplicate routePath "${routeKey}" in WebsiteRootConfig.pageManifests`,
412
+ });
413
+ }
414
+ seenRoutePaths.add(routeKey);
415
+ }
416
+ /**
417
+ * `chromeLabelKeys` uniqueness — a duplicate is harmless at
418
+ * runtime (the validator de-dupes via a Set) but always indicates
419
+ * a copy-paste bug at the consumer's call site. Surfacing it here
420
+ * keeps the chrome contract tidy and matches the discipline applied
421
+ * to `pageManifests[].ref` and `locales`.
422
+ */
423
+ const seenChromeKeys = new Set();
424
+ for (const [index, key] of config.chromeLabelKeys.entries()) {
425
+ const keyStr = key;
426
+ if (seenChromeKeys.has(keyStr)) {
427
+ ctx.addIssue({
428
+ code: 'custom',
429
+ path: ['chromeLabelKeys', index],
430
+ message: `Duplicate chrome label key "${keyStr}" in WebsiteRootConfig.chromeLabelKeys`,
431
+ });
432
+ }
433
+ seenChromeKeys.add(keyStr);
434
+ }
435
+ });
436
+ export const WebsiteRootConfigSchema = _WebsiteRootConfigSchema;
437
+ /** @wildo_source:part:end saas.website.root-config.schema */
438
+ //# sourceMappingURL=website-root-config.shared.schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"website-root-config.shared.schemas.js","sourceRoot":"","sources":["../../../../../src/schemas/manifests/website-root-config.shared.schemas.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ComponentType } from 'react';\nimport { z } from 'zod';\n\nimport { WebsiteDesignTokensSchema } from '../design-tokens/website-design-tokens.shared.schemas';\nimport { WebsiteLabelKeySchema } from '../label-keys/website-label-key.schemas';\nimport {\n WebsitePageManifestSchema,\n type WebsitePageManifest,\n} from './website-page-manifest.shared.schemas';\n\n/**\n * @wildo_source:part:start saas.website.seo.sitemap-config facet:layer:shared facet:family:website\n *\n * `WebsiteSitemapConfig` — site-wide sitemap policy block.\n *\n * Materialized at build time by `@astrojs/sitemap` (the official\n * Astro plugin) when the consumer wires it into `astro.config.ts`\n * (see `website-seo-aeo-geo` SKILL). The framework owns the\n * **schema** (so config + enforcement live in lock-step with the\n * page registry) but the framework does NOT own the runtime\n * generator — `@astrojs/sitemap` already covers per-page\n * `lastmod` / `changefreq` / `priority` + i18n `xhtml:link\n * hreflang` annotations natively, and re-implementing that surface\n * inside the engine would duplicate well-trodden Astro tooling for\n * zero added value.\n *\n * # Field rationale\n *\n * **Why `enabled` defaults to `true`**:\n * - Marketing sites that want to ship public pages overwhelmingly\n * also want them in `sitemap.xml` (search engines treat its\n * absence as a discoverability signal). The opt-OUT shape avoids\n * a silent regression where a consumer ships pages that crawlers\n * never index because they forgot to flip a flag.\n * - The escape hatch (`enabled: false`) covers staging deployments\n * and the rare per-app decision to suppress sitemap emission\n * entirely (e.g. a private beta surface routed under a\n * `noindex` policy).\n *\n * **Why `changefreq` / `priority` are OPTIONAL** (no defaults):\n * - Both fields are non-binding hints — Google explicitly\n * ignores `priority` and treats `changefreq` as a soft signal.\n * Forcing the consumer to pick a value would either invite\n * superstitious authoring (`priority: 1.0` on every page) or\n * bury the field's actual ergonomic shape (per-page overrides\n * via `WebsitePageManifest.seo` — deferred until a real\n * consumer requests it).\n * - Unset values are simply omitted from the emitted `<url>`\n * entries; `@astrojs/sitemap` handles that automatically.\n *\n * **Validation**:\n * - `priority` is `z.number().min(0).max(1)` — outside the spec\n * range would silently break crawler ingestion.\n * - `changefreq` is the union of the seven values the sitemap\n * spec defines; arbitrary strings would be silently dropped by\n * compliant crawlers.\n */\nconst _WebsiteSitemapConfigSchema = z.object({\n enabled: z.boolean().default(true),\n changefreq: z\n .enum(['always', 'hourly', 'daily', 'weekly', 'monthly', 'yearly', 'never'])\n .optional(),\n priority: z\n .number()\n .min(0, { error: 'WebsiteSitemapConfig.priority must be between 0 and 1' })\n .max(1, { error: 'WebsiteSitemapConfig.priority must be between 0 and 1' })\n .optional(),\n});\n\nexport const WebsiteSitemapConfigSchema: typeof _WebsiteSitemapConfigSchema =\n _WebsiteSitemapConfigSchema;\n\nexport type WebsiteSitemapConfig = z.infer<typeof _WebsiteSitemapConfigSchema>;\n/** @wildo_source:part:end saas.website.seo.sitemap-config */\n\n/**\n * @wildo_source:part:start saas.website.seo.robots-config facet:layer:shared facet:family:website\n *\n * `WebsiteRobotsConfig` — site-wide `robots.txt` policy block.\n *\n * Materialized at request time by `renderRobotsTxt(siteContext)`\n * from `@wildo-ai/saas-website/astro` (consumer wires a thin\n * `src/pages/robots.txt.ts` Astro endpoint that returns the helper's\n * output). Scoped to the SITE-WIDE policy surface — per-page\n * `noindex` is a separate concern that lands on\n * `WebsitePageManifest.seo` once a real consumer requests it (today\n * the site-wide `disallow[]` covers staging-environment exclusion of\n * specific path prefixes, the dominant real-world use case).\n *\n * # Field rationale\n *\n * **Why `policy` defaults to `'index'`**:\n * - The default for a public marketing site is \"let crawlers in\";\n * `'noindex'` is the deliberate exception (staging environments,\n * beta surfaces, sites still under construction). The opt-OUT\n * shape mirrors `WebsiteSitemapConfig.enabled` for consistency.\n * - `'noindex'` emits a `User-agent: *\\nDisallow: /` block — the\n * standard \"tell every well-behaved crawler to stay away\"\n * primitive.\n *\n * **Why `disallow[]` is a path-prefix list (not a regex)**:\n * - The `robots.txt` spec only supports literal path prefixes\n * with `*` / `$` wildcards; Disallow is NOT a regex surface.\n * Typing it as `string[]` (validated to start with `/`) keeps\n * the contract honest and lets consumers paste from their CDN\n * allowlists without translation.\n *\n * **Why `allowedCrawlers` and `disallowedCrawlers` are mutually\n * exclusive**:\n * - The two fields are two halves of the SAME AI-crawler policy\n * decision. `allowedCrawlers` is the deny-by-default shape\n * (only the named bots may crawl); `disallowedCrawlers` is the\n * allow-by-default shape (every bot except the named ones may\n * crawl). Mixing both would emit a contradictory `robots.txt`\n * (a bot in both lists would receive conflicting directives).\n * A `superRefine` enforces the mutual-exclusion invariant at\n * parse time so the build fails fast.\n *\n * **Validation**:\n * - `disallow[]` entries must start with `/` (sitemap path-prefix\n * spec) — anything else would silently match nothing.\n * - `allowedCrawlers` / `disallowedCrawlers` entries must be\n * non-empty strings (a blank User-agent token would emit\n * `User-agent: ` which compliant crawlers ignore — silent\n * misconfig).\n * - `superRefine` rejects the combined-list anti-pattern.\n */\nconst _WebsiteRobotsConfigSchema = z\n .object({\n policy: z.enum(['index', 'noindex']).default('index'),\n disallow: z\n .array(\n z\n .string()\n .min(1)\n .refine((path) => path.startsWith('/'), {\n error: 'WebsiteRobotsConfig.disallow[] entries must start with \"/\"',\n }),\n )\n .optional(),\n /**\n * Deny-by-default AI-crawler allowlist. When set, the emitted\n * `robots.txt` lists each named bot under its own\n * `User-agent: <bot>\\nAllow: /` block, then closes with a\n * catch-all `User-agent: *\\nDisallow: /`. Mutually exclusive\n * with `disallowedCrawlers` (see `superRefine` below).\n */\n allowedCrawlers: z.array(z.string().min(1)).optional(),\n /**\n * Allow-by-default AI-crawler denylist. When set, the emitted\n * `robots.txt` lists each named bot under its own\n * `User-agent: <bot>\\nDisallow: /` block. Mutually exclusive\n * with `allowedCrawlers` (see `superRefine` below).\n */\n disallowedCrawlers: z.array(z.string().min(1)).optional(),\n })\n .superRefine((value, ctx) => {\n if (value.allowedCrawlers !== undefined && value.disallowedCrawlers !== undefined) {\n ctx.addIssue({\n code: 'custom',\n path: ['allowedCrawlers'],\n message:\n 'WebsiteRobotsConfig.allowedCrawlers and disallowedCrawlers are mutually exclusive — pick one policy direction (deny-by-default vs allow-by-default).',\n });\n }\n });\n\nexport const WebsiteRobotsConfigSchema: typeof _WebsiteRobotsConfigSchema =\n _WebsiteRobotsConfigSchema;\n\nexport type WebsiteRobotsConfig = z.infer<typeof _WebsiteRobotsConfigSchema>;\n/** @wildo_source:part:end saas.website.seo.robots-config */\n\n/**\n * @wildo_source:part:start saas.website.seo.llms-txt-config facet:layer:shared facet:family:website\n *\n * `WebsiteLlmsTxtConfig` — site-wide `llms.txt` publication policy.\n *\n * The framework owns only the SERVING surface; the CONTENT remains\n * hand-authored in `src/content/llms.txt`. This block therefore needs\n * exactly one knob:\n *\n * - `enabled?: boolean`\n * - `true` → publish when the file exists\n * - `false` → suppress publication even if the file exists\n * - `undefined` → auto-detect (`readLlmsTxtBody` publishes when the\n * file exists, returns `null` when absent)\n *\n * Keeping the \"auto-detect when undefined\" convention in the HELPER\n * (not as a schema default) is deliberate: schema defaults are static,\n * while file presence is runtime/build-time state.\n */\nconst _WebsiteLlmsTxtConfigSchema = z.object({\n enabled: z.boolean().optional(),\n});\n\nexport const WebsiteLlmsTxtConfigSchema: typeof _WebsiteLlmsTxtConfigSchema =\n _WebsiteLlmsTxtConfigSchema;\n\nexport type WebsiteLlmsTxtConfig = z.infer<typeof _WebsiteLlmsTxtConfigSchema>;\n/** @wildo_source:part:end saas.website.seo.llms-txt-config */\n\n/**\n * @wildo_source:part:start saas.website.root-config.seo facet:layer:shared facet:family:website\n *\n * `WebsiteSeoConfig` — site-wide SEO/social-graph configuration\n * AUTHORED ON THE ROOT CONFIG.\n *\n * # Scope\n *\n * The public marketing-site origin belongs only in the per-service\n * `wildo.website.config.ts` declaration. Keep it out of this site-level SEO\n * block so the origin and localized routing have one source of truth.\n *\n * What stays on this block: site-level branding + hero-image\n * fallbacks that are co-authored with chrome labels and page\n * manifests respectively, NOT with the URL/i18n routing surface.\n *\n * # Field rationale\n *\n * **Why `siteName` is REQUIRED**:\n * - `og:site_name` is the brand label social platforms render\n * above the page title in shared previews. Without it, every\n * LinkedIn / Facebook / Slack preview shows the bare title with\n * no brand context.\n * - It is also the recommended `application-name` meta tag value\n * and a useful default for JSON-LD `Organization.name` schema\n * when the application ships structured data.\n *\n * **Why `defaultOgImageUrl` is OPTIONAL**:\n * - Each page's `WebsitePageManifest.metaLabelKeys.ogImageUrl`\n * takes precedence; the site-level default is a fallback for\n * pages that did not commit to a hero image.\n * - Marketing surfaces shipping no OG images at all (acceptable\n * for a placeholder build) should not be forced to author one.\n *\n * **Why `sitemap?` and `robots?` are OPTIONAL** (with sensible\n * defaults inside each sub-schema):\n * - The marketing-site default ships a public surface — every\n * page indexable, no AI-crawler restrictions, no per-path\n * disallow. Forcing every consumer to author both blocks just\n * to land in that default state would pollute the call site.\n * - Omitting either block at the call site is equivalent to\n * authoring `{}` — `WebsiteSitemapConfig.enabled` defaults to\n * `true`, `WebsiteRobotsConfig.policy` defaults to `'index'`.\n * The per-block field rationale lives on each sub-schema.\n * - `llmsTxt?` is similarly optional, but with a different default\n * mechanic: omitting the block means \"auto-detect from file\n * presence\" rather than \"use a static schema default\". The helper\n * `readLlmsTxtBody(...)` publishes when `src/content/llms.txt`\n * exists and returns `null` otherwise.\n *\n * **Validation**:\n * - `siteName` is `z.string().min(1)` — empty strings would emit\n * `<meta property=\"og:site_name\" content=\"\" />` which social\n * platforms render as a blank line.\n * - `defaultOgImageUrl` (when present) is `z.url()`.\n * - `sitemap` / `robots` validation lives on the sub-schemas.\n */\nconst _WebsiteSeoConfigSchema = z\n .object({\n siteName: z\n .string()\n .min(1, { error: 'WebsiteSeoConfig.siteName must be a non-empty string' }),\n defaultOgImageUrl: z\n .url({ error: 'WebsiteSeoConfig.defaultOgImageUrl must be a fully-qualified URL' })\n .optional(),\n /**\n * Sitemap policy block. Optional — omitting it is equivalent to\n * `{ enabled: true }` (the marketing-site default). See\n * `WebsiteSitemapConfigSchema` for field-by-field rationale.\n */\n sitemap: _WebsiteSitemapConfigSchema.optional(),\n /**\n * Robots.txt policy block. Optional — omitting it is equivalent\n * to `{ policy: 'index' }` (the marketing-site default). See\n * `WebsiteRobotsConfigSchema` for field-by-field rationale.\n */\n robots: _WebsiteRobotsConfigSchema.optional(),\n /**\n * `llms.txt` publication policy. Optional — omitting it means\n * \"auto-detect from file presence\". See\n * `WebsiteLlmsTxtConfigSchema` for the serving contract.\n */\n llmsTxt: _WebsiteLlmsTxtConfigSchema.optional(),\n });\n\nexport const WebsiteSeoConfigSchema: typeof _WebsiteSeoConfigSchema = _WebsiteSeoConfigSchema;\n\nexport type WebsiteSeoConfig = z.infer<typeof _WebsiteSeoConfigSchema>;\n/** @wildo_source:part:end saas.website.root-config.seo */\n\n/**\n * @wildo_source:part:start saas.website.root-config.navigation facet:layer:shared facet:family:website\n *\n * `WebsiteNavigationConfig` — site-wide header/footer slot bindings.\n *\n * The framework intentionally ships no concrete header or footer. The\n * application authors both as React components, registers them once here, and\n * the page layout renders the site-wide chrome around every page.\n *\n * Both fields are typed as `unknown` at the schema layer with the\n * `WebsiteNavigationConfig` interface narrowing them to\n * `ComponentType<unknown>` — same rationale as\n * `WebsiteSectionDefinition.Component` and `WebsitePageManifest.pageComponent`.\n */\nconst _WebsiteNavigationConfigSchema = z.object({\n headerComponent: z.unknown(),\n footerComponent: z.unknown(),\n});\n\nexport const WebsiteNavigationConfigSchema: typeof _WebsiteNavigationConfigSchema =\n _WebsiteNavigationConfigSchema;\n\nexport interface WebsiteNavigationConfig\n extends z.infer<typeof _WebsiteNavigationConfigSchema> {\n headerComponent: ComponentType<unknown>;\n footerComponent: ComponentType<unknown>;\n}\n/** @wildo_source:part:end saas.website.root-config.navigation */\n\n/**\n * @wildo_source:part:start saas.website.root-config.schema facet:layer:shared facet:family:website\n *\n * `WebsiteRootConfig` — the site-level configuration consumed by:\n * - the Astro adapter to drive i18n routing, page mounting,\n * and design-token CSS emission,\n * - the website audit command to validate label-pack\n * coverage and SEO structured-data conformance,\n * - the runtime `<WebsitePageLayout>` to render navigation\n * and apply design tokens.\n *\n * **Authoring convention**: each marketing-site service exports a single\n * `WEBSITE_ROOT_CONFIG: WebsiteRootConfig` from `src/website-root.config.ts`.\n * The Astro adapter and the audit command\n * both consume this canonical entry point; there is exactly one site\n * config per marketing site (no per-page or per-section overrides at\n * this level — overrides flow through the L0/L1/L1.5 component\n * registration hierarchy described in D6).\n *\n * # Scope\n *\n * This block carries site-level chrome and registry data only. Per-locale\n * routing (`locales` / `defaultLocale`) and the public origin belong in the\n * per-service `wildo.website.config.ts` declaration, avoiding duplicated\n * configuration that could diverge during site generation.\n *\n * **Field-by-field rationale**:\n *\n * - `pageManifests` — the registry of every page on the site. Indexed\n * downstream by `manifest.ref`. Refs MUST be unique (refinement\n * below).\n * - `designTokens` — see `WebsiteDesignTokensSchema`.\n * - `navigation` — see `WebsiteNavigationConfigSchema`.\n * - `chromeLabelKeys` — OPTIONAL. The set of fully-composed label keys\n * the site-wide chrome (header / footer / any global slot the\n * consumer renders outside a section context) reads via\n * `useWebsiteLabelByKey(...)`. Declared here, NOT in section\n * `expectedLabelKeys`, because chrome is rendered outside the\n * page+section context — `useWebsiteLabel(slot)` is structurally\n * unavailable to it. Threading these through the label-pack\n * validator (a) silences the always-on \"orphaned chrome key\" build\n * warnings and (b) lets the build fail fast when a chrome key is\n * missing from a locale pack, the same way section keys do.\n * Defaults to an empty array; sites with no chrome label reads\n * may omit the field entirely.\n * - `seo` — site-level branding + hero-image fallback (see\n * `WebsiteSeoConfigSchema`). The marketing-site origin USED to live\n * here as `seo.siteOrigin`; it now lives only on\n * `WildoMarketingWebsiteConfig.publicOrigin`.\n * - `skipToMainContentLabelKey` — see field JSDoc below.\n *\n * **Refinements**:\n * - `pageManifests[].ref` uniqueness — the registry is keyed by ref;\n * duplicates would silently overwrite each other in the lookup\n * table the bridge uses for cross-page links.\n * - `pageManifests[].routePath` uniqueness — two pages cannot mount\n * at the same path (Astro would error at build time, but we\n * surface it earlier here with a clearer diagnostic).\n * - `chromeLabelKeys` uniqueness — duplicates indicate copy-paste\n * bugs at the consumer's call site; surface them here.\n */\nconst _WebsiteRootConfigSchema = z\n .object({\n pageManifests: z.array(WebsitePageManifestSchema).min(1, {\n error: 'WebsiteRootConfig must declare at least one page manifest',\n }),\n designTokens: WebsiteDesignTokensSchema,\n navigation: _WebsiteNavigationConfigSchema,\n chromeLabelKeys: z.array(WebsiteLabelKeySchema).default([]),\n /**\n * Site-level branding + hero-image fallback used by the Astro\n * head renderer to compose `<meta property=\"og:site_name\">` and\n * the per-page OG image fallback. The marketing-site origin\n * (`siteOrigin`) USED to live here; it was moved to\n * `WildoMarketingWebsiteConfig.publicOrigin` in the seam-collapse\n * (single source of truth for \"what's the origin this site is\n * reachable at\").\n */\n seo: _WebsiteSeoConfigSchema,\n /**\n * Label key the framework reads to render the \"Skip to main\n * content\" link as the first focusable element on every page\n * Required because:\n * - Skip-to-main is a baseline keyboard-accessibility\n * affordance — WCAG 2.1 §2.4.1 \"Bypass Blocks\" (Level A)\n * mandates it. A marketing-site framework that omits it\n * fails AA for the entire surface; making the contract\n * opt-in invites that regression on every new consumer.\n * - The text is announced verbatim by assistive tech, so it\n * MUST be localized — a hardcoded English fallback would\n * speak \"Skip to main content\" to French users. Forcing the\n * key through the label-pack validation surface means the\n * dev server fails fast when the consumer forgets to add\n * the entry to a locale pack.\n * - The framework (NOT the consumer's chrome) owns rendering\n * the skip link because the chrome is itself the obstacle\n * the link bypasses — a chrome-side implementation would\n * either be inside the chrome (impossible to focus before\n * the chrome) or above it (creating a structural surface\n * the framework needs anyway).\n *\n * The key MUST also be present in `chromeLabelKeys` (the\n * label-pack validator silences \"orphaned\" warnings off\n * `chromeLabelKeys`) — the framework adds it automatically via\n * the `superRefine` pass below so consumers cannot forget.\n */\n skipToMainContentLabelKey: WebsiteLabelKeySchema,\n })\n .superRefine((config, ctx) => {\n const seenRefs = new Set<string>();\n const seenRoutePaths = new Set<string>();\n for (const [index, manifest] of config.pageManifests.entries()) {\n const refKey = manifest.ref as unknown as string;\n if (seenRefs.has(refKey)) {\n ctx.addIssue({\n code: 'custom',\n path: ['pageManifests', index, 'ref'],\n message: `Duplicate page ref \"${refKey}\" in WebsiteRootConfig.pageManifests`,\n });\n }\n seenRefs.add(refKey);\n\n const routeKey = manifest.routePath as unknown as string;\n if (seenRoutePaths.has(routeKey)) {\n ctx.addIssue({\n code: 'custom',\n path: ['pageManifests', index, 'routePath'],\n message: `Duplicate routePath \"${routeKey}\" in WebsiteRootConfig.pageManifests`,\n });\n }\n seenRoutePaths.add(routeKey);\n }\n\n /**\n * `chromeLabelKeys` uniqueness — a duplicate is harmless at\n * runtime (the validator de-dupes via a Set) but always indicates\n * a copy-paste bug at the consumer's call site. Surfacing it here\n * keeps the chrome contract tidy and matches the discipline applied\n * to `pageManifests[].ref` and `locales`.\n */\n const seenChromeKeys = new Set<string>();\n for (const [index, key] of config.chromeLabelKeys.entries()) {\n const keyStr = key as unknown as string;\n if (seenChromeKeys.has(keyStr)) {\n ctx.addIssue({\n code: 'custom',\n path: ['chromeLabelKeys', index],\n message: `Duplicate chrome label key \"${keyStr}\" in WebsiteRootConfig.chromeLabelKeys`,\n });\n }\n seenChromeKeys.add(keyStr);\n }\n });\n\nexport const WebsiteRootConfigSchema: typeof _WebsiteRootConfigSchema = _WebsiteRootConfigSchema;\n\n/**\n * Runtime shape of `WebsiteRootConfig`.\n *\n * Hand-written (NOT a bare `z.infer<typeof _WebsiteRootConfigSchema>`)\n * because `z.infer` walks the schema tree and would type\n * `pageManifests[number].pageComponent`, `navigation.headerComponent`\n * and `navigation.footerComponent` as `unknown` (their schema field\n * type), losing the `ComponentType<unknown>` narrowing carried by the\n * hand-written `WebsitePageManifest` and `WebsiteNavigationConfig`\n * interfaces. Factories such as `defineWebsiteRootConfig` and the\n * layout primitives consume `WebsiteRootConfig` and must see those\n * fields pre-narrowed; otherwise every consumer would need a local\n * `as ComponentType` cast at the JSX call site, defeating the type-safe\n * component contract.\n *\n * The `Omit` + intersection pattern keeps the rest of the inferred\n * shape (`designTokens`, `seo`, `chromeLabelKeys`,\n * `skipToMainContentLabelKey`) sourced directly from the schema.\n */\nexport type WebsiteRootConfig = Omit<\n z.infer<typeof _WebsiteRootConfigSchema>,\n 'pageManifests' | 'navigation'\n> & {\n pageManifests: WebsitePageManifest[];\n navigation: WebsiteNavigationConfig;\n};\n/** @wildo_source:part:end saas.website.root-config.schema */\n"]}
@@ -0,0 +1,40 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * @wildo_source:part:start saas.website.refs.page facet:layer:shared facet:family:website
4
+ *
5
+ * `WebsitePageRef` — branded kebab-case identifier for a single marketing-site
6
+ * page (e.g. `'landing'`, `'pricing'`, `'contact-us'`).
7
+ *
8
+ * The ref is the **structural identity** of a page across three independent
9
+ * surfaces:
10
+ *
11
+ * 1. **Label-key root**: every label key the page consumes is derived as
12
+ * `website.<pageRef>.<sectionRef>.<slot>` (see `WebsiteLabelKeySchema`).
13
+ * Renaming a `WebsitePageRef` therefore renames every label key the
14
+ * page commits to — handle as a labelled rename, never a silent edit.
15
+ * 2. **Manifest registry key**: `WebsiteRootConfig.pageManifests[]` is keyed
16
+ * by `ref`; the Astro adapter looks pages up by ref when resolving
17
+ * cross-page links (`hreflang`, locale switcher, primary nav).
18
+ * 3. **Skill mapping**: skills like `website-page-authoring` reference the
19
+ * ref vocabulary documented here, NOT individual page files.
20
+ *
21
+ * **Format**: lowercase ASCII letters, digits and `-`. Must start with a
22
+ * letter (no leading digit / hyphen). 1–64 characters. The format is the
23
+ * smallest set that survives URL paths, file names, JSON keys and i18n keys
24
+ * without escaping or case-folding.
25
+ *
26
+ * **Why a brand**: prevents accidental cross-talk with `WebsiteSectionRef`
27
+ * (also kebab-case) and with arbitrary user-supplied strings. Consumers must
28
+ * go through `WebsitePageRefSchema.parse(...)` (or the manifest factory)
29
+ * before a value flows into label-key resolution or routing.
30
+ *
31
+ * @example
32
+ * const ref = WebsitePageRefSchema.parse('landing');
33
+ * // ref: WebsitePageRef ("landing")
34
+ */
35
+ declare const _WebsitePageRefSchema: z.core.$ZodBranded<z.ZodString, "WebsitePageRef", "out">;
36
+ export declare const WebsitePageRefSchema: typeof _WebsitePageRefSchema;
37
+ export type WebsitePageRef = z.infer<typeof _WebsitePageRefSchema>;
38
+ export {};
39
+ /** @wildo_source:part:end saas.website.refs.page */
40
+ //# sourceMappingURL=page-ref.schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-ref.schemas.d.ts","sourceRoot":"","sources":["../../../../../src/schemas/refs/page-ref.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,QAAA,MAAM,qBAAqB,0DAQC,CAAC;AAE7B,eAAO,MAAM,oBAAoB,EAAE,OAAO,qBAA6C,CAAC;AAExF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;;AACnE,oDAAoD"}
@@ -0,0 +1,43 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * @wildo_source:part:start saas.website.refs.page facet:layer:shared facet:family:website
4
+ *
5
+ * `WebsitePageRef` — branded kebab-case identifier for a single marketing-site
6
+ * page (e.g. `'landing'`, `'pricing'`, `'contact-us'`).
7
+ *
8
+ * The ref is the **structural identity** of a page across three independent
9
+ * surfaces:
10
+ *
11
+ * 1. **Label-key root**: every label key the page consumes is derived as
12
+ * `website.<pageRef>.<sectionRef>.<slot>` (see `WebsiteLabelKeySchema`).
13
+ * Renaming a `WebsitePageRef` therefore renames every label key the
14
+ * page commits to — handle as a labelled rename, never a silent edit.
15
+ * 2. **Manifest registry key**: `WebsiteRootConfig.pageManifests[]` is keyed
16
+ * by `ref`; the Astro adapter looks pages up by ref when resolving
17
+ * cross-page links (`hreflang`, locale switcher, primary nav).
18
+ * 3. **Skill mapping**: skills like `website-page-authoring` reference the
19
+ * ref vocabulary documented here, NOT individual page files.
20
+ *
21
+ * **Format**: lowercase ASCII letters, digits and `-`. Must start with a
22
+ * letter (no leading digit / hyphen). 1–64 characters. The format is the
23
+ * smallest set that survives URL paths, file names, JSON keys and i18n keys
24
+ * without escaping or case-folding.
25
+ *
26
+ * **Why a brand**: prevents accidental cross-talk with `WebsiteSectionRef`
27
+ * (also kebab-case) and with arbitrary user-supplied strings. Consumers must
28
+ * go through `WebsitePageRefSchema.parse(...)` (or the manifest factory)
29
+ * before a value flows into label-key resolution or routing.
30
+ *
31
+ * @example
32
+ * const ref = WebsitePageRefSchema.parse('landing');
33
+ * // ref: WebsitePageRef ("landing")
34
+ */
35
+ const _WebsitePageRefSchema = z
36
+ .string()
37
+ .min(1, { error: 'WebsitePageRef must be at least 1 character' })
38
+ .max(64, { error: 'WebsitePageRef must be at most 64 characters' })
39
+ .regex(/^[a-z][a-z0-9-]*$/, { error: 'WebsitePageRef must be lowercase kebab-case starting with a letter (e.g. "landing", "pricing-tiers")' })
40
+ .brand();
41
+ export const WebsitePageRefSchema = _WebsitePageRefSchema;
42
+ /** @wildo_source:part:end saas.website.refs.page */
43
+ //# sourceMappingURL=page-ref.schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-ref.schemas.js","sourceRoot":"","sources":["../../../../../src/schemas/refs/page-ref.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,qBAAqB,GAAG,CAAC;KAC5B,MAAM,EAAE;KACR,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,6CAA6C,EAAE,CAAC;KAChE,GAAG,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,8CAA8C,EAAE,CAAC;KAClE,KAAK,CACJ,mBAAmB,EACnB,EAAE,KAAK,EAAE,sGAAsG,EAAE,CAClH;KACA,KAAK,EAAoB,CAAC;AAE7B,MAAM,CAAC,MAAM,oBAAoB,GAAiC,qBAAqB,CAAC;AAGxF,oDAAoD","sourcesContent":["import { z } from 'zod';\n\n/**\n * @wildo_source:part:start saas.website.refs.page facet:layer:shared facet:family:website\n *\n * `WebsitePageRef` — branded kebab-case identifier for a single marketing-site\n * page (e.g. `'landing'`, `'pricing'`, `'contact-us'`).\n *\n * The ref is the **structural identity** of a page across three independent\n * surfaces:\n *\n * 1. **Label-key root**: every label key the page consumes is derived as\n * `website.<pageRef>.<sectionRef>.<slot>` (see `WebsiteLabelKeySchema`).\n * Renaming a `WebsitePageRef` therefore renames every label key the\n * page commits to — handle as a labelled rename, never a silent edit.\n * 2. **Manifest registry key**: `WebsiteRootConfig.pageManifests[]` is keyed\n * by `ref`; the Astro adapter looks pages up by ref when resolving\n * cross-page links (`hreflang`, locale switcher, primary nav).\n * 3. **Skill mapping**: skills like `website-page-authoring` reference the\n * ref vocabulary documented here, NOT individual page files.\n *\n * **Format**: lowercase ASCII letters, digits and `-`. Must start with a\n * letter (no leading digit / hyphen). 1–64 characters. The format is the\n * smallest set that survives URL paths, file names, JSON keys and i18n keys\n * without escaping or case-folding.\n *\n * **Why a brand**: prevents accidental cross-talk with `WebsiteSectionRef`\n * (also kebab-case) and with arbitrary user-supplied strings. Consumers must\n * go through `WebsitePageRefSchema.parse(...)` (or the manifest factory)\n * before a value flows into label-key resolution or routing.\n *\n * @example\n * const ref = WebsitePageRefSchema.parse('landing');\n * // ref: WebsitePageRef (\"landing\")\n */\nconst _WebsitePageRefSchema = z\n .string()\n .min(1, { error: 'WebsitePageRef must be at least 1 character' })\n .max(64, { error: 'WebsitePageRef must be at most 64 characters' })\n .regex(\n /^[a-z][a-z0-9-]*$/,\n { error: 'WebsitePageRef must be lowercase kebab-case starting with a letter (e.g. \"landing\", \"pricing-tiers\")' },\n )\n .brand<'WebsitePageRef'>();\n\nexport const WebsitePageRefSchema: typeof _WebsitePageRefSchema = _WebsitePageRefSchema;\n\nexport type WebsitePageRef = z.infer<typeof _WebsitePageRefSchema>;\n/** @wildo_source:part:end saas.website.refs.page */\n"]}
@@ -0,0 +1,41 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * @wildo_source:part:start saas.website.refs.section facet:layer:shared facet:family:website
4
+ *
5
+ * `WebsiteSectionRef` — branded kebab-case identifier for one section on a
6
+ * page (e.g. `'hero'`, `'social-proof'`, `'pricing-teaser'`, `'final-cta'`).
7
+ *
8
+ * The section ref is the **section-level structural identity**:
9
+ *
10
+ * 1. **Label-key root**: every label leaf consumed inside a section is
11
+ * rooted at `website.<pageRef>.<sectionRef>.<slot>`. The hook
12
+ * `useWebsiteLabel('headline')` (Phase 2) reads `WebsiteSectionContext`
13
+ * to derive the full key; the section author never types the page or
14
+ * section ref into a label call.
15
+ * 2. **Page manifest contract**: `WebsitePageManifest.sectionRefs[]`
16
+ * declares the refs the page commits to. The label-pack validator
17
+ * cross-references the manifest's declared refs against the actual
18
+ * sections rendered, surfacing mismatches at build start.
19
+ * 3. **DOM landmark**: `<WebsiteSection ref="…">` (Phase 2) emits
20
+ * `<section data-section-ref="…">` so analytics, scroll-tracking, and
21
+ * automated audits can identify sections without parsing class names.
22
+ *
23
+ * **Format**: lowercase ASCII letters, digits and `-`. Must start with a
24
+ * letter. 1–64 characters. Same shape as `WebsitePageRef` for consistency
25
+ * across both ref scopes.
26
+ *
27
+ * **Why a brand**: same reasoning as `WebsitePageRef`. The two refs are
28
+ * structurally identical strings but semantically distinct — branding
29
+ * prevents accidental swaps between page-level and section-level APIs at
30
+ * compile time.
31
+ *
32
+ * @example
33
+ * const heroRef = WebsiteSectionRefSchema.parse('hero');
34
+ * const ctaRef = WebsiteSectionRefSchema.parse('final-cta');
35
+ */
36
+ declare const _WebsiteSectionRefSchema: z.core.$ZodBranded<z.ZodString, "WebsiteSectionRef", "out">;
37
+ export declare const WebsiteSectionRefSchema: typeof _WebsiteSectionRefSchema;
38
+ export type WebsiteSectionRef = z.infer<typeof _WebsiteSectionRefSchema>;
39
+ export {};
40
+ /** @wildo_source:part:end saas.website.refs.section */
41
+ //# sourceMappingURL=section-ref.schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"section-ref.schemas.d.ts","sourceRoot":"","sources":["../../../../../src/schemas/refs/section-ref.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,QAAA,MAAM,wBAAwB,6DAQC,CAAC;AAEhC,eAAO,MAAM,uBAAuB,EAAE,OAAO,wBAAmD,CAAC;AAEjG,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;;AACzE,uDAAuD"}