@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,334 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>RFC-0186: Tenant registry for the shared Lagebild sync worker.
4
+ Defines SyncTenant interface, secret reference contracts, and registry CRUD
5
+ operations. Secret values are never stored here — only symbolic reference names
6
+ that the Worker resolves from its environment at runtime.</purpose>
7
+ <non-goals>
8
+ <item>Do not store or transmit secret values.</item>
9
+ <item>Do not implement CLI commands (see cli.ts).</item>
10
+ </non-goals>
11
+ </MODULE_CONTRACT>
12
+ <CHANGE_SUMMARY>
13
+ <item>RFC-0186: Initial creation of tenant registry module.</item>
14
+ <item>RFC-0386: Added p3_stage_map / p4_stage_map to SyncTenant and TenantSecretRefs.</item>
15
+ <item>RFC-0186: Review fixes — extract patchAndParseSingle, add x-set-config to countOutboxByStatus, use Prefer: count=exact, SecretKind union type.</item>
16
+ </CHANGE_SUMMARY>
17
+ */
18
+
19
+ import type { P3StageMap, P4StageMap } from "./pipedrive-sync-target.ts";
20
+
21
+ /** RFC-0186: Row shape for sync_tenants. */
22
+ export interface SyncTenant {
23
+ tenant_id: string;
24
+ site_name: string;
25
+ enabled: boolean;
26
+ supabase_project_ref: string;
27
+ supabase_url_secret_ref: string;
28
+ supabase_service_key_secret_ref: string;
29
+ destination_vendor: string;
30
+ destination_token_secret_ref: string;
31
+ destination_domain_secret_ref: string;
32
+ /** RFC-0386: P3 pipeline stage map (JSON column from sync_tenants). */
33
+ p3_stage_map?: P3StageMap;
34
+ /** RFC-0386: P4 pipeline stage map (JSON column from sync_tenants). */
35
+ p4_stage_map?: P4StageMap;
36
+ cron_group: string;
37
+ batch_size: number;
38
+ max_concurrency: number;
39
+ circuit_breaker_threshold: number;
40
+ last_seen_at: string | null;
41
+ last_success_at: string | null;
42
+ last_error_at: string | null;
43
+ last_error: string | null;
44
+ created_at: string;
45
+ updated_at: string;
46
+ }
47
+
48
+ /** RFC-0186: Resolved secrets from Worker environment (values, not refs). */
49
+ export interface TenantSecretRefs {
50
+ supabase_url: string;
51
+ supabase_service_key: string;
52
+ destination_token: string;
53
+ destination_domain: string;
54
+ /** RFC-0386: P3 pipeline stage map (from registry JSON column). */
55
+ p3StageMap?: P3StageMap;
56
+ /** RFC-0386: P4 pipeline stage map (from registry JSON column). */
57
+ p4StageMap?: P4StageMap;
58
+ }
59
+
60
+ /** RFC-0186: Tenant with resolved secrets or resolution errors. */
61
+ export interface TenantWithSecrets {
62
+ tenant: SyncTenant;
63
+ secrets: TenantSecretRefs | null;
64
+ missing: string[];
65
+ }
66
+
67
+ /** Resolve secret references from Worker env. Returns nulls if any missing. */
68
+ export function resolveTenantSecrets(
69
+ tenant: SyncTenant,
70
+ env: Record<string, string | undefined>,
71
+ ): TenantWithSecrets {
72
+ const url = env[tenant.supabase_url_secret_ref];
73
+ const key = env[tenant.supabase_service_key_secret_ref];
74
+ const token = env[tenant.destination_token_secret_ref];
75
+ const domain = env[tenant.destination_domain_secret_ref];
76
+
77
+ const missing: string[] = [];
78
+ if (!url) missing.push(tenant.supabase_url_secret_ref);
79
+ if (!key) missing.push(tenant.supabase_service_key_secret_ref);
80
+ if (!token) missing.push(tenant.destination_token_secret_ref);
81
+ if (!domain) missing.push(tenant.destination_domain_secret_ref);
82
+
83
+ if (missing.length > 0) {
84
+ return { tenant, secrets: null, missing };
85
+ }
86
+
87
+ return {
88
+ tenant,
89
+ secrets: {
90
+ supabase_url: url!,
91
+ supabase_service_key: key!,
92
+ destination_token: token!,
93
+ destination_domain: domain!,
94
+ p3StageMap: tenant.p3_stage_map,
95
+ p4StageMap: tenant.p4_stage_map,
96
+ },
97
+ missing: [],
98
+ };
99
+ }
100
+
101
+ /** Minimal REST client for sync_tenants (PostgREST-compatible). */
102
+ export interface RegistryClient {
103
+ url: string;
104
+ apiKey: string;
105
+ }
106
+
107
+ /** Fetch enabled tenants for a cron group (default 'default'). */
108
+ export async function getEnabledTenants(
109
+ client: RegistryClient,
110
+ cronGroup = "default",
111
+ ): Promise<SyncTenant[]> {
112
+ const url = `${client.url}/rest/v1/sync_tenants?enabled=eq.true&cron_group=eq.${encodeURIComponent(cronGroup)}&select=*`;
113
+ const res = await fetch(url, {
114
+ headers: {
115
+ apikey: client.apiKey,
116
+ Authorization: `Bearer ${client.apiKey}`,
117
+ Accept: "application/json",
118
+ },
119
+ });
120
+ if (!res.ok) {
121
+ throw new Error(`getEnabledTenants: ${res.status} ${await res.text()}`);
122
+ }
123
+ return res.json() as Promise<SyncTenant[]>;
124
+ }
125
+
126
+ /** Update tenant health columns after processing. */
127
+ export async function updateTenantHealth(
128
+ client: RegistryClient,
129
+ tenantId: string,
130
+ patch: {
131
+ last_seen_at?: string;
132
+ last_success_at?: string;
133
+ last_error_at?: string;
134
+ last_error?: string | null;
135
+ },
136
+ ): Promise<void> {
137
+ const url = `${client.url}/rest/v1/sync_tenants?tenant_id=eq.${encodeURIComponent(tenantId)}`;
138
+ const res = await fetch(url, {
139
+ method: "PATCH",
140
+ headers: {
141
+ apikey: client.apiKey,
142
+ Authorization: `Bearer ${client.apiKey}`,
143
+ "Content-Type": "application/json",
144
+ Accept: "application/vnd.pgrst.object+json",
145
+ },
146
+ body: JSON.stringify(patch),
147
+ });
148
+ if (!res.ok) {
149
+ throw new Error(`updateTenantHealth: ${res.status} ${await res.text()}`);
150
+ }
151
+ }
152
+
153
+ /** RFC-0186: Input for creating a new tenant row. */
154
+ export interface CreateTenantInput {
155
+ tenant_id: string;
156
+ site_name: string;
157
+ supabase_project_ref: string;
158
+ supabase_url_secret_ref: string;
159
+ supabase_service_key_secret_ref: string;
160
+ destination_vendor: string;
161
+ destination_token_secret_ref: string;
162
+ destination_domain_secret_ref: string;
163
+ cron_group?: string;
164
+ batch_size?: number;
165
+ max_concurrency?: number;
166
+ circuit_breaker_threshold?: number;
167
+ }
168
+
169
+ /** RFC-0186: Create a tenant row in sync_tenants (enabled defaults to false). */
170
+ export async function createTenant(
171
+ client: RegistryClient,
172
+ input: CreateTenantInput,
173
+ ): Promise<SyncTenant> {
174
+ const url = `${client.url}/rest/v1/sync_tenants`;
175
+ const body = {
176
+ tenant_id: input.tenant_id,
177
+ site_name: input.site_name,
178
+ enabled: false,
179
+ supabase_project_ref: input.supabase_project_ref,
180
+ supabase_url_secret_ref: input.supabase_url_secret_ref,
181
+ supabase_service_key_secret_ref: input.supabase_service_key_secret_ref,
182
+ destination_vendor: input.destination_vendor,
183
+ destination_token_secret_ref: input.destination_token_secret_ref,
184
+ destination_domain_secret_ref: input.destination_domain_secret_ref,
185
+ cron_group: input.cron_group ?? "default",
186
+ batch_size: input.batch_size ?? 100,
187
+ max_concurrency: input.max_concurrency ?? 1,
188
+ circuit_breaker_threshold: input.circuit_breaker_threshold ?? 5,
189
+ };
190
+ const res = await fetch(url, {
191
+ method: "POST",
192
+ headers: {
193
+ apikey: client.apiKey,
194
+ Authorization: `Bearer ${client.apiKey}`,
195
+ "Content-Type": "application/json",
196
+ Prefer: "return=representation",
197
+ Accept: "application/vnd.pgrst.object+json",
198
+ },
199
+ body: JSON.stringify(body),
200
+ });
201
+ if (!res.ok) {
202
+ const errText = await res.text().catch(() => res.statusText);
203
+ throw new Error(`createTenant: ${res.status} ${errText}`);
204
+ }
205
+ return (await res.json()) as SyncTenant;
206
+ }
207
+
208
+ /** RFC-0186: Get a single tenant by site_name. */
209
+ export async function getTenantBySiteName(
210
+ client: RegistryClient,
211
+ siteName: string,
212
+ ): Promise<SyncTenant | null> {
213
+ const url = `${client.url}/rest/v1/sync_tenants?site_name=eq.${encodeURIComponent(siteName)}&select=*`;
214
+ const res = await fetch(url, {
215
+ headers: {
216
+ apikey: client.apiKey,
217
+ Authorization: `Bearer ${client.apiKey}`,
218
+ Accept: "application/json",
219
+ },
220
+ });
221
+ if (!res.ok) {
222
+ throw new Error(`getTenantBySiteName: ${res.status} ${await res.text()}`);
223
+ }
224
+ const rows = (await res.json()) as SyncTenant[];
225
+ return rows.length > 0 ? rows[0]! : null;
226
+ }
227
+
228
+ /** RFC-0186: Enable or disable a tenant by site_name. */
229
+ export async function setTenantEnabled(
230
+ client: RegistryClient,
231
+ siteName: string,
232
+ enabled: boolean,
233
+ ): Promise<SyncTenant | null> {
234
+ const url = `${client.url}/rest/v1/sync_tenants?site_name=eq.${encodeURIComponent(siteName)}`;
235
+ return patchAndParseSingle(client, url, { enabled }, "setTenantEnabled");
236
+ }
237
+
238
+ /** RFC-0186: Secret kind identifiers for rotate-secret. */
239
+ export type SecretKind =
240
+ "supabase-url" | "supabase-service-key" | "pipedrive-token" | "pipedrive-domain";
241
+
242
+ /** RFC-0186: Map secret kind to sync_tenants column name. */
243
+ const SECRET_KIND_COLUMN: Record<SecretKind, string> = {
244
+ "supabase-url": "supabase_url_secret_ref",
245
+ "supabase-service-key": "supabase_service_key_secret_ref",
246
+ "pipedrive-token": "destination_token_secret_ref",
247
+ "pipedrive-domain": "destination_domain_secret_ref",
248
+ };
249
+
250
+ /** RFC-0186: Shared PATCH helper with Prefer: return=representation parsing. */
251
+ async function patchAndParseSingle(
252
+ client: RegistryClient,
253
+ filterUrl: string,
254
+ body: Record<string, unknown>,
255
+ label: string,
256
+ ): Promise<SyncTenant | null> {
257
+ const res = await fetch(filterUrl, {
258
+ method: "PATCH",
259
+ headers: {
260
+ apikey: client.apiKey,
261
+ Authorization: `Bearer ${client.apiKey}`,
262
+ "Content-Type": "application/json",
263
+ Prefer: "return=representation",
264
+ Accept: "application/vnd.pgrst.object+json",
265
+ },
266
+ body: JSON.stringify(body),
267
+ });
268
+ if (!res.ok) {
269
+ const errText = await res.text().catch(() => res.statusText);
270
+ throw new Error(`${label}: ${res.status} ${errText}`);
271
+ }
272
+ const text = await res.text();
273
+ if (!text) return null;
274
+ const parsed = JSON.parse(text) as SyncTenant | SyncTenant[];
275
+ return Array.isArray(parsed) ? (parsed[0] ?? null) : parsed;
276
+ }
277
+
278
+ /** RFC-0186: Update a secret_ref column for a tenant. */
279
+ export async function updateTenantSecretRef(
280
+ client: RegistryClient,
281
+ siteName: string,
282
+ secretKind: SecretKind,
283
+ newSecretRef: string,
284
+ ): Promise<SyncTenant | null> {
285
+ const column = SECRET_KIND_COLUMN[secretKind];
286
+ if (!column) {
287
+ throw new Error(
288
+ `Unknown secret kind "${secretKind}". Valid kinds: ${Object.keys(SECRET_KIND_COLUMN).join(", ")}`,
289
+ );
290
+ }
291
+ const url = `${client.url}/rest/v1/sync_tenants?site_name=eq.${encodeURIComponent(siteName)}`;
292
+ return patchAndParseSingle(client, url, { [column]: newSecretRef }, "updateTenantSecretRef");
293
+ }
294
+
295
+ /** RFC-0186: Count outbox rows by status for a tenant using PostgREST count=exact. */
296
+ export async function countOutboxByStatus(
297
+ client: RegistryClient,
298
+ tenantId: string,
299
+ ): Promise<{ pending: number; failed: number; dead: number }> {
300
+ const baseUrl = `${client.url}/rest/v1/sync_outbox`;
301
+ const headers = {
302
+ apikey: client.apiKey,
303
+ Authorization: `Bearer ${client.apiKey}`,
304
+ Accept: "application/json",
305
+ "x-set-config": `app.current_tenant=${tenantId}`,
306
+ };
307
+
308
+ async function count(status: string): Promise<number> {
309
+ const url = `${baseUrl}?tenant_id=eq.${encodeURIComponent(tenantId)}&status=eq.${status}&select=id`;
310
+ const res = await fetch(url, {
311
+ headers: { ...headers, Prefer: "count=exact", Range: "0-0" },
312
+ });
313
+ if (!res.ok) {
314
+ const errText = await res.text().catch(() => res.statusText);
315
+ throw new Error(`countOutboxByStatus(${status}): ${res.status} ${errText}`);
316
+ }
317
+ const range = res.headers.get("content-range");
318
+ if (range) {
319
+ const slashIndex = range.lastIndexOf("/");
320
+ if (slashIndex !== -1) {
321
+ const total = range.slice(slashIndex + 1);
322
+ return total === "*" ? 0 : parseInt(total, 10) || 0;
323
+ }
324
+ }
325
+ return 0;
326
+ }
327
+
328
+ const [pending, failed, dead] = await Promise.all([
329
+ count("pending"),
330
+ count("failed"),
331
+ count("dead"),
332
+ ]);
333
+ return { pending, failed, dead };
334
+ }
@@ -0,0 +1,83 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>RFC-0386 / DNA-41: Property-based tests for change-balance monotonicity
4
+ and non-negative clamping. Asserts that decrementing the balance never produces
5
+ a negative result, and that a paid cycle invoice always resets the balance to
6
+ included_changes_per_cycle regardless of prior state.</purpose>
7
+ <non-goals>
8
+ <item>No network — pure property tests on the balance math.</item>
9
+ </non-goals>
10
+ </MODULE_CONTRACT>
11
+ <CHANGE_SUMMARY>
12
+ <item>RFC-0386: Initial PBT for change-balance monotonicity (DNA-41).</item>
13
+ </CHANGE_SUMMARY>
14
+ */
15
+
16
+ import { test, expect } from "vitest";
17
+ import fc from "fast-check";
18
+
19
+ // ---------------------------------------------------------------------------
20
+ // Pure helpers — mirror the balance logic from syncInvoice / adjustChangeBalance
21
+ // ---------------------------------------------------------------------------
22
+
23
+ /** The delta applied to reset the balance to perCycle on a paid cycle invoice. */
24
+ function resetDelta(current: number, perCycle: number): number {
25
+ return perCycle - current;
26
+ }
27
+
28
+ /** The result after applying a decrement, clamped to zero (non-negative). */
29
+ function clampDecrement(balance: number, decrement: number): number {
30
+ return Math.max(0, balance - decrement);
31
+ }
32
+
33
+ // ---------------------------------------------------------------------------
34
+ // Properties
35
+ // ---------------------------------------------------------------------------
36
+
37
+ test("PBT: reset delta always brings balance to perCycle", () => {
38
+ fc.assert(
39
+ fc.property(fc.nat(1000), fc.nat(1000), (current, perCycle) => {
40
+ const delta = resetDelta(current, perCycle);
41
+ expect(current + delta).toBe(perCycle);
42
+ }),
43
+ );
44
+ });
45
+
46
+ test("PBT: decrement never produces a negative balance (non-negative clamp)", () => {
47
+ fc.assert(
48
+ fc.property(fc.nat(1000), fc.nat(1000), (balance, decrement) => {
49
+ const result = clampDecrement(balance, decrement);
50
+ expect(result).toBeGreaterThanOrEqual(0);
51
+ expect(result).toBeLessThanOrEqual(balance);
52
+ }),
53
+ );
54
+ });
55
+
56
+ test("PBT: decrement is monotonic — result never exceeds original balance", () => {
57
+ fc.assert(
58
+ fc.property(fc.nat(1000), fc.nat(1000), (balance, decrement) => {
59
+ const result = clampDecrement(balance, decrement);
60
+ expect(result).toBeLessThanOrEqual(balance);
61
+ }),
62
+ );
63
+ });
64
+
65
+ test("PBT: zero decrement leaves balance unchanged", () => {
66
+ fc.assert(
67
+ fc.property(fc.nat(1000), (balance) => {
68
+ expect(clampDecrement(balance, 0)).toBe(balance);
69
+ }),
70
+ );
71
+ });
72
+
73
+ test("PBT: paid cycle reset is idempotent — applying reset twice yields perCycle", () => {
74
+ fc.assert(
75
+ fc.property(fc.nat(1000), fc.nat(1000), (current, perCycle) => {
76
+ const delta1 = resetDelta(current, perCycle);
77
+ const after1 = current + delta1;
78
+ const delta2 = resetDelta(after1, perCycle);
79
+ expect(delta2).toBe(0);
80
+ expect(after1).toBe(perCycle);
81
+ }),
82
+ );
83
+ });