@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,195 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>RFC-0684: Zod schemas, loaders, merger, and post-filter for the Axiom finding suppression layer. Defines the shape for suppression rules, loads workshop-level and per-site configs, merges them, and applies suppressions to findings.</purpose>
4
+ <non-goals>
5
+ <item>Does not execute Axiom checks — that belongs in mission.check and the external Axiom package.</item>
6
+ <item>Does not validate suppression config — that belongs in suppressions-validate.ts.</item>
7
+ <item>Does not modify evidence files — applySuppressions returns a new array; the caller decides whether to write it back.</item>
8
+ </non-goals>
9
+ </MODULE_CONTRACT>
10
+ <CHANGE_SUMMARY>
11
+ <item>RFC-0684: initial implementation of suppression config schema, loaders, merger, and applySuppressions post-filter.</item>
12
+ <item>RFC-0688: add titlePattern field to match against finding.title (always populated). messagePattern/descriptionPattern kept for forward compatibility but match against non-existent Finding fields.</item>
13
+ </CHANGE_SUMMARY>
14
+ */
15
+
16
+ import { existsSync, readFileSync } from "node:fs";
17
+ import { join } from "node:path";
18
+ import { z } from "zod";
19
+ import { parse as parseYaml } from "yaml";
20
+ import type { Finding } from "@syrokomskyi/axiom-study";
21
+
22
+ export const suppressionRuleSchema = z.object({
23
+ ruleId: z.string().min(1),
24
+ category: z.string().min(1),
25
+ channel: z.enum(["dev", "alt", "main"]).optional(),
26
+ channelNot: z.enum(["dev", "alt", "main"]).optional(),
27
+ contentType: z.array(z.string()).optional(),
28
+ urlPattern: z.string().optional(),
29
+ titlePattern: z.string().optional(),
30
+ messagePattern: z.string().optional(),
31
+ descriptionPattern: z.string().optional(),
32
+ reason: z.string().min(1),
33
+ });
34
+
35
+ export const suppressionsConfigSchema = z.object({
36
+ suppressions: z.array(suppressionRuleSchema),
37
+ });
38
+
39
+ export type SuppressionRule = z.infer<typeof suppressionRuleSchema>;
40
+ export type SuppressionsConfig = z.infer<typeof suppressionsConfigSchema>;
41
+
42
+ export interface SuppressedBy {
43
+ ruleIndex: number;
44
+ ruleId: string;
45
+ category: string;
46
+ reason: string;
47
+ }
48
+
49
+ export type SuppressedFinding = Finding & {
50
+ suppressed?: boolean;
51
+ suppressedBy?: SuppressedBy;
52
+ };
53
+
54
+ export const WORKSHOP_SUPPRESSIONS_PATH = "systems/axiom-suppressions.yaml";
55
+ export const WORKPIECE_SUPPRESSIONS_PATH = "axiom-suppressions.yaml";
56
+
57
+ export function parseSuppressionsConfig(content: string): SuppressionsConfig {
58
+ const raw = parseYaml(content) as unknown;
59
+ return suppressionsConfigSchema.parse(raw);
60
+ }
61
+
62
+ export function loadWorkshopSuppressions(workspaceRoot: string): SuppressionsConfig | undefined {
63
+ const absPath = join(workspaceRoot, WORKSHOP_SUPPRESSIONS_PATH);
64
+ if (!existsSync(absPath)) return undefined;
65
+ const content = readFileSync(absPath, "utf-8");
66
+ return parseSuppressionsConfig(content);
67
+ }
68
+
69
+ export function loadWorkpieceSuppressions(missionDir: string): SuppressionsConfig | undefined {
70
+ const absPath = join(missionDir, "workpiece", WORKPIECE_SUPPRESSIONS_PATH);
71
+ if (!existsSync(absPath)) return undefined;
72
+ const content = readFileSync(absPath, "utf-8");
73
+ return parseSuppressionsConfig(content);
74
+ }
75
+
76
+ export function mergeSuppressions(
77
+ workshop: SuppressionsConfig | undefined,
78
+ workpiece: SuppressionsConfig | undefined,
79
+ ): SuppressionRule[] {
80
+ const workshopRules = workshop?.suppressions ?? [];
81
+ const workpieceRules = workpiece?.suppressions ?? [];
82
+ // Per-site rules can only ADD new suppressions — they cannot remove workshop-level rules.
83
+ // Concatenation is sufficient: workshop rules fire first, workpiece rules fire for
84
+ // findings not already suppressed by workshop rules (first-match-wins in applySuppressions).
85
+ return [...workshopRules, ...workpieceRules];
86
+ }
87
+
88
+ function matchesCondition(
89
+ finding: Finding,
90
+ rule: SuppressionRule,
91
+ context: { channel: string },
92
+ ): boolean {
93
+ // ruleId must match
94
+ if (finding.ruleId !== rule.ruleId) return false;
95
+
96
+ // channel: suppress if context.channel === channel
97
+ if (rule.channel !== undefined && context.channel !== rule.channel) return false;
98
+
99
+ // channelNot: suppress if context.channel !== channelNot
100
+ if (rule.channelNot !== undefined && context.channel === rule.channelNot) return false;
101
+
102
+ // contentType: suppress if the finding's URL ends with one of the listed extensions
103
+ if (rule.contentType !== undefined && rule.contentType.length > 0) {
104
+ const url = finding.affectedSubjectId;
105
+ const matched = rule.contentType.some((ext) => url.endsWith(ext));
106
+ if (!matched) return false;
107
+ }
108
+
109
+ // urlPattern: suppress if the finding's URL matches the regex
110
+ if (rule.urlPattern !== undefined) {
111
+ try {
112
+ const regex = new RegExp(rule.urlPattern);
113
+ if (!regex.test(finding.affectedSubjectId)) return false;
114
+ } catch {
115
+ return false;
116
+ }
117
+ }
118
+
119
+ // titlePattern: suppress if the finding's title contains the pattern (substring match)
120
+ if (rule.titlePattern !== undefined) {
121
+ if (!finding.title.includes(rule.titlePattern)) return false;
122
+ }
123
+
124
+ // messagePattern: suppress if the finding's message contains the pattern (substring match)
125
+ if (rule.messagePattern !== undefined) {
126
+ const message = extractMessage(finding);
127
+ if (message === undefined || !message.includes(rule.messagePattern)) return false;
128
+ }
129
+
130
+ // descriptionPattern: suppress if the finding's description contains the pattern (substring match)
131
+ if (rule.descriptionPattern !== undefined) {
132
+ const description = extractDescription(finding);
133
+ if (description === undefined || !description.includes(rule.descriptionPattern)) return false;
134
+ }
135
+
136
+ return true;
137
+ }
138
+
139
+ function extractMessage(finding: Finding): string | undefined {
140
+ const ext = finding.extension as Record<string, unknown> | undefined;
141
+ if (ext && typeof ext.message === "string") return ext.message;
142
+ return undefined;
143
+ }
144
+
145
+ function extractDescription(finding: Finding): string | undefined {
146
+ const ext = finding.extension as Record<string, unknown> | undefined;
147
+ if (ext && typeof ext.description === "string") return ext.description;
148
+ return undefined;
149
+ }
150
+
151
+ export function applySuppressions(
152
+ findings: Finding[],
153
+ rules: SuppressionRule[],
154
+ context: { channel: string },
155
+ ): SuppressedFinding[] {
156
+ return findings.map((finding) => {
157
+ // If already suppressed, keep as-is
158
+ if ((finding as SuppressedFinding).suppressed) return finding;
159
+
160
+ for (let i = 0; i < rules.length; i++) {
161
+ const rule = rules[i];
162
+ if (matchesCondition(finding, rule, context)) {
163
+ return {
164
+ ...finding,
165
+ suppressed: true,
166
+ suppressedBy: {
167
+ ruleIndex: i,
168
+ ruleId: rule.ruleId,
169
+ category: rule.category,
170
+ reason: rule.reason,
171
+ },
172
+ } as SuppressedFinding;
173
+ }
174
+ }
175
+
176
+ return finding;
177
+ });
178
+ }
179
+
180
+ export function countSuppressedByCategory(findings: SuppressedFinding[]): {
181
+ totalSuppressed: number;
182
+ byCategory: Record<string, number>;
183
+ } {
184
+ let totalSuppressed = 0;
185
+ const byCategory: Record<string, number> = {};
186
+
187
+ for (const f of findings) {
188
+ if (f.suppressed && f.suppressedBy) {
189
+ totalSuppressed++;
190
+ byCategory[f.suppressedBy.category] = (byCategory[f.suppressedBy.category] ?? 0) + 1;
191
+ }
192
+ }
193
+
194
+ return { totalSuppressed, byCategory };
195
+ }
package/src/index.ts ADDED
@@ -0,0 +1,14 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>Package barrel for @warpgogol/werkstatt-shared — stack-agnostic shared infrastructure extracted from werkstatt-site (RFC-0868).</purpose>
4
+ <non-goals>
5
+ <item>Do not export site-specific validators, Astro components, or stack plugin logic.</item>
6
+ <item>Do not import from @warpgogol/werkstatt-site or any stack plugin.</item>
7
+ </non-goals>
8
+ </MODULE_CONTRACT>
9
+ <CHANGE_SUMMARY>
10
+ <item>RFC-0868: initial extraction from werkstatt-site.</item>
11
+ </CHANGE_SUMMARY>
12
+ */
13
+
14
+ export * from "./checks/index.ts";
@@ -0,0 +1,38 @@
1
+ # `@warpgogol/share/integration`
2
+
3
+ Vendor-agnostic lead/event delivery: normalize a captured lead into an `IntegrationEvent`, deliver it reliably, and route it to the client's own destinations (CRM/channels) **executing inside the client's site with the client's tokens**. The studio never becomes a CRM and never holds a destination token.
4
+
5
+ Full architecture + the EU-residency argument: **[`docs/specs/integration-delivery.md`](../../../../docs/specs/integration-delivery.md)**. Governing RFCs: 0168, 0176, 0177, 0179, 0180, **0181**.
6
+
7
+ ## Modules
8
+
9
+ | File | Role |
10
+ | --- | --- |
11
+ | `port.ts` | `IntegrationEvent`, `Lead`, `DestinationAdapter`, secrets bag. The contracts. |
12
+ | `port-barrel.ts` | Types-only barrel (`@warpgogol/share/integration/port`) — re-exports port + sibling type modules without pulling in adapter implementations. Type-only consumers (agent-gate, supabase-crm tests) import from here. |
13
+ | `index.ts` | Full barrel (`@warpgogol/share/integration`) — types + runtime (registries, fan-out, delivery handler). |
14
+ | `orchestration.ts` | Registries + `routeEventToReady`, `authenticateInbound`. |
15
+ | `delivery-handler.ts` | `createDeliveryHandler` — QStash delivery callback factory. |
16
+ | `qstash.ts` | **EU delivery substrate (RFC-0181):** `buildQstashPublish` (→ Upstash QStash EU), `IdempotencyLedger` / `restRedisLedger` (→ Upstash Redis EU). |
17
+ | `dispatch.ts` | `executeDispatch` — the site-side route body that runs destinations with the client's tokens. |
18
+ | `sharding.ts` | RFC-0179 CF-queue placement — **superseded for the EU path by RFC-0181** (retained, not used for EU delivery). |
19
+ | `adapters.ts` | Channel + Pipedrive destination adapters. |
20
+
21
+ ## Delivery flow (EU)
22
+
23
+ 1. A source publishes an `IntegrationEvent` to **Upstash QStash (EU)** via `buildQstashPublish` (dedup on `eventId`, N retries).
24
+ 2. QStash delivers a **signed webhook** to the site's `POST /internal/integration-route`.
25
+ 3. The route verifies the QStash signature, checks `restRedisLedger.firstSeen(eventId)` (Upstash Redis EU), then `executeDispatch` routes to the client's destinations.
26
+ 4. `200` acks; a non-2xx triggers QStash retry → DLQ.
27
+
28
+ ## EU residency — say it accurately
29
+
30
+ Physical EU residency (Frankfurt, eu-central-1) + DPA/SCC/EU-U.S. DPF: **yes**. Structural sovereignty: **no** — Upstash is US-incorporated (CLOUD Act exposure closed contractually, not structurally). Never claim "no US access". See the spec for the exact wording and the tier-2 (EU-incorporated/self-hosted) path.
31
+
32
+ ## Secrets (server-only, never committed)
33
+
34
+ `UPSTASH_QSTASH_URL`, `UPSTASH_QSTASH_TOKEN`, `UPSTASH_QSTASH_CURRENT_SIGNING_KEY`, `UPSTASH_QSTASH_NEXT_SIGNING_KEY`, `UPSTASH_REDIS_REST_URL`, `UPSTASH_REDIS_REST_TOKEN`, plus each destination's tokens (e.g. `INTEGRATION_PIPEDRIVE_API_TOKEN`) and `INTEGRATION_INBOUND_SECRET`. Read via `astro:env/server`; provide through untracked `.env` / deploy secrets only.
35
+
36
+ ## Tests
37
+
38
+ `node --import tsx --test src/integration/tests/*.test.ts` (run via `pnpm --filter @warpgogol/share test`). Covers QStash publish + Redis ledger, the dispatch seam, sharding, and the inbound/route runtime.
@@ -0,0 +1,143 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>RFC-0168/0181: reference Integration Port adapters. Channel adapters (Telegram, WhatsApp
4
+ Cloud API) and a CRM adapter (Pipedrive). Each is fetch-based, secret-driven, and self-disables when
5
+ its required secrets are absent. Email is NOT a fetch adapter — it is sent via Cloudflare Email
6
+ Routing (send_email binding) in the delivery callback (RFC-0181).</purpose>
7
+ <non-goals>
8
+ <item>Do not import vendor SDKs or astro:env — fetch + injected secrets only.</item>
9
+ <item>Do not log or echo secrets.</item>
10
+ </non-goals>
11
+ </MODULE_CONTRACT>
12
+ <CHANGE_SUMMARY>
13
+ <item>RFC-0168: initial implementation.</item>
14
+ </CHANGE_SUMMARY>
15
+ */
16
+
17
+ import type {
18
+ CrmAdapter,
19
+ DestinationAdapter,
20
+ IntegrationChannelAdapter,
21
+ IntegrationEvent,
22
+ IntegrationSecrets,
23
+ Lead,
24
+ LeadMessage,
25
+ } from "./port.ts";
26
+ import { eventToLead } from "./port.ts";
27
+
28
+ function formatMessageText(message: LeadMessage): string {
29
+ return [
30
+ "Neue Kontaktanfrage (send-message)",
31
+ `Formular: ${message.formId}`,
32
+ `Sprache: ${message.locale}`,
33
+ `Zeit: ${message.submittedAt}`,
34
+ "",
35
+ message.message,
36
+ ].join("\n");
37
+ }
38
+
39
+ export const telegramChannelAdapter: IntegrationChannelAdapter = {
40
+ id: "telegram",
41
+ requiredSecrets: ["INTEGRATION_TELEGRAM_BOT_TOKEN", "INTEGRATION_TELEGRAM_CHAT_ID"],
42
+ async deliver(message: LeadMessage, secrets: IntegrationSecrets): Promise<void> {
43
+ const token = secrets.INTEGRATION_TELEGRAM_BOT_TOKEN;
44
+ const chatId = secrets.INTEGRATION_TELEGRAM_CHAT_ID;
45
+ if (!token || !chatId) throw new Error("telegram: missing credentials");
46
+ const res = await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
47
+ method: "POST",
48
+ headers: { "Content-Type": "application/json" },
49
+ body: JSON.stringify({ chat_id: chatId, text: formatMessageText(message) }),
50
+ });
51
+ if (!res.ok) throw new Error(`telegram: API ${res.status}`);
52
+ },
53
+ };
54
+
55
+ // RFC-0181: the Resend email channel adapter was removed. Email notifications are
56
+ // sent via Cloudflare Email Routing (the `send_email` Worker binding), handled in the
57
+ // delivery callback route — not as a fetch+secret channel adapter. See the email
58
+ // notification step in chat-widget-section.delivery.api.ts and docs/specs/integration-delivery.md.
59
+
60
+ export const whatsappChannelAdapter: IntegrationChannelAdapter = {
61
+ id: "whatsapp",
62
+ requiredSecrets: [
63
+ "INTEGRATION_WHATSAPP_TOKEN",
64
+ "INTEGRATION_WHATSAPP_PHONE_ID",
65
+ "INTEGRATION_WHATSAPP_TO",
66
+ ],
67
+ async deliver(message: LeadMessage, secrets: IntegrationSecrets): Promise<void> {
68
+ const token = secrets.INTEGRATION_WHATSAPP_TOKEN;
69
+ const phoneId = secrets.INTEGRATION_WHATSAPP_PHONE_ID;
70
+ const to = secrets.INTEGRATION_WHATSAPP_TO;
71
+ if (!token || !phoneId || !to) throw new Error("whatsapp: missing credentials");
72
+ const res = await fetch(`https://graph.facebook.com/v21.0/${phoneId}/messages`, {
73
+ method: "POST",
74
+ headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
75
+ body: JSON.stringify({
76
+ messaging_product: "whatsapp",
77
+ to,
78
+ type: "text",
79
+ text: { body: formatMessageText(message) },
80
+ }),
81
+ });
82
+ if (!res.ok) throw new Error(`whatsapp: Cloud API ${res.status}`);
83
+ },
84
+ };
85
+
86
+ export const pipedriveCrmAdapter: CrmAdapter = {
87
+ id: "pipedrive",
88
+ requiredSecrets: ["INTEGRATION_PIPEDRIVE_API_TOKEN", "INTEGRATION_PIPEDRIVE_DOMAIN"],
89
+ async upsertLead(lead: Lead, secrets: IntegrationSecrets): Promise<{ id: string } | null> {
90
+ const token = secrets.INTEGRATION_PIPEDRIVE_API_TOKEN;
91
+ const domain = secrets.INTEGRATION_PIPEDRIVE_DOMAIN;
92
+ if (!token || !domain) throw new Error("pipedrive: missing credentials");
93
+ // Create a person first (leads require a linked person/organization in Pipedrive).
94
+ const personRes = await fetch(
95
+ `https://${domain}.pipedrive.com/api/v1/persons?api_token=${encodeURIComponent(token)}`,
96
+ {
97
+ method: "POST",
98
+ headers: { "Content-Type": "application/json" },
99
+ body: JSON.stringify({
100
+ name: lead.name ?? lead.email ?? lead.phone ?? "Website lead",
101
+ ...(lead.email ? { email: [lead.email] } : {}),
102
+ ...(lead.phone ? { phone: [lead.phone] } : {}),
103
+ }),
104
+ },
105
+ );
106
+ if (!personRes.ok) throw new Error(`pipedrive: persons API ${personRes.status}`);
107
+ const personJson = (await personRes.json()) as { data?: { id?: number } };
108
+ const personId = personJson.data?.id;
109
+ if (!personId) return null;
110
+
111
+ const leadRes = await fetch(
112
+ `https://${domain}.pipedrive.com/api/v1/leads?api_token=${encodeURIComponent(token)}`,
113
+ {
114
+ method: "POST",
115
+ headers: { "Content-Type": "application/json" },
116
+ body: JSON.stringify({
117
+ title: `${lead.source}: ${lead.name ?? "lead"}`,
118
+ person_id: personId,
119
+ }),
120
+ },
121
+ );
122
+ if (!leadRes.ok) throw new Error(`pipedrive: leads API ${leadRes.status}`);
123
+ const leadJson = (await leadRes.json()) as { data?: { id?: string } };
124
+ return leadJson.data?.id ? { id: String(leadJson.data.id) } : null;
125
+ },
126
+ };
127
+
128
+ /**
129
+ * RFC-0176: Pipedrive as a destination-hub adapter (kind `crm`, mode `gogol-adapter`).
130
+ * Runs on the client's site with the client's token. Reuses the RFC-0168
131
+ * pipedriveCrmAdapter by mapping the normalized IntegrationEvent → Lead.
132
+ */
133
+ export const pipedriveDestinationAdapter: DestinationAdapter = {
134
+ kind: "crm",
135
+ vendor: "pipedrive",
136
+ requiredSecrets: pipedriveCrmAdapter.requiredSecrets,
137
+ async route(
138
+ event: IntegrationEvent,
139
+ secrets: IntegrationSecrets,
140
+ ): Promise<{ id: string } | null> {
141
+ return pipedriveCrmAdapter.upsertLead(eventToLead(event), secrets);
142
+ },
143
+ };