@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,74 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>
4
+ [RFC-0104] Canonical CtaConfig and CtaGroupConfig — one structured shape used
5
+ by every section that renders a call-to-action. Replaces the four ad-hoc CTA
6
+ shapes that lived on hero / final-cta / hero-decision-card / notausgang-block.
7
+ </purpose>
8
+ <non-goals>
9
+ <item>Do not introduce app-specific runtime composition or deployment behavior into this reusable package source file.</item>
10
+ </non-goals>
11
+ </MODULE_CONTRACT>
12
+ <CHANGE_SUMMARY>
13
+ <item>RFC-0133: backfilled MODULE_MAP and CHANGE_SUMMARY markers for compass.validate compliance.</item>
14
+ </CHANGE_SUMMARY>
15
+ */
16
+
17
+ import { z } from "zod";
18
+ import { horizontalAlignSchema } from "./horizontal-align.ts";
19
+ import { vendorIconConfigSchema } from "./standard-list-item.ts";
20
+
21
+ export const ctaVariantSchema = z.enum(["primary", "secondary", "ghost", "danger"]);
22
+ export type CtaVariant = z.infer<typeof ctaVariantSchema>;
23
+
24
+ export const ctaSizeSchema = z.enum(["sm", "md", "lg"]);
25
+ export type CtaSize = z.infer<typeof ctaSizeSchema>;
26
+
27
+ export const ctaIconPositionSchema = z.enum(["leading", "trailing"]);
28
+ export type CtaIconPosition = z.infer<typeof ctaIconPositionSchema>;
29
+
30
+ export const ctaTargetSchema = z.discriminatedUnion("kind", [
31
+ z
32
+ .object({
33
+ kind: z.literal("internal"),
34
+ pageId: z.string().min(1),
35
+ anchor: z.string().optional(),
36
+ })
37
+ .strict(),
38
+ z
39
+ .object({
40
+ kind: z.literal("external"),
41
+ href: z.string().min(1),
42
+ rel: z.string().optional(),
43
+ })
44
+ .strict(),
45
+ z
46
+ .object({
47
+ kind: z.literal("anchor"),
48
+ anchor: z.string().min(1),
49
+ })
50
+ .strict(),
51
+ ]);
52
+ export type CtaTarget = z.infer<typeof ctaTargetSchema>;
53
+
54
+ export const ctaConfigSchema = z
55
+ .object({
56
+ label: z.string().min(1),
57
+ target: ctaTargetSchema,
58
+ ariaLabel: z.string().optional(),
59
+ variant: ctaVariantSchema.optional(),
60
+ icon: vendorIconConfigSchema.optional(),
61
+ iconPosition: ctaIconPositionSchema.optional(),
62
+ size: ctaSizeSchema.optional(),
63
+ fullWidth: z.boolean().optional(),
64
+ })
65
+ .strict();
66
+ export type CtaConfig = z.infer<typeof ctaConfigSchema>;
67
+
68
+ export const ctaGroupConfigSchema = z
69
+ .object({
70
+ align: horizontalAlignSchema.optional(),
71
+ items: z.array(ctaConfigSchema).min(1),
72
+ })
73
+ .strict();
74
+ export type CtaGroupConfig = z.infer<typeof ctaGroupConfigSchema>;
@@ -0,0 +1,77 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>
4
+ [RFC-0102] Canonical SectionHeader contract — structured heading (string or
5
+ tone-segmented array), optional subheading, independent alignment, optional
6
+ section number, optional level override.
7
+ </purpose>
8
+ <non-goals>
9
+ <item>Do not declare body content (RFC-0103) or CTA shape (RFC-0104).</item>
10
+ <item>Do not couple header alignment to body alignment (each is independent).</item>
11
+ </non-goals>
12
+ </MODULE_CONTRACT>
13
+ <CHANGE_SUMMARY>
14
+ <item>RFC-0133: backfilled MODULE_MAP and CHANGE_SUMMARY markers for compass.validate compliance.</item>
15
+ </CHANGE_SUMMARY>
16
+ */
17
+
18
+ import { z } from "zod";
19
+ import { horizontalAlignSchema } from "./horizontal-align.ts";
20
+ import { effectStackSchema } from "./effects.ts";
21
+
22
+ export const headingToneSchema = z.enum(["default", "primary", "accent", "muted", "inverse"]);
23
+ export type HeadingTone = z.infer<typeof headingToneSchema>;
24
+
25
+ export const headingSegmentSchema = z
26
+ .object({
27
+ text: z.string().min(1),
28
+ tone: headingToneSchema.optional(),
29
+ })
30
+ .strict();
31
+ export type HeadingSegment = z.infer<typeof headingSegmentSchema>;
32
+
33
+ /**
34
+ * RFC-0102 — HeadingContent. Either a plain string (entire title renders in
35
+ * tone "default") or an array of tone-segmented runs that the renderer wraps
36
+ * in <span class="section-header__title-segment section-header__title-segment--{tone}">.
37
+ */
38
+ export const headingContentSchema = z.union([
39
+ z.string().min(1),
40
+ z.array(headingSegmentSchema).min(1),
41
+ ]);
42
+ export type HeadingContent = z.infer<typeof headingContentSchema>;
43
+
44
+ export const sectionHeaderLevelSchema = z.union([z.literal(1), z.literal(2)]);
45
+ export type SectionHeaderLevel = z.infer<typeof sectionHeaderLevelSchema>;
46
+
47
+ export const sectionHeaderSchema = z
48
+ .object({
49
+ /** Resolved upstream by blocks-renderer. */
50
+ sectionNumber: z.string().optional(),
51
+ /** Suppress the section number even if blocks-renderer supplied one. */
52
+ hideSectionNumber: z.boolean().optional(),
53
+ heading: headingContentSchema,
54
+ /** RFC-0567 — short contextual label rendered above the heading. */
55
+ eyebrow: z.string().optional(),
56
+ /** One short paragraph under the title. Longer copy belongs in body.kind: paragraphs (RFC-0103). */
57
+ subheading: z.string().optional(),
58
+ /** Independent header alignment; default "left". */
59
+ align: horizontalAlignSchema.optional(),
60
+ /** h1 for hero archetype, h2 otherwise. Default 2. */
61
+ level: sectionHeaderLevelSchema.optional(),
62
+ /** Used as aria-labelledby target by <SectionShell>. */
63
+ id: z.string().optional(),
64
+ /**
65
+ * RFC-0151 — resolved typographic effect stack for the `heading` target.
66
+ * Section composites pass resolveEffectsForTarget(effects, "heading").
67
+ * When absent or empty, the header renders exactly as before.
68
+ */
69
+ headingEffects: effectStackSchema.optional(),
70
+ /**
71
+ * RFC-0151 — resolved typographic effect stack for the `subheading` target.
72
+ */
73
+ subheadingEffects: effectStackSchema.optional(),
74
+ })
75
+ .strict();
76
+
77
+ export type SectionHeaderProps = z.infer<typeof sectionHeaderSchema>;
@@ -0,0 +1,77 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>
4
+ [RFC-0104 + RFC-0118] Canonical SectionImageProps + ImageFade for the shared
5
+ <SectionImage> primitive. Image fades become a property of the image, not of
6
+ the surrounding section. Parallax accepts boolean | number | object per
7
+ RFC-0118 to align with RFC-0106 ParallaxVariant semantics.
8
+ </purpose>
9
+ <non-goals>
10
+ <item>Do not introduce app-specific runtime composition or deployment behavior into this reusable package source file.</item>
11
+ </non-goals>
12
+ </MODULE_CONTRACT>
13
+ <CHANGE_SUMMARY>
14
+ <item>RFC-0133: backfilled MODULE_MAP and CHANGE_SUMMARY markers for compass.validate compliance.</item>
15
+ </CHANGE_SUMMARY>
16
+ */
17
+
18
+ import { z } from "zod";
19
+ import { livePhotoSchema } from "./live-photo.ts";
20
+
21
+ export const imageFadeSchema = z
22
+ .object({
23
+ top: z.boolean().optional(),
24
+ bottom: z.boolean().optional(),
25
+ left: z.boolean().optional(),
26
+ right: z.boolean().optional(),
27
+ /** 0..0.5 — fade band width as a fraction of the image. Default 0.25. */
28
+ width: z.number().min(0).max(0.5).optional(),
29
+ })
30
+ .strict();
31
+ export type ImageFade = z.infer<typeof imageFadeSchema>;
32
+
33
+ /**
34
+ * RFC-0118: explicit parallax config. Mirrors RFC-0106 ParallaxVariant for
35
+ * vocabulary consistency.
36
+ */
37
+ export const sectionImageParallaxSchema = z
38
+ .object({
39
+ variant: z.enum(["subtle", "balanced", "dramatic"]).optional(),
40
+ /** 0..2; takes precedence over variant default. */
41
+ speed: z.number().min(0).max(2).optional(),
42
+ respectReducedMotion: z.boolean().optional(),
43
+ })
44
+ .strict();
45
+ export type SectionImageParallax = z.infer<typeof sectionImageParallaxSchema>;
46
+
47
+ /**
48
+ * RFC-0118: section image parallax accepts three authoring forms:
49
+ * - boolean — true is equivalent to { variant: "balanced" }; false disables.
50
+ * - number — direct speed (0..2).
51
+ * - object — { variant, speed, respectReducedMotion }.
52
+ */
53
+ export const sectionImageParallaxPropSchema = z.union([
54
+ z.boolean(),
55
+ z.number().min(0).max(2),
56
+ sectionImageParallaxSchema,
57
+ ]);
58
+ export type SectionImageParallaxProp = z.infer<typeof sectionImageParallaxPropSchema>;
59
+
60
+ export const sectionImagePropsSchema = z
61
+ .object({
62
+ /** Bare image name (RFC-0053). */
63
+ imageName: z.string().min(1),
64
+ alt: z.string().min(1),
65
+ fit: z.enum(["cover", "contain"]).optional(),
66
+ quality: z.enum(["low", "mid", "high", "max"]).optional(),
67
+ loading: z.enum(["eager", "lazy"]).optional(),
68
+ aspectRatio: z.string().optional(),
69
+ fade: imageFadeSchema.optional(),
70
+ parallax: sectionImageParallaxPropSchema.optional(),
71
+ /** RFC-0202: opt-in living photo — looping sibling `<imageName>.webm` over this image. */
72
+ live: livePhotoSchema.optional(),
73
+ lang: z.string().optional(),
74
+ subPath: z.string().optional(),
75
+ })
76
+ .strict();
77
+ export type SectionImageProps = z.infer<typeof sectionImagePropsSchema>;
@@ -0,0 +1,52 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>
4
+ [RFC-0106] Canonical SectionMotionConfig. Consumed by <SectionShell motion>;
5
+ the shell emits data-motion-reveal / data-motion-stagger / data-parallax-speed
6
+ attributes that the GSAP scripts pick up via selectors.
7
+ </purpose>
8
+ <non-goals>
9
+ <item>Do not introduce app-specific runtime composition or deployment behavior into this reusable package source file.</item>
10
+ </non-goals>
11
+ </MODULE_CONTRACT>
12
+ <CHANGE_SUMMARY>
13
+ <item>RFC-0133: backfilled MODULE_MAP and CHANGE_SUMMARY markers for compass.validate compliance.</item>
14
+ </CHANGE_SUMMARY>
15
+ */
16
+
17
+ import { z } from "zod";
18
+
19
+ export const revealVariantSchema = z.enum(["fade", "fade-up", "fade-up-stagger"]);
20
+ export type RevealVariant = z.infer<typeof revealVariantSchema>;
21
+
22
+ export const parallaxVariantSchema = z.enum(["subtle", "balanced", "dramatic"]);
23
+ export type ParallaxVariant = z.infer<typeof parallaxVariantSchema>;
24
+
25
+ export const sectionMotionConfigSchema = z
26
+ .object({
27
+ reveal: z
28
+ .object({
29
+ variant: revealVariantSchema.optional(),
30
+ once: z.boolean().optional(),
31
+ threshold: z.number().min(0).max(1).optional(),
32
+ })
33
+ .strict()
34
+ .optional(),
35
+ parallax: z
36
+ .object({
37
+ variant: parallaxVariantSchema.optional(),
38
+ speed: z.number().min(0).max(2).optional(),
39
+ })
40
+ .strict()
41
+ .optional(),
42
+ stagger: z
43
+ .object({
44
+ delay: z.number().min(0).max(2).optional(),
45
+ childSelector: z.string().optional(),
46
+ })
47
+ .strict()
48
+ .optional(),
49
+ off: z.boolean().optional(),
50
+ })
51
+ .strict();
52
+ export type SectionMotionConfig = z.infer<typeof sectionMotionConfigSchema>;
@@ -0,0 +1,63 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>
4
+ [RFC-0101] Canonical SectionShellProps — the typed contract for the universal
5
+ <SectionShell> wrapper used by every shared section in packages/ui. Section
6
+ content and authoring shape live in RFC-0102 (header) and RFC-0103 (body); this
7
+ module owns visual + structural wrapper props only.
8
+ </purpose>
9
+ <non-goals>
10
+ <item>Do not declare header, body, cta, or motion props (their own RFCs).</item>
11
+ <item>Do not import Astro types; this is a framework-agnostic schema module.</item>
12
+ </non-goals>
13
+ </MODULE_CONTRACT>
14
+ <CHANGE_SUMMARY>
15
+ <item>RFC-0133: backfilled MODULE_MAP and CHANGE_SUMMARY markers for compass.validate compliance.</item>
16
+ </CHANGE_SUMMARY>
17
+ */
18
+
19
+ import { z } from "zod";
20
+ import { sectionBackgroundSchema } from "./section-background.ts";
21
+ import { effectsSchema } from "./effects.ts";
22
+ import { sectionMotionConfigSchema } from "./section-motion.ts";
23
+
24
+ export const sectionDensitySchema = z.enum(["compact", "normal", "spacious"]);
25
+ export type SectionDensity = z.infer<typeof sectionDensitySchema>;
26
+
27
+ export const sectionToneSchema = z.enum(["default", "warning", "success", "muted"]);
28
+ export type SectionTone = z.infer<typeof sectionToneSchema>;
29
+
30
+ export const sectionContainerVariantSchema = z.enum(["default", "narrow", "full"]);
31
+ export type SectionContainerVariant = z.infer<typeof sectionContainerVariantSchema>;
32
+
33
+ export const sectionShellAnimatedSchema = z.enum(["none", "reveal"]);
34
+ export type SectionShellAnimated = z.infer<typeof sectionShellAnimatedSchema>;
35
+
36
+ export const sectionShellPropsSchema = z
37
+ .object({
38
+ /** BEM prefix for the section, e.g. "transparency". Used for data attributes. */
39
+ slug: z.string().min(1),
40
+ /** Anchor id (resolved by resolveSectionAnchor upstream). */
41
+ sectionId: z.string().optional(),
42
+ /** Zero-padded section index — used to generate unique ARIA IDs per section instance. */
43
+ sectionNumber: z.string().optional(),
44
+ ariaLabel: z.string().optional(),
45
+ ariaLabelledBy: z.string().optional(),
46
+ background: sectionBackgroundSchema.optional(),
47
+ effects: effectsSchema.optional(),
48
+ density: sectionDensitySchema.optional(),
49
+ tone: sectionToneSchema.optional(),
50
+ containerVariant: sectionContainerVariantSchema.optional(),
51
+ /**
52
+ * RFC-0106 motion bridge. `reveal` opts the section into the platform
53
+ * reveal animation when the biome motion stance permits it. Full motion
54
+ * config (parallax, stagger) lives on a sibling `motion` prop introduced
55
+ * by RFC-0106; this enum is the minimal hook landed with RFC-0101.
56
+ */
57
+ animated: sectionShellAnimatedSchema.optional(),
58
+ /** RFC-0106: full motion config (reveal / parallax / stagger / off). */
59
+ motion: sectionMotionConfigSchema.optional(),
60
+ })
61
+ .strict();
62
+
63
+ export type SectionShellProps = z.infer<typeof sectionShellPropsSchema>;
@@ -0,0 +1,37 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>
4
+ [RFC-0103] Canonical StatItem schema consumed by <SectionStats>.
5
+ GSAP scroll-triggered counter animation (RFC-0040) hooks into the optional
6
+ numericValue / prefix / suffix / decimals / duration fields.
7
+ </purpose>
8
+ <non-goals>
9
+ <item>Do not introduce app-specific runtime composition or deployment behavior into this reusable package source file.</item>
10
+ </non-goals>
11
+ </MODULE_CONTRACT>
12
+ <CHANGE_SUMMARY>
13
+ <item>RFC-0133: backfilled MODULE_MAP and CHANGE_SUMMARY markers for compass.validate compliance.</item>
14
+ </CHANGE_SUMMARY>
15
+ */
16
+
17
+ import { z } from "zod";
18
+
19
+ export const statItemSchema = z
20
+ .object({
21
+ /** Static display fallback — always required so SSR renders something before JS runs. */
22
+ value: z.string().min(1),
23
+ label: z.string().min(1),
24
+ /** Numeric target for the GSAP counter; absent means the value renders statically. */
25
+ numericValue: z.number().optional(),
26
+ /** Symbol rendered before the number (e.g. "€"). */
27
+ prefix: z.string().optional(),
28
+ /** Unit rendered after the number (e.g. "+", "%", "K"). */
29
+ suffix: z.string().optional(),
30
+ /** Decimal places for Intl.NumberFormat. Default 0. */
31
+ decimals: z.number().int().nonnegative().optional(),
32
+ /** GSAP tween duration in seconds. Default 1.8. */
33
+ duration: z.number().positive().optional(),
34
+ })
35
+ .strict();
36
+
37
+ export type StatItem = z.infer<typeof statItemSchema>;
@@ -0,0 +1,78 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>
4
+ [RFC-0105] Canonical SiteBackgroundConfig — global viewport background shell
5
+ block, independent of section-level SectionBackground.
6
+ </purpose>
7
+ <non-goals>
8
+ <item>Do not introduce app-specific runtime composition or deployment behavior into this reusable package source file.</item>
9
+ </non-goals>
10
+ </MODULE_CONTRACT>
11
+ <CHANGE_SUMMARY>
12
+ <item>RFC-0133: backfilled MODULE_MAP and CHANGE_SUMMARY markers for compass.validate compliance.</item>
13
+ </CHANGE_SUMMARY>
14
+ */
15
+
16
+ import { z } from "zod";
17
+
18
+ const colorLayer = z
19
+ .object({
20
+ kind: z.literal("color"),
21
+ color: z.string().min(1).optional(),
22
+ })
23
+ .strict();
24
+
25
+ const imageLayer = z
26
+ .object({
27
+ kind: z.literal("image"),
28
+ imageName: z.string().min(1),
29
+ fit: z.enum(["cover", "tile", "stretch-width", "stretch-height"]).optional(),
30
+ quality: z.enum(["low", "mid", "high", "max"]).optional(),
31
+ loading: z.enum(["eager", "lazy"]).optional(),
32
+ tint: z
33
+ .object({
34
+ color: z.string().min(1).optional(),
35
+ opacity: z.number().min(0).max(1).optional(),
36
+ })
37
+ .strict()
38
+ .optional(),
39
+ parallax: z
40
+ .object({
41
+ speed: z.number().min(0).max(2).optional(),
42
+ respectReducedMotion: z.boolean().optional(),
43
+ })
44
+ .strict()
45
+ .optional(),
46
+ })
47
+ .strict();
48
+
49
+ const gradientStop = z
50
+ .object({
51
+ at: z.number().min(0).max(1),
52
+ color: z.string().min(1),
53
+ opacity: z.number().min(0).max(1).optional(),
54
+ })
55
+ .strict();
56
+
57
+ const gradientLayer = z
58
+ .object({
59
+ kind: z.literal("gradient"),
60
+ direction: z.enum(["vertical", "horizontal", "radial"]),
61
+ stops: z.array(gradientStop).min(2),
62
+ })
63
+ .strict();
64
+
65
+ export const siteBackgroundLayerSchema = z.discriminatedUnion("kind", [
66
+ colorLayer,
67
+ imageLayer,
68
+ gradientLayer,
69
+ ]);
70
+ export type SiteBackgroundLayer = z.infer<typeof siteBackgroundLayerSchema>;
71
+
72
+ export const siteBackgroundConfigSchema = z
73
+ .object({
74
+ layers: z.array(siteBackgroundLayerSchema).min(1),
75
+ lang: z.string().optional(),
76
+ })
77
+ .strict();
78
+ export type SiteBackgroundConfig = z.infer<typeof siteBackgroundConfigSchema>;
@@ -0,0 +1,38 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>
4
+ [RFC-0100 + RFC-0103] Canonical StandardListItem schema mirrored in
5
+ @warpgogol/werkstatt-shared/share so body components can validate items without importing from
6
+ @warpgogol/werkstatt-site/ui (which would create a cyclic dependency). The same shape is
7
+ re-exported by @warpgogol/werkstatt-site/ui/icons/icon-resolver for backwards compatibility.
8
+ </purpose>
9
+ <non-goals>
10
+ <item>Do not introduce app-specific runtime composition or deployment behavior into this reusable package source file.</item>
11
+ </non-goals>
12
+ </MODULE_CONTRACT>
13
+ <CHANGE_SUMMARY>
14
+ <item>RFC-0133: backfilled MODULE_MAP and CHANGE_SUMMARY markers for compass.validate compliance.</item>
15
+ </CHANGE_SUMMARY>
16
+ */
17
+
18
+ import { z } from "zod";
19
+
20
+ export const vendorIconConfigSchema = z
21
+ .object({
22
+ vendor: z.string().min(1),
23
+ collection: z.string().min(1),
24
+ name: z.string().min(1),
25
+ size: z.number().int().positive().optional(),
26
+ })
27
+ .strict();
28
+
29
+ export type VendorIconConfig = z.infer<typeof vendorIconConfigSchema>;
30
+
31
+ export const standardListItemSchema = z
32
+ .object({
33
+ text: z.string().min(1),
34
+ icon: vendorIconConfigSchema.optional(),
35
+ })
36
+ .strict();
37
+
38
+ export type StandardListItem = z.infer<typeof standardListItemSchema>;
@@ -0,0 +1,45 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>Applies security attributes to external anchor elements on the page.</purpose>
4
+ <non-goals>
5
+ <item>Do not handle internal navigation or routing.</item>
6
+ <item>Do not modify non-HTTP links (mailto:, tel:, etc.).</item>
7
+ </non-goals>
8
+ </MODULE_CONTRACT>
9
+ <CHANGE_SUMMARY>
10
+ <item>RFC-0011 Phase 2: Extracted from layout.astro inline script into src/scripts canonical pattern.</item>
11
+ <item>Migrated to @warpgogol/werkstatt-shared/share/scripts for platform-wide reuse.</item>
12
+ </CHANGE_SUMMARY>
13
+ */
14
+
15
+ // @ai-invariant: This function must only modify external HTTP/HTTPS links. Never touch mailto:, tel:, or internal links.
16
+ export function applyExternalLinkBehavior(): void {
17
+ const anchors = document.querySelectorAll("a[href]");
18
+
19
+ for (const anchor of anchors) {
20
+ const href = anchor.getAttribute("href");
21
+
22
+ if (!href) {
23
+ continue;
24
+ }
25
+
26
+ let resolvedUrl;
27
+
28
+ try {
29
+ resolvedUrl = new URL(href, window.location.href);
30
+ } catch {
31
+ continue;
32
+ }
33
+
34
+ const isHttpLink = resolvedUrl.protocol === "http:" || resolvedUrl.protocol === "https:";
35
+ const isExternalLink = isHttpLink && resolvedUrl.origin !== window.location.origin;
36
+
37
+ if (!isExternalLink) {
38
+ continue;
39
+ }
40
+
41
+ anchor.setAttribute("data-external-link", "1");
42
+ anchor.setAttribute("target", "_blank");
43
+ anchor.setAttribute("rel", "noopener noreferrer");
44
+ }
45
+ }