@warpgogol/werkstatt-shared 0.2.0

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 (403) hide show
  1. package/package.json +352 -0
  2. package/src/checks/index.ts +24 -0
  3. package/src/checks/lib/astro-site-url.ts +30 -0
  4. package/src/checks/lib/i18n.ts +30 -0
  5. package/src/checks/result-helpers.ts +102 -0
  6. package/src/checks/suppressions-config.ts +195 -0
  7. package/src/index.ts +14 -0
  8. package/src/integration/README.md +38 -0
  9. package/src/integration/adapters.ts +143 -0
  10. package/src/integration/crm-buffer.ts +491 -0
  11. package/src/integration/dispatch.ts +106 -0
  12. package/src/integration/funnel.ts +379 -0
  13. package/src/integration/index.ts +56 -0
  14. package/src/integration/lifecycle.ts +155 -0
  15. package/src/integration/orchestration.ts +439 -0
  16. package/src/integration/port-barrel.ts +124 -0
  17. package/src/integration/port.ts +143 -0
  18. package/src/integration/qstash.ts +134 -0
  19. package/src/integration/sharding.ts +133 -0
  20. package/src/integration/tests/deliver-event.test.ts +52 -0
  21. package/src/integration/tests/dispatch.test.ts +88 -0
  22. package/src/integration/tests/funnel-bridge.test.ts +46 -0
  23. package/src/integration/tests/hub-runtime.test.ts +128 -0
  24. package/src/integration/tests/lifecycle.test.ts +69 -0
  25. package/src/integration/tests/qstash.test.ts +83 -0
  26. package/src/integration/tests/sharding.test.ts +64 -0
  27. package/src/integration/vitest.config.ts +8 -0
  28. package/src/integration-adapter-supabase-crm/adapter.ts +437 -0
  29. package/src/integration-adapter-supabase-crm/client.ts +605 -0
  30. package/src/integration-adapter-supabase-crm/index.ts +28 -0
  31. package/src/integration-adapter-supabase-crm/pipedrive-sync-target.ts +482 -0
  32. package/src/integration-adapter-supabase-crm/supabase-rest.ts +89 -0
  33. package/src/integration-adapter-supabase-crm/tenant-registry.ts +334 -0
  34. package/src/integration-adapter-supabase-crm/tests/change-balance.pbt.test.ts +83 -0
  35. package/src/integration-adapter-supabase-crm/tests/funnel-persistence.test.ts +409 -0
  36. package/src/integration-adapter-supabase-crm/tests/lifecycle-sync.test.ts +288 -0
  37. package/src/integration-adapter-supabase-crm/tests/stage-map.test.ts +80 -0
  38. package/src/integration-adapter-supabase-crm/vitest.config.ts +8 -0
  39. package/src/integration-adapter-supabase-crm/worker.ts +223 -0
  40. package/src/observability/conventions.ts +93 -0
  41. package/src/observability/env-resolver.ts +57 -0
  42. package/src/observability/index.ts +57 -0
  43. package/src/observability/metric-registry.ts +184 -0
  44. package/src/observability/otlp-converter.ts +125 -0
  45. package/src/observability/otlp-json.ts +135 -0
  46. package/src/observability/otlp-transport.ts +68 -0
  47. package/src/observability/pusher.ts +142 -0
  48. package/src/observability/redact.ts +27 -0
  49. package/src/observability/tests/conventions.test.ts +100 -0
  50. package/src/observability/tests/metric-registry.test.ts +117 -0
  51. package/src/observability/tests/otlp-converter.pbt.test.ts +77 -0
  52. package/src/observability/tests/otlp-converter.test.ts +157 -0
  53. package/src/observability/tests/otlp-json.test.ts +120 -0
  54. package/src/observability/tests/pusher.test.ts +75 -0
  55. package/src/observability/tests/redact.pbt.test.ts +71 -0
  56. package/src/observability/tests/redact.test.ts +37 -0
  57. package/src/observability/typed-refs.ts +137 -0
  58. package/src/observability/vitest.config.ts +8 -0
  59. package/src/ontology/analytics/matomo-binding.yaml +172 -0
  60. package/src/ontology/analytics/matomo-fleet.registry.yaml +26 -0
  61. package/src/ontology/analytics/messkanon.yaml +151 -0
  62. package/src/ontology/archetype-registry.ts +61 -0
  63. package/src/ontology/archetypes/components/brand-label.yaml +19 -0
  64. package/src/ontology/archetypes/components/copyright.yaml +19 -0
  65. package/src/ontology/archetypes/components/currency-aware-price-display.yaml +19 -0
  66. package/src/ontology/archetypes/components/currency-selector.yaml +19 -0
  67. package/src/ontology/archetypes/components/footer-promo.yaml +19 -0
  68. package/src/ontology/archetypes/components/lang-switcher.yaml +19 -0
  69. package/src/ontology/archetypes/components/layout.yaml +19 -0
  70. package/src/ontology/archetypes/components/live-photo.yaml +20 -0
  71. package/src/ontology/archetypes/components/material-credit.yaml +20 -0
  72. package/src/ontology/archetypes/components/media.yaml +21 -0
  73. package/src/ontology/archetypes/components/nachweis-card.yaml +34 -0
  74. package/src/ontology/archetypes/components/nachweis-detail.yaml +43 -0
  75. package/src/ontology/archetypes/components/nachweis-list.yaml +37 -0
  76. package/src/ontology/archetypes/components/nachweis-verify.yaml +31 -0
  77. package/src/ontology/archetypes/components/not-found.yaml +22 -0
  78. package/src/ontology/archetypes/components/offer-capacity.yaml +21 -0
  79. package/src/ontology/archetypes/components/passport-header.yaml +19 -0
  80. package/src/ontology/archetypes/components/passport-provenance.yaml +20 -0
  81. package/src/ontology/archetypes/components/passport-score-grid.yaml +20 -0
  82. package/src/ontology/archetypes/components/passport-star-map.yaml +20 -0
  83. package/src/ontology/archetypes/components/person-profile.yaml +20 -0
  84. package/src/ontology/archetypes/components/pulsar.yaml +20 -0
  85. package/src/ontology/archetypes/components/responsive-image.yaml +19 -0
  86. package/src/ontology/archetypes/components/scroll-to-top.yaml +22 -0
  87. package/src/ontology/archetypes/components/social-meta.yaml +20 -0
  88. package/src/ontology/archetypes/components/structured-data.yaml +19 -0
  89. package/src/ontology/archetypes/index.json +1003 -0
  90. package/src/ontology/archetypes/index.yaml +821 -0
  91. package/src/ontology/archetypes/sections/approach.yaml +23 -0
  92. package/src/ontology/archetypes/sections/article-list.yaml +30 -0
  93. package/src/ontology/archetypes/sections/audience-cards.yaml +30 -0
  94. package/src/ontology/archetypes/sections/breadcrumbs.yaml +21 -0
  95. package/src/ontology/archetypes/sections/chat-widget.yaml +37 -0
  96. package/src/ontology/archetypes/sections/comparison-cards.yaml +31 -0
  97. package/src/ontology/archetypes/sections/controlled-responsibility-block.yaml +34 -0
  98. package/src/ontology/archetypes/sections/credits.yaml +29 -0
  99. package/src/ontology/archetypes/sections/donation-card.yaml +53 -0
  100. package/src/ontology/archetypes/sections/donation-use.yaml +23 -0
  101. package/src/ontology/archetypes/sections/dynamic-status-block.yaml +35 -0
  102. package/src/ontology/archetypes/sections/faq-list.yaml +26 -0
  103. package/src/ontology/archetypes/sections/final-cta.yaml +53 -0
  104. package/src/ontology/archetypes/sections/hero-decision-card.yaml +65 -0
  105. package/src/ontology/archetypes/sections/hero.yaml +50 -0
  106. package/src/ontology/archetypes/sections/impact.yaml +23 -0
  107. package/src/ontology/archetypes/sections/markdown.yaml +43 -0
  108. package/src/ontology/archetypes/sections/mountain-journey.yaml +43 -0
  109. package/src/ontology/archetypes/sections/navigation.yaml +20 -0
  110. package/src/ontology/archetypes/sections/notausgang-block.yaml +41 -0
  111. package/src/ontology/archetypes/sections/open-source-registry.yaml +26 -0
  112. package/src/ontology/archetypes/sections/ownership-block.yaml +57 -0
  113. package/src/ontology/archetypes/sections/people.yaml +48 -0
  114. package/src/ontology/archetypes/sections/price-card.yaml +50 -0
  115. package/src/ontology/archetypes/sections/problem.yaml +23 -0
  116. package/src/ontology/archetypes/sections/send-message.yaml +63 -0
  117. package/src/ontology/archetypes/sections/service-metadata-block.yaml +40 -0
  118. package/src/ontology/archetypes/sections/social-proof.yaml +27 -0
  119. package/src/ontology/archetypes/sections/transparency.yaml +32 -0
  120. package/src/ontology/archetypes/sections/trust-strip.yaml +42 -0
  121. package/src/ontology/archetypes/sections/video-section.yaml +27 -0
  122. package/src/ontology/archetypes/sections/women.yaml +29 -0
  123. package/src/ontology/biome-token-projection.ts +229 -0
  124. package/src/ontology/biomes/check-concrete-blueprint.yaml +118 -0
  125. package/src/ontology/biomes/handwerk-material-warm.yaml +135 -0
  126. package/src/ontology/biomes/nonprofit-trust.yaml +123 -0
  127. package/src/ontology/blueprints/offer.yaml +39 -0
  128. package/src/ontology/blueprints/prompts/local-market-signal.md +13 -0
  129. package/src/ontology/blueprints/prompts/website-local-narrative.md +24 -0
  130. package/src/ontology/blueprints/ratgeber.yaml +62 -0
  131. package/src/ontology/blueprints/website-local.yaml +309 -0
  132. package/src/ontology/blueprints/website-service.yaml +84 -0
  133. package/src/ontology/capabilities/lead.submit.yaml +44 -0
  134. package/src/ontology/cosmic/index.ts +48 -0
  135. package/src/ontology/cosmic/moon-catalog.ts +173 -0
  136. package/src/ontology/cosmic/planet-catalog.ts +82 -0
  137. package/src/ontology/cosmic/star-catalog.ts +337 -0
  138. package/src/ontology/enums.ts +159 -0
  139. package/src/ontology/external-surfaces/index.ts +158 -0
  140. package/src/ontology/external-surfaces/jsonld-types.yaml +135 -0
  141. package/src/ontology/external-surfaces/sitemap-shape.yaml +6 -0
  142. package/src/ontology/external-surfaces/url-schema.yaml +95 -0
  143. package/src/ontology/growth/events/contact-email-click.yaml +21 -0
  144. package/src/ontology/growth/events/contact-form-submit.yaml +25 -0
  145. package/src/ontology/growth/events/contact-phone-click.yaml +21 -0
  146. package/src/ontology/growth/events/contact-route-click.yaml +21 -0
  147. package/src/ontology/growth/events/contact-submit.yaml +28 -0
  148. package/src/ontology/growth/events/contact-whatsapp-click.yaml +21 -0
  149. package/src/ontology/growth/events/cta-click.yaml +30 -0
  150. package/src/ontology/growth/events/donation-confirmed.yaml +32 -0
  151. package/src/ontology/growth/events/donation-form-start.yaml +21 -0
  152. package/src/ontology/growth/events/donation-form-submit.yaml +29 -0
  153. package/src/ontology/growth/events/donation-intent.yaml +29 -0
  154. package/src/ontology/growth/events/form-error.yaml +27 -0
  155. package/src/ontology/growth/events/form-start.yaml +21 -0
  156. package/src/ontology/growth/events/form-submit.yaml +21 -0
  157. package/src/ontology/growth/events/outbound-click.yaml +25 -0
  158. package/src/ontology/growth/events/page-view.yaml +24 -0
  159. package/src/ontology/growth/events/passport-view.yaml +28 -0
  160. package/src/ontology/growth/events/star-map-navigate.yaml +30 -0
  161. package/src/ontology/index.ts +165 -0
  162. package/src/ontology/manifest.ts +344 -0
  163. package/src/ontology/operations/index.ts +1 -0
  164. package/src/ontology/schemas/biome.ts +303 -0
  165. package/src/ontology/schemas/capability.ts +104 -0
  166. package/src/ontology/schemas/constellation.ts +114 -0
  167. package/src/ontology/schemas/dns-records.ts +53 -0
  168. package/src/ontology/schemas/index.ts +95 -0
  169. package/src/ontology/schemas/manifest-resolver.ts +123 -0
  170. package/src/ontology/schemas/page-entry.ts +213 -0
  171. package/src/ontology/schemas/section-archetype.ts +109 -0
  172. package/src/ontology/schemas/site-family.ts +98 -0
  173. package/src/ontology/schemas/system/growth.ts +80 -0
  174. package/src/ontology/schemas/system/integrations.ts +143 -0
  175. package/src/ontology/schemas/system/manifest.ts +492 -0
  176. package/src/ontology/schemas/system/page-output.ts +99 -0
  177. package/src/ontology/schemas/system/release.ts +58 -0
  178. package/src/ontology/schemas/system/text.ts +58 -0
  179. package/src/ontology/schemas/system.ts +53 -0
  180. package/src/ontology/shared-section-props/body-fragments.ts +182 -0
  181. package/src/ontology/shared-section-props/catalog.ts +195 -0
  182. package/src/ontology/shared-section-props/common.ts +178 -0
  183. package/src/ontology/shared-section-props/index.ts +34 -0
  184. package/src/ontology/shared-section-props/visual-header.ts +163 -0
  185. package/src/ontology/site-families/charity-donation-trust/cultural-rules.yaml +6 -0
  186. package/src/ontology/site-families/charity-donation-trust/family.yaml +44 -0
  187. package/src/ontology/site-families/charity-donation-trust/linguistic-rules.yaml +6 -0
  188. package/src/ontology/site-families/check-quality-operator/cultural-rules.yaml +6 -0
  189. package/src/ontology/site-families/check-quality-operator/family.yaml +40 -0
  190. package/src/ontology/site-families/check-quality-operator/linguistic-rules.yaml +6 -0
  191. package/src/ontology/site-families/handwerk-trust-engineering/cultural-rules.yaml +6 -0
  192. package/src/ontology/site-families/handwerk-trust-engineering/family.yaml +53 -0
  193. package/src/ontology/site-families/handwerk-trust-engineering/linguistic-rules.yaml +6 -0
  194. package/src/ontology/tests/catalogs.pbt.test.ts +89 -0
  195. package/src/ontology/tests/enums.test.ts +203 -0
  196. package/src/ontology/tests/sternsystem-owner.test.ts +63 -0
  197. package/src/ontology/vitest.config.ts +8 -0
  198. package/src/passport/dht-sign.test.ts +99 -0
  199. package/src/passport/dht-sign.ts +73 -0
  200. package/src/passport/identity-sign.test.ts +134 -0
  201. package/src/passport/identity-sign.ts +85 -0
  202. package/src/passport/index.ts +53 -0
  203. package/src/passport/key-rotate.ts +133 -0
  204. package/src/passport/schema.ts +198 -0
  205. package/src/passport/sign.ts +225 -0
  206. package/src/passport/tests/schema.pbt.test.ts +93 -0
  207. package/src/passport/tests/schema.test.ts +222 -0
  208. package/src/passport/vitest.config.ts +8 -0
  209. package/src/share/agent/api-catalog.ts +77 -0
  210. package/src/share/agent/capability.ts +68 -0
  211. package/src/share/agent/dns-aid.test.ts +74 -0
  212. package/src/share/agent/dns-aid.ts +53 -0
  213. package/src/share/agent/fleet-catalog.ts +149 -0
  214. package/src/share/agent/index.ts +29 -0
  215. package/src/share/agent/knowledge.ts +96 -0
  216. package/src/share/agent/manifest.ts +126 -0
  217. package/src/share/agent/mcp-card.ts +63 -0
  218. package/src/share/agent/omit-empty.ts +77 -0
  219. package/src/share/agent/openapi.ts +157 -0
  220. package/src/share/agent/proof.ts +61 -0
  221. package/src/share/attribution-display.ts +86 -0
  222. package/src/share/check-hints.ts +38 -0
  223. package/src/share/content/entity-id.ts +65 -0
  224. package/src/share/content/index.ts +16 -0
  225. package/src/share/content/merge.ts +86 -0
  226. package/src/share/content/resolve-field-path.ts +39 -0
  227. package/src/share/content/substitute-deep.ts +47 -0
  228. package/src/share/content-discipline/index.ts +14 -0
  229. package/src/share/content-discipline/parsers.ts +66 -0
  230. package/src/share/content-discipline/types.ts +118 -0
  231. package/src/share/content-reference.ts +333 -0
  232. package/src/share/counter-utils.ts +75 -0
  233. package/src/share/css-value-normalize.ts +48 -0
  234. package/src/share/dev-props-validator.ts +131 -0
  235. package/src/share/entitlement.ts +172 -0
  236. package/src/share/env.d.ts +73 -0
  237. package/src/share/feature-policy.ts +367 -0
  238. package/src/share/formula-eval.ts +364 -0
  239. package/src/share/fs/index.ts +96 -0
  240. package/src/share/i18n/localization.ts +57 -0
  241. package/src/share/image-provider.ts +314 -0
  242. package/src/share/index.ts +86 -0
  243. package/src/share/knowledge/claim.ts +129 -0
  244. package/src/share/knowledge/derivation.ts +55 -0
  245. package/src/share/knowledge/freshness.ts +127 -0
  246. package/src/share/knowledge/index.ts +23 -0
  247. package/src/share/knowledge/ledger.ts +222 -0
  248. package/src/share/knowledge/plan.ts +122 -0
  249. package/src/share/knowledge/source.ts +170 -0
  250. package/src/share/legal/translation-policy.ts +133 -0
  251. package/src/share/material-credits.ts +181 -0
  252. package/src/share/middleware/language-redirect.ts +49 -0
  253. package/src/share/offer-capacity.ts +149 -0
  254. package/src/share/onboarding-yaml/index.ts +162 -0
  255. package/src/share/page.ts +351 -0
  256. package/src/share/redirects.test.ts +62 -0
  257. package/src/share/redirects.ts +54 -0
  258. package/src/share/rfc0042-utils.ts +95 -0
  259. package/src/share/runtime-context.ts +70 -0
  260. package/src/share/schemas/claim-records.ts +69 -0
  261. package/src/share/schemas/claims.ts +150 -0
  262. package/src/share/schemas/effects.ts +212 -0
  263. package/src/share/schemas/features.ts +147 -0
  264. package/src/share/schemas/horizontal-align.ts +22 -0
  265. package/src/share/schemas/icon-color.ts +27 -0
  266. package/src/share/schemas/index.ts +43 -0
  267. package/src/share/schemas/live-photo.ts +53 -0
  268. package/src/share/schemas/material-credit.ts +292 -0
  269. package/src/share/schemas/media.ts +220 -0
  270. package/src/share/schemas/navigation.ts +74 -0
  271. package/src/share/schemas/page-base.ts +33 -0
  272. package/src/share/schemas/participant.ts +247 -0
  273. package/src/share/schemas/person.ts +24 -0
  274. package/src/share/schemas/print.ts +93 -0
  275. package/src/share/schemas/section-background.ts +106 -0
  276. package/src/share/schemas/section-body.ts +138 -0
  277. package/src/share/schemas/section-cards.ts +37 -0
  278. package/src/share/schemas/section-cta.ts +74 -0
  279. package/src/share/schemas/section-header.ts +77 -0
  280. package/src/share/schemas/section-image.ts +77 -0
  281. package/src/share/schemas/section-motion.ts +52 -0
  282. package/src/share/schemas/section-shell.ts +63 -0
  283. package/src/share/schemas/section-stats.ts +37 -0
  284. package/src/share/schemas/site-background.ts +78 -0
  285. package/src/share/schemas/standard-list-item.ts +38 -0
  286. package/src/share/scripts/external-links.ts +45 -0
  287. package/src/share/scripts/gsap-counter.ts +168 -0
  288. package/src/share/scripts/gsap-mountain-journey.ts +236 -0
  289. package/src/share/scripts/gsap-parallax.ts +50 -0
  290. package/src/share/scripts/gsap-reveal.ts +65 -0
  291. package/src/share/scripts/gsap-stagger.ts +54 -0
  292. package/src/share/scripts/index.ts +25 -0
  293. package/src/share/scripts/inline-number-animation.ts +120 -0
  294. package/src/share/scripts/lenis.ts +109 -0
  295. package/src/share/scripts/live-photos.ts +250 -0
  296. package/src/share/scripts/lordicon.ts +94 -0
  297. package/src/share/scripts/orchestrator.ts +138 -0
  298. package/src/share/scripts/scheduler.ts +53 -0
  299. package/src/share/scripts/video-player.ts +116 -0
  300. package/src/share/semantic/ai.ts +140 -0
  301. package/src/share/semantic/block-extraction.ts +52 -0
  302. package/src/share/semantic/block-extractors/index.ts +502 -0
  303. package/src/share/semantic/breadcrumbs.ts +120 -0
  304. package/src/share/semantic/build-page.ts +309 -0
  305. package/src/share/semantic/business-projection.ts +278 -0
  306. package/src/share/semantic/derived-prices-loader.ts +36 -0
  307. package/src/share/semantic/extract.ts +118 -0
  308. package/src/share/semantic/feed.ts +124 -0
  309. package/src/share/semantic/ids.ts +76 -0
  310. package/src/share/semantic/image-sitemap.ts +153 -0
  311. package/src/share/semantic/index.ts +36 -0
  312. package/src/share/semantic/jsonld/article.ts +47 -0
  313. package/src/share/semantic/jsonld/breadcrumb.ts +47 -0
  314. package/src/share/semantic/jsonld/collection-list.ts +30 -0
  315. package/src/share/semantic/jsonld/context.ts +46 -0
  316. package/src/share/semantic/jsonld/faq.ts +49 -0
  317. package/src/share/semantic/jsonld/initiative.ts +53 -0
  318. package/src/share/semantic/jsonld/organization.ts +101 -0
  319. package/src/share/semantic/jsonld/person.ts +71 -0
  320. package/src/share/semantic/jsonld/service.ts +80 -0
  321. package/src/share/semantic/jsonld/shared.ts +31 -0
  322. package/src/share/semantic/jsonld/types.ts +18 -0
  323. package/src/share/semantic/jsonld/webpage.ts +98 -0
  324. package/src/share/semantic/jsonld/website.ts +27 -0
  325. package/src/share/semantic/jsonld.ts +75 -0
  326. package/src/share/semantic/llms-policy.ts +74 -0
  327. package/src/share/semantic/llms.ts +394 -0
  328. package/src/share/semantic/markdown-hygiene.ts +68 -0
  329. package/src/share/semantic/markdown-twin-provenance.ts +242 -0
  330. package/src/share/semantic/models.ts +402 -0
  331. package/src/share/semantic/organization-profile.ts +160 -0
  332. package/src/share/semantic/output-projection.ts +131 -0
  333. package/src/share/semantic/page-builders/markdown-page.ts +84 -0
  334. package/src/share/semantic/page-markdown.ts +234 -0
  335. package/src/share/semantic/page-utils.ts +125 -0
  336. package/src/share/semantic/price-marker-resolver.ts +92 -0
  337. package/src/share/semantic/robots.ts +127 -0
  338. package/src/share/semantic/update-stamp.ts +136 -0
  339. package/src/share/shared-context.ts +177 -0
  340. package/src/share/string-utils.ts +19 -0
  341. package/src/share/tests/api-catalog.test.ts +97 -0
  342. package/src/share/tests/breadcrumbs.test.ts +126 -0
  343. package/src/share/tests/build-page-price-markers.test.ts +160 -0
  344. package/src/share/tests/capability.test.ts +107 -0
  345. package/src/share/tests/claim.test.ts +90 -0
  346. package/src/share/tests/content-ref-index.test.ts +328 -0
  347. package/src/share/tests/create-dev-props-validator.test.ts +38 -0
  348. package/src/share/tests/derivation.test.ts +39 -0
  349. package/src/share/tests/dev-props-validator.test.ts +88 -0
  350. package/src/share/tests/fleet-catalog.test.ts +134 -0
  351. package/src/share/tests/formula-eval.test.ts +619 -0
  352. package/src/share/tests/freshness.test.ts +60 -0
  353. package/src/share/tests/hero-section-numbering-parity.test.ts +51 -0
  354. package/src/share/tests/image-sitemap.test.ts +101 -0
  355. package/src/share/tests/jsonld-service.test.ts +282 -0
  356. package/src/share/tests/knowledge.test.ts +86 -0
  357. package/src/share/tests/ledger.test.ts +125 -0
  358. package/src/share/tests/llms-0789.test.ts +63 -0
  359. package/src/share/tests/manifest.test.ts +100 -0
  360. package/src/share/tests/markdown-twin-provenance.test.ts +108 -0
  361. package/src/share/tests/mcp-card.test.ts +57 -0
  362. package/src/share/tests/onboarding-yaml.test.ts +111 -0
  363. package/src/share/tests/ontology-role-by-cosmic-name.test.ts +28 -0
  364. package/src/share/tests/openapi.test.ts +116 -0
  365. package/src/share/tests/organization-jsonld.test.ts +74 -0
  366. package/src/share/tests/output-projection.test.ts +61 -0
  367. package/src/share/tests/plan.test.ts +97 -0
  368. package/src/share/tests/price-marker-resolver.test.ts +141 -0
  369. package/src/share/tests/proof.test.ts +72 -0
  370. package/src/share/tests/resolve-field-path.test.ts +52 -0
  371. package/src/share/tests/source.test.ts +81 -0
  372. package/src/share/tests/substitute-deep.test.ts +65 -0
  373. package/src/share/tests/text-normalize.pbt.test.ts +143 -0
  374. package/src/share/tests/text-normalize.test.ts +285 -0
  375. package/src/share/tests/twin-path.test.ts +43 -0
  376. package/src/share/text-normalize.ts +548 -0
  377. package/src/share/text-position.ts +19 -0
  378. package/src/share/types/hls-js-light.d.ts +16 -0
  379. package/src/share/visibility.ts +167 -0
  380. package/src/share/vitest.config.ts +8 -0
  381. package/src/share/wrap-inline-numbers.ts +139 -0
  382. package/src/surface/blueprint-schema.ts +314 -0
  383. package/src/surface/blueprint-types.ts +256 -0
  384. package/src/surface/blueprint.ts +300 -0
  385. package/src/surface/breaker.ts +57 -0
  386. package/src/surface/decision-composer.ts +156 -0
  387. package/src/surface/eligibility.ts +372 -0
  388. package/src/surface/evidence-records.ts +97 -0
  389. package/src/surface/fleet.ts +60 -0
  390. package/src/surface/geo.ts +170 -0
  391. package/src/surface/governance.ts +146 -0
  392. package/src/surface/index.ts +216 -0
  393. package/src/surface/io/index.ts +18 -0
  394. package/src/surface/io/surface-module-context-io.ts +60 -0
  395. package/src/surface/io/visibility-outcomes-io.ts +46 -0
  396. package/src/surface/module-context.ts +120 -0
  397. package/src/surface/substance.ts +161 -0
  398. package/src/surface/tests/eligibility.pbt.test.ts +137 -0
  399. package/src/surface/tests/eligibility.test.ts +302 -0
  400. package/src/surface/types.ts +289 -0
  401. package/src/surface/visibility.ts +57 -0
  402. package/src/surface/vitest.config.ts +8 -0
  403. package/tsconfig.json +17 -0
