@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,129 @@
1
+ /**
2
+ * @wildo-package @wildo-ai/saas-website
3
+ *
4
+ * SaaS marketing/landing website engine — schemas + helpers + layout
5
+ * placeholders + Astro/MDX adapters + SEO/AEO/GEO builder library.
6
+ *
7
+ * Per `saas-website-slice.md` D6/D15: this engine ships **NO concrete
8
+ * business sections** (no Hero, no CTA, no Pricing). It ships the
9
+ * structural and helper machinery; consumers author every business
10
+ * section themselves via the `defineWebsiteSection` factory and the
11
+ * accompanying SKILLs in `framework-knowledge`.
12
+ *
13
+ * @wildo-boundary
14
+ * - This barrel MAY re-export from any subdirectory of `src/`.
15
+ * - Subdirectories MUST observe their own boundary contracts (see
16
+ * each subdirectory's own `index.ts` `@wildo-boundary` block):
17
+ * - `schemas/` : NO React, NO Astro, NO `~wildo-frontend-lib/**`
18
+ * - `seo/` : NO React, NO Astro
19
+ * - `core/` : MAY use React; NO `~wildo-frontend-lib/**` (Q17=B)
20
+ * - `astro/` : MAY use Astro; NO React component runtime imports
21
+ * - `mdx/` : MAY use `@mdx-js/*`
22
+ * - `integration/` : MAY use React; MAY import the
23
+ * `@wildo-ai/saas-models/public-runtime` SUBPATH,
24
+ * the `@wildo-ai/presets-components-models/public-runtime`
25
+ * SUBPATH, `@wildo-ai/zod-decorators`,
26
+ * plus the SSR / Astro-middleware tier
27
+ * (`axios`, `jsonwebtoken`, `socket.io-client`,
28
+ * `reflect-metadata`) — D12 revised
29
+ * 2026-04-19 (second same-day loosening);
30
+ * the ROOT barrels of `@wildo-ai/saas-models`
31
+ * and `@wildo-ai/presets-components-models`
32
+ * are FORBIDDEN (they boot the decorator
33
+ * framework / pull the heavy registry);
34
+ * the saas-app DI / backend stack
35
+ * (`inversify`, `mongoose`, `express`,
36
+ * `pino`, `helmet`, `argon2`, `bcrypt`,
37
+ * the `@wildo-ai/saas-frontend-lib` /
38
+ * `@wildo-ai/saas-backend-lib` /
39
+ * `@wildo-ai/external-connectors-models`
40
+ * root + subpath surfaces) is FORBIDDEN;
41
+ * MUST NOT import `~wildo-frontend-lib/**`
42
+ * (Q17=B / D16)
43
+ *
44
+ * D12 (client-bundle import discipline, all `core/`/`schemas/`/`integration/`
45
+ * files): the entire saas-website source tree ships into a browser bundle
46
+ * (Astro SSG + React islands). Every shared model atom MUST come from a
47
+ * side-effect-free `/public-runtime` subpath:
48
+ * - `@wildo-ai/saas-models/public-runtime` is the primary door
49
+ * (saas-models-public-runtime.md K-6 — consumers see one path).
50
+ * - `@wildo-ai/presets-components-models/public-runtime` is the
51
+ * internal seam for symbols not (yet) re-exported by saas-models.
52
+ * - `@wildo-ai/zod-decorators` is allowed to import (first revision
53
+ * 2026-04-19). The package itself is side-effect-free; only an
54
+ * explicit `initZodDecorators()` call mutates `z.ZodType.prototype`,
55
+ * which neither saas-website nor the saas-models /public-runtime
56
+ * barrel does.
57
+ * - `axios`, `jsonwebtoken`, `socket.io-client`, `reflect-metadata` are
58
+ * allowed for SSR / Astro-middleware code paths (second same-day
59
+ * revision 2026-04-19). The website engine needs them to provide
60
+ * middleware utilities (HTTP proxying to the SaaS backend, JWT
61
+ * verification of cross-frontend handoff codes, real-time push,
62
+ * decorator-metadata reads). They are SSR-tier — discipline
63
+ * (and a future strict/loose entry split for React islands vs
64
+ * middleware) keeps them out of the React-island bundle.
65
+ *
66
+ * The ROOT barrel of `@wildo-ai/saas-models` is forbidden everywhere in
67
+ * this package — it calls `initZodDecorators()` at module load and pulls
68
+ * `@wildo-ai/external-connectors-models` + the full schema graph into
69
+ * the bundle. Same forbid applies to the root barrel of
70
+ * `@wildo-ai/presets-components-models`, the saas-app DI runtime
71
+ * (`inversify`, `@wildo-ai/saas-frontend-lib`, `@wildo-ai/saas-backend-lib`),
72
+ * and pure-backend libs (`mongoose`, `express`, `pino`, `helmet`,
73
+ * `argon2`, `bcrypt`). Enforced by `src/__tests__/bundle-isolation.test.ts`.
74
+ *
75
+ * These boundaries are enforced by review + the bundle-isolation test
76
+ * above until Phase 8 promotes them to a programmatic ESLint check
77
+ * (cf. `saas-website-slice.md`
78
+ * §"DEFERRED to Phase 8 — boundary lint mechanism design").
79
+ *
80
+ * Phase 1+2 status: schemas + runtime contexts/hooks + layout
81
+ * primitives + L1 placeholders + factories are all exported. Phase 5
82
+ * adds the Astro adapter; Phase 5.7 the `integration/` layer.
83
+ *
84
+ * D18 (L1 boundary, Phase 2): the L1 primitives (`WebsiteHeading`,
85
+ * `WebsiteText`, `WebsiteButton`, `WebsiteLink`, `WebsiteImage`) are
86
+ * self-contained placeholders — they do NOT consume
87
+ * `ComponentRegistryService` from `saas-frontend-lib` and do NOT
88
+ * re-export `saas-frontend-lib` primitives. Consumers override at the
89
+ * L1 boundary by barrel-re-exporting their preferred styled variant
90
+ * from their app's `app/website/primitives/<Primitive>.tsx`. Phase 6
91
+ * dogfood will revisit and decide whether to promote a registry-based
92
+ * override mechanism.
93
+ */
94
+ export * from './schemas/refs/page-ref.schemas.js';
95
+ export * from './schemas/refs/section-ref.schemas.js';
96
+ export * from './schemas/label-keys/website-label-key.schemas.js';
97
+ export * from './schemas/sections/website-section-category.shared.js';
98
+ export * from './schemas/sections/website-section-definition.shared.schemas.js';
99
+ export * from './schemas/structured-data/website-structured-data.shared.schemas.js';
100
+ export * from './schemas/structured-data/structured-data-reconciliation.shared.js';
101
+ export * from './schemas/design-tokens/website-design-tokens.shared.schemas.js';
102
+ export * from './schemas/manifests/website-page-manifest.shared.schemas.js';
103
+ export * from './schemas/manifests/website-root-config.shared.schemas.js';
104
+ export * from './schemas/blog/blog-post-frontmatter.shared.schemas.js';
105
+ export * from './schemas/validators/label-pack.validator.js';
106
+ export * from './core/contexts/WebsiteRuntimeContext.js';
107
+ export * from './core/contexts/useWebsiteRuntime.js';
108
+ export * from './core/contexts/WebsitePageContext.js';
109
+ export * from './core/contexts/useWebsitePage.js';
110
+ export * from './core/contexts/WebsiteSectionContext.js';
111
+ export * from './core/contexts/useWebsiteSection.js';
112
+ export * from './core/hooks/useWebsiteLabel.js';
113
+ export * from './core/hooks/useWebsiteDesignTokens.js';
114
+ export * from './core/factories/define-website-section.js';
115
+ export * from './core/factories/define-website-page-manifest.js';
116
+ export * from './core/layouts/WebsitePageLayout.js';
117
+ export * from './core/layouts/WebsiteSection.js';
118
+ export * from './core/anonymous-session/website-anonymous-session-client.js';
119
+ export * from './core/anonymous-session/inbound-contact-form.schema.js';
120
+ export * from './core/anonymous-session/InboundContactForm.js';
121
+ export * from './components/low-level/WebsiteHeading.js';
122
+ export * from './components/low-level/WebsiteText.js';
123
+ export * from './components/low-level/WebsiteLink.js';
124
+ export * from './components/low-level/WebsiteInternalLink.js';
125
+ export * from './core/routing/internal-routing.utils.js';
126
+ export * from './components/low-level/WebsiteButton.js';
127
+ export * from './components/low-level/WebsiteInternalButton.js';
128
+ export * from './components/low-level/WebsiteImage.js';
129
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4FG;AAEH,cAAc,iCAAiC,CAAC;AAChD,cAAc,oCAAoC,CAAC;AACnD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,oDAAoD,CAAC;AACnE,cAAc,8DAA8D,CAAC;AAC7E,cAAc,kEAAkE,CAAC;AACjF,cAAc,iEAAiE,CAAC;AAChF,cAAc,8DAA8D,CAAC;AAC7E,cAAc,0DAA0D,CAAC;AACzE,cAAc,wDAAwD,CAAC;AACvE,cAAc,qDAAqD,CAAC;AACpE,cAAc,2CAA2C,CAAC;AAE1D,cAAc,uCAAuC,CAAC;AACtD,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AACnD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uCAAuC,CAAC;AACtD,cAAc,mCAAmC,CAAC;AAClD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qCAAqC,CAAC;AACpD,cAAc,yCAAyC,CAAC;AACxD,cAAc,+CAA+C,CAAC;AAC9D,cAAc,kCAAkC,CAAC;AACjD,cAAc,+BAA+B,CAAC;AAE9C,cAAc,2DAA2D,CAAC;AAC1E,cAAc,sDAAsD,CAAC;AACrE,cAAc,6CAA6C,CAAC;AAE5D,cAAc,uCAAuC,CAAC;AACtD,cAAc,oCAAoC,CAAC;AACnD,cAAc,oCAAoC,CAAC;AACnD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,uCAAuC,CAAC;AACtD,cAAc,sCAAsC,CAAC;AACrD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,qCAAqC,CAAC","sourcesContent":["/**\n * @wildo-package @wildo-ai/saas-website\n *\n * SaaS marketing/landing website engine — schemas + helpers + layout\n * placeholders + Astro/MDX adapters + SEO/AEO/GEO builder library.\n *\n * Per `saas-website-slice.md` D6/D15: this engine ships **NO concrete\n * business sections** (no Hero, no CTA, no Pricing). It ships the\n * structural and helper machinery; consumers author every business\n * section themselves via the `defineWebsiteSection` factory and the\n * accompanying SKILLs in `framework-knowledge`.\n *\n * @wildo-boundary\n * - This barrel MAY re-export from any subdirectory of `src/`.\n * - Subdirectories MUST observe their own boundary contracts (see\n * each subdirectory's own `index.ts` `@wildo-boundary` block):\n * - `schemas/` : NO React, NO Astro, NO `~wildo-frontend-lib/**`\n * - `seo/` : NO React, NO Astro\n * - `core/` : MAY use React; NO `~wildo-frontend-lib/**` (Q17=B)\n * - `astro/` : MAY use Astro; NO React component runtime imports\n * - `mdx/` : MAY use `@mdx-js/*`\n * - `integration/` : MAY use React; MAY import the\n * `@wildo-ai/saas-models/public-runtime` SUBPATH,\n * the `@wildo-ai/presets-components-models/public-runtime`\n * SUBPATH, `@wildo-ai/zod-decorators`,\n * plus the SSR / Astro-middleware tier\n * (`axios`, `jsonwebtoken`, `socket.io-client`,\n * `reflect-metadata`) — D12 revised\n * 2026-04-19 (second same-day loosening);\n * the ROOT barrels of `@wildo-ai/saas-models`\n * and `@wildo-ai/presets-components-models`\n * are FORBIDDEN (they boot the decorator\n * framework / pull the heavy registry);\n * the saas-app DI / backend stack\n * (`inversify`, `mongoose`, `express`,\n * `pino`, `helmet`, `argon2`, `bcrypt`,\n * the `@wildo-ai/saas-frontend-lib` /\n * `@wildo-ai/saas-backend-lib` /\n * `@wildo-ai/external-connectors-models`\n * root + subpath surfaces) is FORBIDDEN;\n * MUST NOT import `~wildo-frontend-lib/**`\n * (Q17=B / D16)\n *\n * D12 (client-bundle import discipline, all `core/`/`schemas/`/`integration/`\n * files): the entire saas-website source tree ships into a browser bundle\n * (Astro SSG + React islands). Every shared model atom MUST come from a\n * side-effect-free `/public-runtime` subpath:\n * - `@wildo-ai/saas-models/public-runtime` is the primary door\n * (saas-models-public-runtime.md K-6 — consumers see one path).\n * - `@wildo-ai/presets-components-models/public-runtime` is the\n * internal seam for symbols not (yet) re-exported by saas-models.\n * - `@wildo-ai/zod-decorators` is allowed to import (first revision\n * 2026-04-19). The package itself is side-effect-free; only an\n * explicit `initZodDecorators()` call mutates `z.ZodType.prototype`,\n * which neither saas-website nor the saas-models /public-runtime\n * barrel does.\n * - `axios`, `jsonwebtoken`, `socket.io-client`, `reflect-metadata` are\n * allowed for SSR / Astro-middleware code paths (second same-day\n * revision 2026-04-19). The website engine needs them to provide\n * middleware utilities (HTTP proxying to the SaaS backend, JWT\n * verification of cross-frontend handoff codes, real-time push,\n * decorator-metadata reads). They are SSR-tier — discipline\n * (and a future strict/loose entry split for React islands vs\n * middleware) keeps them out of the React-island bundle.\n *\n * The ROOT barrel of `@wildo-ai/saas-models` is forbidden everywhere in\n * this package — it calls `initZodDecorators()` at module load and pulls\n * `@wildo-ai/external-connectors-models` + the full schema graph into\n * the bundle. Same forbid applies to the root barrel of\n * `@wildo-ai/presets-components-models`, the saas-app DI runtime\n * (`inversify`, `@wildo-ai/saas-frontend-lib`, `@wildo-ai/saas-backend-lib`),\n * and pure-backend libs (`mongoose`, `express`, `pino`, `helmet`,\n * `argon2`, `bcrypt`). Enforced by `src/__tests__/bundle-isolation.test.ts`.\n *\n * These boundaries are enforced by review + the bundle-isolation test\n * above until Phase 8 promotes them to a programmatic ESLint check\n * (cf. `saas-website-slice.md`\n * §\"DEFERRED to Phase 8 — boundary lint mechanism design\").\n *\n * Phase 1+2 status: schemas + runtime contexts/hooks + layout\n * primitives + L1 placeholders + factories are all exported. Phase 5\n * adds the Astro adapter; Phase 5.7 the `integration/` layer.\n *\n * D18 (L1 boundary, Phase 2): the L1 primitives (`WebsiteHeading`,\n * `WebsiteText`, `WebsiteButton`, `WebsiteLink`, `WebsiteImage`) are\n * self-contained placeholders — they do NOT consume\n * `ComponentRegistryService` from `saas-frontend-lib` and do NOT\n * re-export `saas-frontend-lib` primitives. Consumers override at the\n * L1 boundary by barrel-re-exporting their preferred styled variant\n * from their app's `app/website/primitives/<Primitive>.tsx`. Phase 6\n * dogfood will revisit and decide whether to promote a registry-based\n * override mechanism.\n */\n\nexport * from './schemas/refs/page-ref.schemas';\nexport * from './schemas/refs/section-ref.schemas';\nexport * from './schemas/label-keys/website-label-key.schemas';\nexport * from './schemas/sections/website-section-category.shared';\nexport * from './schemas/sections/website-section-definition.shared.schemas';\nexport * from './schemas/structured-data/website-structured-data.shared.schemas';\nexport * from './schemas/structured-data/structured-data-reconciliation.shared';\nexport * from './schemas/design-tokens/website-design-tokens.shared.schemas';\nexport * from './schemas/manifests/website-page-manifest.shared.schemas';\nexport * from './schemas/manifests/website-root-config.shared.schemas';\nexport * from './schemas/blog/blog-post-frontmatter.shared.schemas';\nexport * from './schemas/validators/label-pack.validator';\n\nexport * from './core/contexts/WebsiteRuntimeContext';\nexport * from './core/contexts/useWebsiteRuntime';\nexport * from './core/contexts/WebsitePageContext';\nexport * from './core/contexts/useWebsitePage';\nexport * from './core/contexts/WebsiteSectionContext';\nexport * from './core/contexts/useWebsiteSection';\nexport * from './core/hooks/useWebsiteLabel';\nexport * from './core/hooks/useWebsiteDesignTokens';\nexport * from './core/factories/define-website-section';\nexport * from './core/factories/define-website-page-manifest';\nexport * from './core/layouts/WebsitePageLayout';\nexport * from './core/layouts/WebsiteSection';\n\nexport * from './core/anonymous-session/website-anonymous-session-client';\nexport * from './core/anonymous-session/inbound-contact-form.schema';\nexport * from './core/anonymous-session/InboundContactForm';\n\nexport * from './components/low-level/WebsiteHeading';\nexport * from './components/low-level/WebsiteText';\nexport * from './components/low-level/WebsiteLink';\nexport * from './components/low-level/WebsiteInternalLink';\nexport * from './core/routing/internal-routing.utils';\nexport * from './components/low-level/WebsiteButton';\nexport * from './components/low-level/WebsiteInternalButton';\nexport * from './components/low-level/WebsiteImage';\n"]}
@@ -0,0 +1,193 @@
1
+ import type { ComponentType, ReactNode } from 'react';
2
+ import type { WebsitePageRef } from '../schemas/refs/page-ref.schemas';
3
+ import { type WebsiteMdxComponentsMap } from './website-mdx-provider';
4
+ /**
5
+ * @wildo_source:part:start saas.website.blog.post-renderer facet:layer:mdx facet:family:website
6
+ *
7
+ * `<BlogPost>` — engine-owned per-post page renderer for the marketing
8
+ * blog adapter.
9
+ *
10
+ * # What it does, end-to-end
11
+ *
12
+ * 1. **Strict frontmatter parse.** Reads the raw `entry.data` Astro
13
+ * hands the page (passthrough at the content-collection layer per
14
+ * Path Z, see `blog-post-collection.config.ts`) and runs it
15
+ * through `BlogPostFrontmatterSchema` (Zod 4) — branded `slug` /
16
+ * `authorRef` / `tags`, ISO-8601 `publishedAt`, optional
17
+ * `coverImageUrl`. A failure throws synchronously with a
18
+ * `[blog-post] (source="…")` message; Astro halts the build and
19
+ * points the operator to the offending MDX file.
20
+ * 2. **Renders `<WebsitePageLayout>` with a stable blog-post page
21
+ * ref.** The framework reserves `'blog-post'` as the
22
+ * `WebsitePageRef` for every blog post (see `BLOG_POST_PAGE_REF`
23
+ * below for the rationale). All blog posts share one page ref
24
+ * because the SECTION ref under that page is what's
25
+ * blog-author-controlled (see point 3) — the page-level chrome,
26
+ * label scope, and analytics signal are the same across the entire
27
+ * blog surface.
28
+ * 3. **Wraps the MDX body in `<WebsiteMdxProvider>`.** The consumer
29
+ * passes a `mdxComponents` map (typically containing one or two
30
+ * business-section refs they want available inside post bodies —
31
+ * `<CTASection ref="post-cta" />`, etc.). The provider scopes the
32
+ * map for the duration of the render and ONLY the duration of the
33
+ * render, so two blog posts on the same site can ship different
34
+ * provider configs without leaking.
35
+ * 4. **Emits a hero block (title / summary / publish date / author
36
+ * handle / cover image)** from the parsed frontmatter, then yields
37
+ * to the MDX body. Hero markup is intentionally minimal — the
38
+ * consumer styles it via `WebsiteDesignTokens` custom properties.
39
+ * No CSS file ships from this component; everything is inline
40
+ * style + design-token references.
41
+ *
42
+ * # Why a blog-specific page renderer (vs. the generic page bridge)
43
+ *
44
+ * The `createWebsitePageBridgeIsland` factory takes a `PageComponent`
45
+ * — a React component the page author writes. A blog post has NO React
46
+ * component; the MDX file IS the component (compiled by `@astrojs/mdx`
47
+ * to a default-export React tree). Reusing the page-bridge factory
48
+ * would force the consumer to write a ten-line wrapper per post that
49
+ * imports the MDX module, calls `<MdxBody />`, and re-passes the
50
+ * frontmatter — a cold violation of the "every blog post is one MDX
51
+ * file, period" principle. `<BlogPost>` is the framework's
52
+ * single ten-line wrapper, written once.
53
+ *
54
+ * # Why no per-post `pageRef` / per-section `sectionRef` knobs
55
+ *
56
+ * Two reasons:
57
+ *
58
+ * - **Label-key scope semantics.** A blog post's body has no
59
+ * framework-routed labels (the prose IS in the MDX). The section
60
+ * refs that DO need labels are those an MDX file embeds via the
61
+ * `mdxComponents` map — and those sections were already registered
62
+ * in the consumer's `WEBSITE_SECTIONS` registry with their
63
+ * own `expectedLabelKeys`. Letting blog authors pass arbitrary
64
+ * `sectionRef`s would create unbounded label-key surface area that
65
+ * `assertLabelPacksValid` cannot validate at build start.
66
+ * - **Analytics + chrome consistency.** Marketing teams treat "the
67
+ * blog" as one funnel. A single `pageRef='blog-post'` keeps the
68
+ * `data-website-page-ref` attribute on the layout root constant
69
+ * across every post, so the analytics ingest sees one blog-post
70
+ * page event regardless of slug. Per-post overrides would fragment
71
+ * this without buying any operator value.
72
+ *
73
+ * # Hydration + bundle boundary
74
+ *
75
+ * This component is NOT itself a Bridge factory — it's plain React
76
+ * meant to be rendered inside an Astro `.astro` page. The consumer's
77
+ * per-post Astro template (typically `src/pages/[locale]/blog/[slug].astro`)
78
+ * imports `<BlogPost>` directly and renders it; the surrounding
79
+ * `<WebsitePageBridgeIsland>` provides the runtime context. The MDX
80
+ * runtime (`@mdx-js/react`) is React-only and pulls into the React
81
+ * island bundle — bundle-isolation tests walk `mdx.ts` as their own
82
+ * entry to keep the browser-facing closure auditable.
83
+ *
84
+ * Authoring example:
85
+ *
86
+ * ```astro
87
+ * ---
88
+ * // src/pages/blog/[slug].astro
89
+ * import { getCollection, getEntry } from 'astro:content';
90
+ * import { BlogPost } from '@wildo-ai/saas-website/mdx';
91
+ * import { BLOG_POST_MDX_COMPONENTS } from '@/blog/mdx-components';
92
+ *
93
+ * export async function getStaticPaths() {
94
+ * const posts = await getCollection('blog');
95
+ * return posts
96
+ * .filter((p) => p.data.locale === 'en')
97
+ * .map((p) => ({ params: { slug: p.data.slug }, props: { entry: p } }));
98
+ * }
99
+ *
100
+ * const { entry } = Astro.props;
101
+ * const { Content } = await entry.render();
102
+ * ---
103
+ * <BlogPost
104
+ * rawFrontmatter={entry.data}
105
+ * source={entry.id}
106
+ * mdxComponents={BLOG_POST_MDX_COMPONENTS}
107
+ * client:load
108
+ * >
109
+ * <Content />
110
+ * </BlogPost>
111
+ * ```
112
+ */
113
+ /**
114
+ * Reserved `WebsitePageRef` for every blog post page. Exported so
115
+ * consumers can register a matching `BLOG_POST_PAGE_MANIFEST` in
116
+ * their site root config (the page manifest carries the navigation
117
+ * + label-pack scope; the renderer carries the structural layout).
118
+ *
119
+ * Branded as a plain string literal (cast through `unknown`) because:
120
+ * - The `WebsitePageRef` brand is enforced via Zod's `.brand<>()`,
121
+ * and parsing a string literal at module load time would require
122
+ * dragging the Zod runtime into module init — gratuitous when the
123
+ * ref is a compile-time constant.
124
+ * - `WebsitePageLayout` re-parses any incoming `pageRef` string
125
+ * defensively (see `WebsitePageLayoutProps.pageRef` JSDoc), so the
126
+ * brand is re-asserted at render time anyway.
127
+ */
128
+ export declare const BLOG_POST_PAGE_REF: WebsitePageRef;
129
+ export interface BlogPostProps {
130
+ /**
131
+ * Raw frontmatter object Astro hands the page from `entry.data` (or
132
+ * equivalent). The renderer validates this through
133
+ * `BlogPostFrontmatterSchema` synchronously — invalid shapes throw
134
+ * with a `[blog-post]`-prefixed message. Pass `entry.data` directly;
135
+ * do NOT pre-parse on the consumer side (the framework owns the
136
+ * validation surface so a future schema change lands in ONE place).
137
+ */
138
+ rawFrontmatter: unknown;
139
+ /**
140
+ * Diagnostic source identifier echoed into validation errors —
141
+ * typically `entry.id` from Astro's content collection (`'en/why-context.mdx'`
142
+ * or similar). Optional but strongly recommended; without it,
143
+ * `parseBlogPostFrontmatter` throws with a generic
144
+ * `[blog-post] Frontmatter failed …` message that does not name the
145
+ * offending file.
146
+ */
147
+ source?: string;
148
+ /**
149
+ * MDX-tag → React-component map made available inside the post
150
+ * body via `<WebsiteMdxProvider>`. Typically a small object literal
151
+ * exporting one or two business sections the consumer wants
152
+ * available everywhere in the blog surface
153
+ * (`<CTASection ref="post-cta" />`, `<NewsletterSignup />`, etc.).
154
+ *
155
+ * Empty maps are valid — a post body using only standard markdown
156
+ * (no embedded React) needs no overrides.
157
+ */
158
+ mdxComponents?: WebsiteMdxComponentsMap;
159
+ /**
160
+ * Per-page chrome overrides forwarded straight into
161
+ * `<WebsitePageLayout>`. `null` suppresses the slot entirely;
162
+ * `undefined` (the default) inherits the runtime navigation
163
+ * config's header/footer components. Most blog posts leave both
164
+ * unset to inherit the site-wide chrome.
165
+ */
166
+ header?: ReactNode | null;
167
+ footer?: ReactNode | null;
168
+ /**
169
+ * The compiled MDX body — typically `<Content />` from Astro's
170
+ * `await entry.render()` call. Rendered inside the
171
+ * `<WebsiteMdxProvider>` boundary so its inline `<TagName />`
172
+ * references resolve against `mdxComponents`.
173
+ */
174
+ children: ReactNode;
175
+ }
176
+ export declare function BlogPost(props: BlogPostProps): ReactNode;
177
+ export declare namespace BlogPost {
178
+ var displayName: string;
179
+ }
180
+ /**
181
+ * Type alias re-export so consumers writing `BLOG_POST_MDX_COMPONENTS:
182
+ * BlogPostMdxComponents = { … }` have a stable name (the underlying
183
+ * type is the same `WebsiteMdxComponentsMap` from the provider).
184
+ */
185
+ export type BlogPostMdxComponents = WebsiteMdxComponentsMap;
186
+ /**
187
+ * Convenience type — the Astro `ComponentType` consumers write inline
188
+ * inside a `mdxComponents` map. Re-exported so consumer authoring
189
+ * doesn't need to import from `react` directly.
190
+ */
191
+ export type BlogPostMdxComponent = ComponentType<any>;
192
+ /** @wildo_source:part:end saas.website.blog.post-renderer */
193
+ //# sourceMappingURL=BlogPost.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BlogPost.d.ts","sourceRoot":"","sources":["../../../../src/mdx/BlogPost.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAMvE,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,wBAAwB,CAAC;AAEhC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4GG;AAEH;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,kBAAkB,EAAE,cAAyD,CAAC;AAE3F,MAAM,WAAW,aAAa;IAC5B;;;;;;;OAOG;IACH,cAAc,EAAE,OAAO,CAAC;IACxB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,uBAAuB,CAAC;IACxC;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC1B;;;;;OAKG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB;AAWD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,CAiFxD;yBAjFe,QAAQ;;;AAoFxB;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,uBAAuB,CAAC;AAE5D;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;AACtD,6DAA6D"}
@@ -0,0 +1,161 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { WebsitePageLayout } from '../core/layouts/WebsitePageLayout.js';
3
+ import { parseBlogPostFrontmatter, } from './blog-post-collection.config.js';
4
+ import { WebsiteMdxProvider, } from './website-mdx-provider.js';
5
+ /**
6
+ * @wildo_source:part:start saas.website.blog.post-renderer facet:layer:mdx facet:family:website
7
+ *
8
+ * `<BlogPost>` — engine-owned per-post page renderer for the marketing
9
+ * blog adapter.
10
+ *
11
+ * # What it does, end-to-end
12
+ *
13
+ * 1. **Strict frontmatter parse.** Reads the raw `entry.data` Astro
14
+ * hands the page (passthrough at the content-collection layer per
15
+ * Path Z, see `blog-post-collection.config.ts`) and runs it
16
+ * through `BlogPostFrontmatterSchema` (Zod 4) — branded `slug` /
17
+ * `authorRef` / `tags`, ISO-8601 `publishedAt`, optional
18
+ * `coverImageUrl`. A failure throws synchronously with a
19
+ * `[blog-post] (source="…")` message; Astro halts the build and
20
+ * points the operator to the offending MDX file.
21
+ * 2. **Renders `<WebsitePageLayout>` with a stable blog-post page
22
+ * ref.** The framework reserves `'blog-post'` as the
23
+ * `WebsitePageRef` for every blog post (see `BLOG_POST_PAGE_REF`
24
+ * below for the rationale). All blog posts share one page ref
25
+ * because the SECTION ref under that page is what's
26
+ * blog-author-controlled (see point 3) — the page-level chrome,
27
+ * label scope, and analytics signal are the same across the entire
28
+ * blog surface.
29
+ * 3. **Wraps the MDX body in `<WebsiteMdxProvider>`.** The consumer
30
+ * passes a `mdxComponents` map (typically containing one or two
31
+ * business-section refs they want available inside post bodies —
32
+ * `<CTASection ref="post-cta" />`, etc.). The provider scopes the
33
+ * map for the duration of the render and ONLY the duration of the
34
+ * render, so two blog posts on the same site can ship different
35
+ * provider configs without leaking.
36
+ * 4. **Emits a hero block (title / summary / publish date / author
37
+ * handle / cover image)** from the parsed frontmatter, then yields
38
+ * to the MDX body. Hero markup is intentionally minimal — the
39
+ * consumer styles it via `WebsiteDesignTokens` custom properties.
40
+ * No CSS file ships from this component; everything is inline
41
+ * style + design-token references.
42
+ *
43
+ * # Why a blog-specific page renderer (vs. the generic page bridge)
44
+ *
45
+ * The `createWebsitePageBridgeIsland` factory takes a `PageComponent`
46
+ * — a React component the page author writes. A blog post has NO React
47
+ * component; the MDX file IS the component (compiled by `@astrojs/mdx`
48
+ * to a default-export React tree). Reusing the page-bridge factory
49
+ * would force the consumer to write a ten-line wrapper per post that
50
+ * imports the MDX module, calls `<MdxBody />`, and re-passes the
51
+ * frontmatter — a cold violation of the "every blog post is one MDX
52
+ * file, period" principle. `<BlogPost>` is the framework's
53
+ * single ten-line wrapper, written once.
54
+ *
55
+ * # Why no per-post `pageRef` / per-section `sectionRef` knobs
56
+ *
57
+ * Two reasons:
58
+ *
59
+ * - **Label-key scope semantics.** A blog post's body has no
60
+ * framework-routed labels (the prose IS in the MDX). The section
61
+ * refs that DO need labels are those an MDX file embeds via the
62
+ * `mdxComponents` map — and those sections were already registered
63
+ * in the consumer's `WEBSITE_SECTIONS` registry with their
64
+ * own `expectedLabelKeys`. Letting blog authors pass arbitrary
65
+ * `sectionRef`s would create unbounded label-key surface area that
66
+ * `assertLabelPacksValid` cannot validate at build start.
67
+ * - **Analytics + chrome consistency.** Marketing teams treat "the
68
+ * blog" as one funnel. A single `pageRef='blog-post'` keeps the
69
+ * `data-website-page-ref` attribute on the layout root constant
70
+ * across every post, so the analytics ingest sees one blog-post
71
+ * page event regardless of slug. Per-post overrides would fragment
72
+ * this without buying any operator value.
73
+ *
74
+ * # Hydration + bundle boundary
75
+ *
76
+ * This component is NOT itself a Bridge factory — it's plain React
77
+ * meant to be rendered inside an Astro `.astro` page. The consumer's
78
+ * per-post Astro template (typically `src/pages/[locale]/blog/[slug].astro`)
79
+ * imports `<BlogPost>` directly and renders it; the surrounding
80
+ * `<WebsitePageBridgeIsland>` provides the runtime context. The MDX
81
+ * runtime (`@mdx-js/react`) is React-only and pulls into the React
82
+ * island bundle — bundle-isolation tests walk `mdx.ts` as their own
83
+ * entry to keep the browser-facing closure auditable.
84
+ *
85
+ * Authoring example:
86
+ *
87
+ * ```astro
88
+ * ---
89
+ * // src/pages/blog/[slug].astro
90
+ * import { getCollection, getEntry } from 'astro:content';
91
+ * import { BlogPost } from '@wildo-ai/saas-website/mdx';
92
+ * import { BLOG_POST_MDX_COMPONENTS } from '@/blog/mdx-components';
93
+ *
94
+ * export async function getStaticPaths() {
95
+ * const posts = await getCollection('blog');
96
+ * return posts
97
+ * .filter((p) => p.data.locale === 'en')
98
+ * .map((p) => ({ params: { slug: p.data.slug }, props: { entry: p } }));
99
+ * }
100
+ *
101
+ * const { entry } = Astro.props;
102
+ * const { Content } = await entry.render();
103
+ * ---
104
+ * <BlogPost
105
+ * rawFrontmatter={entry.data}
106
+ * source={entry.id}
107
+ * mdxComponents={BLOG_POST_MDX_COMPONENTS}
108
+ * client:load
109
+ * >
110
+ * <Content />
111
+ * </BlogPost>
112
+ * ```
113
+ */
114
+ /**
115
+ * Reserved `WebsitePageRef` for every blog post page. Exported so
116
+ * consumers can register a matching `BLOG_POST_PAGE_MANIFEST` in
117
+ * their site root config (the page manifest carries the navigation
118
+ * + label-pack scope; the renderer carries the structural layout).
119
+ *
120
+ * Branded as a plain string literal (cast through `unknown`) because:
121
+ * - The `WebsitePageRef` brand is enforced via Zod's `.brand<>()`,
122
+ * and parsing a string literal at module load time would require
123
+ * dragging the Zod runtime into module init — gratuitous when the
124
+ * ref is a compile-time constant.
125
+ * - `WebsitePageLayout` re-parses any incoming `pageRef` string
126
+ * defensively (see `WebsitePageLayoutProps.pageRef` JSDoc), so the
127
+ * brand is re-asserted at render time anyway.
128
+ */
129
+ export const BLOG_POST_PAGE_REF = 'blog-post';
130
+ /**
131
+ * Empty default for `mdxComponents` — defined at module scope (NOT
132
+ * inline in the destructure default) so the object identity is
133
+ * stable across re-renders. Stable identity matters here because
134
+ * `<MDXProvider>`'s internal context value is `useMemo`-derived from
135
+ * the `components` prop; inline `{}` would invalidate every render.
136
+ */
137
+ const EMPTY_MDX_COMPONENTS = Object.freeze({});
138
+ export function BlogPost(props) {
139
+ const { rawFrontmatter, source, mdxComponents = EMPTY_MDX_COMPONENTS, header, footer, children, } = props;
140
+ /**
141
+ * Build the diagnostic context once per render. We do not memoize
142
+ * (one object literal per render is cheaper than the `useMemo`
143
+ * accounting), but we also do not pass `source: undefined`
144
+ * unconditionally because `parseBlogPostFrontmatter` switches on
145
+ * `ctx.source !== undefined` for the error-suffix; passing `{}`
146
+ * when undefined keeps the suffix absent in that case.
147
+ */
148
+ const parseCtx = source !== undefined ? { source } : {};
149
+ const frontmatter = parseBlogPostFrontmatter(rawFrontmatter, parseCtx);
150
+ /**
151
+ * The hero markup intentionally uses semantic HTML5 elements
152
+ * (`<header>`, `<h1>`, `<time>`, `<address>`) rather than raw
153
+ * `<div>`s so screen readers and crawlers see the post structure
154
+ * without consumer styling intervention. The styling story is:
155
+ * design tokens via the surrounding `WebsiteRuntimeContext` +
156
+ * the consumer's stylesheet — NO CSS ships from this file.
157
+ */
158
+ return (_jsx(WebsitePageLayout, { pageRef: BLOG_POST_PAGE_REF, header: header, footer: footer, children: _jsxs("article", { "data-website-blog-post-slug": frontmatter.slug, children: [_jsxs("header", { children: [frontmatter.coverImageUrl !== undefined ? (_jsx("img", { src: frontmatter.coverImageUrl, alt: "", loading: "eager", "data-website-blog-post-cover": true })) : null, _jsx("h1", { children: frontmatter.title }), _jsx("p", { "data-website-blog-post-summary": true, children: frontmatter.summary }), _jsxs("div", { "data-website-blog-post-meta": true, children: [_jsx("time", { dateTime: frontmatter.publishedAt, children: frontmatter.publishedAt }), ' · ', _jsx("address", { "data-website-blog-post-author": true, children: frontmatter.authorRef })] }), frontmatter.tags.length > 0 ? (_jsx("ul", { "data-website-blog-post-tags": true, children: frontmatter.tags.map((tag) => (_jsx("li", { children: tag }, tag))) })) : null] }), _jsx(WebsiteMdxProvider, { components: mdxComponents, children: children })] }) }));
159
+ }
160
+ BlogPost.displayName = 'BlogPost';
161
+ //# sourceMappingURL=BlogPost.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BlogPost.js","sourceRoot":"","sources":["../../../../src/mdx/BlogPost.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAGtE,OAAO,EACL,wBAAwB,GAEzB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,kBAAkB,GAEnB,MAAM,wBAAwB,CAAC;AAEhC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4GG;AAEH;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAmB,WAAwC,CAAC;AAkD3F;;;;;;GAMG;AACH,MAAM,oBAAoB,GAA4B,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAExE,MAAM,UAAU,QAAQ,CAAC,KAAoB;IAC3C,MAAM,EACJ,cAAc,EACd,MAAM,EACN,aAAa,GAAG,oBAAoB,EACpC,MAAM,EACN,MAAM,EACN,QAAQ,GACT,GAAG,KAAK,CAAC;IAEV;;;;;;;OAOG;IACH,MAAM,QAAQ,GACZ,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACzC,MAAM,WAAW,GAAG,wBAAwB,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;IAEvE;;;;;;;OAOG;IACH,OAAO,CACL,KAAC,iBAAiB,IAChB,OAAO,EAAE,kBAAkB,EAC3B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,YAEd,kDAAsC,WAAW,CAAC,IAAyB,aACzE,6BACG,WAAW,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,CACzC,cACE,GAAG,EAAE,WAAW,CAAC,aAAa,EAC9B,GAAG,EAAC,EAAE,EACN,OAAO,EAAC,OAAO,yCAEf,CACH,CAAC,CAAC,CAAC,IAAI,EACR,uBAAK,WAAW,CAAC,KAAK,GAAM,EAC5B,8DAAmC,WAAW,CAAC,OAAO,GAAK,EAS3D,+DACE,eAAM,QAAQ,EAAE,WAAW,CAAC,WAAW,YACpC,WAAW,CAAC,WAAW,GACnB,EACN,KAAK,EACN,mEACG,WAAW,CAAC,SAA8B,GACnC,IACN,EACL,WAAW,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAC7B,4DACG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAC7B,uBACG,GAAwB,IADlB,GAAwB,CAE5B,CACN,CAAC,GACC,CACN,CAAC,CAAC,CAAC,IAAI,IACD,EACT,KAAC,kBAAkB,IAAC,UAAU,EAAE,aAAa,YAC1C,QAAQ,GACU,IACb,GACQ,CACrB,CAAC;AACJ,CAAC;AACD,QAAQ,CAAC,WAAW,GAAG,UAAU,CAAC","sourcesContent":["import type { ComponentType, ReactNode } from 'react';\n\nimport { WebsitePageLayout } from '../core/layouts/WebsitePageLayout';\nimport type { WebsitePageRef } from '../schemas/refs/page-ref.schemas';\n\nimport {\n parseBlogPostFrontmatter,\n type ParseBlogPostFrontmatterContext,\n} from './blog-post-collection.config';\nimport {\n WebsiteMdxProvider,\n type WebsiteMdxComponentsMap,\n} from './website-mdx-provider';\n\n/**\n * @wildo_source:part:start saas.website.blog.post-renderer facet:layer:mdx facet:family:website\n *\n * `<BlogPost>` — engine-owned per-post page renderer for the marketing\n * blog adapter.\n *\n * # What it does, end-to-end\n *\n * 1. **Strict frontmatter parse.** Reads the raw `entry.data` Astro\n * hands the page (passthrough at the content-collection layer per\n * Path Z, see `blog-post-collection.config.ts`) and runs it\n * through `BlogPostFrontmatterSchema` (Zod 4) — branded `slug` /\n * `authorRef` / `tags`, ISO-8601 `publishedAt`, optional\n * `coverImageUrl`. A failure throws synchronously with a\n * `[blog-post] (source=\"…\")` message; Astro halts the build and\n * points the operator to the offending MDX file.\n * 2. **Renders `<WebsitePageLayout>` with a stable blog-post page\n * ref.** The framework reserves `'blog-post'` as the\n * `WebsitePageRef` for every blog post (see `BLOG_POST_PAGE_REF`\n * below for the rationale). All blog posts share one page ref\n * because the SECTION ref under that page is what's\n * blog-author-controlled (see point 3) — the page-level chrome,\n * label scope, and analytics signal are the same across the entire\n * blog surface.\n * 3. **Wraps the MDX body in `<WebsiteMdxProvider>`.** The consumer\n * passes a `mdxComponents` map (typically containing one or two\n * business-section refs they want available inside post bodies —\n * `<CTASection ref=\"post-cta\" />`, etc.). The provider scopes the\n * map for the duration of the render and ONLY the duration of the\n * render, so two blog posts on the same site can ship different\n * provider configs without leaking.\n * 4. **Emits a hero block (title / summary / publish date / author\n * handle / cover image)** from the parsed frontmatter, then yields\n * to the MDX body. Hero markup is intentionally minimal — the\n * consumer styles it via `WebsiteDesignTokens` custom properties.\n * No CSS file ships from this component; everything is inline\n * style + design-token references.\n *\n * # Why a blog-specific page renderer (vs. the generic page bridge)\n *\n * The `createWebsitePageBridgeIsland` factory takes a `PageComponent`\n * — a React component the page author writes. A blog post has NO React\n * component; the MDX file IS the component (compiled by `@astrojs/mdx`\n * to a default-export React tree). Reusing the page-bridge factory\n * would force the consumer to write a ten-line wrapper per post that\n * imports the MDX module, calls `<MdxBody />`, and re-passes the\n * frontmatter — a cold violation of the \"every blog post is one MDX\n * file, period\" principle. `<BlogPost>` is the framework's\n * single ten-line wrapper, written once.\n *\n * # Why no per-post `pageRef` / per-section `sectionRef` knobs\n *\n * Two reasons:\n *\n * - **Label-key scope semantics.** A blog post's body has no\n * framework-routed labels (the prose IS in the MDX). The section\n * refs that DO need labels are those an MDX file embeds via the\n * `mdxComponents` map — and those sections were already registered\n * in the consumer's `WEBSITE_SECTIONS` registry with their\n * own `expectedLabelKeys`. Letting blog authors pass arbitrary\n * `sectionRef`s would create unbounded label-key surface area that\n * `assertLabelPacksValid` cannot validate at build start.\n * - **Analytics + chrome consistency.** Marketing teams treat \"the\n * blog\" as one funnel. A single `pageRef='blog-post'` keeps the\n * `data-website-page-ref` attribute on the layout root constant\n * across every post, so the analytics ingest sees one blog-post\n * page event regardless of slug. Per-post overrides would fragment\n * this without buying any operator value.\n *\n * # Hydration + bundle boundary\n *\n * This component is NOT itself a Bridge factory — it's plain React\n * meant to be rendered inside an Astro `.astro` page. The consumer's\n * per-post Astro template (typically `src/pages/[locale]/blog/[slug].astro`)\n * imports `<BlogPost>` directly and renders it; the surrounding\n * `<WebsitePageBridgeIsland>` provides the runtime context. The MDX\n * runtime (`@mdx-js/react`) is React-only and pulls into the React\n * island bundle — bundle-isolation tests walk `mdx.ts` as their own\n * entry to keep the browser-facing closure auditable.\n *\n * Authoring example:\n *\n * ```astro\n * ---\n * // src/pages/blog/[slug].astro\n * import { getCollection, getEntry } from 'astro:content';\n * import { BlogPost } from '@wildo-ai/saas-website/mdx';\n * import { BLOG_POST_MDX_COMPONENTS } from '@/blog/mdx-components';\n *\n * export async function getStaticPaths() {\n * const posts = await getCollection('blog');\n * return posts\n * .filter((p) => p.data.locale === 'en')\n * .map((p) => ({ params: { slug: p.data.slug }, props: { entry: p } }));\n * }\n *\n * const { entry } = Astro.props;\n * const { Content } = await entry.render();\n * ---\n * <BlogPost\n * rawFrontmatter={entry.data}\n * source={entry.id}\n * mdxComponents={BLOG_POST_MDX_COMPONENTS}\n * client:load\n * >\n * <Content />\n * </BlogPost>\n * ```\n */\n\n/**\n * Reserved `WebsitePageRef` for every blog post page. Exported so\n * consumers can register a matching `BLOG_POST_PAGE_MANIFEST` in\n * their site root config (the page manifest carries the navigation\n * + label-pack scope; the renderer carries the structural layout).\n *\n * Branded as a plain string literal (cast through `unknown`) because:\n * - The `WebsitePageRef` brand is enforced via Zod's `.brand<>()`,\n * and parsing a string literal at module load time would require\n * dragging the Zod runtime into module init — gratuitous when the\n * ref is a compile-time constant.\n * - `WebsitePageLayout` re-parses any incoming `pageRef` string\n * defensively (see `WebsitePageLayoutProps.pageRef` JSDoc), so the\n * brand is re-asserted at render time anyway.\n */\nexport const BLOG_POST_PAGE_REF: WebsitePageRef = 'blog-post' as unknown as WebsitePageRef;\n\nexport interface BlogPostProps {\n /**\n * Raw frontmatter object Astro hands the page from `entry.data` (or\n * equivalent). The renderer validates this through\n * `BlogPostFrontmatterSchema` synchronously — invalid shapes throw\n * with a `[blog-post]`-prefixed message. Pass `entry.data` directly;\n * do NOT pre-parse on the consumer side (the framework owns the\n * validation surface so a future schema change lands in ONE place).\n */\n rawFrontmatter: unknown;\n /**\n * Diagnostic source identifier echoed into validation errors —\n * typically `entry.id` from Astro's content collection (`'en/why-context.mdx'`\n * or similar). Optional but strongly recommended; without it,\n * `parseBlogPostFrontmatter` throws with a generic\n * `[blog-post] Frontmatter failed …` message that does not name the\n * offending file.\n */\n source?: string;\n /**\n * MDX-tag → React-component map made available inside the post\n * body via `<WebsiteMdxProvider>`. Typically a small object literal\n * exporting one or two business sections the consumer wants\n * available everywhere in the blog surface\n * (`<CTASection ref=\"post-cta\" />`, `<NewsletterSignup />`, etc.).\n *\n * Empty maps are valid — a post body using only standard markdown\n * (no embedded React) needs no overrides.\n */\n mdxComponents?: WebsiteMdxComponentsMap;\n /**\n * Per-page chrome overrides forwarded straight into\n * `<WebsitePageLayout>`. `null` suppresses the slot entirely;\n * `undefined` (the default) inherits the runtime navigation\n * config's header/footer components. Most blog posts leave both\n * unset to inherit the site-wide chrome.\n */\n header?: ReactNode | null;\n footer?: ReactNode | null;\n /**\n * The compiled MDX body — typically `<Content />` from Astro's\n * `await entry.render()` call. Rendered inside the\n * `<WebsiteMdxProvider>` boundary so its inline `<TagName />`\n * references resolve against `mdxComponents`.\n */\n children: ReactNode;\n}\n\n/**\n * Empty default for `mdxComponents` — defined at module scope (NOT\n * inline in the destructure default) so the object identity is\n * stable across re-renders. Stable identity matters here because\n * `<MDXProvider>`'s internal context value is `useMemo`-derived from\n * the `components` prop; inline `{}` would invalidate every render.\n */\nconst EMPTY_MDX_COMPONENTS: WebsiteMdxComponentsMap = Object.freeze({});\n\nexport function BlogPost(props: BlogPostProps): ReactNode {\n const {\n rawFrontmatter,\n source,\n mdxComponents = EMPTY_MDX_COMPONENTS,\n header,\n footer,\n children,\n } = props;\n\n /**\n * Build the diagnostic context once per render. We do not memoize\n * (one object literal per render is cheaper than the `useMemo`\n * accounting), but we also do not pass `source: undefined`\n * unconditionally because `parseBlogPostFrontmatter` switches on\n * `ctx.source !== undefined` for the error-suffix; passing `{}`\n * when undefined keeps the suffix absent in that case.\n */\n const parseCtx: ParseBlogPostFrontmatterContext =\n source !== undefined ? { source } : {};\n const frontmatter = parseBlogPostFrontmatter(rawFrontmatter, parseCtx);\n\n /**\n * The hero markup intentionally uses semantic HTML5 elements\n * (`<header>`, `<h1>`, `<time>`, `<address>`) rather than raw\n * `<div>`s so screen readers and crawlers see the post structure\n * without consumer styling intervention. The styling story is:\n * design tokens via the surrounding `WebsiteRuntimeContext` +\n * the consumer's stylesheet — NO CSS ships from this file.\n */\n return (\n <WebsitePageLayout\n pageRef={BLOG_POST_PAGE_REF}\n header={header}\n footer={footer}\n >\n <article data-website-blog-post-slug={frontmatter.slug as unknown as string}>\n <header>\n {frontmatter.coverImageUrl !== undefined ? (\n <img\n src={frontmatter.coverImageUrl}\n alt=\"\"\n loading=\"eager\"\n data-website-blog-post-cover\n />\n ) : null}\n <h1>{frontmatter.title}</h1>\n <p data-website-blog-post-summary>{frontmatter.summary}</p>\n {/*\n * Meta line is a `<div>`, not a `<p>` — `<address>` is a flow-\n * content element and cannot be a descendant of `<p>` per HTML5\n * (browsers auto-close the `<p>` on `<address>`, which produces\n * a hydration mismatch in React 19). The `<div>` keeps the\n * semantic `<time>` + `<address>` landmarks intact for screen\n * readers + crawlers without violating the parsing rules.\n */}\n <div data-website-blog-post-meta>\n <time dateTime={frontmatter.publishedAt}>\n {frontmatter.publishedAt}\n </time>\n {' · '}\n <address data-website-blog-post-author>\n {frontmatter.authorRef as unknown as string}\n </address>\n </div>\n {frontmatter.tags.length > 0 ? (\n <ul data-website-blog-post-tags>\n {frontmatter.tags.map((tag) => (\n <li key={tag as unknown as string}>\n {tag as unknown as string}\n </li>\n ))}\n </ul>\n ) : null}\n </header>\n <WebsiteMdxProvider components={mdxComponents}>\n {children}\n </WebsiteMdxProvider>\n </article>\n </WebsitePageLayout>\n );\n}\nBlogPost.displayName = 'BlogPost';\n\n/**\n * Type alias re-export so consumers writing `BLOG_POST_MDX_COMPONENTS:\n * BlogPostMdxComponents = { … }` have a stable name (the underlying\n * type is the same `WebsiteMdxComponentsMap` from the provider).\n */\nexport type BlogPostMdxComponents = WebsiteMdxComponentsMap;\n\n/**\n * Convenience type — the Astro `ComponentType` consumers write inline\n * inside a `mdxComponents` map. Re-exported so consumer authoring\n * doesn't need to import from `react` directly.\n */\nexport type BlogPostMdxComponent = ComponentType<any>;\n/** @wildo_source:part:end saas.website.blog.post-renderer */\n"]}