@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,175 @@
1
+ import React, { createContext, type ReactNode } from 'react';
2
+
3
+ import type { AvailableLanguage } from '@wildo-ai/saas-models/public-runtime';
4
+
5
+ import type { WebsiteDesignTokens } from '../../schemas/design-tokens/website-design-tokens.shared.schemas';
6
+ import type { FrontendWebsiteProviderRegistry } from '../external-providers/frontend-provider-registry.website';
7
+ import type { WebsiteLabelKey } from '../../schemas/label-keys/website-label-key.schemas';
8
+ import type { WebsiteNavigationConfig } from '../../schemas/manifests/website-root-config.shared.schemas';
9
+ import type { LabelPack } from '../../schemas/validators/label-pack.validator';
10
+
11
+ /**
12
+ * @wildo_source:part:start saas.website.runtime.context facet:layer:core facet:family:website
13
+ *
14
+ * `WebsiteRuntimeContext` — site-wide runtime state for the marketing
15
+ * surface. Created **once per page render** by the host adapter
16
+ * (Phase 5 `WebsitePageBridge.astro` reads `WebsiteRootConfig` and the
17
+ * resolved label pack from disk and calls
18
+ * `<WebsiteRuntimeContextProvider value={…}>` around the page tree).
19
+ *
20
+ * **Why "runtime" and not "config"**: the values here are the
21
+ * locale-resolved subset of `WebsiteRootConfig` — only the active
22
+ * locale's label pack travels with the React tree (the other locales
23
+ * live in their own per-locale static builds). A `*Config` name would
24
+ * suggest the full multi-locale surface is in scope.
25
+ *
26
+ * **Three pieces of state**:
27
+ *
28
+ * - `locale` — the currently-rendering locale. Sections that need
29
+ * locale-aware formatting (number/date in marketing copy is rare
30
+ * but legitimate) read it via `useWebsiteRuntime()`.
31
+ * - `labelPack` — the locale-resolved flat key→string map, validated
32
+ * against the manifest by `validateLabelPackAgainstManifest` at
33
+ * build start. Consumed by `useWebsiteLabel` and
34
+ * `useWebsiteLabelByKey`.
35
+ * - `designTokens` — the `WebsiteDesignTokens` from
36
+ * `WebsiteRootConfig.designTokens`. Consumed by
37
+ * `useWebsiteDesignTokens` and by the Phase 5 CSS emitter that
38
+ * materializes them as `--website-*` custom properties on the
39
+ * `<WebsitePageLayout>` root.
40
+ * - `navigation` — the `WebsiteNavigationConfig` from
41
+ * `WebsiteRootConfig.navigation`. Carried in the runtime context
42
+ * (rather than as a separate `WebsiteNavigationContext`) because
43
+ * `<WebsitePageLayout>` already reads runtime state and
44
+ * header/footer slots are inseparable from "the site is rendering
45
+ * right now". A second context for two component refs would split
46
+ * the host-adapter's wiring surface without buying isolation.
47
+ * - `frontendProviderRegistry` — optional website-facing public provider
48
+ * registry hydrated from the materialized provider artifact for the
49
+ * concrete `STATIC_WEBSITE` service. This keeps analytics / captcha /
50
+ * browser-monitoring integrations on the same frontend-provider
51
+ * contract the SaaS app now uses, instead of inventing a website-only
52
+ * metadata seam.
53
+ *
54
+ * **Why a separate file from the hook + provider**: split for React
55
+ * Fast Refresh — when a `.tsx` exports both a React component and a
56
+ * React Context object, edits to either one invalidate the entire
57
+ * module's HMR boundary. Keeping the bare context here, the hook in
58
+ * `useWebsiteRuntime.ts`, and the provider component in
59
+ * `WebsiteRuntimeContextProvider.tsx` makes section authors edit
60
+ * components without retriggering the runtime context's identity.
61
+ */
62
+ export interface WebsiteRuntimeContextValue {
63
+ /**
64
+ * The currently-rendering locale. Marketing-site routing emits one
65
+ * static build per locale (D8), so this value is constant per build
66
+ * — never re-renders mid-session.
67
+ */
68
+ locale: AvailableLanguage;
69
+ /**
70
+ * The site's default locale (mirrors `WebsiteRootConfig.defaultLocale`).
71
+ * Carried in the runtime context so client-tier components — namely
72
+ * `WebsiteInternalLink` (Phase 6 fix H-β) — can compute the correct
73
+ * locale-prefixed pathname (`/pricing` on the EN site,
74
+ * `/fr/pricing` on the FR site) without re-importing the root
75
+ * config. Plumbing it through the runtime keeps the routing rule
76
+ * a framework-internal concern: section authors NEVER hand-prefix
77
+ * paths.
78
+ */
79
+ defaultLocale: AvailableLanguage;
80
+ /**
81
+ * Flat `Record<string, string>` label pack for the active locale.
82
+ * Lookup keys MUST be fully-composed `website.<page>.<section>.<slot>`
83
+ * strings; consumers that hold leaf paths use `useWebsiteLabel(leaf)`
84
+ * which composes the full key against the page+section context.
85
+ */
86
+ labelPack: LabelPack;
87
+ /**
88
+ * Design-token bundle for the active site. Same object referenced
89
+ * by `WebsiteRootConfig.designTokens`; passed by reference (not
90
+ * cloned) so token-aware components can rely on referential
91
+ * stability across renders.
92
+ */
93
+ designTokens: WebsiteDesignTokens;
94
+ /**
95
+ * Site-wide navigation slot bindings (header / footer components).
96
+ * Same object referenced by `WebsiteRootConfig.navigation`. Read
97
+ * by `<WebsitePageLayout>` to render the chrome around each page's
98
+ * `<main>` content; per-page `header` / `footer` props on
99
+ * `<WebsitePageLayout>` override these defaults.
100
+ */
101
+ navigation: WebsiteNavigationConfig;
102
+ /**
103
+ * Fully-composed label key the framework reads to render the
104
+ * "Skip to main content" affordance as the FIRST focusable element
105
+ * on every page (Phase 6 third audit fix M-α). Mirrors
106
+ * `WebsiteRootConfig.skipToMainContentLabelKey`. Carried in the
107
+ * runtime context (NOT re-derived from the root config inside
108
+ * `WebsitePageLayout`) for two reasons:
109
+ * - The layout is a client-tier React component; it cannot import
110
+ * the consumer's `WEBSITE_ROOT_CONFIG` symbol without dragging
111
+ * server-only code (manifest registry, page components) into
112
+ * the client bundle.
113
+ * - Threading the key through the runtime keeps the layout's
114
+ * contract symmetric with how every other localized text on the
115
+ * page is sourced (label pack + key), so the skip link is
116
+ * translated automatically without any per-locale branching.
117
+ */
118
+ skipToMainContentLabelKey: WebsiteLabelKey;
119
+ /**
120
+ * Website-facing public providers for the active static website
121
+ * service. Optional so older tests and provider-free sites can omit
122
+ * it, but when present it is the canonical frontend-safe provider
123
+ * catalog for analytics / captcha / browser-monitoring slices.
124
+ */
125
+ frontendProviderRegistry?: FrontendWebsiteProviderRegistry;
126
+ /**
127
+ * Backend API origin (WITHOUT a trailing slash) that anonymous-capture
128
+ * sections POST to when constructing a `WebsiteAnonymousSessionClient`
129
+ * (lead / draft-note forms). Sourced from
130
+ * `WildoMarketingWebsiteConfig.apiOrigin` and passed as a
131
+ * JSON-serializable island prop (the `.astro` page resolves the
132
+ * per-environment value and forwards it).
133
+ *
134
+ * Optional because only pages that host an anonymous-capture section
135
+ * need it — brochure pages omit it. A capture section that reads
136
+ * `undefined` here surfaces a loud misconfiguration rather than
137
+ * silently failing to submit.
138
+ */
139
+ apiOrigin?: string;
140
+ }
141
+
142
+ /**
143
+ * Bare React context. Default `null` — `useWebsiteRuntime()` throws
144
+ * with a clear error message when invoked outside of
145
+ * `<WebsiteRuntimeContextProvider>`. The defensive throw is preferred
146
+ * over a silent default value so a missing provider is detected at
147
+ * the first hook call rather than at render time when a missing
148
+ * label silently renders as the key string.
149
+ */
150
+ export const WebsiteRuntimeContext: React.Context<WebsiteRuntimeContextValue | null> =
151
+ createContext<WebsiteRuntimeContextValue | null>(null);
152
+
153
+ export interface WebsiteRuntimeContextProviderProps {
154
+ value: WebsiteRuntimeContextValue;
155
+ children: ReactNode;
156
+ }
157
+
158
+ /**
159
+ * Provider component. Authored as a thin wrapper so consumers do NOT
160
+ * have to import `WebsiteRuntimeContext.Provider` directly — the
161
+ * provider component carries the documented authoring API and is the
162
+ * Fast-Refresh-stable surface section authors compose against.
163
+ */
164
+ export function WebsiteRuntimeContextProvider({
165
+ value,
166
+ children,
167
+ }: WebsiteRuntimeContextProviderProps): ReactNode {
168
+ return (
169
+ <WebsiteRuntimeContext.Provider value={value}>
170
+ {children}
171
+ </WebsiteRuntimeContext.Provider>
172
+ );
173
+ }
174
+ WebsiteRuntimeContextProvider.displayName = 'WebsiteRuntimeContextProvider';
175
+ /** @wildo_source:part:end saas.website.runtime.context */
@@ -0,0 +1,59 @@
1
+ import React, { createContext, type ReactNode } from 'react';
2
+
3
+ import type { WebsiteSectionCategory } from '../../schemas/sections/website-section-category.shared';
4
+ import type { WebsiteSectionRef } from '../../schemas/refs/section-ref.schemas';
5
+
6
+ /**
7
+ * @wildo_source:part:start saas.website.section.context facet:layer:core facet:family:website
8
+ *
9
+ * `WebsiteSectionContext` — identity + metadata of the section
10
+ * currently rendering. Provided by `<WebsiteSection>` and consumed
11
+ * by `useWebsiteLabel(leaf)` to compose the full label key, by
12
+ * analytics overlays that need the category, and by SEO emitters
13
+ * that decorate sections with `data-*` attributes.
14
+ *
15
+ * **Why expose `category` here (not just `sectionRef`)**: the
16
+ * category is the section's semantic role (`hero`, `cta`, `social`,
17
+ * etc.) and is needed by overlay tooling and analytics consumers
18
+ * that don't know the per-site `sectionRef` vocabulary. Bundling
19
+ * both saves consumers from having to thread the manifest just to
20
+ * map a ref back to its category.
21
+ *
22
+ * **Why a separate file from the hook**: same Fast-Refresh rationale
23
+ * as the runtime + page contexts.
24
+ */
25
+ export interface WebsiteSectionContextValue {
26
+ /**
27
+ * The validated `WebsiteSectionRef` of the section currently
28
+ * rendering. Composed by `useWebsiteLabel(leaf)` into the full key.
29
+ */
30
+ sectionRef: WebsiteSectionRef;
31
+ /**
32
+ * The semantic category of the section (`hero` / `cta` / etc.).
33
+ * Sourced from the matching `WebsiteSectionDefinition.category`
34
+ * by the host adapter and surfaced here so analytics + SEO
35
+ * tooling does not need to re-resolve it.
36
+ */
37
+ category: WebsiteSectionCategory;
38
+ }
39
+
40
+ export const WebsiteSectionContext: React.Context<WebsiteSectionContextValue | null> =
41
+ createContext<WebsiteSectionContextValue | null>(null);
42
+
43
+ export interface WebsiteSectionContextProviderProps {
44
+ value: WebsiteSectionContextValue;
45
+ children: ReactNode;
46
+ }
47
+
48
+ export function WebsiteSectionContextProvider({
49
+ value,
50
+ children,
51
+ }: WebsiteSectionContextProviderProps): ReactNode {
52
+ return (
53
+ <WebsiteSectionContext.Provider value={value}>
54
+ {children}
55
+ </WebsiteSectionContext.Provider>
56
+ );
57
+ }
58
+ WebsiteSectionContextProvider.displayName = 'WebsiteSectionContextProvider';
59
+ /** @wildo_source:part:end saas.website.section.context */
@@ -0,0 +1,28 @@
1
+ import { useContext } from 'react';
2
+
3
+ import {
4
+ WebsitePageContext,
5
+ type WebsitePageContextValue,
6
+ } from './WebsitePageContext';
7
+
8
+ /**
9
+ * @wildo_source:part:start saas.website.use-page.hook facet:layer:core facet:family:website
10
+ *
11
+ * Returns the active page identity. Throws when called outside a
12
+ * `<WebsitePageLayout>` so a section dropped at the wrong level (eg.
13
+ * directly under the runtime provider, before the page layout) fails
14
+ * loud at first render rather than silently composing a malformed
15
+ * label key.
16
+ */
17
+ export function useWebsitePage(): WebsitePageContextValue {
18
+ const value = useContext(WebsitePageContext);
19
+ if (value === null) {
20
+ throw new Error(
21
+ '[useWebsitePage] must be called inside <WebsitePageLayout>. ' +
22
+ 'Sections that need to compose a label key require a page identity ' +
23
+ '— wrap your content in `<WebsitePageLayout pageRef="…">` first.',
24
+ );
25
+ }
26
+ return value;
27
+ }
28
+ /** @wildo_source:part:end saas.website.use-page.hook */
@@ -0,0 +1,34 @@
1
+ import { useContext } from 'react';
2
+
3
+ import {
4
+ WebsiteRuntimeContext,
5
+ type WebsiteRuntimeContextValue,
6
+ } from './WebsiteRuntimeContext';
7
+
8
+ /**
9
+ * @wildo_source:part:start saas.website.use-runtime.hook facet:layer:core facet:family:website
10
+ *
11
+ * `useWebsiteRuntime()` — read access to the
12
+ * `WebsiteRuntimeContextValue`. Throws if invoked outside of a
13
+ * `<WebsiteRuntimeContextProvider>` so a missing host adapter is
14
+ * detected at the first hook call (fail-loud).
15
+ *
16
+ * Section authors usually do NOT call this directly — prefer the
17
+ * higher-level hooks (`useWebsiteLabel`, `useWebsiteLabelByKey`,
18
+ * `useWebsiteDesignTokens`) which expose only the slice they need.
19
+ * Direct access is reserved for layout primitives and locale-aware
20
+ * formatters that legitimately need the active locale or the raw
21
+ * label pack.
22
+ */
23
+ export function useWebsiteRuntime(): WebsiteRuntimeContextValue {
24
+ const value = useContext(WebsiteRuntimeContext);
25
+ if (value === null) {
26
+ throw new Error(
27
+ '[useWebsiteRuntime] must be called inside <WebsiteRuntimeContextProvider>. ' +
28
+ 'In Astro pages this is provided by `WebsitePageBridge.astro` — make sure ' +
29
+ 'your page imports the bridge instead of rendering React components directly.',
30
+ );
31
+ }
32
+ return value;
33
+ }
34
+ /** @wildo_source:part:end saas.website.use-runtime.hook */
@@ -0,0 +1,28 @@
1
+ import { useContext } from 'react';
2
+
3
+ import {
4
+ WebsiteSectionContext,
5
+ type WebsiteSectionContextValue,
6
+ } from './WebsiteSectionContext';
7
+
8
+ /**
9
+ * @wildo_source:part:start saas.website.use-section.hook facet:layer:core facet:family:website
10
+ *
11
+ * Returns the active section identity + category. Throws when called
12
+ * outside `<WebsiteSection>` so a leaf primitive that needs the
13
+ * section ref (eg. a CMS-bound text block calling `useWebsiteLabel`)
14
+ * fails loud the moment it's dropped at the wrong nesting depth.
15
+ */
16
+ export function useWebsiteSection(): WebsiteSectionContextValue {
17
+ const value = useContext(WebsiteSectionContext);
18
+ if (value === null) {
19
+ throw new Error(
20
+ '[useWebsiteSection] must be called inside <WebsiteSection>. ' +
21
+ 'Leaf primitives that compose label keys (`useWebsiteLabel(leaf)`) ' +
22
+ 'require a section identity — wrap your content in ' +
23
+ '`<WebsiteSection sectionRef="…" category="…">` first.',
24
+ );
25
+ }
26
+ return value;
27
+ }
28
+ /** @wildo_source:part:end saas.website.use-section.hook */
@@ -0,0 +1,62 @@
1
+ import type {
2
+ FrontendProviderEntry,
3
+ FrontendProvidersBlock,
4
+ ProviderCapability,
5
+ } from '@wildo-ai/saas-models/public-runtime';
6
+
7
+ export type FrontendWebsiteProviderRef = string & {
8
+ readonly __brand: 'FrontendWebsiteProviderRef';
9
+ };
10
+
11
+ export type FrontendWebsiteProviderModule = FrontendProviderEntry;
12
+
13
+ export interface FrontendWebsiteProviderRegistry {
14
+ readonly modules: ReadonlyMap<
15
+ FrontendWebsiteProviderRef,
16
+ FrontendWebsiteProviderModule
17
+ >;
18
+
19
+ getProviderByRef(
20
+ ref: FrontendWebsiteProviderRef,
21
+ ): FrontendWebsiteProviderModule | undefined;
22
+
23
+ getProvidersByProviderCapability(
24
+ providerCapability: ProviderCapability,
25
+ ): ReadonlyArray<FrontendWebsiteProviderModule>;
26
+
27
+ findProviderByProviderCapability(
28
+ providerCapability: ProviderCapability,
29
+ ): FrontendWebsiteProviderModule | undefined;
30
+ }
31
+
32
+ /**
33
+ * Website-side public-provider registry hydrated from the materialized
34
+ * frontend-provider bootstrap block.
35
+ */
36
+ export function createFrontendWebsiteProviderRegistry(
37
+ frontendProviders?: FrontendProvidersBlock,
38
+ ): FrontendWebsiteProviderRegistry {
39
+ const modules = new Map<FrontendWebsiteProviderRef, FrontendWebsiteProviderModule>(
40
+ Object.entries(frontendProviders?.providers ?? {}).map(([ref, provider]) => [
41
+ ref as FrontendWebsiteProviderRef,
42
+ provider as FrontendWebsiteProviderModule,
43
+ ]),
44
+ );
45
+
46
+ return {
47
+ modules,
48
+ getProviderByRef(ref: FrontendWebsiteProviderRef) {
49
+ return modules.get(ref);
50
+ },
51
+ getProvidersByProviderCapability(providerCapability: ProviderCapability) {
52
+ return [...modules.values()].filter((provider) =>
53
+ provider.providerCapabilities.includes(providerCapability),
54
+ );
55
+ },
56
+ findProviderByProviderCapability(providerCapability: ProviderCapability) {
57
+ return [...modules.values()].find((provider) =>
58
+ provider.providerCapabilities.includes(providerCapability),
59
+ );
60
+ },
61
+ };
62
+ }
@@ -0,0 +1,102 @@
1
+ import type { ComponentType } from 'react';
2
+
3
+ import {
4
+ WebsitePageManifestSchema,
5
+ type WebsitePageManifest,
6
+ type WebsitePageMetaLabelKeys,
7
+ type WebsitePageRoutePath,
8
+ type WebsitePageSeoConfig,
9
+ WebsitePageHydrationStrategy,
10
+ } from '../../schemas/manifests/website-page-manifest.shared.schemas';
11
+ import type { WebsitePageRef } from '../../schemas/refs/page-ref.schemas';
12
+ import type { WebsiteSectionRef } from '../../schemas/refs/section-ref.schemas';
13
+
14
+ /**
15
+ * @wildo_source:part:start saas.website.factories.define-page-manifest facet:layer:core facet:family:website
16
+ *
17
+ * Input shape consumed by `defineWebsitePageManifest<TProps>`.
18
+ *
19
+ * `TProps` is rarely non-empty for top-level marketing pages (which
20
+ * are usually rendered by Astro with no React-side props), but the
21
+ * generic exists for two legitimate cases:
22
+ * - templated pages (eg. `/blog/[slug]` whose page component
23
+ * accepts `{ slug, frontmatter }` from the Astro adapter),
24
+ * - pages whose host adapter wants to inject server-side resolved
25
+ * props (eg. an A/B-test variant id) before hydration.
26
+ *
27
+ * **String inputs vs. branded inputs**: `ref`, `routePath`, and
28
+ * `sectionRefs` accept raw strings — the factory parses them through
29
+ * the underlying schemas. Same ergonomic + safety trade-off as
30
+ * `defineWebsiteSection`.
31
+ */
32
+ export interface DefineWebsitePageManifestInput<TProps> {
33
+ ref: WebsitePageRef | string;
34
+ routePath: WebsitePageRoutePath | string;
35
+ pageComponent: ComponentType<TProps>;
36
+ sectionRefs: readonly (WebsiteSectionRef | string)[];
37
+ metaLabelKeys: WebsitePageMetaLabelKeys;
38
+ hydration?: WebsitePageHydrationStrategy;
39
+ seo?: WebsitePageSeoConfig;
40
+ }
41
+
42
+ /**
43
+ * Return shape of `defineWebsitePageManifest<TProps>`. Identical to
44
+ * `WebsitePageManifest` except `pageComponent` retains the
45
+ * caller-supplied generic prop shape.
46
+ */
47
+ export interface TypedWebsitePageManifest<TProps>
48
+ extends Omit<WebsitePageManifest, 'pageComponent'> {
49
+ pageComponent: ComponentType<TProps>;
50
+ }
51
+
52
+ /**
53
+ * `defineWebsitePageManifest<TProps>` — factory that materializes a
54
+ * `WebsitePageManifest` from authored input.
55
+ *
56
+ * Same two responsibilities as `defineWebsiteSection`: runtime
57
+ * validation through the schema (incl. the schema's `superRefine`
58
+ * for unique sectionRefs and meta-key prefixing) plus type
59
+ * preservation for `pageComponent`.
60
+ *
61
+ * **Why a separate factory** (and not a single `defineWebsite*` API):
62
+ * a section and a page have different validation semantics
63
+ * (`expectedLabelKeys` discipline vs. `metaLabelKeys` prefix
64
+ * discipline) and different override paths (sections via L2
65
+ * import-swap; pages via root-config registration). Conflating them
66
+ * would force one of the two contracts onto the other's authors.
67
+ *
68
+ * @example
69
+ * export const LANDING_PAGE_MANIFEST = defineWebsitePageManifest({
70
+ * ref: 'landing',
71
+ * routePath: '/',
72
+ * pageComponent: LandingPage,
73
+ * sectionRefs: ['hero', 'social-proof', 'pricing-teaser', 'final-cta'],
74
+ * metaLabelKeys: {
75
+ * titleKey: WebsiteLabelKeySchema.parse('website.landing.meta.title'),
76
+ * descriptionKey: WebsiteLabelKeySchema.parse('website.landing.meta.description'),
77
+ * },
78
+ * });
79
+ */
80
+ export function defineWebsitePageManifest<TProps = Record<string, never>>(
81
+ input: DefineWebsitePageManifestInput<TProps>,
82
+ ): TypedWebsitePageManifest<TProps> {
83
+ const parsed = WebsitePageManifestSchema.parse({
84
+ ref: input.ref,
85
+ routePath: input.routePath,
86
+ pageComponent: input.pageComponent,
87
+ sectionRefs: input.sectionRefs,
88
+ metaLabelKeys: input.metaLabelKeys,
89
+ hydration: input.hydration,
90
+ seo: input.seo,
91
+ });
92
+ return {
93
+ ref: parsed.ref,
94
+ routePath: parsed.routePath,
95
+ pageComponent: input.pageComponent,
96
+ sectionRefs: parsed.sectionRefs,
97
+ metaLabelKeys: parsed.metaLabelKeys,
98
+ ...(parsed.hydration !== undefined ? { hydration: parsed.hydration } : {}),
99
+ ...(parsed.seo !== undefined ? { seo: parsed.seo } : {}),
100
+ };
101
+ }
102
+ /** @wildo_source:part:end saas.website.factories.define-page-manifest */
@@ -0,0 +1,128 @@
1
+ import type { ComponentType } from 'react';
2
+
3
+ import { WebsiteSectionDefinitionSchema } from '../../schemas/sections/website-section-definition.shared.schemas';
4
+ import type { WebsiteSectionDefinition } from '../../schemas/sections/website-section-definition.shared.schemas';
5
+ import type { WebsiteSectionCategory } from '../../schemas/sections/website-section-category.shared';
6
+ import type { WebsiteSectionRef } from '../../schemas/refs/section-ref.schemas';
7
+ import type { WebsiteLabelKey } from '../../schemas/label-keys/website-label-key.schemas';
8
+ import type { WebsiteStructuredDataReturn } from '../../schemas/structured-data/website-structured-data.shared.schemas';
9
+
10
+ /**
11
+ * @wildo_source:part:start saas.website.factories.define-section facet:layer:core facet:family:website
12
+ *
13
+ * Input shape consumed by `defineWebsiteSection<TProps>`. Mirrors
14
+ * `WebsiteSectionDefinition` but keeps `Component` typed against the
15
+ * caller-supplied generic so the precise prop shape survives end-to-end
16
+ * (the consumer's `<HeroSection />` JSX can keep its strongly-typed
17
+ * props after going through the factory).
18
+ *
19
+ * **String inputs vs. branded inputs**: `sectionRef` and
20
+ * `expectedLabelKeys` accept raw strings as well as already-branded
21
+ * values. The factory parses them through the underlying schemas, so
22
+ * either path is safe — accepting strings directly removes the
23
+ * ergonomic drag of forcing every section author to remember to call
24
+ * `WebsiteSectionRefSchema.parse(...)` in their definition.
25
+ */
26
+ export interface DefineWebsiteSectionInput<TProps> {
27
+ sectionRef: WebsiteSectionRef | string;
28
+ category: WebsiteSectionCategory;
29
+ expectedLabelKeys: readonly (WebsiteLabelKey | string)[];
30
+ Component: ComponentType<TProps>;
31
+ /**
32
+ * See `WebsiteSectionDefinition.getStructuredData?` JSDoc for the
33
+ * full authoring contract. The factory passes the function through
34
+ * unchanged; the framework invokes it at static-build time and
35
+ * forwards the return value to `renderPageStructuredData()`.
36
+ */
37
+ getStructuredData?: () => WebsiteStructuredDataReturn;
38
+ }
39
+
40
+ /**
41
+ * Return shape of `defineWebsiteSection<TProps>`. Identical to
42
+ * `WebsiteSectionDefinition` except `Component` retains the
43
+ * caller-supplied generic prop shape rather than the schema's
44
+ * lowest-common-denominator `ComponentType<unknown>`.
45
+ *
46
+ * **Why this matters**: a consumer's `pageComponent` JSX composes
47
+ * sections like `<HERO_SECTION.Component {...heroProps} />`. Without
48
+ * preserving `TProps`, the spread would be untyped and a renamed prop
49
+ * would silently miss the type system. With `TProps` preserved, the
50
+ * call site fails to compile the moment the prop contract drifts.
51
+ */
52
+ export interface TypedWebsiteSectionDefinition<TProps>
53
+ extends Omit<WebsiteSectionDefinition, 'Component' | 'getStructuredData'> {
54
+ Component: ComponentType<TProps>;
55
+ getStructuredData?: () => WebsiteStructuredDataReturn;
56
+ }
57
+
58
+ /**
59
+ * `defineWebsiteSection<TProps>` — factory that materializes a
60
+ * `WebsiteSectionDefinition` from authored input.
61
+ *
62
+ * **Two responsibilities**, one entry point:
63
+ * 1. Runtime validation — parses the input through
64
+ * `WebsiteSectionDefinitionSchema` so brand checks, regex
65
+ * validations, and array refinements run at module load time
66
+ * (not at render time, not at build-output time).
67
+ * 2. Type preservation — returns an object whose `Component` field
68
+ * keeps the caller-supplied `TProps`, so JSX usage of the
69
+ * returned section retains compile-time prop checking.
70
+ *
71
+ * **Why a factory instead of constructing the literal directly**:
72
+ * - Consumers don't have to remember to parse refs / keys
73
+ * themselves before assembling the literal.
74
+ * - The schema parse provides a single audited validation chokepoint
75
+ * so `wildo website audit` (Phase 7) can re-validate definitions
76
+ * without re-entering the React graph.
77
+ * - The factory is the documented authoring API the
78
+ * `website_factory_authoring` skill targets — keeping the
79
+ * authoring surface narrow lets the framework evolve the
80
+ * internal schema (add fields, refinements) without churning
81
+ * every section definition in every consumer app.
82
+ *
83
+ * @param input section authoring input (see `DefineWebsiteSectionInput`).
84
+ * @returns a `TypedWebsiteSectionDefinition<TProps>` with `Component`
85
+ * preserved at the precise prop type.
86
+ *
87
+ * @example
88
+ * interface HeroProps {
89
+ * headlineKey: WebsiteLabelKey;
90
+ * subheadlineKey: WebsiteLabelKey;
91
+ * }
92
+ * function HeroSection({ headlineKey, subheadlineKey }: HeroProps) {
93
+ * // …
94
+ * }
95
+ * export const HERO_SECTION = defineWebsiteSection<HeroProps>({
96
+ * sectionRef: 'hero',
97
+ * category: WebsiteSectionCategory.HERO,
98
+ * expectedLabelKeys: [
99
+ * 'website.landing.hero.headline',
100
+ * 'website.landing.hero.subheadline',
101
+ * ],
102
+ * Component: HeroSection,
103
+ * });
104
+ */
105
+ export function defineWebsiteSection<TProps>(
106
+ input: DefineWebsiteSectionInput<TProps>,
107
+ ): TypedWebsiteSectionDefinition<TProps> {
108
+ const parsed = WebsiteSectionDefinitionSchema.parse({
109
+ sectionRef: input.sectionRef,
110
+ category: input.category,
111
+ expectedLabelKeys: input.expectedLabelKeys,
112
+ Component: input.Component,
113
+ getStructuredData: input.getStructuredData,
114
+ });
115
+ /**
116
+ * Re-attach `Component` and `getStructuredData` from the original
117
+ * input so the precise generic types survive — `parsed.Component`
118
+ * is `unknown` per the schema's `z.unknown()` contract.
119
+ */
120
+ return {
121
+ sectionRef: parsed.sectionRef,
122
+ category: parsed.category,
123
+ expectedLabelKeys: parsed.expectedLabelKeys,
124
+ Component: input.Component,
125
+ ...(input.getStructuredData ? { getStructuredData: input.getStructuredData } : {}),
126
+ };
127
+ }
128
+ /** @wildo_source:part:end saas.website.factories.define-section */
@@ -0,0 +1,26 @@
1
+ import { useWebsiteRuntime } from '../contexts/useWebsiteRuntime';
2
+ import type { WebsiteDesignTokens } from '../../schemas/design-tokens/website-design-tokens.shared.schemas';
3
+
4
+ /**
5
+ * @wildo_source:part:start saas.website.use-tokens.hook facet:layer:core facet:family:website
6
+ *
7
+ * `useWebsiteDesignTokens()` — narrow read of the runtime context's
8
+ * `designTokens` slice.
9
+ *
10
+ * Existence rationale (vs. asking section authors to call
11
+ * `useWebsiteRuntime().designTokens` directly): hook discoverability
12
+ * + intent clarity. A section needing tokens has a single hook to
13
+ * import; refactoring the runtime context to add unrelated fields
14
+ * (eg. a future `analytics` slice) does NOT broaden the API surface
15
+ * the section consumes. Keeps the dependency graph between sections
16
+ * and runtime state explicit and minimal.
17
+ *
18
+ * Read-by-reference — the returned object is the same instance held
19
+ * by the runtime context, so memoization (`useMemo` /
20
+ * `React.memo` deps) using the returned reference works correctly
21
+ * across the static build's single render lifecycle.
22
+ */
23
+ export function useWebsiteDesignTokens(): WebsiteDesignTokens {
24
+ return useWebsiteRuntime().designTokens;
25
+ }
26
+ /** @wildo_source:part:end saas.website.use-tokens.hook */