@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,85 @@
1
+ import { z } from 'zod';
2
+ import { AvailableLanguage } from '@wildo-ai/saas-models/public-runtime';
3
+ /**
4
+ * @wildo_source:part:start saas.website.blog.frontmatter facet:layer:shared facet:family:website
5
+ *
6
+ * `BlogPostFrontmatter` — the YAML frontmatter contract every blog
7
+ * post MDX file under `examples/<app>/website/src/content/blog/<locale>/`
8
+ * MUST satisfy.
9
+ *
10
+ * **Q16=B context**: blogs are authored as full per-locale MDX files
11
+ * (one MDX per (slug, locale) pair), NOT as label-pack-keyed content.
12
+ * The frontmatter therefore carries strings directly (`title`,
13
+ * `summary`) rather than label keys — there is no shared
14
+ * label-pack-driven authoring surface for blog content. This is
15
+ * intentional: blog copy is long-form and locale-divergent; forcing
16
+ * it through a structural label-pack would either inflate the pack
17
+ * or fragment the prose.
18
+ *
19
+ * **Field rationale**:
20
+ *
21
+ * - `title` — REQUIRED. Renders into `<title>`, `og:title`, and the
22
+ * in-page H1. Authored as a direct string, deliberately.
23
+ * - `summary` — REQUIRED. Renders into `<meta name="description">`,
24
+ * `og:description`, and listing-card descriptions. Direct string.
25
+ * - `slug` — REQUIRED. URL slug (lowercase kebab-case). Brand prevents
26
+ * accidental swap with `WebsitePageRef` (same shape, different role).
27
+ * - `locale` — REQUIRED. The post's locale. Drives the URL prefix
28
+ * (`/<locale>/blog/<slug>`) and `<html lang>`. Cross-locale
29
+ * correspondence is established by sharing the `slug` across
30
+ * per-locale MDX files (e.g. `en/why-context.md` and
31
+ * `fr/why-context.md` are the same post in two locales).
32
+ * - `publishedAt` — REQUIRED. ISO-8601 date-time string. Renders into
33
+ * `og:article:published_time` and the listing-card date label.
34
+ * Stored as string (not `z.coerce.date`) because YAML frontmatter
35
+ * parsers preserve the original string and the SEO emitters need
36
+ * the original ISO formatting (no Date.toISOString() round-trip
37
+ * loss).
38
+ * - `authorRef` — REQUIRED. Identifier of the author resolved by the
39
+ * consumer's author registry (typically a `src/content/authors/<ref>.ts`
40
+ * file). Brand keeps it distinct from page/section refs.
41
+ * - `tags` — REQUIRED, possibly empty. Lowercase kebab-case tag
42
+ * identifiers. Drives `og:article:tag` and the listing-page facets.
43
+ * - `coverImageUrl` — OPTIONAL. CDN URL for the blog post hero image
44
+ * and `og:image`.
45
+ *
46
+ * **Why a separate file from the page-manifest**: a blog post is NOT
47
+ * a `WebsitePageManifest` (no React `pageComponent` to mount — the
48
+ * MDX file IS the content). The Astro adapter emits one MDX route
49
+ * per post via `content collections`, with `BlogPostFrontmatter`
50
+ * driving the route generation and the SEO emission.
51
+ */
52
+ const _BlogPostSlugSchema = z
53
+ .string()
54
+ .min(1, { error: 'BlogPostSlug must not be empty' })
55
+ .max(96, { error: 'BlogPostSlug must be at most 96 characters' })
56
+ .regex(/^[a-z][a-z0-9-]*$/, { error: 'BlogPostSlug must be lowercase kebab-case starting with a letter' })
57
+ .brand();
58
+ export const BlogPostSlugSchema = _BlogPostSlugSchema;
59
+ const _BlogAuthorRefSchema = z
60
+ .string()
61
+ .min(1, { error: 'BlogAuthorRef must not be empty' })
62
+ .max(64, { error: 'BlogAuthorRef must be at most 64 characters' })
63
+ .regex(/^[a-z][a-z0-9-]*$/, { error: 'BlogAuthorRef must be lowercase kebab-case starting with a letter' })
64
+ .brand();
65
+ export const BlogAuthorRefSchema = _BlogAuthorRefSchema;
66
+ const _BlogPostTagSchema = z
67
+ .string()
68
+ .min(1, { error: 'BlogPostTag must not be empty' })
69
+ .max(48, { error: 'BlogPostTag must be at most 48 characters' })
70
+ .regex(/^[a-z][a-z0-9-]*$/, { error: 'BlogPostTag must be lowercase kebab-case starting with a letter' })
71
+ .brand();
72
+ export const BlogPostTagSchema = _BlogPostTagSchema;
73
+ const _BlogPostFrontmatterSchema = z.object({
74
+ title: z.string().min(1, { error: 'title must not be empty' }).max(200, { error: 'title must be at most 200 characters' }),
75
+ summary: z.string().min(1, { error: 'summary must not be empty' }).max(400, { error: 'summary must be at most 400 characters' }),
76
+ slug: _BlogPostSlugSchema,
77
+ locale: z.enum(AvailableLanguage),
78
+ publishedAt: z.iso.datetime({ error: 'publishedAt must be an ISO-8601 datetime string' }),
79
+ authorRef: _BlogAuthorRefSchema,
80
+ tags: z.array(_BlogPostTagSchema),
81
+ coverImageUrl: z.url({ error: 'coverImageUrl must be a valid URL' }).optional(),
82
+ });
83
+ export const BlogPostFrontmatterSchema = _BlogPostFrontmatterSchema;
84
+ /** @wildo_source:part:end saas.website.blog.frontmatter */
85
+ //# sourceMappingURL=blog-post-frontmatter.shared.schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blog-post-frontmatter.shared.schemas.js","sourceRoot":"","sources":["../../../../../src/schemas/blog/blog-post-frontmatter.shared.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,MAAM,mBAAmB,GAAG,CAAC;KAC1B,MAAM,EAAE;KACR,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAC;KACnD,GAAG,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,4CAA4C,EAAE,CAAC;KAChE,KAAK,CACJ,mBAAmB,EACnB,EAAE,KAAK,EAAE,kEAAkE,EAAE,CAC9E;KACA,KAAK,EAAkB,CAAC;AAE3B,MAAM,CAAC,MAAM,kBAAkB,GAA+B,mBAAmB,CAAC;AAIlF,MAAM,oBAAoB,GAAG,CAAC;KAC3B,MAAM,EAAE;KACR,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,iCAAiC,EAAE,CAAC;KACpD,GAAG,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,6CAA6C,EAAE,CAAC;KACjE,KAAK,CACJ,mBAAmB,EACnB,EAAE,KAAK,EAAE,mEAAmE,EAAE,CAC/E;KACA,KAAK,EAAmB,CAAC;AAE5B,MAAM,CAAC,MAAM,mBAAmB,GAAgC,oBAAoB,CAAC;AAIrF,MAAM,kBAAkB,GAAG,CAAC;KACzB,MAAM,EAAE;KACR,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAC;KAClD,GAAG,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,2CAA2C,EAAE,CAAC;KAC/D,KAAK,CACJ,mBAAmB,EACnB,EAAE,KAAK,EAAE,iEAAiE,EAAE,CAC7E;KACA,KAAK,EAAiB,CAAC;AAE1B,MAAM,CAAC,MAAM,iBAAiB,GAA8B,kBAAkB,CAAC;AAI/E,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,sCAAsC,EAAE,CAAC;IAC1H,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,2BAA2B,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,wCAAwC,EAAE,CAAC;IAChI,IAAI,EAAE,mBAAmB;IACzB,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC;IACjC,WAAW,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,iDAAiD,EAAE,CAAC;IACzF,SAAS,EAAE,oBAAoB;IAC/B,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC;IACjC,aAAa,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,mCAAmC,EAAE,CAAC,CAAC,QAAQ,EAAE;CAChF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,yBAAyB,GACpC,0BAA0B,CAAC;AAG7B,2DAA2D","sourcesContent":["import { z } from 'zod';\n\nimport { AvailableLanguage } from '@wildo-ai/saas-models/public-runtime';\n\n/**\n * @wildo_source:part:start saas.website.blog.frontmatter facet:layer:shared facet:family:website\n *\n * `BlogPostFrontmatter` — the YAML frontmatter contract every blog\n * post MDX file under `examples/<app>/website/src/content/blog/<locale>/`\n * MUST satisfy.\n *\n * **Q16=B context**: blogs are authored as full per-locale MDX files\n * (one MDX per (slug, locale) pair), NOT as label-pack-keyed content.\n * The frontmatter therefore carries strings directly (`title`,\n * `summary`) rather than label keys — there is no shared\n * label-pack-driven authoring surface for blog content. This is\n * intentional: blog copy is long-form and locale-divergent; forcing\n * it through a structural label-pack would either inflate the pack\n * or fragment the prose.\n *\n * **Field rationale**:\n *\n * - `title` — REQUIRED. Renders into `<title>`, `og:title`, and the\n * in-page H1. Authored as a direct string, deliberately.\n * - `summary` — REQUIRED. Renders into `<meta name=\"description\">`,\n * `og:description`, and listing-card descriptions. Direct string.\n * - `slug` — REQUIRED. URL slug (lowercase kebab-case). Brand prevents\n * accidental swap with `WebsitePageRef` (same shape, different role).\n * - `locale` — REQUIRED. The post's locale. Drives the URL prefix\n * (`/<locale>/blog/<slug>`) and `<html lang>`. Cross-locale\n * correspondence is established by sharing the `slug` across\n * per-locale MDX files (e.g. `en/why-context.md` and\n * `fr/why-context.md` are the same post in two locales).\n * - `publishedAt` — REQUIRED. ISO-8601 date-time string. Renders into\n * `og:article:published_time` and the listing-card date label.\n * Stored as string (not `z.coerce.date`) because YAML frontmatter\n * parsers preserve the original string and the SEO emitters need\n * the original ISO formatting (no Date.toISOString() round-trip\n * loss).\n * - `authorRef` — REQUIRED. Identifier of the author resolved by the\n * consumer's author registry (typically a `src/content/authors/<ref>.ts`\n * file). Brand keeps it distinct from page/section refs.\n * - `tags` — REQUIRED, possibly empty. Lowercase kebab-case tag\n * identifiers. Drives `og:article:tag` and the listing-page facets.\n * - `coverImageUrl` — OPTIONAL. CDN URL for the blog post hero image\n * and `og:image`.\n *\n * **Why a separate file from the page-manifest**: a blog post is NOT\n * a `WebsitePageManifest` (no React `pageComponent` to mount — the\n * MDX file IS the content). The Astro adapter emits one MDX route\n * per post via `content collections`, with `BlogPostFrontmatter`\n * driving the route generation and the SEO emission.\n */\nconst _BlogPostSlugSchema = z\n .string()\n .min(1, { error: 'BlogPostSlug must not be empty' })\n .max(96, { error: 'BlogPostSlug must be at most 96 characters' })\n .regex(\n /^[a-z][a-z0-9-]*$/,\n { error: 'BlogPostSlug must be lowercase kebab-case starting with a letter' },\n )\n .brand<'BlogPostSlug'>();\n\nexport const BlogPostSlugSchema: typeof _BlogPostSlugSchema = _BlogPostSlugSchema;\n\nexport type BlogPostSlug = z.infer<typeof _BlogPostSlugSchema>;\n\nconst _BlogAuthorRefSchema = z\n .string()\n .min(1, { error: 'BlogAuthorRef must not be empty' })\n .max(64, { error: 'BlogAuthorRef must be at most 64 characters' })\n .regex(\n /^[a-z][a-z0-9-]*$/,\n { error: 'BlogAuthorRef must be lowercase kebab-case starting with a letter' },\n )\n .brand<'BlogAuthorRef'>();\n\nexport const BlogAuthorRefSchema: typeof _BlogAuthorRefSchema = _BlogAuthorRefSchema;\n\nexport type BlogAuthorRef = z.infer<typeof _BlogAuthorRefSchema>;\n\nconst _BlogPostTagSchema = z\n .string()\n .min(1, { error: 'BlogPostTag must not be empty' })\n .max(48, { error: 'BlogPostTag must be at most 48 characters' })\n .regex(\n /^[a-z][a-z0-9-]*$/,\n { error: 'BlogPostTag must be lowercase kebab-case starting with a letter' },\n )\n .brand<'BlogPostTag'>();\n\nexport const BlogPostTagSchema: typeof _BlogPostTagSchema = _BlogPostTagSchema;\n\nexport type BlogPostTag = z.infer<typeof _BlogPostTagSchema>;\n\nconst _BlogPostFrontmatterSchema = z.object({\n title: z.string().min(1, { error: 'title must not be empty' }).max(200, { error: 'title must be at most 200 characters' }),\n summary: z.string().min(1, { error: 'summary must not be empty' }).max(400, { error: 'summary must be at most 400 characters' }),\n slug: _BlogPostSlugSchema,\n locale: z.enum(AvailableLanguage),\n publishedAt: z.iso.datetime({ error: 'publishedAt must be an ISO-8601 datetime string' }),\n authorRef: _BlogAuthorRefSchema,\n tags: z.array(_BlogPostTagSchema),\n coverImageUrl: z.url({ error: 'coverImageUrl must be a valid URL' }).optional(),\n});\n\nexport const BlogPostFrontmatterSchema: typeof _BlogPostFrontmatterSchema =\n _BlogPostFrontmatterSchema;\n\nexport type BlogPostFrontmatter = z.infer<typeof _BlogPostFrontmatterSchema>;\n/** @wildo_source:part:end saas.website.blog.frontmatter */\n"]}
@@ -0,0 +1,120 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * @wildo_source:part:start saas.website.design-tokens.colors facet:layer:shared facet:family:website
4
+ *
5
+ * `WebsiteColorTokens` — minimal palette the marketing-site exposes as
6
+ * CSS custom properties (`--website-color-<token>`) on the
7
+ * `<WebsitePageLayout>` root.
8
+ *
9
+ * **Why a dedicated marketing palette** (vs. reusing
10
+ * `presets-components-models/design-tokens-config`):
11
+ *
12
+ * - The SaaS app's design tokens carry many semantic states (`muted`,
13
+ * `destructive`, `ring`, `sidebar-*`, …) that have no marketing-site
14
+ * analogue. Forcing the website to consume the full palette would
15
+ * leak app-internal semantics into a public surface.
16
+ * - Marketing pages need *display-grade* colors (heavily branded
17
+ * accents, gradient stops, hero-overlay tints) that the SaaS app's
18
+ * functional palette deliberately avoids.
19
+ * - Designers overriding website tokens (Phase 6 dogfood proves this
20
+ * path) should not be able to break the SaaS app by editing one
21
+ * tailwind.config — the two surfaces stay decoupled.
22
+ *
23
+ * **Token format**: every value is a CSS color string. Shape validation
24
+ * is intentionally permissive (accepts hex, rgb/rgba, hsl/hsla, oklch,
25
+ * `currentColor`, named colors, CSS variable references) — a strict
26
+ * color-string regex would reject legitimate values (oklch grammar
27
+ * alone is ~80 lines) and a malformed-but-syntactically-valid color
28
+ * fails loudly at render time.
29
+ *
30
+ * **What IS strictly enforced**: every value passes `cssSafeValue`,
31
+ * which rejects the six characters that can break out of a CSS
32
+ * property declaration (`;`, `{`, `}`, `/*`, `*\/`, newline). See the
33
+ * `cssSafeValue` JSDoc above for the full threat model.
34
+ *
35
+ * **Adding a token**: append the field here using `cssSafeValue(...)`,
36
+ * document its semantic intent in the JSDoc, and update the matching
37
+ * CSS-emit helper in Phase 2 (`emitWebsiteColorTokensCss`).
38
+ */
39
+ declare const _WebsiteColorTokensSchema: z.ZodObject<{
40
+ background: z.ZodString;
41
+ foreground: z.ZodString;
42
+ primary: z.ZodString;
43
+ primaryForeground: z.ZodString;
44
+ accent: z.ZodString;
45
+ accentForeground: z.ZodString;
46
+ surface: z.ZodString;
47
+ surfaceForeground: z.ZodString;
48
+ border: z.ZodString;
49
+ muted: z.ZodString;
50
+ mutedForeground: z.ZodString;
51
+ }, z.core.$strip>;
52
+ export declare const WebsiteColorTokensSchema: typeof _WebsiteColorTokensSchema;
53
+ export type WebsiteColorTokens = z.infer<typeof _WebsiteColorTokensSchema>;
54
+ /** @wildo_source:part:end saas.website.design-tokens.colors */
55
+ /**
56
+ * @wildo_source:part:start saas.website.design-tokens.radius facet:layer:shared facet:family:website
57
+ *
58
+ * `WebsiteRadiusTokens` — border-radius scale exposed as
59
+ * `--website-radius-<token>` CSS variables.
60
+ *
61
+ * Marketing radii are intentionally a separate token set from the
62
+ * SaaS app's radii: the website typically wants larger pill / hero
63
+ * radii than the app's compact-UI radii. Keeping them separate lets
64
+ * either surface evolve without coupling.
65
+ *
66
+ * Values are CSS length strings (`'0.25rem'`, `'12px'`,
67
+ * `'9999px'`). Same permissive-shape + strict-CSS-injection
68
+ * rationale as `WebsiteColorTokens` (every value runs through
69
+ * `cssSafeValue`).
70
+ */
71
+ declare const _WebsiteRadiusTokensSchema: z.ZodObject<{
72
+ none: z.ZodString;
73
+ sm: z.ZodString;
74
+ md: z.ZodString;
75
+ lg: z.ZodString;
76
+ xl: z.ZodString;
77
+ full: z.ZodString;
78
+ }, z.core.$strip>;
79
+ export declare const WebsiteRadiusTokensSchema: typeof _WebsiteRadiusTokensSchema;
80
+ export type WebsiteRadiusTokens = z.infer<typeof _WebsiteRadiusTokensSchema>;
81
+ /** @wildo_source:part:end saas.website.design-tokens.radius */
82
+ /**
83
+ * @wildo_source:part:start saas.website.design-tokens.bundle facet:layer:shared facet:family:website
84
+ *
85
+ * `WebsiteDesignTokens` — the complete design-token bundle attached to
86
+ * `WebsiteRootConfig.designTokens`. Currently colors + radii only
87
+ * (per plan Phase 1 scope: "WebsiteColorTokensSchema + WebsiteRadiusTokensSchema (only)").
88
+ *
89
+ * Future expansions (typography scale, motion tokens, shadow elevation)
90
+ * will land as additional fields here without breaking the
91
+ * `WebsiteRootConfig` shape.
92
+ */
93
+ declare const _WebsiteDesignTokensSchema: z.ZodObject<{
94
+ colors: z.ZodObject<{
95
+ background: z.ZodString;
96
+ foreground: z.ZodString;
97
+ primary: z.ZodString;
98
+ primaryForeground: z.ZodString;
99
+ accent: z.ZodString;
100
+ accentForeground: z.ZodString;
101
+ surface: z.ZodString;
102
+ surfaceForeground: z.ZodString;
103
+ border: z.ZodString;
104
+ muted: z.ZodString;
105
+ mutedForeground: z.ZodString;
106
+ }, z.core.$strip>;
107
+ radii: z.ZodObject<{
108
+ none: z.ZodString;
109
+ sm: z.ZodString;
110
+ md: z.ZodString;
111
+ lg: z.ZodString;
112
+ xl: z.ZodString;
113
+ full: z.ZodString;
114
+ }, z.core.$strip>;
115
+ }, z.core.$strip>;
116
+ export declare const WebsiteDesignTokensSchema: typeof _WebsiteDesignTokensSchema;
117
+ export type WebsiteDesignTokens = z.infer<typeof _WebsiteDesignTokensSchema>;
118
+ export {};
119
+ /** @wildo_source:part:end saas.website.design-tokens.bundle */
120
+ //# sourceMappingURL=website-design-tokens.shared.schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"website-design-tokens.shared.schemas.d.ts","sourceRoot":"","sources":["../../../../../src/schemas/design-tokens/website-design-tokens.shared.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA4DxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,QAAA,MAAM,yBAAyB;;;;;;;;;;;;iBAY7B,CAAC;AAEH,eAAO,MAAM,wBAAwB,EAAE,OAAO,yBAAqD,CAAC;AAEpG,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAC3E,+DAA+D;AAE/D;;;;;;;;;;;;;;;GAeG;AACH,QAAA,MAAM,0BAA0B;;;;;;;iBAO9B,CAAC;AAEH,eAAO,MAAM,yBAAyB,EAAE,OAAO,0BAAuD,CAAC;AAEvG,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAC7E,+DAA+D;AAE/D;;;;;;;;;;GAUG;AACH,QAAA,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;iBAG9B,CAAC;AAEH,eAAO,MAAM,yBAAyB,EAAE,OAAO,0BAAuD,CAAC;AAEvG,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;;AAC7E,+DAA+D"}
@@ -0,0 +1,152 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * CSS-injection-safe value validator shared by every design-token field.
4
+ *
5
+ * **Threat model** — TWO escape surfaces, BOTH covered:
6
+ *
7
+ * 1. CSS *declaration* break-out (Phase 6 third audit fix H-α):
8
+ * the renderer `renderWebsiteDesignTokensCss` interpolates token
9
+ * values **raw** into a `:root { --website-<group>-<token>: <value>; }`
10
+ * block. A value containing any of `;`, `}`, `{`, `/*`, `*\/`, or a
11
+ * newline can break out of the property declaration and inject
12
+ * arbitrary CSS — at minimum a config typo silently corrupts the
13
+ * page; at worst a malicious or untrusted config author injects a
14
+ * `body { display: none; }` rule that blanks the entire site.
15
+ *
16
+ * 2. HTML *style-element* break-out (Phase 6 fourth audit fix H-Χ):
17
+ * the rendered `:root { ... }` block is itself wrapped in an inline
18
+ * `<style>…</style>` element by the head renderer. Per the HTML spec
19
+ * the `<style>` element is a *raw-text* element — its only
20
+ * terminator is the literal sequence `</style`. A token value
21
+ * containing `<` (or, for symmetry, `>`) can therefore close the
22
+ * `<style>` element early and follow up with `<svg onload=alert(1)>`
23
+ * or any other HTML / JS payload, which the H-α deny-list (which
24
+ * did NOT forbid `<` / `>`) failed to catch. CSS values legitimately
25
+ * need NEITHER `<` NOR `>` (no CSS grammar uses them — no color,
26
+ * length, variable reference, calc expression, or functional
27
+ * notation does), so denying both is conservative and correct.
28
+ *
29
+ * **Why validate at the schema layer (not inside the renderer)**:
30
+ * 1. Fail at config load (build-time / boot-time), not at every
31
+ * `<head>` render — a malformed token surfaces in the schema-parse
32
+ * error message instead of silently emitting broken CSS / HTML.
33
+ * 2. Single source of truth — every field that flows into the
34
+ * `<style>`-wrapped CSS block gets the same guard (impossible to
35
+ * add a future token field that bypasses the renderer's escape
36
+ * pass).
37
+ * 3. The renderer stays a simple interpolator, which makes its own
38
+ * audit surface trivially small.
39
+ *
40
+ * **Why a `.refine` over a strict color-string regex**: colors accept
41
+ * `currentColor`, named colors, `var(--foo)` references, oklch
42
+ * functional notation, etc. — a strict positive grammar is ~80 lines
43
+ * and high-maintenance. A negative deny-list of the eight characters
44
+ * that are LITERALLY the only ones that can break out of either the CSS
45
+ * property declaration OR the wrapping `<style>` element is small,
46
+ * complete, and obviously correct.
47
+ */
48
+ const CSS_INJECTION_FORBIDDEN_PATTERN = /[;{}<>\n\r]|\/\*|\*\//;
49
+ const cssSafeValue = (fieldName) => z
50
+ .string()
51
+ .min(1, { error: `${fieldName} must not be empty` })
52
+ .refine((value) => !CSS_INJECTION_FORBIDDEN_PATTERN.test(value), {
53
+ error: `${fieldName} must not contain CSS-injection or HTML break-out ` +
54
+ `metacharacters (; { } < > /* */ newline) — token values are ` +
55
+ `interpolated raw into <style>:root { --website-...: <value>; }</style>`,
56
+ });
57
+ /**
58
+ * @wildo_source:part:start saas.website.design-tokens.colors facet:layer:shared facet:family:website
59
+ *
60
+ * `WebsiteColorTokens` — minimal palette the marketing-site exposes as
61
+ * CSS custom properties (`--website-color-<token>`) on the
62
+ * `<WebsitePageLayout>` root.
63
+ *
64
+ * **Why a dedicated marketing palette** (vs. reusing
65
+ * `presets-components-models/design-tokens-config`):
66
+ *
67
+ * - The SaaS app's design tokens carry many semantic states (`muted`,
68
+ * `destructive`, `ring`, `sidebar-*`, …) that have no marketing-site
69
+ * analogue. Forcing the website to consume the full palette would
70
+ * leak app-internal semantics into a public surface.
71
+ * - Marketing pages need *display-grade* colors (heavily branded
72
+ * accents, gradient stops, hero-overlay tints) that the SaaS app's
73
+ * functional palette deliberately avoids.
74
+ * - Designers overriding website tokens (Phase 6 dogfood proves this
75
+ * path) should not be able to break the SaaS app by editing one
76
+ * tailwind.config — the two surfaces stay decoupled.
77
+ *
78
+ * **Token format**: every value is a CSS color string. Shape validation
79
+ * is intentionally permissive (accepts hex, rgb/rgba, hsl/hsla, oklch,
80
+ * `currentColor`, named colors, CSS variable references) — a strict
81
+ * color-string regex would reject legitimate values (oklch grammar
82
+ * alone is ~80 lines) and a malformed-but-syntactically-valid color
83
+ * fails loudly at render time.
84
+ *
85
+ * **What IS strictly enforced**: every value passes `cssSafeValue`,
86
+ * which rejects the six characters that can break out of a CSS
87
+ * property declaration (`;`, `{`, `}`, `/*`, `*\/`, newline). See the
88
+ * `cssSafeValue` JSDoc above for the full threat model.
89
+ *
90
+ * **Adding a token**: append the field here using `cssSafeValue(...)`,
91
+ * document its semantic intent in the JSDoc, and update the matching
92
+ * CSS-emit helper in Phase 2 (`emitWebsiteColorTokensCss`).
93
+ */
94
+ const _WebsiteColorTokensSchema = z.object({
95
+ background: cssSafeValue('background color'),
96
+ foreground: cssSafeValue('foreground color'),
97
+ primary: cssSafeValue('primary color'),
98
+ primaryForeground: cssSafeValue('primaryForeground color'),
99
+ accent: cssSafeValue('accent color'),
100
+ accentForeground: cssSafeValue('accentForeground color'),
101
+ surface: cssSafeValue('surface color'),
102
+ surfaceForeground: cssSafeValue('surfaceForeground color'),
103
+ border: cssSafeValue('border color'),
104
+ muted: cssSafeValue('muted color'),
105
+ mutedForeground: cssSafeValue('mutedForeground color'),
106
+ });
107
+ export const WebsiteColorTokensSchema = _WebsiteColorTokensSchema;
108
+ /** @wildo_source:part:end saas.website.design-tokens.colors */
109
+ /**
110
+ * @wildo_source:part:start saas.website.design-tokens.radius facet:layer:shared facet:family:website
111
+ *
112
+ * `WebsiteRadiusTokens` — border-radius scale exposed as
113
+ * `--website-radius-<token>` CSS variables.
114
+ *
115
+ * Marketing radii are intentionally a separate token set from the
116
+ * SaaS app's radii: the website typically wants larger pill / hero
117
+ * radii than the app's compact-UI radii. Keeping them separate lets
118
+ * either surface evolve without coupling.
119
+ *
120
+ * Values are CSS length strings (`'0.25rem'`, `'12px'`,
121
+ * `'9999px'`). Same permissive-shape + strict-CSS-injection
122
+ * rationale as `WebsiteColorTokens` (every value runs through
123
+ * `cssSafeValue`).
124
+ */
125
+ const _WebsiteRadiusTokensSchema = z.object({
126
+ none: cssSafeValue('none radius'),
127
+ sm: cssSafeValue('sm radius'),
128
+ md: cssSafeValue('md radius'),
129
+ lg: cssSafeValue('lg radius'),
130
+ xl: cssSafeValue('xl radius'),
131
+ full: cssSafeValue('full radius'),
132
+ });
133
+ export const WebsiteRadiusTokensSchema = _WebsiteRadiusTokensSchema;
134
+ /** @wildo_source:part:end saas.website.design-tokens.radius */
135
+ /**
136
+ * @wildo_source:part:start saas.website.design-tokens.bundle facet:layer:shared facet:family:website
137
+ *
138
+ * `WebsiteDesignTokens` — the complete design-token bundle attached to
139
+ * `WebsiteRootConfig.designTokens`. Currently colors + radii only
140
+ * (per plan Phase 1 scope: "WebsiteColorTokensSchema + WebsiteRadiusTokensSchema (only)").
141
+ *
142
+ * Future expansions (typography scale, motion tokens, shadow elevation)
143
+ * will land as additional fields here without breaking the
144
+ * `WebsiteRootConfig` shape.
145
+ */
146
+ const _WebsiteDesignTokensSchema = z.object({
147
+ colors: _WebsiteColorTokensSchema,
148
+ radii: _WebsiteRadiusTokensSchema,
149
+ });
150
+ export const WebsiteDesignTokensSchema = _WebsiteDesignTokensSchema;
151
+ /** @wildo_source:part:end saas.website.design-tokens.bundle */
152
+ //# sourceMappingURL=website-design-tokens.shared.schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"website-design-tokens.shared.schemas.js","sourceRoot":"","sources":["../../../../../src/schemas/design-tokens/website-design-tokens.shared.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,MAAM,+BAA+B,GAAG,uBAAuB,CAAC;AAChE,MAAM,YAAY,GAAG,CAAC,SAAiB,EAAe,EAAE,CACtD,CAAC;KACE,MAAM,EAAE;KACR,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,SAAS,oBAAoB,EAAE,CAAC;KACnD,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,+BAA+B,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;IAC/D,KAAK,EACH,GAAG,SAAS,oDAAoD;QAChE,8DAA8D;QAC9D,wEAAwE;CAC3E,CAA2B,CAAC;AAEjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,UAAU,EAAE,YAAY,CAAC,kBAAkB,CAAC;IAC5C,UAAU,EAAE,YAAY,CAAC,kBAAkB,CAAC;IAC5C,OAAO,EAAE,YAAY,CAAC,eAAe,CAAC;IACtC,iBAAiB,EAAE,YAAY,CAAC,yBAAyB,CAAC;IAC1D,MAAM,EAAE,YAAY,CAAC,cAAc,CAAC;IACpC,gBAAgB,EAAE,YAAY,CAAC,wBAAwB,CAAC;IACxD,OAAO,EAAE,YAAY,CAAC,eAAe,CAAC;IACtC,iBAAiB,EAAE,YAAY,CAAC,yBAAyB,CAAC;IAC1D,MAAM,EAAE,YAAY,CAAC,cAAc,CAAC;IACpC,KAAK,EAAE,YAAY,CAAC,aAAa,CAAC;IAClC,eAAe,EAAE,YAAY,CAAC,uBAAuB,CAAC;CACvD,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAqC,yBAAyB,CAAC;AAGpG,+DAA+D;AAE/D;;;;;;;;;;;;;;;GAeG;AACH,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,IAAI,EAAE,YAAY,CAAC,aAAa,CAAC;IACjC,EAAE,EAAE,YAAY,CAAC,WAAW,CAAC;IAC7B,EAAE,EAAE,YAAY,CAAC,WAAW,CAAC;IAC7B,EAAE,EAAE,YAAY,CAAC,WAAW,CAAC;IAC7B,EAAE,EAAE,YAAY,CAAC,WAAW,CAAC;IAC7B,IAAI,EAAE,YAAY,CAAC,aAAa,CAAC;CAClC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,yBAAyB,GAAsC,0BAA0B,CAAC;AAGvG,+DAA+D;AAE/D;;;;;;;;;;GAUG;AACH,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,MAAM,EAAE,yBAAyB;IACjC,KAAK,EAAE,0BAA0B;CAClC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,yBAAyB,GAAsC,0BAA0B,CAAC;AAGvG,+DAA+D","sourcesContent":["import { z } from 'zod';\n\n/**\n * CSS-injection-safe value validator shared by every design-token field.\n *\n * **Threat model** — TWO escape surfaces, BOTH covered:\n *\n * 1. CSS *declaration* break-out (Phase 6 third audit fix H-α):\n * the renderer `renderWebsiteDesignTokensCss` interpolates token\n * values **raw** into a `:root { --website-<group>-<token>: <value>; }`\n * block. A value containing any of `;`, `}`, `{`, `/*`, `*\\/`, or a\n * newline can break out of the property declaration and inject\n * arbitrary CSS — at minimum a config typo silently corrupts the\n * page; at worst a malicious or untrusted config author injects a\n * `body { display: none; }` rule that blanks the entire site.\n *\n * 2. HTML *style-element* break-out (Phase 6 fourth audit fix H-Χ):\n * the rendered `:root { ... }` block is itself wrapped in an inline\n * `<style>…</style>` element by the head renderer. Per the HTML spec\n * the `<style>` element is a *raw-text* element — its only\n * terminator is the literal sequence `</style`. A token value\n * containing `<` (or, for symmetry, `>`) can therefore close the\n * `<style>` element early and follow up with `<svg onload=alert(1)>`\n * or any other HTML / JS payload, which the H-α deny-list (which\n * did NOT forbid `<` / `>`) failed to catch. CSS values legitimately\n * need NEITHER `<` NOR `>` (no CSS grammar uses them — no color,\n * length, variable reference, calc expression, or functional\n * notation does), so denying both is conservative and correct.\n *\n * **Why validate at the schema layer (not inside the renderer)**:\n * 1. Fail at config load (build-time / boot-time), not at every\n * `<head>` render — a malformed token surfaces in the schema-parse\n * error message instead of silently emitting broken CSS / HTML.\n * 2. Single source of truth — every field that flows into the\n * `<style>`-wrapped CSS block gets the same guard (impossible to\n * add a future token field that bypasses the renderer's escape\n * pass).\n * 3. The renderer stays a simple interpolator, which makes its own\n * audit surface trivially small.\n *\n * **Why a `.refine` over a strict color-string regex**: colors accept\n * `currentColor`, named colors, `var(--foo)` references, oklch\n * functional notation, etc. — a strict positive grammar is ~80 lines\n * and high-maintenance. A negative deny-list of the eight characters\n * that are LITERALLY the only ones that can break out of either the CSS\n * property declaration OR the wrapping `<style>` element is small,\n * complete, and obviously correct.\n */\nconst CSS_INJECTION_FORBIDDEN_PATTERN = /[;{}<>\\n\\r]|\\/\\*|\\*\\//;\nconst cssSafeValue = (fieldName: string): z.ZodString =>\n z\n .string()\n .min(1, { error: `${fieldName} must not be empty` })\n .refine((value) => !CSS_INJECTION_FORBIDDEN_PATTERN.test(value), {\n error:\n `${fieldName} must not contain CSS-injection or HTML break-out ` +\n `metacharacters (; { } < > /* */ newline) — token values are ` +\n `interpolated raw into <style>:root { --website-...: <value>; }</style>`,\n }) as unknown as z.ZodString;\n\n/**\n * @wildo_source:part:start saas.website.design-tokens.colors facet:layer:shared facet:family:website\n *\n * `WebsiteColorTokens` — minimal palette the marketing-site exposes as\n * CSS custom properties (`--website-color-<token>`) on the\n * `<WebsitePageLayout>` root.\n *\n * **Why a dedicated marketing palette** (vs. reusing\n * `presets-components-models/design-tokens-config`):\n *\n * - The SaaS app's design tokens carry many semantic states (`muted`,\n * `destructive`, `ring`, `sidebar-*`, …) that have no marketing-site\n * analogue. Forcing the website to consume the full palette would\n * leak app-internal semantics into a public surface.\n * - Marketing pages need *display-grade* colors (heavily branded\n * accents, gradient stops, hero-overlay tints) that the SaaS app's\n * functional palette deliberately avoids.\n * - Designers overriding website tokens (Phase 6 dogfood proves this\n * path) should not be able to break the SaaS app by editing one\n * tailwind.config — the two surfaces stay decoupled.\n *\n * **Token format**: every value is a CSS color string. Shape validation\n * is intentionally permissive (accepts hex, rgb/rgba, hsl/hsla, oklch,\n * `currentColor`, named colors, CSS variable references) — a strict\n * color-string regex would reject legitimate values (oklch grammar\n * alone is ~80 lines) and a malformed-but-syntactically-valid color\n * fails loudly at render time.\n *\n * **What IS strictly enforced**: every value passes `cssSafeValue`,\n * which rejects the six characters that can break out of a CSS\n * property declaration (`;`, `{`, `}`, `/*`, `*\\/`, newline). See the\n * `cssSafeValue` JSDoc above for the full threat model.\n *\n * **Adding a token**: append the field here using `cssSafeValue(...)`,\n * document its semantic intent in the JSDoc, and update the matching\n * CSS-emit helper in Phase 2 (`emitWebsiteColorTokensCss`).\n */\nconst _WebsiteColorTokensSchema = z.object({\n background: cssSafeValue('background color'),\n foreground: cssSafeValue('foreground color'),\n primary: cssSafeValue('primary color'),\n primaryForeground: cssSafeValue('primaryForeground color'),\n accent: cssSafeValue('accent color'),\n accentForeground: cssSafeValue('accentForeground color'),\n surface: cssSafeValue('surface color'),\n surfaceForeground: cssSafeValue('surfaceForeground color'),\n border: cssSafeValue('border color'),\n muted: cssSafeValue('muted color'),\n mutedForeground: cssSafeValue('mutedForeground color'),\n});\n\nexport const WebsiteColorTokensSchema: typeof _WebsiteColorTokensSchema = _WebsiteColorTokensSchema;\n\nexport type WebsiteColorTokens = z.infer<typeof _WebsiteColorTokensSchema>;\n/** @wildo_source:part:end saas.website.design-tokens.colors */\n\n/**\n * @wildo_source:part:start saas.website.design-tokens.radius facet:layer:shared facet:family:website\n *\n * `WebsiteRadiusTokens` — border-radius scale exposed as\n * `--website-radius-<token>` CSS variables.\n *\n * Marketing radii are intentionally a separate token set from the\n * SaaS app's radii: the website typically wants larger pill / hero\n * radii than the app's compact-UI radii. Keeping them separate lets\n * either surface evolve without coupling.\n *\n * Values are CSS length strings (`'0.25rem'`, `'12px'`,\n * `'9999px'`). Same permissive-shape + strict-CSS-injection\n * rationale as `WebsiteColorTokens` (every value runs through\n * `cssSafeValue`).\n */\nconst _WebsiteRadiusTokensSchema = z.object({\n none: cssSafeValue('none radius'),\n sm: cssSafeValue('sm radius'),\n md: cssSafeValue('md radius'),\n lg: cssSafeValue('lg radius'),\n xl: cssSafeValue('xl radius'),\n full: cssSafeValue('full radius'),\n});\n\nexport const WebsiteRadiusTokensSchema: typeof _WebsiteRadiusTokensSchema = _WebsiteRadiusTokensSchema;\n\nexport type WebsiteRadiusTokens = z.infer<typeof _WebsiteRadiusTokensSchema>;\n/** @wildo_source:part:end saas.website.design-tokens.radius */\n\n/**\n * @wildo_source:part:start saas.website.design-tokens.bundle facet:layer:shared facet:family:website\n *\n * `WebsiteDesignTokens` — the complete design-token bundle attached to\n * `WebsiteRootConfig.designTokens`. Currently colors + radii only\n * (per plan Phase 1 scope: \"WebsiteColorTokensSchema + WebsiteRadiusTokensSchema (only)\").\n *\n * Future expansions (typography scale, motion tokens, shadow elevation)\n * will land as additional fields here without breaking the\n * `WebsiteRootConfig` shape.\n */\nconst _WebsiteDesignTokensSchema = z.object({\n colors: _WebsiteColorTokensSchema,\n radii: _WebsiteRadiusTokensSchema,\n});\n\nexport const WebsiteDesignTokensSchema: typeof _WebsiteDesignTokensSchema = _WebsiteDesignTokensSchema;\n\nexport type WebsiteDesignTokens = z.infer<typeof _WebsiteDesignTokensSchema>;\n/** @wildo_source:part:end saas.website.design-tokens.bundle */\n"]}
@@ -0,0 +1,73 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * @wildo_source:part:start saas.website.label-keys.format facet:layer:shared facet:family:i18n
4
+ *
5
+ * `WebsiteLabelKey` — branded i18n key for marketing-site copy.
6
+ *
7
+ * **Format**: `website.<pageRef>.<sectionRef>.<slotPath>`
8
+ *
9
+ * - `website.` — fixed namespace prefix that disambiguates marketing-site
10
+ * labels from app i18n keys (`labels.`, `errors.`, `notifications.`).
11
+ * Marketing-site label packs ship as a separate file per locale
12
+ * (`website/src/i18n/<locale>.json`) so they never bloat the SaaS app
13
+ * bundle.
14
+ * - `<pageRef>` — kebab-case page ref (validated independently by
15
+ * `WebsitePageRefSchema`).
16
+ * - `<sectionRef>` — kebab-case section ref (validated independently by
17
+ * `WebsiteSectionRefSchema`).
18
+ * - `<slotPath>` — leaf identifier the section consumes via
19
+ * `useWebsiteLabel('<slotPath>')` (Phase 2). Allows dots for nested
20
+ * structures (`'cta.primary'`), brackets for indexed array slots
21
+ * (`'tiers[0].name'`), and hyphens for multi-word leaves.
22
+ *
23
+ * **Examples**:
24
+ * - `website.landing.hero.headline`
25
+ * - `website.landing.hero.cta.primary`
26
+ * - `website.pricing.tiers.tiers[0].name`
27
+ * - `website.contact.form.field.email-placeholder`
28
+ *
29
+ * **Why a brand**: prevents the "label key as bare string" failure mode
30
+ * where a typo in `'webiste.landing.hero.headline'` (note the typo) silently
31
+ * resolves to undefined at runtime. Sections must accept
32
+ * `WebsiteLabelKey`-typed props; consumers go through
33
+ * `WebsiteLabelKeySchema.parse(...)` (or the manifest's `metaLabelKeys`
34
+ * fields, which are typed against this schema) before a string flows into
35
+ * label resolution.
36
+ *
37
+ * **Why a single regex**: the three nested refs (`page`, `section`, `slot`)
38
+ * are validated separately by their own schemas inside the `defineWebsiteSection`
39
+ * factory and `WebsitePageManifestSchema`. This schema's job is to validate
40
+ * a fully-composed key — typically inserted directly into JSX as a string
41
+ * literal — without re-parsing the parts.
42
+ */
43
+ declare const _WebsiteLabelKeySchema: z.core.$ZodBranded<z.ZodString, "WebsiteLabelKey", "out">;
44
+ export declare const WebsiteLabelKeySchema: typeof _WebsiteLabelKeySchema;
45
+ export type WebsiteLabelKey = z.infer<typeof _WebsiteLabelKeySchema>;
46
+ /** @wildo_source:part:end saas.website.label-keys.format */
47
+ /**
48
+ * @wildo_source:part:start saas.website.label-keys.compose-helper facet:layer:shared facet:family:i18n
49
+ *
50
+ * `composeWebsiteLabelKey` — pure helper that composes a `WebsiteLabelKey`
51
+ * from its three parts. Used by `useWebsiteLabel` (Phase 2) and by the
52
+ * label-pack validator to materialize the keys a section commits to.
53
+ *
54
+ * Returns the key as a parsed `WebsiteLabelKey` (brand applied), throwing
55
+ * if the composed string fails the format check (defensive guard against
56
+ * stale refs / inconsistent slot paths leaking past type-system narrowing).
57
+ *
58
+ * @example
59
+ * composeWebsiteLabelKey({
60
+ * pageRef: WebsitePageRefSchema.parse('landing'),
61
+ * sectionRef: WebsiteSectionRefSchema.parse('hero'),
62
+ * slotPath: 'headline',
63
+ * });
64
+ * // -> WebsiteLabelKey ("website.landing.hero.headline")
65
+ */
66
+ export declare function composeWebsiteLabelKey(parts: {
67
+ pageRef: string;
68
+ sectionRef: string;
69
+ slotPath: string;
70
+ }): WebsiteLabelKey;
71
+ export {};
72
+ /** @wildo_source:part:end saas.website.label-keys.compose-helper */
73
+ //# sourceMappingURL=website-label-key.schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"website-label-key.schemas.d.ts","sourceRoot":"","sources":["../../../../../src/schemas/label-keys/website-label-key.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,QAAA,MAAM,sBAAsB,2DAWC,CAAC;AAE9B,eAAO,MAAM,qBAAqB,EAAE,OAAO,sBAA+C,CAAC;AAE3F,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACrE,4DAA4D;AAE5D;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,eAAe,CAElB;;AACD,oEAAoE"}
@@ -0,0 +1,76 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * @wildo_source:part:start saas.website.label-keys.format facet:layer:shared facet:family:i18n
4
+ *
5
+ * `WebsiteLabelKey` — branded i18n key for marketing-site copy.
6
+ *
7
+ * **Format**: `website.<pageRef>.<sectionRef>.<slotPath>`
8
+ *
9
+ * - `website.` — fixed namespace prefix that disambiguates marketing-site
10
+ * labels from app i18n keys (`labels.`, `errors.`, `notifications.`).
11
+ * Marketing-site label packs ship as a separate file per locale
12
+ * (`website/src/i18n/<locale>.json`) so they never bloat the SaaS app
13
+ * bundle.
14
+ * - `<pageRef>` — kebab-case page ref (validated independently by
15
+ * `WebsitePageRefSchema`).
16
+ * - `<sectionRef>` — kebab-case section ref (validated independently by
17
+ * `WebsiteSectionRefSchema`).
18
+ * - `<slotPath>` — leaf identifier the section consumes via
19
+ * `useWebsiteLabel('<slotPath>')` (Phase 2). Allows dots for nested
20
+ * structures (`'cta.primary'`), brackets for indexed array slots
21
+ * (`'tiers[0].name'`), and hyphens for multi-word leaves.
22
+ *
23
+ * **Examples**:
24
+ * - `website.landing.hero.headline`
25
+ * - `website.landing.hero.cta.primary`
26
+ * - `website.pricing.tiers.tiers[0].name`
27
+ * - `website.contact.form.field.email-placeholder`
28
+ *
29
+ * **Why a brand**: prevents the "label key as bare string" failure mode
30
+ * where a typo in `'webiste.landing.hero.headline'` (note the typo) silently
31
+ * resolves to undefined at runtime. Sections must accept
32
+ * `WebsiteLabelKey`-typed props; consumers go through
33
+ * `WebsiteLabelKeySchema.parse(...)` (or the manifest's `metaLabelKeys`
34
+ * fields, which are typed against this schema) before a string flows into
35
+ * label resolution.
36
+ *
37
+ * **Why a single regex**: the three nested refs (`page`, `section`, `slot`)
38
+ * are validated separately by their own schemas inside the `defineWebsiteSection`
39
+ * factory and `WebsitePageManifestSchema`. This schema's job is to validate
40
+ * a fully-composed key — typically inserted directly into JSX as a string
41
+ * literal — without re-parsing the parts.
42
+ */
43
+ const _WebsiteLabelKeySchema = z
44
+ .string()
45
+ .min(10, { error: 'WebsiteLabelKey is too short (must include website.<page>.<section>.<slot>)' })
46
+ .max(256, { error: 'WebsiteLabelKey must be at most 256 characters' })
47
+ .regex(/^website\.[a-z][a-z0-9-]*\.[a-z][a-z0-9-]*\.[a-zA-Z0-9.\[\]_-]+$/, {
48
+ error: 'WebsiteLabelKey must match `website.<page>.<section>.<slot>` where page/section are kebab-case and slot allows dot/bracket/hyphen/underscore (e.g. "website.landing.hero.headline")',
49
+ })
50
+ .brand();
51
+ export const WebsiteLabelKeySchema = _WebsiteLabelKeySchema;
52
+ /** @wildo_source:part:end saas.website.label-keys.format */
53
+ /**
54
+ * @wildo_source:part:start saas.website.label-keys.compose-helper facet:layer:shared facet:family:i18n
55
+ *
56
+ * `composeWebsiteLabelKey` — pure helper that composes a `WebsiteLabelKey`
57
+ * from its three parts. Used by `useWebsiteLabel` (Phase 2) and by the
58
+ * label-pack validator to materialize the keys a section commits to.
59
+ *
60
+ * Returns the key as a parsed `WebsiteLabelKey` (brand applied), throwing
61
+ * if the composed string fails the format check (defensive guard against
62
+ * stale refs / inconsistent slot paths leaking past type-system narrowing).
63
+ *
64
+ * @example
65
+ * composeWebsiteLabelKey({
66
+ * pageRef: WebsitePageRefSchema.parse('landing'),
67
+ * sectionRef: WebsiteSectionRefSchema.parse('hero'),
68
+ * slotPath: 'headline',
69
+ * });
70
+ * // -> WebsiteLabelKey ("website.landing.hero.headline")
71
+ */
72
+ export function composeWebsiteLabelKey(parts) {
73
+ return WebsiteLabelKeySchema.parse(`website.${parts.pageRef}.${parts.sectionRef}.${parts.slotPath}`);
74
+ }
75
+ /** @wildo_source:part:end saas.website.label-keys.compose-helper */
76
+ //# sourceMappingURL=website-label-key.schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"website-label-key.schemas.js","sourceRoot":"","sources":["../../../../../src/schemas/label-keys/website-label-key.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,MAAM,sBAAsB,GAAG,CAAC;KAC7B,MAAM,EAAE;KACR,GAAG,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,6EAA6E,EAAE,CAAC;KACjG,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,gDAAgD,EAAE,CAAC;KACrE,KAAK,CACJ,kEAAkE,EAClE;IACE,KAAK,EACH,qLAAqL;CACxL,CACF;KACA,KAAK,EAAqB,CAAC;AAE9B,MAAM,CAAC,MAAM,qBAAqB,GAAkC,sBAAsB,CAAC;AAG3F,4DAA4D;AAE5D;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAItC;IACC,OAAO,qBAAqB,CAAC,KAAK,CAAC,WAAW,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;AACvG,CAAC;AACD,oEAAoE","sourcesContent":["import { z } from 'zod';\n\n/**\n * @wildo_source:part:start saas.website.label-keys.format facet:layer:shared facet:family:i18n\n *\n * `WebsiteLabelKey` — branded i18n key for marketing-site copy.\n *\n * **Format**: `website.<pageRef>.<sectionRef>.<slotPath>`\n *\n * - `website.` — fixed namespace prefix that disambiguates marketing-site\n * labels from app i18n keys (`labels.`, `errors.`, `notifications.`).\n * Marketing-site label packs ship as a separate file per locale\n * (`website/src/i18n/<locale>.json`) so they never bloat the SaaS app\n * bundle.\n * - `<pageRef>` — kebab-case page ref (validated independently by\n * `WebsitePageRefSchema`).\n * - `<sectionRef>` — kebab-case section ref (validated independently by\n * `WebsiteSectionRefSchema`).\n * - `<slotPath>` — leaf identifier the section consumes via\n * `useWebsiteLabel('<slotPath>')` (Phase 2). Allows dots for nested\n * structures (`'cta.primary'`), brackets for indexed array slots\n * (`'tiers[0].name'`), and hyphens for multi-word leaves.\n *\n * **Examples**:\n * - `website.landing.hero.headline`\n * - `website.landing.hero.cta.primary`\n * - `website.pricing.tiers.tiers[0].name`\n * - `website.contact.form.field.email-placeholder`\n *\n * **Why a brand**: prevents the \"label key as bare string\" failure mode\n * where a typo in `'webiste.landing.hero.headline'` (note the typo) silently\n * resolves to undefined at runtime. Sections must accept\n * `WebsiteLabelKey`-typed props; consumers go through\n * `WebsiteLabelKeySchema.parse(...)` (or the manifest's `metaLabelKeys`\n * fields, which are typed against this schema) before a string flows into\n * label resolution.\n *\n * **Why a single regex**: the three nested refs (`page`, `section`, `slot`)\n * are validated separately by their own schemas inside the `defineWebsiteSection`\n * factory and `WebsitePageManifestSchema`. This schema's job is to validate\n * a fully-composed key — typically inserted directly into JSX as a string\n * literal — without re-parsing the parts.\n */\nconst _WebsiteLabelKeySchema = z\n .string()\n .min(10, { error: 'WebsiteLabelKey is too short (must include website.<page>.<section>.<slot>)' })\n .max(256, { error: 'WebsiteLabelKey must be at most 256 characters' })\n .regex(\n /^website\\.[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*\\.[a-zA-Z0-9.\\[\\]_-]+$/,\n {\n error:\n 'WebsiteLabelKey must match `website.<page>.<section>.<slot>` where page/section are kebab-case and slot allows dot/bracket/hyphen/underscore (e.g. \"website.landing.hero.headline\")',\n },\n )\n .brand<'WebsiteLabelKey'>();\n\nexport const WebsiteLabelKeySchema: typeof _WebsiteLabelKeySchema = _WebsiteLabelKeySchema;\n\nexport type WebsiteLabelKey = z.infer<typeof _WebsiteLabelKeySchema>;\n/** @wildo_source:part:end saas.website.label-keys.format */\n\n/**\n * @wildo_source:part:start saas.website.label-keys.compose-helper facet:layer:shared facet:family:i18n\n *\n * `composeWebsiteLabelKey` — pure helper that composes a `WebsiteLabelKey`\n * from its three parts. Used by `useWebsiteLabel` (Phase 2) and by the\n * label-pack validator to materialize the keys a section commits to.\n *\n * Returns the key as a parsed `WebsiteLabelKey` (brand applied), throwing\n * if the composed string fails the format check (defensive guard against\n * stale refs / inconsistent slot paths leaking past type-system narrowing).\n *\n * @example\n * composeWebsiteLabelKey({\n * pageRef: WebsitePageRefSchema.parse('landing'),\n * sectionRef: WebsiteSectionRefSchema.parse('hero'),\n * slotPath: 'headline',\n * });\n * // -> WebsiteLabelKey (\"website.landing.hero.headline\")\n */\nexport function composeWebsiteLabelKey(parts: {\n pageRef: string;\n sectionRef: string;\n slotPath: string;\n}): WebsiteLabelKey {\n return WebsiteLabelKeySchema.parse(`website.${parts.pageRef}.${parts.sectionRef}.${parts.slotPath}`);\n}\n/** @wildo_source:part:end saas.website.label-keys.compose-helper */\n"]}