@@ -0,0 +1,213 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>
4
+ Zod schema for block-declarative page content entries (DNA-24, RFC-0026).
5
+ Every page .md file under apps/<app>/src/content/pages/ must conform to PageEntrySchema.
6
+ Exports BlockEntrySchema and PageEntrySchema — pure declarative schemas, no I/O.
7
+ </purpose>
8
+ <non-goals>
9
+ <item>Do not implement the buildPage pipeline here — that lives in @warpgogol/werkstatt-shared/share/page.</item>
10
+ <item>Do not parse YAML here; callers provide parsed objects to schema.parse().</item>
11
+ <item>Do not validate cross-system.yaml references — that is page.block.validate's job.</item>
12
+ </non-goals>
13
+ </MODULE_CONTRACT>
14
+ <CHANGE_SUMMARY>
15
+ <item>Wave 1 (RFC-0026): Initial creation.</item>
16
+ <item>Architecture review 2026-07-10: extracted getSectionPropsSchema into manifest-resolver.ts — page-entry.ts is now pure declarative schemas with no I/O.</item>
17
+ </CHANGE_SUMMARY>
18
+ */
19
+
20
+ import { z } from "zod";
21
+ import { MoonCatalog, PlanetCatalog, StarCatalog } from "../cosmic/index.ts";
22
+
23
+ const PRINT_ORIENTATIONS = ["portrait", "landscape", "auto"] as const;
24
+ const PRINT_PAGE_SIZES = ["a4", "letter", "legal"] as const;
25
+ const PRINT_MARGINS = ["normal", "narrow", "none"] as const;
26
+ const PRINT_BACKGROUND_MODES = ["preserve", "flatten"] as const;
27
+ const PRINT_REGIONS = [
28
+ "navigation",
29
+ "breadcrumbs",
30
+ "cta",
31
+ "footer-links",
32
+ "header-logo",
33
+ "site-background",
34
+ "hero-animation",
35
+ ] as const;
36
+
37
+ // ---------------------------------------------------------------------------
38
+ // VisibilityExprSchema (re-declared here to avoid cross-package dep on @warpgogol/werkstatt-shared/share)
39
+ // page.block.validate uses the canonical one from @warpgogol/werkstatt-shared/share;
40
+ // the schema here is for Astro content-collection integration.
41
+ // ---------------------------------------------------------------------------
42
+
43
+ const visibilityExprSchema: z.ZodType<unknown> = z.lazy(() =>
44
+ z.union([
45
+ z.object({ feature: z.string().min(1) }),
46
+ z.object({ locale: z.union([z.string().min(1), z.array(z.string().min(1))]) }),
47
+ z.object({ segment: z.union([z.string().min(1), z.array(z.string().min(1))]) }),
48
+ z.object({ flag: z.string().min(1) }),
49
+ z.object({ all: z.array(visibilityExprSchema).min(1) }),
50
+ z.object({ any: z.array(visibilityExprSchema).min(1) }),
51
+ z.object({ not: visibilityExprSchema }),
52
+ ]),
53
+ );
54
+
55
+ // ---------------------------------------------------------------------------
56
+ // BlockEntrySchema
57
+ // ---------------------------------------------------------------------------
58
+
59
+ /**
60
+ * Schema for a single block inside a page content entry.
61
+ *
62
+ * `use` is validated against PlanetCatalog — only known planet names are allowed.
63
+ * `props` is loose here (Record<string, unknown>); strict per-planet validation
64
+ * against propsSchema runs at build time in page.block.validate.
65
+ */
66
+ export const BlockEntrySchema = z
67
+ .object({
68
+ /**
69
+ * Optional stable block identifier for analytics, anchor links, and
70
+ * block-level attribution. Must be kebab-case when provided.
71
+ * page.block.validate enforces uniqueness within a page.
72
+ */
73
+ id: z
74
+ .string()
75
+ .regex(/^[a-z0-9-]+$/, "Block id must be kebab-case")
76
+ .optional(),
77
+
78
+ /**
79
+ * Cosmic name identifying the section/component for this block.
80
+ * Normally a `PlanetCatalog` value (section archetype). The five
81
+ * **PASSPORT-RESERVED moons** (`Methone`, `Despina`, `Klarissa`, `Bianca`,
82
+ * `Adrastea`) are also accepted because the cosmic-passport routes invoke
83
+ * passport components as page-blocks (see RFC-0028). Other Moon names
84
+ * remain rejected.
85
+ * Must be pinned in system.yaml pages[route].planets[].
86
+ */
87
+ type: z.string().min(1).optional(),
88
+
89
+ use: z
90
+ .enum([
91
+ ...PlanetCatalog,
92
+ ...MoonCatalog.filter((m) =>
93
+ ["Methone", "Despina", "Klarissa", "Bianca", "Adrastea"].includes(m),
94
+ ),
95
+ ] as [string, ...string[]])
96
+ .optional(),
97
+
98
+ /**
99
+ * Props passed to the section component. Validated against the pinned
100
+ * manifest's propsSchema (strict mode, no extra keys) by page.block.validate.
101
+ * Loose here to allow Astro content-collections to parse the entry.
102
+ */
103
+ props: z.record(z.string(), z.unknown()).default({}),
104
+
105
+ /**
106
+ * Optional visibility expression. When absent the block is unconditionally visible.
107
+ * Evaluated at build time by evalVisibility against the RuntimeContext.
108
+ */
109
+ visibility: visibilityExprSchema.optional(),
110
+ })
111
+ .superRefine((data, ctx) => {
112
+ if (!data.type && !data.use) {
113
+ ctx.addIssue({
114
+ code: "custom",
115
+ path: ["type"],
116
+ message: "Block selector is required; use author-facing `type` in page content",
117
+ });
118
+ }
119
+ });
120
+
121
+ export type BlockEntry = z.infer<typeof BlockEntrySchema>;
122
+
123
+ // ---------------------------------------------------------------------------
124
+ // PageEntrySchema
125
+ // ---------------------------------------------------------------------------
126
+
127
+ /**
128
+ * Schema for a block-declarative page content entry (DNA-24, RFC-0026).
129
+ *
130
+ * Stored at: apps/<app>/src/content/pages/<page-id>/<page-id>.<lang>.md
131
+ * Format: YAML frontmatter only — no markdown body allowed (enforced by mirror.quintet.validate).
132
+ *
133
+ * Example:
134
+ * ```yaml
135
+ * kind: page
136
+ * cosmicStar: Vega
137
+ * title: "Startseite"
138
+ * description: "Beispielorganisation — Bildung, Gesundheit, Solidarität."
139
+ * lang: de
140
+ * blocks:
141
+ * - id: hero
142
+ * use: Europa
143
+ * props:
144
+ * headline: "Bildung für Kinder in León"
145
+ * subline: "Seit 2008 — jeden Tag."
146
+ * ```
147
+ */
148
+ export const PageEntrySchema = z
149
+ .object({
150
+ /**
151
+ * Discriminator identifying the entry kind.
152
+ * - `page`: standard block-declarative page (must have ≥1 block).
153
+ * - `redirect`: language-root redirect helper (no blocks required) — used by
154
+ * files like `src/content/pages/root-redirect.md` that resolve to a
155
+ * client-side redirect script rather than a rendered section sequence.
156
+ */
157
+ kind: z.enum(["page", "redirect"]).default("page"),
158
+
159
+ /**
160
+ * IAU star name for this page — must match a StarCatalog entry and
161
+ * the cosmicName of the page's manifest.yaml.
162
+ * Cross-reference against system.yaml is validated by page.block.validate.
163
+ */
164
+ cosmicStar: z.enum(StarCatalog),
165
+
166
+ /** Page <title> and social/SEO title. */
167
+ title: z.string().min(1),
168
+
169
+ /** Page meta description for SEO and social cards. */
170
+ description: z.string().min(1),
171
+
172
+ /**
173
+ * BCP-47 language code matching the file's language suffix (e.g. "de", "en").
174
+ * The pipeline uses this as the locale for RuntimeContext.
175
+ */
176
+ lang: z.string().min(1),
177
+
178
+ /**
179
+ * Ordered list of blocks composing this page.
180
+ * For `kind: page`, must have at least one block (enforced by superRefine).
181
+ * For `kind: redirect`, may be empty.
182
+ * Every `use` value must be pinned in system.yaml pages[route].planets[].
183
+ * Props are validated against the pinned manifest's propsSchema by page.block.validate.
184
+ */
185
+ blocks: z.array(BlockEntrySchema).default([]),
186
+
187
+ /**
188
+ * RFC-0257: per-page print configuration. Optional — when absent, defaults
189
+ * are applied by the print validators and PDF generator.
190
+ */
191
+ print: z
192
+ .object({
193
+ enabled: z.boolean().optional(),
194
+ orientation: z.enum(PRINT_ORIENTATIONS).optional(),
195
+ pageSize: z.enum(PRINT_PAGE_SIZES).optional(),
196
+ margins: z.enum(PRINT_MARGINS).optional(),
197
+ expandDetails: z.boolean().optional(),
198
+ hide: z.array(z.enum(PRINT_REGIONS)).optional(),
199
+ background: z.enum(PRINT_BACKGROUND_MODES).optional(),
200
+ })
201
+ .optional(),
202
+ })
203
+ .superRefine((data, ctx) => {
204
+ if (data.kind === "page" && data.blocks.length === 0) {
205
+ ctx.addIssue({
206
+ code: "custom",
207
+ path: ["blocks"],
208
+ message: "A page must have at least one block",
209
+ });
210
+ }
211
+ });
212
+
213
+ export type PageEntry = z.infer<typeof PageEntrySchema>;
@@ -0,0 +1,109 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>
4
+ Zod schema for RFC-0072 section archetype catalog entries stored under
5
+ packages/werkstatt-site/src/domain/ontology/archetypes/sections/ recursive YAML catalog files.
6
+ </purpose>
7
+ <non-goals>
8
+ <item>Do not parse YAML here.</item>
9
+ <item>Do not resolve imports or generate files here.</item>
10
+ </non-goals>
11
+ </MODULE_CONTRACT>
12
+ <CHANGE_SUMMARY>
13
+ <item>RFC-0072: Initial archetype catalog contract.</item>
14
+ </CHANGE_SUMMARY>
15
+ */
16
+
17
+ import { z } from "zod";
18
+ import { cosmicNameSchema } from "../cosmic/index.ts";
19
+ import { industrySchema } from "../enums.ts";
20
+
21
+ const archetypeIdSchema = z
22
+ .string()
23
+ .regex(
24
+ /^[a-z][a-z0-9-]*(?:\.[a-z][a-z0-9-]*)*$/,
25
+ "archetype id must be kebab-case segments separated by dots",
26
+ );
27
+
28
+ const layoutHintSchema = z.enum([
29
+ "single-column",
30
+ "split",
31
+ "card-grid",
32
+ "decision-card",
33
+ "horizontal-row",
34
+ "stacked-bands",
35
+ ]);
36
+
37
+ /**
38
+ * RFC-0103: closed enum of canonical body kinds. Each non-composite archetype
39
+ * declares which body component renders authored content (list / split-list /
40
+ * stats / cards / paragraphs / comparison / rich). Composite archetypes (hero,
41
+ * hero-decision-card, founder-trust-card, donation-card, price-card, faq-list,
42
+ * markdown) declare `bodyKind: composite` and own their bespoke layout.
43
+ */
44
+ const archetypeBodyKindSchema = z.enum([
45
+ "list",
46
+ "split-list",
47
+ "stats",
48
+ "cards",
49
+ "paragraphs",
50
+ "comparison",
51
+ "rich",
52
+ "composite",
53
+ ]);
54
+
55
+ const recommendedItemCountSchema = z
56
+ .object({
57
+ min: z.number().int().nonnegative().optional(),
58
+ max: z.number().int().nonnegative().optional(),
59
+ })
60
+ .strict();
61
+
62
+ /**
63
+ * RFC-0101 + RFC-0102 + RFC-0103: archetype propsSchema accepts either
64
+ * (a) a `shape:` string with a Zod / JSON Schema expression (legacy form), or
65
+ * (b) a `compose: [...]` list of shared-section-props fragment ids that the
66
+ * runtime resolves through composeManifestPropsSchema().
67
+ * Both forms may be combined when the archetype needs to add section-specific
68
+ * fields on top of the shared fragments — see transparency.yaml.
69
+ */
70
+ const propsSchemaFragmentSchema = z
71
+ .object({
72
+ $shape: z.enum(["zod", "json-schema"]).default("zod"),
73
+ shape: z.string().min(1).optional(),
74
+ compose: z
75
+ .array(
76
+ z
77
+ .string()
78
+ .regex(/^[a-z][a-z0-9-]*(@\d+)?$/, "must match `<id>` or `<id>@<version>` (RFC-0119)"),
79
+ )
80
+ .optional(),
81
+ })
82
+ .refine((v) => Boolean(v.shape) || Boolean(v.compose && v.compose.length > 0), {
83
+ message: "propsSchema must declare `shape` or non-empty `compose` (or both)",
84
+ });
85
+
86
+ export const sectionArchetypeSchema = z.object({
87
+ id: archetypeIdSchema,
88
+ displayName: z.string().min(1),
89
+ version: z.string().regex(/^\d+\.\d+\.\d+(?:-[a-z0-9.-]+)?$/i, "version must be valid semver"),
90
+ semanticRole: z.string().min(1),
91
+ description: z.string().min(1),
92
+ expectedIntents: z.array(z.string().min(1)).min(1),
93
+ expectedIndustryFit: z.array(industrySchema).default([]),
94
+ layoutHint: layoutHintSchema,
95
+ /** RFC-0103: required for non-composite archetypes; composite signals bespoke layout. */
96
+ bodyKind: archetypeBodyKindSchema.optional(),
97
+ /** RFC-0072: advisory min/max number of body items the archetype expects. */
98
+ recommendedItemCount: recommendedItemCountSchema.optional(),
99
+ propsSchema: propsSchemaFragmentSchema,
100
+ acceptedCosmicNames: z.array(cosmicNameSchema).min(1),
101
+ constraints: z.record(z.string(), z.unknown()).default({}),
102
+ });
103
+
104
+ export type ArchetypeBodyKind = z.infer<typeof archetypeBodyKindSchema>;
105
+ export type RecommendedItemCount = z.infer<typeof recommendedItemCountSchema>;
106
+
107
+ export type SectionArchetypeContract = z.infer<typeof sectionArchetypeSchema>;
108
+ export type SectionArchetypeId = z.infer<typeof archetypeIdSchema>;
109
+ export type SectionArchetypeLayoutHint = z.infer<typeof layoutHintSchema>;
@@ -0,0 +1,98 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>
4
+ Zod schema for site-family definition files under packages/werkstatt-site/src/domain/ontology/site-families/<id>/family.yaml.
5
+ A Site Family captures reusable onboarding recipes: detection signals, candidate biomes,
6
+ candidate constellations, required section archetypes, audit thresholds, and readiness baselines.
7
+ </purpose>
8
+ <non-goals>
9
+ <item>Do not read files from disk.</item>
10
+ <item>Do not validate referenced biome/constellation/archetype files here; runtime validators do that.</item>
11
+ </non-goals>
12
+ </MODULE_CONTRACT>
13
+ <CHANGE_SUMMARY>
14
+ <item>RFC-0071: Add site-family contract to @warpgogol/werkstatt-shared/ontology.</item>
15
+ </CHANGE_SUMMARY>
16
+ */
17
+
18
+ import { z } from "zod";
19
+
20
+ const kebabId = z
21
+ .string()
22
+ .regex(/^[a-z][a-z0-9-]*$/, "id must be kebab-case (lowercase letters, digits, hyphens)");
23
+ const semver = z
24
+ .string()
25
+ .regex(/^\d+\.\d+\.\d+(?:-[a-z0-9.-]+)?$/i, "version must be valid semver");
26
+
27
+ const eventNameSchema = z
28
+ .string()
29
+ .regex(/^[a-z][a-z0-9-]*(?:-[a-z0-9-]+)*$/, "eventName must be kebab-case");
30
+
31
+ const detectionSignalsSchema = z
32
+ .object({
33
+ archetypePrimary: kebabId.optional(),
34
+ audienceAny: z.array(z.string().min(1)).default([]),
35
+ conversionPrimary: kebabId.optional(),
36
+ materialMentionsAny: z.array(z.string().min(1)).default([]),
37
+ })
38
+ .strict();
39
+
40
+ export const siteFamilyDetectionSchema = z
41
+ .object({
42
+ signals: detectionSignalsSchema,
43
+ threshold: z.number().min(0).max(1),
44
+ })
45
+ .strict();
46
+
47
+ const conversionGoalSchema = z
48
+ .object({
49
+ id: kebabId,
50
+ eventName: eventNameSchema,
51
+ })
52
+ .strict();
53
+
54
+ const auditThresholdValueSchema = z.enum([
55
+ "info",
56
+ "warn",
57
+ "warning",
58
+ "required",
59
+ "error",
60
+ "forbidden",
61
+ ]);
62
+
63
+ export const siteFamilyRecipeSchema = z
64
+ .object({
65
+ candidateBiomes: z.array(kebabId).min(1),
66
+ candidateConstellations: z.array(kebabId).min(1),
67
+ requiredSectionArchetypes: z.array(kebabId).min(1),
68
+ conversionGoals: z
69
+ .object({
70
+ primary: conversionGoalSchema,
71
+ secondary: z.array(conversionGoalSchema).default([]),
72
+ })
73
+ .strict(),
74
+ auditThresholds: z.record(z.string().min(1), auditThresholdValueSchema),
75
+ agentReadinessBaseline: z
76
+ .object({
77
+ maxBytesToCta: z.number().int().positive(),
78
+ requireStructuredData: z.array(z.string().min(1)).default([]),
79
+ })
80
+ .strict(),
81
+ })
82
+ .strict();
83
+
84
+ export const siteFamilySchema = z
85
+ .object({
86
+ id: kebabId,
87
+ displayName: z.string().min(1),
88
+ version: semver,
89
+ description: z.string().min(1),
90
+ detection: siteFamilyDetectionSchema,
91
+ recipe: siteFamilyRecipeSchema,
92
+ })
93
+ .strict();
94
+
95
+ export type SiteFamilyDetection = z.infer<typeof siteFamilyDetectionSchema>;
96
+ export type SiteFamilyRecipe = z.infer<typeof siteFamilyRecipeSchema>;
97
+ export type SiteFamily = z.infer<typeof siteFamilySchema>;
98
+ export const SiteFamilyContract = siteFamilySchema;
@@ -0,0 +1,80 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>Growth block schema (RFC-0027) and shared context schema for the system manifest.
4
+ Exports growthVendorSchema as the canonical vendor config shape, reused by @warpgogol/werkstatt-site/growth/config.ts.</purpose>
5
+ <non-goals>
6
+ <item>Do not introduce app-specific runtime composition or deployment behavior into this reusable package source file.</item>
7
+ </non-goals>
8
+ </MODULE_CONTRACT>
9
+ <CHANGE_SUMMARY>
10
+ <item>RFC-0303 Phase 3: extracted from schemas/system.ts as part of the domain split.</item>
11
+ <item>Architecture review 2026-07-10: Extracted growthVendorSchema so @warpgogol/werkstatt-site/growth/config.ts can import it instead of duplicating the shape.</item>
12
+ </CHANGE_SUMMARY>
13
+ */
14
+
15
+ import { z } from "zod";
16
+
17
+ export const systemSharedContextSchema = z.object({
18
+ requiredPageIds: z.array(z.string().min(1)).optional().default([]),
19
+ });
20
+
21
+ /**
22
+ * Vendor adapter binding — the canonical schema for the `growth.vendor` block.
23
+ * Shared by systemGrowthSchema (ontology) and GrowthConfigSchema (@warpgogol/werkstatt-site/growth/config.ts).
24
+ *
25
+ * adapter: id of the GrowthAdapter package (e.g. "null", "matomo").
26
+ * options: vendor-specific key/value pairs forwarded to GrowthAdapter.init().
27
+ */
28
+ export const growthVendorSchema = z.object({
29
+ adapter: z.string().min(1),
30
+ options: z.record(z.string(), z.string()).optional().default({}),
31
+ });
32
+
33
+ export type GrowthVendor = z.infer<typeof growthVendorSchema>;
34
+
35
+ /**
36
+ * The `growth:` block in src/content/system.md. Activates the vendor-agnostic growth
37
+ * layer for this app. When absent, <GrowthProvider> is omitted and no events
38
+ * are emitted (null-adapter mode).
39
+ *
40
+ * Example src/content/system.md growth block:
41
+ * growth:
42
+ * vendor:
43
+ * adapter: matomo
44
+ * options:
45
+ * proxyBaseUrl: /_wg/analytics/
46
+ * siteId: "1"
47
+ * privacyProfile: bannerfrei-v1
48
+ * funnels:
49
+ * - donation-intent-to-confirmation
50
+ * experiments: []
51
+ */
52
+ export const systemGrowthSchema = z.object({
53
+ /**
54
+ * Vendor adapter binding — uses the canonical growthVendorSchema.
55
+ */
56
+ vendor: growthVendorSchema,
57
+
58
+ /**
59
+ * Funnel ids to activate for this app.
60
+ * Each id must match a file in packages/werkstatt-site/src/domain/ontology/growth/funnels/<id>.yaml.
61
+ * Validated by growth.funnel.validate.
62
+ */
63
+ funnels: z
64
+ .array(z.string().regex(/^[a-z][a-z0-9-]*$/))
65
+ .optional()
66
+ .default([]),
67
+
68
+ /**
69
+ * Experiment ids available for this app.
70
+ * Each id must match a file in packages/werkstatt-site/src/domain/ontology/growth/experiments/<id>.yaml.
71
+ * Active experiment assignment per page is resolved server-side.
72
+ * Validated by growth.experiment.validate.
73
+ */
74
+ experiments: z
75
+ .array(z.string().regex(/^[a-z][a-z0-9-]*$/))
76
+ .optional()
77
+ .default([]),
78
+ });
79
+
80
+ export type SystemGrowth = z.infer<typeof systemGrowthSchema>;
@@ -0,0 +1,143 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>Integrations schema for the system manifest: vendor adapter bindings and integration configuration.</purpose>
4
+ <non-goals>
5
+ <item>Do not introduce app-specific runtime composition or deployment behavior into this reusable package source file.</item>
6
+ </non-goals>
7
+ </MODULE_CONTRACT>
8
+ <CHANGE_SUMMARY>
9
+ <item>RFC-0303 Phase 3: extracted from schemas/system.ts as part of the domain split.</item>
10
+ </CHANGE_SUMMARY>
11
+ */
12
+
13
+ import { z } from "zod";
14
+
15
+ /**
16
+ * The `integrations:` block in system.yaml (engineering-owned). Declares which
17
+ * outbound channel adapters and (optionally) which CRM adapter this app activates
18
+ * through the Integration Port (RFC-0168).
19
+ *
20
+ * Adapter ids are validated against the closed adapter catalog in
21
+ * @warpgogol/werkstatt-site/integration by `integration.config.validate`; each configured
22
+ * adapter's required secret names are validated against the generated env schema
23
+ * by `integration.secrets.validate`.
24
+ *
25
+ * When the block is absent, channels self-enable purely by secret presence at
26
+ * runtime (back-compat) and the validators are a no-op pass.
27
+ *
28
+ * Example:
29
+ * integrations:
30
+ * channels:
31
+ * - adapter: telegram
32
+ * - adapter: email
33
+ * options: { to: "info@example.org" }
34
+ * crm:
35
+ * adapter: pipedrive
36
+ */
37
+ export const systemIntegrationsSchema = z.object({
38
+ /** Outbound channel adapter bindings (telegram | email | whatsapp | null). */
39
+ channels: z
40
+ .array(
41
+ z.object({
42
+ adapter: z.string().min(1),
43
+ options: z.record(z.string(), z.string()).optional(),
44
+ }),
45
+ )
46
+ .optional()
47
+ .default([]),
48
+
49
+ /** Optional CRM adapter binding (pipedrive | null). */
50
+ crm: z
51
+ .object({
52
+ adapter: z.string().min(1),
53
+ options: z.record(z.string(), z.string()).optional(),
54
+ })
55
+ .optional(),
56
+
57
+ /**
58
+ * Optional consent-gated chat widget binding (uchat | null) — RFC-0175.
59
+ * `options` carries PUBLIC vendor values only (e.g. uchat needs widgetId or a
60
+ * full scriptUrl). Validated by `chat.config.validate`; gated by the
61
+ * `integrations.chat` entitlement (RFC-0169). The widget is click-to-load: no
62
+ * third-party script/storage exists before the visitor activates the launcher.
63
+ */
64
+ chat: z
65
+ .object({
66
+ adapter: z.string().min(1),
67
+ options: z.record(z.string(), z.string()).optional(),
68
+ })
69
+ .optional(),
70
+
71
+ /**
72
+ * RFC-0176: out-of-process source bindings. When a source is enabled (e.g.
73
+ * `uchat`), the inbound route `/api/integration-inbound` is generated and
74
+ * requires `INTEGRATION_INBOUND_SECRET` to authenticate posts.
75
+ */
76
+ inbound: z
77
+ .object({
78
+ sources: z.array(z.string().min(1)).default([]),
79
+ })
80
+ .optional(),
81
+
82
+ /**
83
+ * RFC-0176: source-agnostic destination hub. Each destination declares a kind,
84
+ * a vendor, and an execution mode. `gogol-adapter` (default) runs on the
85
+ * client's site with the client's tokens; `vendor-native` is executed by an
86
+ * upstream vendor. Validated by `integration.config.validate`.
87
+ */
88
+ destinations: z
89
+ .array(
90
+ z.object({
91
+ kind: z.string().min(1),
92
+ vendor: z.string().min(1),
93
+ mode: z.enum(["gogol-adapter", "vendor-native"]).default("gogol-adapter"),
94
+ }),
95
+ )
96
+ .optional()
97
+ .default([]),
98
+
99
+ /**
100
+ * RFC-0179: the site's placement on the shared, sharded delivery backbone.
101
+ * `region` pins the site's events to a jurisdiction's queue/dedup shard (data
102
+ * residency); `tier` is `shared` (the low-volume long tail, hash-fanned across
103
+ * the region's shared pool) or `dedicated` (a noisy/high-volume client isolated
104
+ * onto its own queue). Both default so existing apps need no edit. Validated by
105
+ * `integration.config.validate`; consumed by `integration.infrastructure.generate`
106
+ * (RFC-0180) to resolve the `ShardAssignment`.
107
+ */
108
+ region: z.enum(["eu", "us"]).optional().default("eu"),
109
+ tier: z.enum(["shared", "dedicated"]).optional().default("shared"),
110
+
111
+ /**
112
+ * RFC-0181: EU-resident delivery substrate. `provider: upstash` routes leads via
113
+ * Upstash QStash (EU, eu-central-1) with an Upstash Redis (EU) idempotency ledger
114
+ * — Cloudflare Queues/KV cannot be EU-pinned. `region: eu` keeps lead PII physically
115
+ * in the EU. Validated by `integration.config.validate`.
116
+ */
117
+ delivery: z
118
+ .object({
119
+ provider: z.enum(["upstash"]).default("upstash"),
120
+ region: z.enum(["eu"]).default("eu"),
121
+ })
122
+ .optional(),
123
+
124
+ /**
125
+ * RFC-0188: Visitor Sales Funnel binding. The PLATFORM owns the stage/event/
126
+ * transition graph (@warpgogol/werkstatt-site/integration funnel.ts); this block only declares
127
+ * which canonical funnel `version` the app renders, which event `sources` feed it
128
+ * (e.g. uchat, stripe, operator), and whether the pilot is `enabled`. UChat is the
129
+ * conversation runtime — it renders the funnel and requests transitions; it never
130
+ * owns the graph, pricing, or canonical state. Make.com is never a source. Validated
131
+ * by `funnel.contract.validate` / `funnel.stage.validate` / `funnel.lagebild.validate`.
132
+ * Absent ⇒ the funnel validators are a no-op pass (funnel not yet enabled for the app).
133
+ */
134
+ funnel: z
135
+ .object({
136
+ version: z.string().min(1),
137
+ sources: z.array(z.string().min(1)).optional().default([]),
138
+ enabled: z.boolean().optional().default(false),
139
+ })
140
+ .optional(),
141
+ });
142
+
143
+ export type SystemIntegrations = z.infer<typeof systemIntegrationsSchema>;