@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,51 @@
1
+ import { WebsitePageManifestSchema, } from '../../schemas/manifests/website-page-manifest.shared.schemas.js';
2
+ /**
3
+ * `defineWebsitePageManifest<TProps>` — factory that materializes a
4
+ * `WebsitePageManifest` from authored input.
5
+ *
6
+ * Same two responsibilities as `defineWebsiteSection`: runtime
7
+ * validation through the schema (incl. the schema's `superRefine`
8
+ * for unique sectionRefs and meta-key prefixing) plus type
9
+ * preservation for `pageComponent`.
10
+ *
11
+ * **Why a separate factory** (and not a single `defineWebsite*` API):
12
+ * a section and a page have different validation semantics
13
+ * (`expectedLabelKeys` discipline vs. `metaLabelKeys` prefix
14
+ * discipline) and different override paths (sections via L2
15
+ * import-swap; pages via root-config registration). Conflating them
16
+ * would force one of the two contracts onto the other's authors.
17
+ *
18
+ * @example
19
+ * export const LANDING_PAGE_MANIFEST = defineWebsitePageManifest({
20
+ * ref: 'landing',
21
+ * routePath: '/',
22
+ * pageComponent: LandingPage,
23
+ * sectionRefs: ['hero', 'social-proof', 'pricing-teaser', 'final-cta'],
24
+ * metaLabelKeys: {
25
+ * titleKey: WebsiteLabelKeySchema.parse('website.landing.meta.title'),
26
+ * descriptionKey: WebsiteLabelKeySchema.parse('website.landing.meta.description'),
27
+ * },
28
+ * });
29
+ */
30
+ export function defineWebsitePageManifest(input) {
31
+ const parsed = WebsitePageManifestSchema.parse({
32
+ ref: input.ref,
33
+ routePath: input.routePath,
34
+ pageComponent: input.pageComponent,
35
+ sectionRefs: input.sectionRefs,
36
+ metaLabelKeys: input.metaLabelKeys,
37
+ hydration: input.hydration,
38
+ seo: input.seo,
39
+ });
40
+ return {
41
+ ref: parsed.ref,
42
+ routePath: parsed.routePath,
43
+ pageComponent: input.pageComponent,
44
+ sectionRefs: parsed.sectionRefs,
45
+ metaLabelKeys: parsed.metaLabelKeys,
46
+ ...(parsed.hydration !== undefined ? { hydration: parsed.hydration } : {}),
47
+ ...(parsed.seo !== undefined ? { seo: parsed.seo } : {}),
48
+ };
49
+ }
50
+ /** @wildo_source:part:end saas.website.factories.define-page-manifest */
51
+ //# sourceMappingURL=define-website-page-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-website-page-manifest.js","sourceRoot":"","sources":["../../../../../src/core/factories/define-website-page-manifest.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,yBAAyB,GAM1B,MAAM,8DAA8D,CAAC;AA0CtE;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,yBAAyB,CACvC,KAA6C;IAE7C,MAAM,MAAM,GAAG,yBAAyB,CAAC,KAAK,CAAC;QAC7C,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,aAAa,EAAE,KAAK,CAAC,aAAa;QAClC,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,aAAa,EAAE,KAAK,CAAC,aAAa;QAClC,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,GAAG,EAAE,KAAK,CAAC,GAAG;KACf,CAAC,CAAC;IACH,OAAO;QACL,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,aAAa,EAAE,KAAK,CAAC,aAAa;QAClC,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,GAAG,CAAC,MAAM,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1E,GAAG,CAAC,MAAM,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACzD,CAAC;AACJ,CAAC;AACD,yEAAyE","sourcesContent":["import type { ComponentType } from 'react';\n\nimport {\n WebsitePageManifestSchema,\n type WebsitePageManifest,\n type WebsitePageMetaLabelKeys,\n type WebsitePageRoutePath,\n type WebsitePageSeoConfig,\n WebsitePageHydrationStrategy,\n} from '../../schemas/manifests/website-page-manifest.shared.schemas';\nimport type { WebsitePageRef } from '../../schemas/refs/page-ref.schemas';\nimport type { WebsiteSectionRef } from '../../schemas/refs/section-ref.schemas';\n\n/**\n * @wildo_source:part:start saas.website.factories.define-page-manifest facet:layer:core facet:family:website\n *\n * Input shape consumed by `defineWebsitePageManifest<TProps>`.\n *\n * `TProps` is rarely non-empty for top-level marketing pages (which\n * are usually rendered by Astro with no React-side props), but the\n * generic exists for two legitimate cases:\n * - templated pages (eg. `/blog/[slug]` whose page component\n * accepts `{ slug, frontmatter }` from the Astro adapter),\n * - pages whose host adapter wants to inject server-side resolved\n * props (eg. an A/B-test variant id) before hydration.\n *\n * **String inputs vs. branded inputs**: `ref`, `routePath`, and\n * `sectionRefs` accept raw strings — the factory parses them through\n * the underlying schemas. Same ergonomic + safety trade-off as\n * `defineWebsiteSection`.\n */\nexport interface DefineWebsitePageManifestInput<TProps> {\n ref: WebsitePageRef | string;\n routePath: WebsitePageRoutePath | string;\n pageComponent: ComponentType<TProps>;\n sectionRefs: readonly (WebsiteSectionRef | string)[];\n metaLabelKeys: WebsitePageMetaLabelKeys;\n hydration?: WebsitePageHydrationStrategy;\n seo?: WebsitePageSeoConfig;\n}\n\n/**\n * Return shape of `defineWebsitePageManifest<TProps>`. Identical to\n * `WebsitePageManifest` except `pageComponent` retains the\n * caller-supplied generic prop shape.\n */\nexport interface TypedWebsitePageManifest<TProps>\n extends Omit<WebsitePageManifest, 'pageComponent'> {\n pageComponent: ComponentType<TProps>;\n}\n\n/**\n * `defineWebsitePageManifest<TProps>` — factory that materializes a\n * `WebsitePageManifest` from authored input.\n *\n * Same two responsibilities as `defineWebsiteSection`: runtime\n * validation through the schema (incl. the schema's `superRefine`\n * for unique sectionRefs and meta-key prefixing) plus type\n * preservation for `pageComponent`.\n *\n * **Why a separate factory** (and not a single `defineWebsite*` API):\n * a section and a page have different validation semantics\n * (`expectedLabelKeys` discipline vs. `metaLabelKeys` prefix\n * discipline) and different override paths (sections via L2\n * import-swap; pages via root-config registration). Conflating them\n * would force one of the two contracts onto the other's authors.\n *\n * @example\n * export const LANDING_PAGE_MANIFEST = defineWebsitePageManifest({\n * ref: 'landing',\n * routePath: '/',\n * pageComponent: LandingPage,\n * sectionRefs: ['hero', 'social-proof', 'pricing-teaser', 'final-cta'],\n * metaLabelKeys: {\n * titleKey: WebsiteLabelKeySchema.parse('website.landing.meta.title'),\n * descriptionKey: WebsiteLabelKeySchema.parse('website.landing.meta.description'),\n * },\n * });\n */\nexport function defineWebsitePageManifest<TProps = Record<string, never>>(\n input: DefineWebsitePageManifestInput<TProps>,\n): TypedWebsitePageManifest<TProps> {\n const parsed = WebsitePageManifestSchema.parse({\n ref: input.ref,\n routePath: input.routePath,\n pageComponent: input.pageComponent,\n sectionRefs: input.sectionRefs,\n metaLabelKeys: input.metaLabelKeys,\n hydration: input.hydration,\n seo: input.seo,\n });\n return {\n ref: parsed.ref,\n routePath: parsed.routePath,\n pageComponent: input.pageComponent,\n sectionRefs: parsed.sectionRefs,\n metaLabelKeys: parsed.metaLabelKeys,\n ...(parsed.hydration !== undefined ? { hydration: parsed.hydration } : {}),\n ...(parsed.seo !== undefined ? { seo: parsed.seo } : {}),\n };\n}\n/** @wildo_source:part:end saas.website.factories.define-page-manifest */\n"]}
@@ -0,0 +1,101 @@
1
+ import type { ComponentType } from 'react';
2
+ import type { WebsiteSectionDefinition } from '../../schemas/sections/website-section-definition.shared.schemas';
3
+ import type { WebsiteSectionCategory } from '../../schemas/sections/website-section-category.shared';
4
+ import type { WebsiteSectionRef } from '../../schemas/refs/section-ref.schemas';
5
+ import type { WebsiteLabelKey } from '../../schemas/label-keys/website-label-key.schemas';
6
+ import type { WebsiteStructuredDataReturn } from '../../schemas/structured-data/website-structured-data.shared.schemas';
7
+ /**
8
+ * @wildo_source:part:start saas.website.factories.define-section facet:layer:core facet:family:website
9
+ *
10
+ * Input shape consumed by `defineWebsiteSection<TProps>`. Mirrors
11
+ * `WebsiteSectionDefinition` but keeps `Component` typed against the
12
+ * caller-supplied generic so the precise prop shape survives end-to-end
13
+ * (the consumer's `<HeroSection />` JSX can keep its strongly-typed
14
+ * props after going through the factory).
15
+ *
16
+ * **String inputs vs. branded inputs**: `sectionRef` and
17
+ * `expectedLabelKeys` accept raw strings as well as already-branded
18
+ * values. The factory parses them through the underlying schemas, so
19
+ * either path is safe — accepting strings directly removes the
20
+ * ergonomic drag of forcing every section author to remember to call
21
+ * `WebsiteSectionRefSchema.parse(...)` in their definition.
22
+ */
23
+ export interface DefineWebsiteSectionInput<TProps> {
24
+ sectionRef: WebsiteSectionRef | string;
25
+ category: WebsiteSectionCategory;
26
+ expectedLabelKeys: readonly (WebsiteLabelKey | string)[];
27
+ Component: ComponentType<TProps>;
28
+ /**
29
+ * See `WebsiteSectionDefinition.getStructuredData?` JSDoc for the
30
+ * full authoring contract. The factory passes the function through
31
+ * unchanged; the framework invokes it at static-build time and
32
+ * forwards the return value to `renderPageStructuredData()`.
33
+ */
34
+ getStructuredData?: () => WebsiteStructuredDataReturn;
35
+ }
36
+ /**
37
+ * Return shape of `defineWebsiteSection<TProps>`. Identical to
38
+ * `WebsiteSectionDefinition` except `Component` retains the
39
+ * caller-supplied generic prop shape rather than the schema's
40
+ * lowest-common-denominator `ComponentType<unknown>`.
41
+ *
42
+ * **Why this matters**: a consumer's `pageComponent` JSX composes
43
+ * sections like `<HERO_SECTION.Component {...heroProps} />`. Without
44
+ * preserving `TProps`, the spread would be untyped and a renamed prop
45
+ * would silently miss the type system. With `TProps` preserved, the
46
+ * call site fails to compile the moment the prop contract drifts.
47
+ */
48
+ export interface TypedWebsiteSectionDefinition<TProps> extends Omit<WebsiteSectionDefinition, 'Component' | 'getStructuredData'> {
49
+ Component: ComponentType<TProps>;
50
+ getStructuredData?: () => WebsiteStructuredDataReturn;
51
+ }
52
+ /**
53
+ * `defineWebsiteSection<TProps>` — factory that materializes a
54
+ * `WebsiteSectionDefinition` from authored input.
55
+ *
56
+ * **Two responsibilities**, one entry point:
57
+ * 1. Runtime validation — parses the input through
58
+ * `WebsiteSectionDefinitionSchema` so brand checks, regex
59
+ * validations, and array refinements run at module load time
60
+ * (not at render time, not at build-output time).
61
+ * 2. Type preservation — returns an object whose `Component` field
62
+ * keeps the caller-supplied `TProps`, so JSX usage of the
63
+ * returned section retains compile-time prop checking.
64
+ *
65
+ * **Why a factory instead of constructing the literal directly**:
66
+ * - Consumers don't have to remember to parse refs / keys
67
+ * themselves before assembling the literal.
68
+ * - The schema parse provides a single audited validation chokepoint
69
+ * so `wildo website audit` (Phase 7) can re-validate definitions
70
+ * without re-entering the React graph.
71
+ * - The factory is the documented authoring API the
72
+ * `website_factory_authoring` skill targets — keeping the
73
+ * authoring surface narrow lets the framework evolve the
74
+ * internal schema (add fields, refinements) without churning
75
+ * every section definition in every consumer app.
76
+ *
77
+ * @param input section authoring input (see `DefineWebsiteSectionInput`).
78
+ * @returns a `TypedWebsiteSectionDefinition<TProps>` with `Component`
79
+ * preserved at the precise prop type.
80
+ *
81
+ * @example
82
+ * interface HeroProps {
83
+ * headlineKey: WebsiteLabelKey;
84
+ * subheadlineKey: WebsiteLabelKey;
85
+ * }
86
+ * function HeroSection({ headlineKey, subheadlineKey }: HeroProps) {
87
+ * // …
88
+ * }
89
+ * export const HERO_SECTION = defineWebsiteSection<HeroProps>({
90
+ * sectionRef: 'hero',
91
+ * category: WebsiteSectionCategory.HERO,
92
+ * expectedLabelKeys: [
93
+ * 'website.landing.hero.headline',
94
+ * 'website.landing.hero.subheadline',
95
+ * ],
96
+ * Component: HeroSection,
97
+ * });
98
+ */
99
+ export declare function defineWebsiteSection<TProps>(input: DefineWebsiteSectionInput<TProps>): TypedWebsiteSectionDefinition<TProps>;
100
+ /** @wildo_source:part:end saas.website.factories.define-section */
101
+ //# sourceMappingURL=define-website-section.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-website-section.d.ts","sourceRoot":"","sources":["../../../../../src/core/factories/define-website-section.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAG3C,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kEAAkE,CAAC;AACjH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wDAAwD,CAAC;AACrG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAChF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oDAAoD,CAAC;AAC1F,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,sEAAsE,CAAC;AAExH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,yBAAyB,CAAC,MAAM;IAC/C,UAAU,EAAE,iBAAiB,GAAG,MAAM,CAAC;IACvC,QAAQ,EAAE,sBAAsB,CAAC;IACjC,iBAAiB,EAAE,SAAS,CAAC,eAAe,GAAG,MAAM,CAAC,EAAE,CAAC;IACzD,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACjC;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,2BAA2B,CAAC;CACvD;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,6BAA6B,CAAC,MAAM,CACnD,SAAQ,IAAI,CAAC,wBAAwB,EAAE,WAAW,GAAG,mBAAmB,CAAC;IACzE,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACjC,iBAAiB,CAAC,EAAE,MAAM,2BAA2B,CAAC;CACvD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EACzC,KAAK,EAAE,yBAAyB,CAAC,MAAM,CAAC,GACvC,6BAA6B,CAAC,MAAM,CAAC,CAoBvC;AACD,mEAAmE"}
@@ -0,0 +1,71 @@
1
+ import { WebsiteSectionDefinitionSchema } from '../../schemas/sections/website-section-definition.shared.schemas.js';
2
+ /**
3
+ * `defineWebsiteSection<TProps>` — factory that materializes a
4
+ * `WebsiteSectionDefinition` from authored input.
5
+ *
6
+ * **Two responsibilities**, one entry point:
7
+ * 1. Runtime validation — parses the input through
8
+ * `WebsiteSectionDefinitionSchema` so brand checks, regex
9
+ * validations, and array refinements run at module load time
10
+ * (not at render time, not at build-output time).
11
+ * 2. Type preservation — returns an object whose `Component` field
12
+ * keeps the caller-supplied `TProps`, so JSX usage of the
13
+ * returned section retains compile-time prop checking.
14
+ *
15
+ * **Why a factory instead of constructing the literal directly**:
16
+ * - Consumers don't have to remember to parse refs / keys
17
+ * themselves before assembling the literal.
18
+ * - The schema parse provides a single audited validation chokepoint
19
+ * so `wildo website audit` (Phase 7) can re-validate definitions
20
+ * without re-entering the React graph.
21
+ * - The factory is the documented authoring API the
22
+ * `website_factory_authoring` skill targets — keeping the
23
+ * authoring surface narrow lets the framework evolve the
24
+ * internal schema (add fields, refinements) without churning
25
+ * every section definition in every consumer app.
26
+ *
27
+ * @param input section authoring input (see `DefineWebsiteSectionInput`).
28
+ * @returns a `TypedWebsiteSectionDefinition<TProps>` with `Component`
29
+ * preserved at the precise prop type.
30
+ *
31
+ * @example
32
+ * interface HeroProps {
33
+ * headlineKey: WebsiteLabelKey;
34
+ * subheadlineKey: WebsiteLabelKey;
35
+ * }
36
+ * function HeroSection({ headlineKey, subheadlineKey }: HeroProps) {
37
+ * // …
38
+ * }
39
+ * export const HERO_SECTION = defineWebsiteSection<HeroProps>({
40
+ * sectionRef: 'hero',
41
+ * category: WebsiteSectionCategory.HERO,
42
+ * expectedLabelKeys: [
43
+ * 'website.landing.hero.headline',
44
+ * 'website.landing.hero.subheadline',
45
+ * ],
46
+ * Component: HeroSection,
47
+ * });
48
+ */
49
+ export function defineWebsiteSection(input) {
50
+ const parsed = WebsiteSectionDefinitionSchema.parse({
51
+ sectionRef: input.sectionRef,
52
+ category: input.category,
53
+ expectedLabelKeys: input.expectedLabelKeys,
54
+ Component: input.Component,
55
+ getStructuredData: input.getStructuredData,
56
+ });
57
+ /**
58
+ * Re-attach `Component` and `getStructuredData` from the original
59
+ * input so the precise generic types survive — `parsed.Component`
60
+ * is `unknown` per the schema's `z.unknown()` contract.
61
+ */
62
+ return {
63
+ sectionRef: parsed.sectionRef,
64
+ category: parsed.category,
65
+ expectedLabelKeys: parsed.expectedLabelKeys,
66
+ Component: input.Component,
67
+ ...(input.getStructuredData ? { getStructuredData: input.getStructuredData } : {}),
68
+ };
69
+ }
70
+ /** @wildo_source:part:end saas.website.factories.define-section */
71
+ //# sourceMappingURL=define-website-section.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-website-section.js","sourceRoot":"","sources":["../../../../../src/core/factories/define-website-section.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,8BAA8B,EAAE,MAAM,kEAAkE,CAAC;AAuDlH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,MAAM,UAAU,oBAAoB,CAClC,KAAwC;IAExC,MAAM,MAAM,GAAG,8BAA8B,CAAC,KAAK,CAAC;QAClD,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;QAC1C,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;KAC3C,CAAC,CAAC;IACH;;;;OAIG;IACH,OAAO;QACL,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,iBAAiB,EAAE,MAAM,CAAC,iBAAiB;QAC3C,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,KAAK,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACnF,CAAC;AACJ,CAAC;AACD,mEAAmE","sourcesContent":["import type { ComponentType } from 'react';\n\nimport { WebsiteSectionDefinitionSchema } from '../../schemas/sections/website-section-definition.shared.schemas';\nimport type { WebsiteSectionDefinition } from '../../schemas/sections/website-section-definition.shared.schemas';\nimport type { WebsiteSectionCategory } from '../../schemas/sections/website-section-category.shared';\nimport type { WebsiteSectionRef } from '../../schemas/refs/section-ref.schemas';\nimport type { WebsiteLabelKey } from '../../schemas/label-keys/website-label-key.schemas';\nimport type { WebsiteStructuredDataReturn } from '../../schemas/structured-data/website-structured-data.shared.schemas';\n\n/**\n * @wildo_source:part:start saas.website.factories.define-section facet:layer:core facet:family:website\n *\n * Input shape consumed by `defineWebsiteSection<TProps>`. Mirrors\n * `WebsiteSectionDefinition` but keeps `Component` typed against the\n * caller-supplied generic so the precise prop shape survives end-to-end\n * (the consumer's `<HeroSection />` JSX can keep its strongly-typed\n * props after going through the factory).\n *\n * **String inputs vs. branded inputs**: `sectionRef` and\n * `expectedLabelKeys` accept raw strings as well as already-branded\n * values. The factory parses them through the underlying schemas, so\n * either path is safe — accepting strings directly removes the\n * ergonomic drag of forcing every section author to remember to call\n * `WebsiteSectionRefSchema.parse(...)` in their definition.\n */\nexport interface DefineWebsiteSectionInput<TProps> {\n sectionRef: WebsiteSectionRef | string;\n category: WebsiteSectionCategory;\n expectedLabelKeys: readonly (WebsiteLabelKey | string)[];\n Component: ComponentType<TProps>;\n /**\n * See `WebsiteSectionDefinition.getStructuredData?` JSDoc for the\n * full authoring contract. The factory passes the function through\n * unchanged; the framework invokes it at static-build time and\n * forwards the return value to `renderPageStructuredData()`.\n */\n getStructuredData?: () => WebsiteStructuredDataReturn;\n}\n\n/**\n * Return shape of `defineWebsiteSection<TProps>`. Identical to\n * `WebsiteSectionDefinition` except `Component` retains the\n * caller-supplied generic prop shape rather than the schema's\n * lowest-common-denominator `ComponentType<unknown>`.\n *\n * **Why this matters**: a consumer's `pageComponent` JSX composes\n * sections like `<HERO_SECTION.Component {...heroProps} />`. Without\n * preserving `TProps`, the spread would be untyped and a renamed prop\n * would silently miss the type system. With `TProps` preserved, the\n * call site fails to compile the moment the prop contract drifts.\n */\nexport interface TypedWebsiteSectionDefinition<TProps>\n extends Omit<WebsiteSectionDefinition, 'Component' | 'getStructuredData'> {\n Component: ComponentType<TProps>;\n getStructuredData?: () => WebsiteStructuredDataReturn;\n}\n\n/**\n * `defineWebsiteSection<TProps>` — factory that materializes a\n * `WebsiteSectionDefinition` from authored input.\n *\n * **Two responsibilities**, one entry point:\n * 1. Runtime validation — parses the input through\n * `WebsiteSectionDefinitionSchema` so brand checks, regex\n * validations, and array refinements run at module load time\n * (not at render time, not at build-output time).\n * 2. Type preservation — returns an object whose `Component` field\n * keeps the caller-supplied `TProps`, so JSX usage of the\n * returned section retains compile-time prop checking.\n *\n * **Why a factory instead of constructing the literal directly**:\n * - Consumers don't have to remember to parse refs / keys\n * themselves before assembling the literal.\n * - The schema parse provides a single audited validation chokepoint\n * so `wildo website audit` (Phase 7) can re-validate definitions\n * without re-entering the React graph.\n * - The factory is the documented authoring API the\n * `website_factory_authoring` skill targets — keeping the\n * authoring surface narrow lets the framework evolve the\n * internal schema (add fields, refinements) without churning\n * every section definition in every consumer app.\n *\n * @param input section authoring input (see `DefineWebsiteSectionInput`).\n * @returns a `TypedWebsiteSectionDefinition<TProps>` with `Component`\n * preserved at the precise prop type.\n *\n * @example\n * interface HeroProps {\n * headlineKey: WebsiteLabelKey;\n * subheadlineKey: WebsiteLabelKey;\n * }\n * function HeroSection({ headlineKey, subheadlineKey }: HeroProps) {\n * // …\n * }\n * export const HERO_SECTION = defineWebsiteSection<HeroProps>({\n * sectionRef: 'hero',\n * category: WebsiteSectionCategory.HERO,\n * expectedLabelKeys: [\n * 'website.landing.hero.headline',\n * 'website.landing.hero.subheadline',\n * ],\n * Component: HeroSection,\n * });\n */\nexport function defineWebsiteSection<TProps>(\n input: DefineWebsiteSectionInput<TProps>,\n): TypedWebsiteSectionDefinition<TProps> {\n const parsed = WebsiteSectionDefinitionSchema.parse({\n sectionRef: input.sectionRef,\n category: input.category,\n expectedLabelKeys: input.expectedLabelKeys,\n Component: input.Component,\n getStructuredData: input.getStructuredData,\n });\n /**\n * Re-attach `Component` and `getStructuredData` from the original\n * input so the precise generic types survive — `parsed.Component`\n * is `unknown` per the schema's `z.unknown()` contract.\n */\n return {\n sectionRef: parsed.sectionRef,\n category: parsed.category,\n expectedLabelKeys: parsed.expectedLabelKeys,\n Component: input.Component,\n ...(input.getStructuredData ? { getStructuredData: input.getStructuredData } : {}),\n };\n}\n/** @wildo_source:part:end saas.website.factories.define-section */\n"]}
@@ -0,0 +1,23 @@
1
+ import type { WebsiteDesignTokens } from '../../schemas/design-tokens/website-design-tokens.shared.schemas';
2
+ /**
3
+ * @wildo_source:part:start saas.website.use-tokens.hook facet:layer:core facet:family:website
4
+ *
5
+ * `useWebsiteDesignTokens()` — narrow read of the runtime context's
6
+ * `designTokens` slice.
7
+ *
8
+ * Existence rationale (vs. asking section authors to call
9
+ * `useWebsiteRuntime().designTokens` directly): hook discoverability
10
+ * + intent clarity. A section needing tokens has a single hook to
11
+ * import; refactoring the runtime context to add unrelated fields
12
+ * (eg. a future `analytics` slice) does NOT broaden the API surface
13
+ * the section consumes. Keeps the dependency graph between sections
14
+ * and runtime state explicit and minimal.
15
+ *
16
+ * Read-by-reference — the returned object is the same instance held
17
+ * by the runtime context, so memoization (`useMemo` /
18
+ * `React.memo` deps) using the returned reference works correctly
19
+ * across the static build's single render lifecycle.
20
+ */
21
+ export declare function useWebsiteDesignTokens(): WebsiteDesignTokens;
22
+ /** @wildo_source:part:end saas.website.use-tokens.hook */
23
+ //# sourceMappingURL=useWebsiteDesignTokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWebsiteDesignTokens.d.ts","sourceRoot":"","sources":["../../../../../src/core/hooks/useWebsiteDesignTokens.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kEAAkE,CAAC;AAE5G;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,IAAI,mBAAmB,CAE5D;AACD,0DAA0D"}
@@ -0,0 +1,25 @@
1
+ import { useWebsiteRuntime } from '../contexts/useWebsiteRuntime.js';
2
+ /**
3
+ * @wildo_source:part:start saas.website.use-tokens.hook facet:layer:core facet:family:website
4
+ *
5
+ * `useWebsiteDesignTokens()` — narrow read of the runtime context's
6
+ * `designTokens` slice.
7
+ *
8
+ * Existence rationale (vs. asking section authors to call
9
+ * `useWebsiteRuntime().designTokens` directly): hook discoverability
10
+ * + intent clarity. A section needing tokens has a single hook to
11
+ * import; refactoring the runtime context to add unrelated fields
12
+ * (eg. a future `analytics` slice) does NOT broaden the API surface
13
+ * the section consumes. Keeps the dependency graph between sections
14
+ * and runtime state explicit and minimal.
15
+ *
16
+ * Read-by-reference — the returned object is the same instance held
17
+ * by the runtime context, so memoization (`useMemo` /
18
+ * `React.memo` deps) using the returned reference works correctly
19
+ * across the static build's single render lifecycle.
20
+ */
21
+ export function useWebsiteDesignTokens() {
22
+ return useWebsiteRuntime().designTokens;
23
+ }
24
+ /** @wildo_source:part:end saas.website.use-tokens.hook */
25
+ //# sourceMappingURL=useWebsiteDesignTokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWebsiteDesignTokens.js","sourceRoot":"","sources":["../../../../../src/core/hooks/useWebsiteDesignTokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAGlE;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO,iBAAiB,EAAE,CAAC,YAAY,CAAC;AAC1C,CAAC;AACD,0DAA0D","sourcesContent":["import { useWebsiteRuntime } from '../contexts/useWebsiteRuntime';\nimport type { WebsiteDesignTokens } from '../../schemas/design-tokens/website-design-tokens.shared.schemas';\n\n/**\n * @wildo_source:part:start saas.website.use-tokens.hook facet:layer:core facet:family:website\n *\n * `useWebsiteDesignTokens()` — narrow read of the runtime context's\n * `designTokens` slice.\n *\n * Existence rationale (vs. asking section authors to call\n * `useWebsiteRuntime().designTokens` directly): hook discoverability\n * + intent clarity. A section needing tokens has a single hook to\n * import; refactoring the runtime context to add unrelated fields\n * (eg. a future `analytics` slice) does NOT broaden the API surface\n * the section consumes. Keeps the dependency graph between sections\n * and runtime state explicit and minimal.\n *\n * Read-by-reference — the returned object is the same instance held\n * by the runtime context, so memoization (`useMemo` /\n * `React.memo` deps) using the returned reference works correctly\n * across the static build's single render lifecycle.\n */\nexport function useWebsiteDesignTokens(): WebsiteDesignTokens {\n return useWebsiteRuntime().designTokens;\n}\n/** @wildo_source:part:end saas.website.use-tokens.hook */\n"]}
@@ -0,0 +1,68 @@
1
+ import { type WebsiteLabelKey } from '../../schemas/label-keys/website-label-key.schemas';
2
+ /**
3
+ * @wildo_source:part:start saas.website.use-label.hook facet:layer:core facet:family:website
4
+ *
5
+ * `useWebsiteLabel(slotPath)` — leaf-relative label resolution.
6
+ *
7
+ * Composes the slot leaf with the active page+section context to
8
+ * derive the full `WebsiteLabelKey` (`website.{pageRef}.{sectionRef}.{slotPath}`),
9
+ * looks it up in the active locale's label pack, and returns the
10
+ * resolved string.
11
+ *
12
+ * **Author ergonomics**: section authors call
13
+ * `useWebsiteLabel('headline')` from inside their section component
14
+ * without ever typing the page or section ref — the hook reads them
15
+ * from context. This keeps section components portable across pages
16
+ * (the same `<HeroSection />` can be reused on `landing` and on a
17
+ * dedicated `/about` page; only the surrounding `<WebsiteSection
18
+ * sectionRef="hero">` differs, and the label keys re-root accordingly).
19
+ *
20
+ * **Fail-loud diagnostics** for missing keys: returns the composed key
21
+ * itself (visible in the rendered DOM as e.g. `website.landing.hero.headline`)
22
+ * AND emits a `console.warn`. The visible-key fallback is preferred
23
+ * over an empty string or a thrown error because:
24
+ * - empty string silently breaks layout (zero-height heading) and
25
+ * leaks past visual review,
26
+ * - throwing would crash the entire page on a single missing label
27
+ * while the SEO crawler indexes a 500 page,
28
+ * - the rendered key is a clear authoring signal ("ship the missing
29
+ * pack entry") that designers and copywriters can spot without
30
+ * opening DevTools.
31
+ *
32
+ * **Hard guards** (each enforced by the underlying context hooks):
33
+ * - MUST be called inside `<WebsiteRuntimeContextProvider>`,
34
+ * - MUST be called inside `<WebsitePageLayout>`,
35
+ * - MUST be called inside `<WebsiteSection>`.
36
+ *
37
+ * @param slotPath leaf identifier (eg. `'headline'`, `'cta.primary'`,
38
+ * `'tiers[0].name'`). Anything that survives the slot
39
+ * portion of `WebsiteLabelKeySchema`'s regex.
40
+ * @returns the resolved label string, or the composed key itself when
41
+ * the pack lacks an entry (with a `console.warn`).
42
+ */
43
+ export declare function useWebsiteLabel(slotPath: string): string;
44
+ /** @wildo_source:part:end saas.website.use-label.hook */
45
+ /**
46
+ * @wildo_source:part:start saas.website.use-label-by-key.hook facet:layer:core facet:family:website
47
+ *
48
+ * `useWebsiteLabelByKey(key)` — absolute key lookup.
49
+ *
50
+ * Use when the consumer already holds a fully-composed label key and
51
+ * does NOT need page+section composition. Two main call sites:
52
+ * - the navigation header/footer rendering page meta titles
53
+ * (`useWebsiteLabelByKey(manifest.metaLabelKeys.titleKey)`),
54
+ * - section components that accept a `*Key` prop from their parent
55
+ * page (`<HeroSection headlineKey="website.landing.hero.headline" />`)
56
+ * instead of using the leaf-relative hook.
57
+ *
58
+ * Same fail-loud diagnostics as `useWebsiteLabel`: returns the key
59
+ * string and emits a `console.warn` on miss.
60
+ *
61
+ * Defensively re-parses the key through `WebsiteLabelKeySchema` so a
62
+ * caller that bypassed the type system (eg. an `as WebsiteLabelKey`
63
+ * cast on a malformed string) gets caught at the hook boundary
64
+ * instead of silently looking up garbage.
65
+ */
66
+ export declare function useWebsiteLabelByKey(key: WebsiteLabelKey): string;
67
+ /** @wildo_source:part:end saas.website.use-label-by-key.hook */
68
+ //# sourceMappingURL=useWebsiteLabel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWebsiteLabel.d.ts","sourceRoot":"","sources":["../../../../../src/core/hooks/useWebsiteLabel.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,oDAAoD,CAAC;AAE5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA8BxD;AACD,yDAAyD;AAEzD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,CAajE;AACD,gEAAgE"}
@@ -0,0 +1,103 @@
1
+ import { useMemo } from 'react';
2
+ import { useWebsitePage } from '../contexts/useWebsitePage.js';
3
+ import { useWebsiteRuntime } from '../contexts/useWebsiteRuntime.js';
4
+ import { useWebsiteSection } from '../contexts/useWebsiteSection.js';
5
+ import { WebsiteLabelKeySchema, composeWebsiteLabelKey, } from '../../schemas/label-keys/website-label-key.schemas.js';
6
+ /**
7
+ * @wildo_source:part:start saas.website.use-label.hook facet:layer:core facet:family:website
8
+ *
9
+ * `useWebsiteLabel(slotPath)` — leaf-relative label resolution.
10
+ *
11
+ * Composes the slot leaf with the active page+section context to
12
+ * derive the full `WebsiteLabelKey` (`website.{pageRef}.{sectionRef}.{slotPath}`),
13
+ * looks it up in the active locale's label pack, and returns the
14
+ * resolved string.
15
+ *
16
+ * **Author ergonomics**: section authors call
17
+ * `useWebsiteLabel('headline')` from inside their section component
18
+ * without ever typing the page or section ref — the hook reads them
19
+ * from context. This keeps section components portable across pages
20
+ * (the same `<HeroSection />` can be reused on `landing` and on a
21
+ * dedicated `/about` page; only the surrounding `<WebsiteSection
22
+ * sectionRef="hero">` differs, and the label keys re-root accordingly).
23
+ *
24
+ * **Fail-loud diagnostics** for missing keys: returns the composed key
25
+ * itself (visible in the rendered DOM as e.g. `website.landing.hero.headline`)
26
+ * AND emits a `console.warn`. The visible-key fallback is preferred
27
+ * over an empty string or a thrown error because:
28
+ * - empty string silently breaks layout (zero-height heading) and
29
+ * leaks past visual review,
30
+ * - throwing would crash the entire page on a single missing label
31
+ * while the SEO crawler indexes a 500 page,
32
+ * - the rendered key is a clear authoring signal ("ship the missing
33
+ * pack entry") that designers and copywriters can spot without
34
+ * opening DevTools.
35
+ *
36
+ * **Hard guards** (each enforced by the underlying context hooks):
37
+ * - MUST be called inside `<WebsiteRuntimeContextProvider>`,
38
+ * - MUST be called inside `<WebsitePageLayout>`,
39
+ * - MUST be called inside `<WebsiteSection>`.
40
+ *
41
+ * @param slotPath leaf identifier (eg. `'headline'`, `'cta.primary'`,
42
+ * `'tiers[0].name'`). Anything that survives the slot
43
+ * portion of `WebsiteLabelKeySchema`'s regex.
44
+ * @returns the resolved label string, or the composed key itself when
45
+ * the pack lacks an entry (with a `console.warn`).
46
+ */
47
+ export function useWebsiteLabel(slotPath) {
48
+ const { labelPack } = useWebsiteRuntime();
49
+ const { pageRef } = useWebsitePage();
50
+ const { sectionRef } = useWebsiteSection();
51
+ /**
52
+ * Compose + parse memoized on the three identity inputs. The parse
53
+ * itself is cheap (regex + brand) but executing it on every render
54
+ * of every label-bound primitive in a section adds up across a
55
+ * 12-section landing page.
56
+ */
57
+ const fullKey = useMemo(() => composeWebsiteLabelKey({
58
+ pageRef: pageRef,
59
+ sectionRef: sectionRef,
60
+ slotPath,
61
+ }), [pageRef, sectionRef, slotPath]);
62
+ const resolved = labelPack[fullKey];
63
+ if (resolved === undefined) {
64
+ console.warn(`[useWebsiteLabel] Missing label for key "${fullKey}". ` +
65
+ `Add it to the active locale's pack (or remove the section's claim on this slot).`);
66
+ return fullKey;
67
+ }
68
+ return resolved;
69
+ }
70
+ /** @wildo_source:part:end saas.website.use-label.hook */
71
+ /**
72
+ * @wildo_source:part:start saas.website.use-label-by-key.hook facet:layer:core facet:family:website
73
+ *
74
+ * `useWebsiteLabelByKey(key)` — absolute key lookup.
75
+ *
76
+ * Use when the consumer already holds a fully-composed label key and
77
+ * does NOT need page+section composition. Two main call sites:
78
+ * - the navigation header/footer rendering page meta titles
79
+ * (`useWebsiteLabelByKey(manifest.metaLabelKeys.titleKey)`),
80
+ * - section components that accept a `*Key` prop from their parent
81
+ * page (`<HeroSection headlineKey="website.landing.hero.headline" />`)
82
+ * instead of using the leaf-relative hook.
83
+ *
84
+ * Same fail-loud diagnostics as `useWebsiteLabel`: returns the key
85
+ * string and emits a `console.warn` on miss.
86
+ *
87
+ * Defensively re-parses the key through `WebsiteLabelKeySchema` so a
88
+ * caller that bypassed the type system (eg. an `as WebsiteLabelKey`
89
+ * cast on a malformed string) gets caught at the hook boundary
90
+ * instead of silently looking up garbage.
91
+ */
92
+ export function useWebsiteLabelByKey(key) {
93
+ const { labelPack } = useWebsiteRuntime();
94
+ const safeKey = useMemo(() => WebsiteLabelKeySchema.parse(key), [key]);
95
+ const resolved = labelPack[safeKey];
96
+ if (resolved === undefined) {
97
+ console.warn(`[useWebsiteLabelByKey] Missing label for key "${safeKey}".`);
98
+ return safeKey;
99
+ }
100
+ return resolved;
101
+ }
102
+ /** @wildo_source:part:end saas.website.use-label-by-key.hook */
103
+ //# sourceMappingURL=useWebsiteLabel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWebsiteLabel.js","sourceRoot":"","sources":["../../../../../src/core/hooks/useWebsiteLabel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GAEvB,MAAM,oDAAoD,CAAC;AAE5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,MAAM,EAAE,SAAS,EAAE,GAAG,iBAAiB,EAAE,CAAC;IAC1C,MAAM,EAAE,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IACrC,MAAM,EAAE,UAAU,EAAE,GAAG,iBAAiB,EAAE,CAAC;IAE3C;;;;;OAKG;IACH,MAAM,OAAO,GAAG,OAAO,CACrB,GAAG,EAAE,CACH,sBAAsB,CAAC;QACrB,OAAO,EAAE,OAA4B;QACrC,UAAU,EAAE,UAA+B;QAC3C,QAAQ;KACT,CAAC,EACJ,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,CAChC,CAAC;IAEF,MAAM,QAAQ,GAAG,SAAS,CAAC,OAA4B,CAAC,CAAC;IACzD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,CAAC,IAAI,CACV,4CAA4C,OAA4B,KAAK;YAC3E,kFAAkF,CACrF,CAAC;QACF,OAAO,OAA4B,CAAC;IACtC,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AACD,yDAAyD;AAEzD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAoB;IACvD,MAAM,EAAE,SAAS,EAAE,GAAG,iBAAiB,EAAE,CAAC;IAE1C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,qBAAqB,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAEvE,MAAM,QAAQ,GAAG,SAAS,CAAC,OAA4B,CAAC,CAAC;IACzD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,CAAC,IAAI,CACV,iDAAiD,OAA4B,IAAI,CAClF,CAAC;QACF,OAAO,OAA4B,CAAC;IACtC,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AACD,gEAAgE","sourcesContent":["import { useMemo } from 'react';\n\nimport { useWebsitePage } from '../contexts/useWebsitePage';\nimport { useWebsiteRuntime } from '../contexts/useWebsiteRuntime';\nimport { useWebsiteSection } from '../contexts/useWebsiteSection';\nimport {\n WebsiteLabelKeySchema,\n composeWebsiteLabelKey,\n type WebsiteLabelKey,\n} from '../../schemas/label-keys/website-label-key.schemas';\n\n/**\n * @wildo_source:part:start saas.website.use-label.hook facet:layer:core facet:family:website\n *\n * `useWebsiteLabel(slotPath)` — leaf-relative label resolution.\n *\n * Composes the slot leaf with the active page+section context to\n * derive the full `WebsiteLabelKey` (`website.{pageRef}.{sectionRef}.{slotPath}`),\n * looks it up in the active locale's label pack, and returns the\n * resolved string.\n *\n * **Author ergonomics**: section authors call\n * `useWebsiteLabel('headline')` from inside their section component\n * without ever typing the page or section ref — the hook reads them\n * from context. This keeps section components portable across pages\n * (the same `<HeroSection />` can be reused on `landing` and on a\n * dedicated `/about` page; only the surrounding `<WebsiteSection\n * sectionRef=\"hero\">` differs, and the label keys re-root accordingly).\n *\n * **Fail-loud diagnostics** for missing keys: returns the composed key\n * itself (visible in the rendered DOM as e.g. `website.landing.hero.headline`)\n * AND emits a `console.warn`. The visible-key fallback is preferred\n * over an empty string or a thrown error because:\n * - empty string silently breaks layout (zero-height heading) and\n * leaks past visual review,\n * - throwing would crash the entire page on a single missing label\n * while the SEO crawler indexes a 500 page,\n * - the rendered key is a clear authoring signal (\"ship the missing\n * pack entry\") that designers and copywriters can spot without\n * opening DevTools.\n *\n * **Hard guards** (each enforced by the underlying context hooks):\n * - MUST be called inside `<WebsiteRuntimeContextProvider>`,\n * - MUST be called inside `<WebsitePageLayout>`,\n * - MUST be called inside `<WebsiteSection>`.\n *\n * @param slotPath leaf identifier (eg. `'headline'`, `'cta.primary'`,\n * `'tiers[0].name'`). Anything that survives the slot\n * portion of `WebsiteLabelKeySchema`'s regex.\n * @returns the resolved label string, or the composed key itself when\n * the pack lacks an entry (with a `console.warn`).\n */\nexport function useWebsiteLabel(slotPath: string): string {\n const { labelPack } = useWebsiteRuntime();\n const { pageRef } = useWebsitePage();\n const { sectionRef } = useWebsiteSection();\n\n /**\n * Compose + parse memoized on the three identity inputs. The parse\n * itself is cheap (regex + brand) but executing it on every render\n * of every label-bound primitive in a section adds up across a\n * 12-section landing page.\n */\n const fullKey = useMemo<WebsiteLabelKey>(\n () =>\n composeWebsiteLabelKey({\n pageRef: pageRef as unknown as string,\n sectionRef: sectionRef as unknown as string,\n slotPath,\n }),\n [pageRef, sectionRef, slotPath],\n );\n\n const resolved = labelPack[fullKey as unknown as string];\n if (resolved === undefined) {\n console.warn(\n `[useWebsiteLabel] Missing label for key \"${fullKey as unknown as string}\". ` +\n `Add it to the active locale's pack (or remove the section's claim on this slot).`,\n );\n return fullKey as unknown as string;\n }\n return resolved;\n}\n/** @wildo_source:part:end saas.website.use-label.hook */\n\n/**\n * @wildo_source:part:start saas.website.use-label-by-key.hook facet:layer:core facet:family:website\n *\n * `useWebsiteLabelByKey(key)` — absolute key lookup.\n *\n * Use when the consumer already holds a fully-composed label key and\n * does NOT need page+section composition. Two main call sites:\n * - the navigation header/footer rendering page meta titles\n * (`useWebsiteLabelByKey(manifest.metaLabelKeys.titleKey)`),\n * - section components that accept a `*Key` prop from their parent\n * page (`<HeroSection headlineKey=\"website.landing.hero.headline\" />`)\n * instead of using the leaf-relative hook.\n *\n * Same fail-loud diagnostics as `useWebsiteLabel`: returns the key\n * string and emits a `console.warn` on miss.\n *\n * Defensively re-parses the key through `WebsiteLabelKeySchema` so a\n * caller that bypassed the type system (eg. an `as WebsiteLabelKey`\n * cast on a malformed string) gets caught at the hook boundary\n * instead of silently looking up garbage.\n */\nexport function useWebsiteLabelByKey(key: WebsiteLabelKey): string {\n const { labelPack } = useWebsiteRuntime();\n\n const safeKey = useMemo(() => WebsiteLabelKeySchema.parse(key), [key]);\n\n const resolved = labelPack[safeKey as unknown as string];\n if (resolved === undefined) {\n console.warn(\n `[useWebsiteLabelByKey] Missing label for key \"${safeKey as unknown as string}\".`,\n );\n return safeKey as unknown as string;\n }\n return resolved;\n}\n/** @wildo_source:part:end saas.website.use-label-by-key.hook */\n"]}
@@ -0,0 +1,87 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type WebsitePageRef } from '../../schemas/refs/page-ref.schemas';
3
+ /**
4
+ * @wildo_source:part:start saas.website.page-layout.component facet:layer:core facet:family:website
5
+ *
6
+ * `WebsitePageLayout` — the per-page structural primitive.
7
+ *
8
+ * **Three responsibilities** (each carrying its own semantic weight):
9
+ *
10
+ * 1. **Provides `WebsitePageContext`** — registers the active page
11
+ * ref so child sections (`<WebsiteSection>`) and label hooks
12
+ * (`useWebsiteLabel`) can derive label keys without re-typing
13
+ * the page ref at every leaf.
14
+ * 2. **Renders the site-wide chrome** — pulls
15
+ * `headerComponent` and `footerComponent` from the runtime
16
+ * navigation config and wraps the page's main content in the
17
+ * site's standard header/main/footer scaffold. Per-page
18
+ * overrides (`header={…}` / `footer={…}` props) take precedence
19
+ * over the runtime defaults so individual pages can opt into a
20
+ * custom chrome (eg. a campaign landing page running with
21
+ * header-only minimal chrome).
22
+ * 3. **Stamps DOM landmarks** — emits `data-website-page-ref` on
23
+ * the layout root for analytics / SEO crawlers / overlay
24
+ * tooling that needs to identify the active page from the DOM
25
+ * without booting React. When the website facet hydrates
26
+ * frontend-provider bootstraps, the same root also carries the
27
+ * active public provider refs for analytics / browser-monitoring /
28
+ * captcha so non-React tooling can detect the configured vendor
29
+ * without reverse-engineering app code.
30
+ *
31
+ * **Why semantic `<header>` / `<main>` / `<footer>` elements**:
32
+ * marketing-site SEO scoring penalizes pages that ship a single
33
+ * unstructured `<div>` tree. Using semantic landmarks costs nothing
34
+ * and improves crawler accessibility AND screen-reader
35
+ * navigability — both are first-class concerns for a public
36
+ * marketing surface.
37
+ *
38
+ * **Why this lives in `core/`** (not `components/`): the layout is
39
+ * structural framework machinery (it owns the page-context
40
+ * provisioning + the navigation slot resolution), not a styled
41
+ * primitive. Designers override `header` / `footer` via runtime
42
+ * config or per-page props, NOT by replacing this component.
43
+ */
44
+ export interface WebsitePageLayoutProps {
45
+ /**
46
+ * The active page's ref. Accepts either an already-branded
47
+ * `WebsitePageRef` or a raw string — the layout parses through
48
+ * `WebsitePageRefSchema` so a malformed ref fails loud at render.
49
+ *
50
+ * Typically sourced from the page's `WebsitePageManifest.ref`
51
+ * (eg. `<WebsitePageLayout pageRef={LANDING_PAGE_MANIFEST.ref}>`).
52
+ */
53
+ pageRef: WebsitePageRef | string;
54
+ /**
55
+ * Per-page header override. When supplied, takes precedence over
56
+ * `WebsiteRuntimeContext.designTokens` navigation config's
57
+ * `headerComponent`. Pass `null` explicitly to suppress the header
58
+ * entirely (campaign landing pages without site-wide nav).
59
+ */
60
+ header?: ReactNode | null;
61
+ /**
62
+ * Per-page footer override. Same semantics as `header`.
63
+ */
64
+ footer?: ReactNode | null;
65
+ /**
66
+ * Optional className applied to the root `<div data-website-page-ref="…">`
67
+ * wrapper. Use for page-level layout tweaks (eg. `min-h-screen` on
68
+ * landing pages).
69
+ */
70
+ className?: string;
71
+ /**
72
+ * Optional className applied to the inner `<main>` element. Use for
73
+ * vertical-rhythm overrides on long-scroll landing pages.
74
+ */
75
+ mainClassName?: string;
76
+ /**
77
+ * The page's section composition. Typically a sequence of
78
+ * `<WebsiteSection>` wrappers around concrete section components.
79
+ */
80
+ children: ReactNode;
81
+ }
82
+ export declare function WebsitePageLayout({ pageRef, header, footer, className, mainClassName, children, }: WebsitePageLayoutProps): ReactNode;
83
+ export declare namespace WebsitePageLayout {
84
+ var displayName: string;
85
+ }
86
+ /** @wildo_source:part:end saas.website.page-layout.component */
87
+ //# sourceMappingURL=WebsitePageLayout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebsitePageLayout.d.ts","sourceRoot":"","sources":["../../../../../src/core/layouts/WebsitePageLayout.tsx"],"names":[],"mappings":"AAAA,OAAc,EAAW,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAOvD,OAAO,EAEL,KAAK,cAAc,EACpB,MAAM,qCAAqC,CAAC;AA6F7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;;;;OAOG;IACH,OAAO,EAAE,cAAc,GAAG,MAAM,CAAC;IACjC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC1B;;OAEG;IACH,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC1B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,EACP,MAAM,EACN,MAAM,EACN,SAAS,EACT,aAAa,EACb,QAAQ,GACT,EAAE,sBAAsB,GAAG,SAAS,CAsHpC;yBA7He,iBAAiB;;;AA+HjC,gEAAgE"}