@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,47 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { AvailableLanguage } from '@wildo-ai/saas-models/public-runtime';
3
+ import { useWebsiteRuntime } from '../../core/contexts/useWebsiteRuntime.js';
4
+ import { buildLocalizedRoutePath } from '../../core/routing/internal-routing.utils.js';
5
+ import { WebsiteButton, } from './WebsiteButton.js';
6
+ /**
7
+ * Pre-computed set of every known locale code; mirrors the guard in
8
+ * `WebsiteInternalLink` (kept duplicated rather than shared so each
9
+ * primitive's audit surface stays self-contained — the set is tiny).
10
+ */
11
+ const ALL_LOCALE_CODES = new Set(Object.values(AvailableLanguage));
12
+ function detectAccidentalLocalePrefix(routePath) {
13
+ const slashIdx = routePath.indexOf('/', 1);
14
+ const firstSegment = slashIdx === -1 ? routePath.slice(1) : routePath.slice(1, slashIdx);
15
+ if (firstSegment === '')
16
+ return null;
17
+ return ALL_LOCALE_CODES.has(firstSegment) ? firstSegment : null;
18
+ }
19
+ export function WebsiteInternalButton({ routePath, variant, size, className, style, id, ariaLabel, children, }) {
20
+ const runtime = useWebsiteRuntime();
21
+ if (!routePath.startsWith('/')) {
22
+ throw new Error(`[WebsiteInternalButton] routePath="${routePath}" must start with "/" ` +
23
+ `(framework-relative path). Anchors ("#..."), URL schemes ` +
24
+ `("mailto:" / "tel:"), and fully-qualified external URLs are ` +
25
+ `NOT supported by this primitive — use <WebsiteButton href={...} external={true}> ` +
26
+ `(or omit \`external\` for in-app anchors and scheme links). ` +
27
+ `For NAVIGATION links (not styled as a CTA), see <WebsiteInternalLink routePath={...}>.`);
28
+ }
29
+ const accidentalPrefix = detectAccidentalLocalePrefix(routePath);
30
+ if (accidentalPrefix !== null) {
31
+ throw new Error(`[WebsiteInternalButton] routePath="${routePath}" begins with the ` +
32
+ `locale segment "/${accidentalPrefix}" — the framework prefixes ` +
33
+ `the active locale automatically, so passing a pre-prefixed path ` +
34
+ `would render as "/${accidentalPrefix}${routePath}" on non-default ` +
35
+ `locale pages (double-prefix) or silently break locale routing on ` +
36
+ `default-locale pages. Pass the locale-NEUTRAL path instead ` +
37
+ `(eg. "/pricing", not "/${accidentalPrefix}/pricing").`);
38
+ }
39
+ const href = buildLocalizedRoutePath({
40
+ locale: runtime.locale,
41
+ defaultLocale: runtime.defaultLocale,
42
+ routePath,
43
+ });
44
+ return (_jsx(WebsiteButton, { href: href, external: false, variant: variant, size: size, className: className, style: style, id: id, ariaLabel: ariaLabel, children: children }));
45
+ }
46
+ WebsiteInternalButton.displayName = 'WebsiteInternalButton';
47
+ //# sourceMappingURL=WebsiteInternalButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebsiteInternalButton.js","sourceRoot":"","sources":["../../../../../src/components/low-level/WebsiteInternalButton.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAEzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,uBAAuB,EAAE,MAAM,2CAA2C,CAAC;AAEpF,OAAO,EACL,aAAa,GAGd,MAAM,iBAAiB,CAAC;AAEzB;;;;GAIG;AACH,MAAM,gBAAgB,GAAwB,IAAI,GAAG,CACnD,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAsB,CACtD,CAAC;AAEF,SAAS,4BAA4B,CAAC,SAAiB;IACrD,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAC3C,MAAM,YAAY,GAChB,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IACtE,IAAI,YAAY,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IACrC,OAAO,gBAAgB,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;AAClE,CAAC;AAqFD,MAAM,UAAU,qBAAqB,CAAC,EACpC,SAAS,EACT,OAAO,EACP,IAAI,EACJ,SAAS,EACT,KAAK,EACL,EAAE,EACF,SAAS,EACT,QAAQ,GACmB;IAC3B,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAC;IAEpC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CACb,sCAAsC,SAAS,wBAAwB;YACrE,2DAA2D;YAC3D,8DAA8D;YAC9D,mFAAmF;YACnF,8DAA8D;YAC9D,wFAAwF,CAC3F,CAAC;IACJ,CAAC;IAED,MAAM,gBAAgB,GAAG,4BAA4B,CAAC,SAAS,CAAC,CAAC;IACjE,IAAI,gBAAgB,KAAK,IAAI,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACb,sCAAsC,SAAS,oBAAoB;YACjE,oBAAoB,gBAAgB,6BAA6B;YACjE,kEAAkE;YAClE,qBAAqB,gBAAgB,GAAG,SAAS,mBAAmB;YACpE,mEAAmE;YACnE,6DAA6D;YAC7D,0BAA0B,gBAAgB,aAAa,CAC1D,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,uBAAuB,CAAC;QACnC,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,aAAa,EAAE,OAAO,CAAC,aAAa;QACpC,SAAS;KACV,CAAC,CAAC;IAEH,OAAO,CACL,KAAC,aAAa,IACZ,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,KAAK,EACf,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,KAAK,EACZ,EAAE,EAAE,EAAE,EACN,SAAS,EAAE,SAAS,YAEnB,QAAQ,GACK,CACjB,CAAC;AACJ,CAAC;AACD,qBAAqB,CAAC,WAAW,GAAG,uBAAuB,CAAC","sourcesContent":["import React, { type CSSProperties, type ReactNode } from 'react';\n\nimport { AvailableLanguage } from '@wildo-ai/saas-models/public-runtime';\n\nimport { useWebsiteRuntime } from '../../core/contexts/useWebsiteRuntime';\nimport { buildLocalizedRoutePath } from '../../core/routing/internal-routing.utils';\n\nimport {\n WebsiteButton,\n type WebsiteButtonSize,\n type WebsiteButtonVariant,\n} from './WebsiteButton';\n\n/**\n * Pre-computed set of every known locale code; mirrors the guard in\n * `WebsiteInternalLink` (kept duplicated rather than shared so each\n * primitive's audit surface stays self-contained — the set is tiny).\n */\nconst ALL_LOCALE_CODES: ReadonlySet<string> = new Set(\n Object.values(AvailableLanguage) as readonly string[],\n);\n\nfunction detectAccidentalLocalePrefix(routePath: string): string | null {\n const slashIdx = routePath.indexOf('/', 1);\n const firstSegment =\n slashIdx === -1 ? routePath.slice(1) : routePath.slice(1, slashIdx);\n if (firstSegment === '') return null;\n return ALL_LOCALE_CODES.has(firstSegment) ? firstSegment : null;\n}\n\n/**\n * @wildo_source:part:start saas.website.primitives.internal-button facet:layer:components facet:family:website\n *\n * `WebsiteInternalButton` — L1 marketing-site CTA primitive for\n * INTERNAL anchor-mode buttons (CTAs that navigate to another route\n * served by the same Astro build, e.g. \"Get in touch\" → `/contact`).\n *\n * **The architectural problem this solves** (Phase 6 fourth audit fix\n * H-Φ): the H-β fix shipped `WebsiteInternalLink` for header/footer\n * navigation links but `WebsiteButton` consumers in section bodies\n * (hero / features / pricing / contact) continued to write\n * `<WebsiteButton href=\"/contact\">` with raw locale-neutral paths. On\n * `/fr/…` pages those CTAs navigated to the EN-default `/contact`\n * URL — exactly the cross-locale leak H-β was meant to kill, just on\n * the page body instead of the chrome. Authors had to know the\n * routing rule and call `buildLocalizedRoutePath` manually on every\n * CTA they shipped, and the audit confirmed they did not.\n *\n * **Why a parallel primitive** (mirrors the H-β reasoning, NOT a\n * `routePath` flag on `WebsiteButton`):\n * 1. The two primitives have different authoring contracts —\n * `WebsiteButton`'s `href` is a fully-qualified URL the author\n * already commits to (or an anchor `#section`, or external);\n * this primitive's `routePath` is a raw locale-neutral path that\n * the framework prefixes. Mixing both shapes behind one prop\n * forces the author to think about a routing rule on every CTA\n * they place; mixing them without a type-system signal invites\n * the wrong shape on the wrong branch.\n * 2. Internal CTAs REQUIRE the runtime context; external/anchor\n * CTAs do not. Forcing every external-link `WebsiteButton`\n * consumer to wrap in `<WebsiteRuntimeContextProvider>` is wrong.\n * Two primitives keep the dependency surface honest.\n * 3. Symmetric with `WebsiteInternalLink` — section authors learn\n * one rule (\"use the `Internal` variant for app-served paths,\n * the bare variant for external/scheme/anchor URLs\") and apply\n * it identically to both link and button shapes.\n *\n * **Button-only render mode**: this primitive is anchor-mode-only by\n * construction (every internal target is a route → an anchor element\n * with appropriate href). Consumers who need a real `<button>` (no\n * navigation, just an `onClick` handler) keep using `<WebsiteButton>`\n * directly — there is no `routePath`-based real-button concept.\n *\n * **Anchor-only links** (`routePath=\"#features\"`) and URL schemes\n * (`mailto:`/`tel:`) are rejected at runtime: those targets do NOT\n * benefit from locale prefixing, and surfacing them through this\n * primitive would invite the SAME confusion that motivated splitting\n * `WebsiteInternalLink` from `WebsiteLink` in the first place. Use\n * `<WebsiteButton href=\"...\" external={true}>` for those cases.\n *\n * **Boundary**: this component MUST stay in the React-island bundle\n * tier (`components/low-level/`). It depends on `useWebsiteRuntime`\n * (which throws when called outside a `<WebsiteRuntimeContextProvider>`)\n * — the throw is the contract that prevents body CTAs from being\n * rendered outside a bridged page accidentally.\n *\n * @example\n * ```tsx\n * // Hero CTA — auto-prefixes the active locale\n * // (`/contact` on EN pages, `/fr/contact` on FR pages):\n * <WebsiteInternalButton routePath=\"/contact\" variant={WebsiteButtonVariant.PRIMARY}>\n * {useWebsiteLabel('cta.primary')}\n * </WebsiteInternalButton>\n * ```\n */\nexport interface WebsiteInternalButtonProps {\n /**\n * The locale-NEUTRAL route path. Must match a value the consumer's\n * Astro build serves (typically a `WebsitePageManifest.routePath`).\n * MUST start with `/` — anchor-only `#section` and URL schemes\n * (`mailto:` / `tel:`) are rejected (use `<WebsiteButton href={...}>`\n * for those cases).\n */\n routePath: string;\n variant?: WebsiteButtonVariant;\n size?: WebsiteButtonSize;\n className?: string;\n style?: CSSProperties;\n id?: string;\n ariaLabel?: string;\n children: ReactNode;\n}\n\nexport function WebsiteInternalButton({\n routePath,\n variant,\n size,\n className,\n style,\n id,\n ariaLabel,\n children,\n}: WebsiteInternalButtonProps): ReactNode {\n const runtime = useWebsiteRuntime();\n\n if (!routePath.startsWith('/')) {\n throw new Error(\n `[WebsiteInternalButton] routePath=\"${routePath}\" must start with \"/\" ` +\n `(framework-relative path). Anchors (\"#...\"), URL schemes ` +\n `(\"mailto:\" / \"tel:\"), and fully-qualified external URLs are ` +\n `NOT supported by this primitive — use <WebsiteButton href={...} external={true}> ` +\n `(or omit \\`external\\` for in-app anchors and scheme links). ` +\n `For NAVIGATION links (not styled as a CTA), see <WebsiteInternalLink routePath={...}>.`,\n );\n }\n\n const accidentalPrefix = detectAccidentalLocalePrefix(routePath);\n if (accidentalPrefix !== null) {\n throw new Error(\n `[WebsiteInternalButton] routePath=\"${routePath}\" begins with the ` +\n `locale segment \"/${accidentalPrefix}\" — the framework prefixes ` +\n `the active locale automatically, so passing a pre-prefixed path ` +\n `would render as \"/${accidentalPrefix}${routePath}\" on non-default ` +\n `locale pages (double-prefix) or silently break locale routing on ` +\n `default-locale pages. Pass the locale-NEUTRAL path instead ` +\n `(eg. \"/pricing\", not \"/${accidentalPrefix}/pricing\").`,\n );\n }\n\n const href = buildLocalizedRoutePath({\n locale: runtime.locale,\n defaultLocale: runtime.defaultLocale,\n routePath,\n });\n\n return (\n <WebsiteButton\n href={href}\n external={false}\n variant={variant}\n size={size}\n className={className}\n style={style}\n id={id}\n ariaLabel={ariaLabel}\n >\n {children}\n </WebsiteButton>\n );\n}\nWebsiteInternalButton.displayName = 'WebsiteInternalButton';\n/** @wildo_source:part:end saas.website.primitives.internal-button */\n"]}
@@ -0,0 +1,99 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ /**
3
+ * @wildo_source:part:start saas.website.primitives.internal-link facet:layer:components facet:family:website
4
+ *
5
+ * `WebsiteInternalLink` — L1 marketing-site link primitive for
6
+ * INTERNAL routes (any path served by the same Astro build).
7
+ *
8
+ * **The architectural problem this solves** (Phase 6 third audit fix
9
+ * H-β): the marketing site mounts the default locale at the
10
+ * un-prefixed path (`/`, `/pricing`) and every other locale under
11
+ * `/<locale>/…` (`/fr/`, `/fr/pricing`). A naive `<a href="/pricing">`
12
+ * authored in the chrome therefore works on EN pages and SILENTLY
13
+ * BREAKS on FR pages — the visitor falls out of their locale on every
14
+ * navigation. The dist-HTML audit confirmed the regression.
15
+ *
16
+ * **Why a dedicated primitive** (parallel to `WebsiteLink`, not a flag
17
+ * on it):
18
+ * 1. The two primitives have different authoring contracts — an
19
+ * external link's `href` is a fully-qualified URL the author
20
+ * already commits to; an internal link's `href` is a raw
21
+ * `routePath` (`'/pricing'`) that the framework prefixes. Mixing
22
+ * both shapes behind one `external?` prop forces the author to
23
+ * think about a routing rule on every link they place; mixing
24
+ * them behind one component invites the wrong shape on the wrong
25
+ * branch (an internal href passed with `external` set, or vice
26
+ * versa) without a type-system signal.
27
+ * 2. Internal links REQUIRE the runtime context; external links do
28
+ * not. Forcing every external-link consumer to wrap in
29
+ * `<WebsiteRuntimeContextProvider>` (or pay the
30
+ * throw-on-missing-context cost) is wrong. Two primitives keep
31
+ * the dependency surface honest.
32
+ * 3. The framework can layer additional internal-link concerns
33
+ * later (active-route highlighting, prefetch directives,
34
+ * router-aware navigation when the consumer overrides
35
+ * `WebsiteLink`) without complicating the external-link
36
+ * contract.
37
+ *
38
+ * **Why `routePath` is a string and NOT `WebsitePageRef`**:
39
+ * - Many internal targets are NOT pages (anchor links to a section
40
+ * within the current page: `'#features'`; same-locale subroutes
41
+ * served by the consumer's Astro build but not registered as
42
+ * `WebsitePageManifest` entries: `'/blog/launch'`). A `pageRef`
43
+ * prop would force every link target to be a registered manifest,
44
+ * which is too restrictive for chrome.
45
+ * - The consumer's chrome typically links to a small fixed set of
46
+ * `routePath` values they author once. The boilerplate cost of
47
+ * looking up the matching manifest by ref is non-trivial; the
48
+ * payoff (typo protection on `'/pricing'`) is small.
49
+ * - We DO validate at runtime that `routePath` starts with `/` and
50
+ * does not double-prefix (a path already starting with `/<locale>/`
51
+ * would otherwise become `/fr/fr/pricing` on a FR page) — see the
52
+ * in-render guard below.
53
+ *
54
+ * **Anchor-only links** (`href="#features"`) are passed through
55
+ * verbatim: they navigate within the current page, no locale prefix
56
+ * applies. Same for `mailto:` / `tel:` — recognized by colon presence
57
+ * and forwarded as-is.
58
+ *
59
+ * **Boundary**: this component MUST stay in the React-island bundle
60
+ * tier (`components/low-level/`). It depends on `useWebsiteRuntime`
61
+ * (which throws when called outside a `<WebsiteRuntimeContextProvider>`)
62
+ * — the throw is the contract that prevents the chrome from being
63
+ * rendered outside a bridged page accidentally.
64
+ *
65
+ * @example
66
+ * ```tsx
67
+ * // In HeaderComponent.tsx — the framework computes the right URL
68
+ * // automatically (`/pricing` on EN pages, `/fr/pricing` on FR
69
+ * // pages):
70
+ * <WebsiteInternalLink routePath="/pricing">
71
+ * <WebsiteText variant={WebsiteTextVariant.BODY}>Pricing</WebsiteText>
72
+ * </WebsiteInternalLink>
73
+ * ```
74
+ */
75
+ export interface WebsiteInternalLinkProps {
76
+ /**
77
+ * The locale-NEUTRAL route path. Must match a value the consumer's
78
+ * Astro build serves (typically a `WebsitePageManifest.routePath`,
79
+ * but anchor-only `#section` and same-page subroutes are also
80
+ * accepted). MUST start with `/` (or `#` for in-page anchors, or
81
+ * include `:` for `mailto:` / `tel:`).
82
+ */
83
+ routePath: string;
84
+ className?: string;
85
+ style?: CSSProperties;
86
+ id?: string;
87
+ /**
88
+ * Optional `aria-label` for icon-only links (where the link text
89
+ * is a glyph or sr-only).
90
+ */
91
+ ariaLabel?: string;
92
+ children: ReactNode;
93
+ }
94
+ export declare function WebsiteInternalLink({ routePath, className, style, id, ariaLabel, children, }: WebsiteInternalLinkProps): ReactNode;
95
+ export declare namespace WebsiteInternalLink {
96
+ var displayName: string;
97
+ }
98
+ /** @wildo_source:part:end saas.website.primitives.internal-link */
99
+ //# sourceMappingURL=WebsiteInternalLink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebsiteInternalLink.d.ts","sourceRoot":"","sources":["../../../../../src/components/low-level/WebsiteInternalLink.tsx"],"names":[],"mappings":"AAAA,OAAc,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AASlE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwEG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;;;;OAMG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAqCD,wBAAgB,mBAAmB,CAAC,EAClC,SAAS,EACT,SAAS,EACT,KAAK,EACL,EAAE,EACF,SAAS,EACT,QAAQ,GACT,EAAE,wBAAwB,GAAG,SAAS,CA8CtC;yBArDe,mBAAmB;;;AAuDnC,mEAAmE"}
@@ -0,0 +1,68 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { AvailableLanguage } from '@wildo-ai/saas-models/public-runtime';
3
+ import { useWebsiteRuntime } from '../../core/contexts/useWebsiteRuntime.js';
4
+ import { buildLocalizedRoutePath } from '../../core/routing/internal-routing.utils.js';
5
+ import { WebsiteLink } from './WebsiteLink.js';
6
+ function isAnchorOrUrlScheme(routePath) {
7
+ return routePath.startsWith('#') || routePath.includes(':');
8
+ }
9
+ /**
10
+ * Pre-computed set of every known locale code (`'en'`, `'fr'`,
11
+ * `'en-GB'`, …). Built ONCE at module load from `AvailableLanguage`
12
+ * so the per-render double-prefix guard below is an O(1) Set.has
13
+ * check rather than an Object.values() walk on every link render.
14
+ */
15
+ const ALL_LOCALE_CODES = new Set(Object.values(AvailableLanguage));
16
+ /**
17
+ * Defensive in-render guard: rejects route paths whose first segment
18
+ * matches a known locale code. The marketing-site convention is that
19
+ * the consumer authors locale-NEUTRAL paths and the framework
20
+ * prefixes them; an already-prefixed path would either render as a
21
+ * `/<locale>/<locale>/pricing` double-prefix on non-default-locale
22
+ * pages or silently work on default-locale pages and break on other
23
+ * locales — both are silent regressions. Throwing here makes the
24
+ * misuse loud at first render.
25
+ *
26
+ * Returns the offending locale segment if the path is misused, or
27
+ * `null` if the path is well-formed.
28
+ */
29
+ function detectAccidentalLocalePrefix(routePath) {
30
+ const slashIdx = routePath.indexOf('/', 1);
31
+ const firstSegment = slashIdx === -1 ? routePath.slice(1) : routePath.slice(1, slashIdx);
32
+ if (firstSegment === '')
33
+ return null;
34
+ return ALL_LOCALE_CODES.has(firstSegment) ? firstSegment : null;
35
+ }
36
+ export function WebsiteInternalLink({ routePath, className, style, id, ariaLabel, children, }) {
37
+ const runtime = useWebsiteRuntime();
38
+ let href;
39
+ if (isAnchorOrUrlScheme(routePath)) {
40
+ href = routePath;
41
+ }
42
+ else {
43
+ if (!routePath.startsWith('/')) {
44
+ throw new Error(`[WebsiteInternalLink] routePath="${routePath}" must start with "/" ` +
45
+ `(framework-relative path), "#" (in-page anchor) or include ":" ` +
46
+ `(URL scheme like mailto:/tel:). Use <WebsiteLink href={...} external={true}> ` +
47
+ `for fully-qualified external URLs.`);
48
+ }
49
+ const accidentalPrefix = detectAccidentalLocalePrefix(routePath);
50
+ if (accidentalPrefix !== null) {
51
+ throw new Error(`[WebsiteInternalLink] routePath="${routePath}" begins with the ` +
52
+ `locale segment "/${accidentalPrefix}" — the framework prefixes ` +
53
+ `the active locale automatically, so passing a pre-prefixed path ` +
54
+ `would render as "/${accidentalPrefix}${routePath}" on non-default ` +
55
+ `locale pages (double-prefix) or silently break locale routing on ` +
56
+ `default-locale pages. Pass the locale-NEUTRAL path instead ` +
57
+ `(eg. "/pricing", not "/${accidentalPrefix}/pricing").`);
58
+ }
59
+ href = buildLocalizedRoutePath({
60
+ locale: runtime.locale,
61
+ defaultLocale: runtime.defaultLocale,
62
+ routePath,
63
+ });
64
+ }
65
+ return (_jsx(WebsiteLink, { href: href, external: false, className: className, style: style, id: id, ariaLabel: ariaLabel, children: children }));
66
+ }
67
+ WebsiteInternalLink.displayName = 'WebsiteInternalLink';
68
+ //# sourceMappingURL=WebsiteInternalLink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebsiteInternalLink.js","sourceRoot":"","sources":["../../../../../src/components/low-level/WebsiteInternalLink.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAEzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,uBAAuB,EAAE,MAAM,2CAA2C,CAAC;AAEpF,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AA+F5C,SAAS,mBAAmB,CAAC,SAAiB;IAC5C,OAAO,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AAC9D,CAAC;AAED;;;;;GAKG;AACH,MAAM,gBAAgB,GAAwB,IAAI,GAAG,CACnD,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAsB,CACtD,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,SAAS,4BAA4B,CAAC,SAAiB;IACrD,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAC3C,MAAM,YAAY,GAChB,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IACtE,IAAI,YAAY,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IACrC,OAAO,gBAAgB,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,EAClC,SAAS,EACT,SAAS,EACT,KAAK,EACL,EAAE,EACF,SAAS,EACT,QAAQ,GACiB;IACzB,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAC;IAEpC,IAAI,IAAY,CAAC;IACjB,IAAI,mBAAmB,CAAC,SAAS,CAAC,EAAE,CAAC;QACnC,IAAI,GAAG,SAAS,CAAC;IACnB,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CACb,oCAAoC,SAAS,wBAAwB;gBACnE,iEAAiE;gBACjE,+EAA+E;gBAC/E,oCAAoC,CACvC,CAAC;QACJ,CAAC;QACD,MAAM,gBAAgB,GAAG,4BAA4B,CAAC,SAAS,CAAC,CAAC;QACjE,IAAI,gBAAgB,KAAK,IAAI,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CACb,oCAAoC,SAAS,oBAAoB;gBAC/D,oBAAoB,gBAAgB,6BAA6B;gBACjE,kEAAkE;gBAClE,qBAAqB,gBAAgB,GAAG,SAAS,mBAAmB;gBACpE,mEAAmE;gBACnE,6DAA6D;gBAC7D,0BAA0B,gBAAgB,aAAa,CAC1D,CAAC;QACJ,CAAC;QACD,IAAI,GAAG,uBAAuB,CAAC;YAC7B,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,aAAa,EAAE,OAAO,CAAC,aAAa;YACpC,SAAS;SACV,CAAC,CAAC;IACL,CAAC;IAED,OAAO,CACL,KAAC,WAAW,IACV,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,KAAK,EACf,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,KAAK,EACZ,EAAE,EAAE,EAAE,EACN,SAAS,EAAE,SAAS,YAEnB,QAAQ,GACG,CACf,CAAC;AACJ,CAAC;AACD,mBAAmB,CAAC,WAAW,GAAG,qBAAqB,CAAC","sourcesContent":["import React, { type CSSProperties, type ReactNode } from 'react';\n\nimport { AvailableLanguage } from '@wildo-ai/saas-models/public-runtime';\n\nimport { useWebsiteRuntime } from '../../core/contexts/useWebsiteRuntime';\nimport { buildLocalizedRoutePath } from '../../core/routing/internal-routing.utils';\n\nimport { WebsiteLink } from './WebsiteLink';\n\n/**\n * @wildo_source:part:start saas.website.primitives.internal-link facet:layer:components facet:family:website\n *\n * `WebsiteInternalLink` — L1 marketing-site link primitive for\n * INTERNAL routes (any path served by the same Astro build).\n *\n * **The architectural problem this solves** (Phase 6 third audit fix\n * H-β): the marketing site mounts the default locale at the\n * un-prefixed path (`/`, `/pricing`) and every other locale under\n * `/<locale>/…` (`/fr/`, `/fr/pricing`). A naive `<a href=\"/pricing\">`\n * authored in the chrome therefore works on EN pages and SILENTLY\n * BREAKS on FR pages — the visitor falls out of their locale on every\n * navigation. The dist-HTML audit confirmed the regression.\n *\n * **Why a dedicated primitive** (parallel to `WebsiteLink`, not a flag\n * on it):\n * 1. The two primitives have different authoring contracts — an\n * external link's `href` is a fully-qualified URL the author\n * already commits to; an internal link's `href` is a raw\n * `routePath` (`'/pricing'`) that the framework prefixes. Mixing\n * both shapes behind one `external?` prop forces the author to\n * think about a routing rule on every link they place; mixing\n * them behind one component invites the wrong shape on the wrong\n * branch (an internal href passed with `external` set, or vice\n * versa) without a type-system signal.\n * 2. Internal links REQUIRE the runtime context; external links do\n * not. Forcing every external-link consumer to wrap in\n * `<WebsiteRuntimeContextProvider>` (or pay the\n * throw-on-missing-context cost) is wrong. Two primitives keep\n * the dependency surface honest.\n * 3. The framework can layer additional internal-link concerns\n * later (active-route highlighting, prefetch directives,\n * router-aware navigation when the consumer overrides\n * `WebsiteLink`) without complicating the external-link\n * contract.\n *\n * **Why `routePath` is a string and NOT `WebsitePageRef`**:\n * - Many internal targets are NOT pages (anchor links to a section\n * within the current page: `'#features'`; same-locale subroutes\n * served by the consumer's Astro build but not registered as\n * `WebsitePageManifest` entries: `'/blog/launch'`). A `pageRef`\n * prop would force every link target to be a registered manifest,\n * which is too restrictive for chrome.\n * - The consumer's chrome typically links to a small fixed set of\n * `routePath` values they author once. The boilerplate cost of\n * looking up the matching manifest by ref is non-trivial; the\n * payoff (typo protection on `'/pricing'`) is small.\n * - We DO validate at runtime that `routePath` starts with `/` and\n * does not double-prefix (a path already starting with `/<locale>/`\n * would otherwise become `/fr/fr/pricing` on a FR page) — see the\n * in-render guard below.\n *\n * **Anchor-only links** (`href=\"#features\"`) are passed through\n * verbatim: they navigate within the current page, no locale prefix\n * applies. Same for `mailto:` / `tel:` — recognized by colon presence\n * and forwarded as-is.\n *\n * **Boundary**: this component MUST stay in the React-island bundle\n * tier (`components/low-level/`). It depends on `useWebsiteRuntime`\n * (which throws when called outside a `<WebsiteRuntimeContextProvider>`)\n * — the throw is the contract that prevents the chrome from being\n * rendered outside a bridged page accidentally.\n *\n * @example\n * ```tsx\n * // In HeaderComponent.tsx — the framework computes the right URL\n * // automatically (`/pricing` on EN pages, `/fr/pricing` on FR\n * // pages):\n * <WebsiteInternalLink routePath=\"/pricing\">\n * <WebsiteText variant={WebsiteTextVariant.BODY}>Pricing</WebsiteText>\n * </WebsiteInternalLink>\n * ```\n */\nexport interface WebsiteInternalLinkProps {\n /**\n * The locale-NEUTRAL route path. Must match a value the consumer's\n * Astro build serves (typically a `WebsitePageManifest.routePath`,\n * but anchor-only `#section` and same-page subroutes are also\n * accepted). MUST start with `/` (or `#` for in-page anchors, or\n * include `:` for `mailto:` / `tel:`).\n */\n routePath: string;\n className?: string;\n style?: CSSProperties;\n id?: string;\n /**\n * Optional `aria-label` for icon-only links (where the link text\n * is a glyph or sr-only).\n */\n ariaLabel?: string;\n children: ReactNode;\n}\n\nfunction isAnchorOrUrlScheme(routePath: string): boolean {\n return routePath.startsWith('#') || routePath.includes(':');\n}\n\n/**\n * Pre-computed set of every known locale code (`'en'`, `'fr'`,\n * `'en-GB'`, …). Built ONCE at module load from `AvailableLanguage`\n * so the per-render double-prefix guard below is an O(1) Set.has\n * check rather than an Object.values() walk on every link render.\n */\nconst ALL_LOCALE_CODES: ReadonlySet<string> = new Set(\n Object.values(AvailableLanguage) as readonly string[],\n);\n\n/**\n * Defensive in-render guard: rejects route paths whose first segment\n * matches a known locale code. The marketing-site convention is that\n * the consumer authors locale-NEUTRAL paths and the framework\n * prefixes them; an already-prefixed path would either render as a\n * `/<locale>/<locale>/pricing` double-prefix on non-default-locale\n * pages or silently work on default-locale pages and break on other\n * locales — both are silent regressions. Throwing here makes the\n * misuse loud at first render.\n *\n * Returns the offending locale segment if the path is misused, or\n * `null` if the path is well-formed.\n */\nfunction detectAccidentalLocalePrefix(routePath: string): string | null {\n const slashIdx = routePath.indexOf('/', 1);\n const firstSegment =\n slashIdx === -1 ? routePath.slice(1) : routePath.slice(1, slashIdx);\n if (firstSegment === '') return null;\n return ALL_LOCALE_CODES.has(firstSegment) ? firstSegment : null;\n}\n\nexport function WebsiteInternalLink({\n routePath,\n className,\n style,\n id,\n ariaLabel,\n children,\n}: WebsiteInternalLinkProps): ReactNode {\n const runtime = useWebsiteRuntime();\n\n let href: string;\n if (isAnchorOrUrlScheme(routePath)) {\n href = routePath;\n } else {\n if (!routePath.startsWith('/')) {\n throw new Error(\n `[WebsiteInternalLink] routePath=\"${routePath}\" must start with \"/\" ` +\n `(framework-relative path), \"#\" (in-page anchor) or include \":\" ` +\n `(URL scheme like mailto:/tel:). Use <WebsiteLink href={...} external={true}> ` +\n `for fully-qualified external URLs.`,\n );\n }\n const accidentalPrefix = detectAccidentalLocalePrefix(routePath);\n if (accidentalPrefix !== null) {\n throw new Error(\n `[WebsiteInternalLink] routePath=\"${routePath}\" begins with the ` +\n `locale segment \"/${accidentalPrefix}\" — the framework prefixes ` +\n `the active locale automatically, so passing a pre-prefixed path ` +\n `would render as \"/${accidentalPrefix}${routePath}\" on non-default ` +\n `locale pages (double-prefix) or silently break locale routing on ` +\n `default-locale pages. Pass the locale-NEUTRAL path instead ` +\n `(eg. \"/pricing\", not \"/${accidentalPrefix}/pricing\").`,\n );\n }\n href = buildLocalizedRoutePath({\n locale: runtime.locale,\n defaultLocale: runtime.defaultLocale,\n routePath,\n });\n }\n\n return (\n <WebsiteLink\n href={href}\n external={false}\n className={className}\n style={style}\n id={id}\n ariaLabel={ariaLabel}\n >\n {children}\n </WebsiteLink>\n );\n}\nWebsiteInternalLink.displayName = 'WebsiteInternalLink';\n/** @wildo_source:part:end saas.website.primitives.internal-link */\n"]}
@@ -0,0 +1,50 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ /**
3
+ * @wildo_source:part:start saas.website.primitives.link facet:layer:components facet:family:website
4
+ *
5
+ * `WebsiteLink` — L1 marketing-site link primitive.
6
+ *
7
+ * **Status (Phase 2 / D18)**: minimal placeholder. Renders a plain
8
+ * `<a>` with `data-website-primitive="link"` and forwards href +
9
+ * standard link attributes. Consumers override at the L1 boundary
10
+ * to wire in their preferred client-side router (Astro `<a>` does
11
+ * full navigation by default; consumers using View Transitions or
12
+ * a router-aware link wrap that here).
13
+ *
14
+ * **Why `external` is an explicit prop** (vs. inferred from the
15
+ * href shape): inference is unreliable (relative paths from a CMS
16
+ * may resolve to external; protocol-relative URLs are external but
17
+ * don't start with `http`). An explicit prop forces the section
18
+ * author to decide. When `external === true`, the primitive applies
19
+ * `rel="noopener noreferrer"` and `target="_blank"` automatically
20
+ * — security best-practice baked in.
21
+ *
22
+ * **Why no `variant`**: link visual variants (button-like CTA,
23
+ * inline-text link, icon-only) are too tightly coupled to the
24
+ * design system to be useful as a placeholder vocabulary. The
25
+ * override implementation defines its own variants; the
26
+ * placeholder ships only the security-correct attribute defaults.
27
+ */
28
+ export interface WebsiteLinkProps {
29
+ href: string;
30
+ /**
31
+ * Marks the link as external. Adds `target="_blank"` and
32
+ * `rel="noopener noreferrer"`. Defaults to `false`.
33
+ */
34
+ external?: boolean;
35
+ className?: string;
36
+ style?: CSSProperties;
37
+ id?: string;
38
+ /**
39
+ * Optional `aria-label` for icon-only links (where the link text
40
+ * is a glyph or sr-only).
41
+ */
42
+ ariaLabel?: string;
43
+ children: ReactNode;
44
+ }
45
+ export declare function WebsiteLink({ href, external, className, style, id, ariaLabel, children, }: WebsiteLinkProps): ReactNode;
46
+ export declare namespace WebsiteLink {
47
+ var displayName: string;
48
+ }
49
+ /** @wildo_source:part:end saas.website.primitives.link */
50
+ //# sourceMappingURL=WebsiteLink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebsiteLink.d.ts","sourceRoot":"","sources":["../../../../../src/components/low-level/WebsiteLink.tsx"],"names":[],"mappings":"AAAA,OAAc,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAElE;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,QAAgB,EAChB,SAAS,EACT,KAAK,EACL,EAAE,EACF,SAAS,EACT,QAAQ,GACT,EAAE,gBAAgB,GAAG,SAAS,CAc9B;yBAtBe,WAAW;;;AAwB3B,0DAA0D"}
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ export function WebsiteLink({ href, external = false, className, style, id, ariaLabel, children, }) {
3
+ const attrs = {
4
+ 'data-website-primitive': 'link',
5
+ href,
6
+ };
7
+ if (external) {
8
+ attrs.target = '_blank';
9
+ attrs.rel = 'noopener noreferrer';
10
+ }
11
+ if (className !== undefined)
12
+ attrs.className = className;
13
+ if (style !== undefined)
14
+ attrs.style = style;
15
+ if (id !== undefined)
16
+ attrs.id = id;
17
+ if (ariaLabel !== undefined)
18
+ attrs['aria-label'] = ariaLabel;
19
+ return _jsx("a", { ...attrs, children: children });
20
+ }
21
+ WebsiteLink.displayName = 'WebsiteLink';
22
+ //# sourceMappingURL=WebsiteLink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebsiteLink.js","sourceRoot":"","sources":["../../../../../src/components/low-level/WebsiteLink.tsx"],"names":[],"mappings":";AA8CA,MAAM,UAAU,WAAW,CAAC,EAC1B,IAAI,EACJ,QAAQ,GAAG,KAAK,EAChB,SAAS,EACT,KAAK,EACL,EAAE,EACF,SAAS,EACT,QAAQ,GACS;IACjB,MAAM,KAAK,GAA4B;QACrC,wBAAwB,EAAE,MAAM;QAChC,IAAI;KACL,CAAC;IACF,IAAI,QAAQ,EAAE,CAAC;QACb,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC;QACxB,KAAK,CAAC,GAAG,GAAG,qBAAqB,CAAC;IACpC,CAAC;IACD,IAAI,SAAS,KAAK,SAAS;QAAE,KAAK,CAAC,SAAS,GAAG,SAAS,CAAC;IACzD,IAAI,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC;IAC7C,IAAI,EAAE,KAAK,SAAS;QAAE,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;IACpC,IAAI,SAAS,KAAK,SAAS;QAAE,KAAK,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC;IAC7D,OAAO,eAAO,KAAK,YAAG,QAAQ,GAAK,CAAC;AACtC,CAAC;AACD,WAAW,CAAC,WAAW,GAAG,aAAa,CAAC","sourcesContent":["import React, { type CSSProperties, type ReactNode } from 'react';\n\n/**\n * @wildo_source:part:start saas.website.primitives.link facet:layer:components facet:family:website\n *\n * `WebsiteLink` — L1 marketing-site link primitive.\n *\n * **Status (Phase 2 / D18)**: minimal placeholder. Renders a plain\n * `<a>` with `data-website-primitive=\"link\"` and forwards href +\n * standard link attributes. Consumers override at the L1 boundary\n * to wire in their preferred client-side router (Astro `<a>` does\n * full navigation by default; consumers using View Transitions or\n * a router-aware link wrap that here).\n *\n * **Why `external` is an explicit prop** (vs. inferred from the\n * href shape): inference is unreliable (relative paths from a CMS\n * may resolve to external; protocol-relative URLs are external but\n * don't start with `http`). An explicit prop forces the section\n * author to decide. When `external === true`, the primitive applies\n * `rel=\"noopener noreferrer\"` and `target=\"_blank\"` automatically\n * — security best-practice baked in.\n *\n * **Why no `variant`**: link visual variants (button-like CTA,\n * inline-text link, icon-only) are too tightly coupled to the\n * design system to be useful as a placeholder vocabulary. The\n * override implementation defines its own variants; the\n * placeholder ships only the security-correct attribute defaults.\n */\nexport interface WebsiteLinkProps {\n href: string;\n /**\n * Marks the link as external. Adds `target=\"_blank\"` and\n * `rel=\"noopener noreferrer\"`. Defaults to `false`.\n */\n external?: boolean;\n className?: string;\n style?: CSSProperties;\n id?: string;\n /**\n * Optional `aria-label` for icon-only links (where the link text\n * is a glyph or sr-only).\n */\n ariaLabel?: string;\n children: ReactNode;\n}\n\nexport function WebsiteLink({\n href,\n external = false,\n className,\n style,\n id,\n ariaLabel,\n children,\n}: WebsiteLinkProps): ReactNode {\n const attrs: Record<string, unknown> = {\n 'data-website-primitive': 'link',\n href,\n };\n if (external) {\n attrs.target = '_blank';\n attrs.rel = 'noopener noreferrer';\n }\n if (className !== undefined) attrs.className = className;\n if (style !== undefined) attrs.style = style;\n if (id !== undefined) attrs.id = id;\n if (ariaLabel !== undefined) attrs['aria-label'] = ariaLabel;\n return <a {...attrs}>{children}</a>;\n}\nWebsiteLink.displayName = 'WebsiteLink';\n/** @wildo_source:part:end saas.website.primitives.link */\n"]}
@@ -0,0 +1,57 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ /**
3
+ * @wildo_source:part:start saas.website.primitives.text facet:layer:components facet:family:website
4
+ *
5
+ * `WebsiteText` — L1 marketing-site body-text primitive.
6
+ *
7
+ * Same Phase 2 / D18 status as `WebsiteHeading` — minimal,
8
+ * self-contained placeholder; consumers override at the L1 boundary
9
+ * via barrel re-export. The skill-driven authoring path will require
10
+ * an override before shipping a public marketing site.
11
+ *
12
+ * **Why `variant` (lead vs. body vs. caption) is shipped here**:
13
+ * marketing-site body copy has a distinct typographic scale from
14
+ * in-app body copy (looser line-height for scannability, larger
15
+ * `lead` paragraphs under headlines, smaller `caption` under
16
+ * pricing tier features). The variant slot exists at the
17
+ * placeholder level so section authors call the same prop the
18
+ * override implementation honors.
19
+ *
20
+ * **Why default tag is `<p>`**: the overwhelming majority of
21
+ * marketing copy is a paragraph. The `as` prop allows escaping to
22
+ * `<span>` (inline copy inside a heading), `<strong>` (emphatic
23
+ * inline), or `<em>` (italicized inline) without compromising the
24
+ * paragraph default.
25
+ */
26
+ export declare enum WebsiteTextVariant {
27
+ /**
28
+ * Lead paragraph immediately under a section headline (slightly
29
+ * larger / less dense than body).
30
+ */
31
+ LEAD = "lead",
32
+ /**
33
+ * Standard body copy. The default.
34
+ */
35
+ BODY = "body",
36
+ /**
37
+ * Small / supporting copy (footnotes, captions, fine print).
38
+ */
39
+ CAPTION = "caption"
40
+ }
41
+ export type WebsiteTextElement = 'p' | 'span' | 'strong' | 'em' | 'div';
42
+ export interface WebsiteTextProps {
43
+ /** Visual variant. Defaults to `BODY`. */
44
+ variant?: WebsiteTextVariant;
45
+ /** Rendered tag. Defaults to `'p'`. */
46
+ as?: WebsiteTextElement;
47
+ className?: string;
48
+ style?: CSSProperties;
49
+ id?: string;
50
+ children: ReactNode;
51
+ }
52
+ export declare function WebsiteText({ variant, as, className, style, id, children, }: WebsiteTextProps): ReactNode;
53
+ export declare namespace WebsiteText {
54
+ var displayName: string;
55
+ }
56
+ /** @wildo_source:part:end saas.website.primitives.text */
57
+ //# sourceMappingURL=WebsiteText.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebsiteText.d.ts","sourceRoot":"","sources":["../../../../../src/components/low-level/WebsiteText.tsx"],"names":[],"mappings":"AAAA,OAAc,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAElE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,oBAAY,kBAAkB;IAC5B;;;OAGG;IACH,IAAI,SAAS;IACb;;OAEG;IACH,IAAI,SAAS;IACb;;OAEG;IACH,OAAO,YAAY;CACpB;AAED,MAAM,MAAM,kBAAkB,GAAG,GAAG,GAAG,MAAM,GAAG,QAAQ,GAAG,IAAI,GAAG,KAAK,CAAC;AAExE,MAAM,WAAW,gBAAgB;IAC/B,0CAA0C;IAC1C,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,uCAAuC;IACvC,EAAE,CAAC,EAAE,kBAAkB,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,WAAW,CAAC,EAC1B,OAAiC,EACjC,EAAQ,EACR,SAAS,EACT,KAAK,EACL,EAAE,EACF,QAAQ,GACT,EAAE,gBAAgB,GAAG,SAAS,CAU9B;yBAjBe,WAAW;;;AAmB3B,0DAA0D"}
@@ -0,0 +1,57 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * @wildo_source:part:start saas.website.primitives.text facet:layer:components facet:family:website
4
+ *
5
+ * `WebsiteText` — L1 marketing-site body-text primitive.
6
+ *
7
+ * Same Phase 2 / D18 status as `WebsiteHeading` — minimal,
8
+ * self-contained placeholder; consumers override at the L1 boundary
9
+ * via barrel re-export. The skill-driven authoring path will require
10
+ * an override before shipping a public marketing site.
11
+ *
12
+ * **Why `variant` (lead vs. body vs. caption) is shipped here**:
13
+ * marketing-site body copy has a distinct typographic scale from
14
+ * in-app body copy (looser line-height for scannability, larger
15
+ * `lead` paragraphs under headlines, smaller `caption` under
16
+ * pricing tier features). The variant slot exists at the
17
+ * placeholder level so section authors call the same prop the
18
+ * override implementation honors.
19
+ *
20
+ * **Why default tag is `<p>`**: the overwhelming majority of
21
+ * marketing copy is a paragraph. The `as` prop allows escaping to
22
+ * `<span>` (inline copy inside a heading), `<strong>` (emphatic
23
+ * inline), or `<em>` (italicized inline) without compromising the
24
+ * paragraph default.
25
+ */
26
+ export var WebsiteTextVariant;
27
+ (function (WebsiteTextVariant) {
28
+ /**
29
+ * Lead paragraph immediately under a section headline (slightly
30
+ * larger / less dense than body).
31
+ */
32
+ WebsiteTextVariant["LEAD"] = "lead";
33
+ /**
34
+ * Standard body copy. The default.
35
+ */
36
+ WebsiteTextVariant["BODY"] = "body";
37
+ /**
38
+ * Small / supporting copy (footnotes, captions, fine print).
39
+ */
40
+ WebsiteTextVariant["CAPTION"] = "caption";
41
+ })(WebsiteTextVariant || (WebsiteTextVariant = {}));
42
+ export function WebsiteText({ variant = WebsiteTextVariant.BODY, as = 'p', className, style, id, children, }) {
43
+ const Tag = as;
44
+ const attrs = {
45
+ 'data-website-primitive': 'text',
46
+ 'data-website-text-variant': variant,
47
+ };
48
+ if (className !== undefined)
49
+ attrs.className = className;
50
+ if (style !== undefined)
51
+ attrs.style = style;
52
+ if (id !== undefined)
53
+ attrs.id = id;
54
+ return _jsx(Tag, { ...attrs, children: children });
55
+ }
56
+ WebsiteText.displayName = 'WebsiteText';
57
+ //# sourceMappingURL=WebsiteText.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebsiteText.js","sourceRoot":"","sources":["../../../../../src/components/low-level/WebsiteText.tsx"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAN,IAAY,kBAcX;AAdD,WAAY,kBAAkB;IAC5B;;;OAGG;IACH,mCAAa,CAAA;IACb;;OAEG;IACH,mCAAa,CAAA;IACb;;OAEG;IACH,yCAAmB,CAAA;AACrB,CAAC,EAdW,kBAAkB,KAAlB,kBAAkB,QAc7B;AAeD,MAAM,UAAU,WAAW,CAAC,EAC1B,OAAO,GAAG,kBAAkB,CAAC,IAAI,EACjC,EAAE,GAAG,GAAG,EACR,SAAS,EACT,KAAK,EACL,EAAE,EACF,QAAQ,GACS;IACjB,MAAM,GAAG,GAAG,EAAE,CAAC;IACf,MAAM,KAAK,GAA4B;QACrC,wBAAwB,EAAE,MAAM;QAChC,2BAA2B,EAAE,OAAO;KACrC,CAAC;IACF,IAAI,SAAS,KAAK,SAAS;QAAE,KAAK,CAAC,SAAS,GAAG,SAAS,CAAC;IACzD,IAAI,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC;IAC7C,IAAI,EAAE,KAAK,SAAS;QAAE,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;IACpC,OAAO,KAAC,GAAG,OAAK,KAAK,YAAG,QAAQ,GAAO,CAAC;AAC1C,CAAC;AACD,WAAW,CAAC,WAAW,GAAG,aAAa,CAAC","sourcesContent":["import React, { type CSSProperties, type ReactNode } from 'react';\n\n/**\n * @wildo_source:part:start saas.website.primitives.text facet:layer:components facet:family:website\n *\n * `WebsiteText` — L1 marketing-site body-text primitive.\n *\n * Same Phase 2 / D18 status as `WebsiteHeading` — minimal,\n * self-contained placeholder; consumers override at the L1 boundary\n * via barrel re-export. The skill-driven authoring path will require\n * an override before shipping a public marketing site.\n *\n * **Why `variant` (lead vs. body vs. caption) is shipped here**:\n * marketing-site body copy has a distinct typographic scale from\n * in-app body copy (looser line-height for scannability, larger\n * `lead` paragraphs under headlines, smaller `caption` under\n * pricing tier features). The variant slot exists at the\n * placeholder level so section authors call the same prop the\n * override implementation honors.\n *\n * **Why default tag is `<p>`**: the overwhelming majority of\n * marketing copy is a paragraph. The `as` prop allows escaping to\n * `<span>` (inline copy inside a heading), `<strong>` (emphatic\n * inline), or `<em>` (italicized inline) without compromising the\n * paragraph default.\n */\nexport enum WebsiteTextVariant {\n /**\n * Lead paragraph immediately under a section headline (slightly\n * larger / less dense than body).\n */\n LEAD = 'lead',\n /**\n * Standard body copy. The default.\n */\n BODY = 'body',\n /**\n * Small / supporting copy (footnotes, captions, fine print).\n */\n CAPTION = 'caption',\n}\n\nexport type WebsiteTextElement = 'p' | 'span' | 'strong' | 'em' | 'div';\n\nexport interface WebsiteTextProps {\n /** Visual variant. Defaults to `BODY`. */\n variant?: WebsiteTextVariant;\n /** Rendered tag. Defaults to `'p'`. */\n as?: WebsiteTextElement;\n className?: string;\n style?: CSSProperties;\n id?: string;\n children: ReactNode;\n}\n\nexport function WebsiteText({\n variant = WebsiteTextVariant.BODY,\n as = 'p',\n className,\n style,\n id,\n children,\n}: WebsiteTextProps): ReactNode {\n const Tag = as;\n const attrs: Record<string, unknown> = {\n 'data-website-primitive': 'text',\n 'data-website-text-variant': variant,\n };\n if (className !== undefined) attrs.className = className;\n if (style !== undefined) attrs.style = style;\n if (id !== undefined) attrs.id = id;\n return <Tag {...attrs}>{children}</Tag>;\n}\nWebsiteText.displayName = 'WebsiteText';\n/** @wildo_source:part:end saas.website.primitives.text */\n"]}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @fileoverview Author helper for `wildo.website.config.ts` files.
3
+ *
4
+ * `defineWebsiteConfig({...})` mirrors the `defineSaasConfig` /
5
+ * `defineInfraEnvConfig` helpers from `@wildo-ai/platform-config-lib`
6
+ * and `defineTechnicalDocConfig` from `@wildo-ai/saas-technical-doc`:
7
+ * it wraps `WildoMarketingWebsiteConfigSchema.parse(...)` with full
8
+ * IDE autocompletion on the input shape, and emits a parse-time
9
+ * stderr warning for any authored field that has no runtime
10
+ * consumer yet.
11
+ *
12
+ * # `@unimplemented` channel — current state
13
+ *
14
+ * The warner has ZERO branches today because every OPTIONAL field that
15
+ * exists is already wired (`csp?` now flows through the website-local
16
+ * CSP sync step) and the only unwired field left is `appOrigin`, which
17
+ * is REQUIRED. After the seam-collapse (`saas-website-seam-collapse.md`
18
+ * — SHIPPED), the routing/origin fields (`publicOrigin`,
19
+ * `defaultLocale`, `locales`) are consumed directly by every Astro
20
+ * engine helper via `WebsiteSiteContext`, so they are no longer
21
+ * candidates for a "deferred wiring" warning either. The
22
+ * `@unimplemented` warner is for fields that are parsed-but-unused AND
23
+ * opt-in — firing on every Astro build for a required field would drown
24
+ * the dev console.
25
+ *
26
+ * Two valid futures will trigger adding warner branches:
27
+ * 1. A future optional field lands (e.g. `seo?.{title,description}`,
28
+ * `structuredData?.organization`) whose runtime wiring ships
29
+ * in a later PR — that would get
30
+ * `if (config.seo !== undefined) warn('seo', ...)` until the
31
+ * renderer reads it.
32
+ * 2. A required field temporarily loses its consumer (e.g. a
33
+ * large refactor splits the SEO renderer into two PRs); the
34
+ * branch fires unconditionally for the duration.
35
+ *
36
+ * The scaffold is kept (and the no-warning contract is pinned by
37
+ * the test suite) so the moment either case lands, the warning
38
+ * channel is one branch addition away — matching the
39
+ * `defineTechnicalDocConfig` shape exactly so future authors
40
+ * grepping for `@unimplemented` find a uniform pattern.
41
+ *
42
+ * Why we don't reuse `platform-config-lib`'s
43
+ * `createUnimplementedFieldWarner`:
44
+ *
45
+ * `platform-config-lib` is the platform-level boundary; this engine
46
+ * package is downstream of it for everything else. Importing the
47
+ * warner from `platform-config-lib` would invert the dependency
48
+ * direction (engine → platform-config), creating the same architectural
49
+ * defect Step 7.5 set out to fix. The warning format is small and
50
+ * stable enough to inline here — kept structurally similar to the
51
+ * platform-config-lib warner so readers grepping for `@unimplemented`
52
+ * still find both surfaces.
53
+ */
54
+ import { type WildoMarketingWebsiteConfig, type WildoMarketingWebsiteConfigInput } from './wildo-website-config.schemas';
55
+ /**
56
+ * Define a per-service marketing-website config. Provides full IDE
57
+ * autocompletion on the input shape, runs Zod validation (fail-closed
58
+ * on typos / unknown keys / out-of-range values / cross-field
59
+ * invariants like `defaultLocale ∈ locales`), and emits parse-time
60
+ * `@unimplemented` warnings for fields that are authored but have no
61
+ * runtime consumer yet.
62
+ *
63
+ * Throws on validation failure — same contract as `defineSaasConfig`
64
+ * and `defineTechnicalDocConfig`.
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * import { AvailableLanguage } from '@wildo-ai/saas-models/public-runtime';
69
+ * import { defineWebsiteConfig } from '@wildo-ai/saas-website';
70
+ *
71
+ * export default defineWebsiteConfig({
72
+ * publicOrigin: 'https://wonder-todos.example.com',
73
+ * appOrigin: 'https://app.wonder-todos.example.com',
74
+ * defaultLocale: AvailableLanguage.EN,
75
+ * locales: [
76
+ * { locale: AvailableLanguage.EN, path: 'en' },
77
+ * { locale: AvailableLanguage.FR, path: 'fr' },
78
+ * ],
79
+ * });
80
+ * ```
81
+ */
82
+ export declare function defineWebsiteConfig(config: WildoMarketingWebsiteConfigInput): WildoMarketingWebsiteConfig;
83
+ //# sourceMappingURL=define-website-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-website-config.d.ts","sourceRoot":"","sources":["../../../../src/config/define-website-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,OAAO,EAEL,KAAK,2BAA2B,EAChC,KAAK,gCAAgC,EACtC,MAAM,gCAAgC,CAAC;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,gCAAgC,GACvC,2BAA2B,CAI7B"}