@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.
- package/package.json +352 -0
- package/src/checks/index.ts +24 -0
- package/src/checks/lib/astro-site-url.ts +30 -0
- package/src/checks/lib/i18n.ts +30 -0
- package/src/checks/result-helpers.ts +102 -0
- package/src/checks/suppressions-config.ts +195 -0
- package/src/index.ts +14 -0
- package/src/integration/README.md +38 -0
- package/src/integration/adapters.ts +143 -0
- package/src/integration/crm-buffer.ts +491 -0
- package/src/integration/dispatch.ts +106 -0
- package/src/integration/funnel.ts +379 -0
- package/src/integration/index.ts +56 -0
- package/src/integration/lifecycle.ts +155 -0
- package/src/integration/orchestration.ts +439 -0
- package/src/integration/port-barrel.ts +124 -0
- package/src/integration/port.ts +143 -0
- package/src/integration/qstash.ts +134 -0
- package/src/integration/sharding.ts +133 -0
- package/src/integration/tests/deliver-event.test.ts +52 -0
- package/src/integration/tests/dispatch.test.ts +88 -0
- package/src/integration/tests/funnel-bridge.test.ts +46 -0
- package/src/integration/tests/hub-runtime.test.ts +128 -0
- package/src/integration/tests/lifecycle.test.ts +69 -0
- package/src/integration/tests/qstash.test.ts +83 -0
- package/src/integration/tests/sharding.test.ts +64 -0
- package/src/integration/vitest.config.ts +8 -0
- package/src/integration-adapter-supabase-crm/adapter.ts +437 -0
- package/src/integration-adapter-supabase-crm/client.ts +605 -0
- package/src/integration-adapter-supabase-crm/index.ts +28 -0
- package/src/integration-adapter-supabase-crm/pipedrive-sync-target.ts +482 -0
- package/src/integration-adapter-supabase-crm/supabase-rest.ts +89 -0
- package/src/integration-adapter-supabase-crm/tenant-registry.ts +334 -0
- package/src/integration-adapter-supabase-crm/tests/change-balance.pbt.test.ts +83 -0
- package/src/integration-adapter-supabase-crm/tests/funnel-persistence.test.ts +409 -0
- package/src/integration-adapter-supabase-crm/tests/lifecycle-sync.test.ts +288 -0
- package/src/integration-adapter-supabase-crm/tests/stage-map.test.ts +80 -0
- package/src/integration-adapter-supabase-crm/vitest.config.ts +8 -0
- package/src/integration-adapter-supabase-crm/worker.ts +223 -0
- package/src/observability/conventions.ts +93 -0
- package/src/observability/env-resolver.ts +57 -0
- package/src/observability/index.ts +57 -0
- package/src/observability/metric-registry.ts +184 -0
- package/src/observability/otlp-converter.ts +125 -0
- package/src/observability/otlp-json.ts +135 -0
- package/src/observability/otlp-transport.ts +68 -0
- package/src/observability/pusher.ts +142 -0
- package/src/observability/redact.ts +27 -0
- package/src/observability/tests/conventions.test.ts +100 -0
- package/src/observability/tests/metric-registry.test.ts +117 -0
- package/src/observability/tests/otlp-converter.pbt.test.ts +77 -0
- package/src/observability/tests/otlp-converter.test.ts +157 -0
- package/src/observability/tests/otlp-json.test.ts +120 -0
- package/src/observability/tests/pusher.test.ts +75 -0
- package/src/observability/tests/redact.pbt.test.ts +71 -0
- package/src/observability/tests/redact.test.ts +37 -0
- package/src/observability/typed-refs.ts +137 -0
- package/src/observability/vitest.config.ts +8 -0
- package/src/ontology/analytics/matomo-binding.yaml +172 -0
- package/src/ontology/analytics/matomo-fleet.registry.yaml +26 -0
- package/src/ontology/analytics/messkanon.yaml +151 -0
- package/src/ontology/archetype-registry.ts +61 -0
- package/src/ontology/archetypes/components/brand-label.yaml +19 -0
- package/src/ontology/archetypes/components/copyright.yaml +19 -0
- package/src/ontology/archetypes/components/currency-aware-price-display.yaml +19 -0
- package/src/ontology/archetypes/components/currency-selector.yaml +19 -0
- package/src/ontology/archetypes/components/footer-promo.yaml +19 -0
- package/src/ontology/archetypes/components/lang-switcher.yaml +19 -0
- package/src/ontology/archetypes/components/layout.yaml +19 -0
- package/src/ontology/archetypes/components/live-photo.yaml +20 -0
- package/src/ontology/archetypes/components/material-credit.yaml +20 -0
- package/src/ontology/archetypes/components/media.yaml +21 -0
- package/src/ontology/archetypes/components/nachweis-card.yaml +34 -0
- package/src/ontology/archetypes/components/nachweis-detail.yaml +43 -0
- package/src/ontology/archetypes/components/nachweis-list.yaml +37 -0
- package/src/ontology/archetypes/components/nachweis-verify.yaml +31 -0
- package/src/ontology/archetypes/components/not-found.yaml +22 -0
- package/src/ontology/archetypes/components/offer-capacity.yaml +21 -0
- package/src/ontology/archetypes/components/passport-header.yaml +19 -0
- package/src/ontology/archetypes/components/passport-provenance.yaml +20 -0
- package/src/ontology/archetypes/components/passport-score-grid.yaml +20 -0
- package/src/ontology/archetypes/components/passport-star-map.yaml +20 -0
- package/src/ontology/archetypes/components/person-profile.yaml +20 -0
- package/src/ontology/archetypes/components/pulsar.yaml +20 -0
- package/src/ontology/archetypes/components/responsive-image.yaml +19 -0
- package/src/ontology/archetypes/components/scroll-to-top.yaml +22 -0
- package/src/ontology/archetypes/components/social-meta.yaml +20 -0
- package/src/ontology/archetypes/components/structured-data.yaml +19 -0
- package/src/ontology/archetypes/index.json +1003 -0
- package/src/ontology/archetypes/index.yaml +821 -0
- package/src/ontology/archetypes/sections/approach.yaml +23 -0
- package/src/ontology/archetypes/sections/article-list.yaml +30 -0
- package/src/ontology/archetypes/sections/audience-cards.yaml +30 -0
- package/src/ontology/archetypes/sections/breadcrumbs.yaml +21 -0
- package/src/ontology/archetypes/sections/chat-widget.yaml +37 -0
- package/src/ontology/archetypes/sections/comparison-cards.yaml +31 -0
- package/src/ontology/archetypes/sections/controlled-responsibility-block.yaml +34 -0
- package/src/ontology/archetypes/sections/credits.yaml +29 -0
- package/src/ontology/archetypes/sections/donation-card.yaml +53 -0
- package/src/ontology/archetypes/sections/donation-use.yaml +23 -0
- package/src/ontology/archetypes/sections/dynamic-status-block.yaml +35 -0
- package/src/ontology/archetypes/sections/faq-list.yaml +26 -0
- package/src/ontology/archetypes/sections/final-cta.yaml +53 -0
- package/src/ontology/archetypes/sections/hero-decision-card.yaml +65 -0
- package/src/ontology/archetypes/sections/hero.yaml +50 -0
- package/src/ontology/archetypes/sections/impact.yaml +23 -0
- package/src/ontology/archetypes/sections/markdown.yaml +43 -0
- package/src/ontology/archetypes/sections/mountain-journey.yaml +43 -0
- package/src/ontology/archetypes/sections/navigation.yaml +20 -0
- package/src/ontology/archetypes/sections/notausgang-block.yaml +41 -0
- package/src/ontology/archetypes/sections/open-source-registry.yaml +26 -0
- package/src/ontology/archetypes/sections/ownership-block.yaml +57 -0
- package/src/ontology/archetypes/sections/people.yaml +48 -0
- package/src/ontology/archetypes/sections/price-card.yaml +50 -0
- package/src/ontology/archetypes/sections/problem.yaml +23 -0
- package/src/ontology/archetypes/sections/send-message.yaml +63 -0
- package/src/ontology/archetypes/sections/service-metadata-block.yaml +40 -0
- package/src/ontology/archetypes/sections/social-proof.yaml +27 -0
- package/src/ontology/archetypes/sections/transparency.yaml +32 -0
- package/src/ontology/archetypes/sections/trust-strip.yaml +42 -0
- package/src/ontology/archetypes/sections/video-section.yaml +27 -0
- package/src/ontology/archetypes/sections/women.yaml +29 -0
- package/src/ontology/biome-token-projection.ts +229 -0
- package/src/ontology/biomes/check-concrete-blueprint.yaml +118 -0
- package/src/ontology/biomes/handwerk-material-warm.yaml +135 -0
- package/src/ontology/biomes/nonprofit-trust.yaml +123 -0
- package/src/ontology/blueprints/offer.yaml +39 -0
- package/src/ontology/blueprints/prompts/local-market-signal.md +13 -0
- package/src/ontology/blueprints/prompts/website-local-narrative.md +24 -0
- package/src/ontology/blueprints/ratgeber.yaml +62 -0
- package/src/ontology/blueprints/website-local.yaml +309 -0
- package/src/ontology/blueprints/website-service.yaml +84 -0
- package/src/ontology/capabilities/lead.submit.yaml +44 -0
- package/src/ontology/cosmic/index.ts +48 -0
- package/src/ontology/cosmic/moon-catalog.ts +173 -0
- package/src/ontology/cosmic/planet-catalog.ts +82 -0
- package/src/ontology/cosmic/star-catalog.ts +337 -0
- package/src/ontology/enums.ts +159 -0
- package/src/ontology/external-surfaces/index.ts +158 -0
- package/src/ontology/external-surfaces/jsonld-types.yaml +135 -0
- package/src/ontology/external-surfaces/sitemap-shape.yaml +6 -0
- package/src/ontology/external-surfaces/url-schema.yaml +95 -0
- package/src/ontology/growth/events/contact-email-click.yaml +21 -0
- package/src/ontology/growth/events/contact-form-submit.yaml +25 -0
- package/src/ontology/growth/events/contact-phone-click.yaml +21 -0
- package/src/ontology/growth/events/contact-route-click.yaml +21 -0
- package/src/ontology/growth/events/contact-submit.yaml +28 -0
- package/src/ontology/growth/events/contact-whatsapp-click.yaml +21 -0
- package/src/ontology/growth/events/cta-click.yaml +30 -0
- package/src/ontology/growth/events/donation-confirmed.yaml +32 -0
- package/src/ontology/growth/events/donation-form-start.yaml +21 -0
- package/src/ontology/growth/events/donation-form-submit.yaml +29 -0
- package/src/ontology/growth/events/donation-intent.yaml +29 -0
- package/src/ontology/growth/events/form-error.yaml +27 -0
- package/src/ontology/growth/events/form-start.yaml +21 -0
- package/src/ontology/growth/events/form-submit.yaml +21 -0
- package/src/ontology/growth/events/outbound-click.yaml +25 -0
- package/src/ontology/growth/events/page-view.yaml +24 -0
- package/src/ontology/growth/events/passport-view.yaml +28 -0
- package/src/ontology/growth/events/star-map-navigate.yaml +30 -0
- package/src/ontology/index.ts +165 -0
- package/src/ontology/manifest.ts +344 -0
- package/src/ontology/operations/index.ts +1 -0
- package/src/ontology/schemas/biome.ts +303 -0
- package/src/ontology/schemas/capability.ts +104 -0
- package/src/ontology/schemas/constellation.ts +114 -0
- package/src/ontology/schemas/dns-records.ts +53 -0
- package/src/ontology/schemas/index.ts +95 -0
- package/src/ontology/schemas/manifest-resolver.ts +123 -0
- package/src/ontology/schemas/page-entry.ts +213 -0
- package/src/ontology/schemas/section-archetype.ts +109 -0
- package/src/ontology/schemas/site-family.ts +98 -0
- package/src/ontology/schemas/system/growth.ts +80 -0
- package/src/ontology/schemas/system/integrations.ts +143 -0
- package/src/ontology/schemas/system/manifest.ts +492 -0
- package/src/ontology/schemas/system/page-output.ts +99 -0
- package/src/ontology/schemas/system/release.ts +58 -0
- package/src/ontology/schemas/system/text.ts +58 -0
- package/src/ontology/schemas/system.ts +53 -0
- package/src/ontology/shared-section-props/body-fragments.ts +182 -0
- package/src/ontology/shared-section-props/catalog.ts +195 -0
- package/src/ontology/shared-section-props/common.ts +178 -0
- package/src/ontology/shared-section-props/index.ts +34 -0
- package/src/ontology/shared-section-props/visual-header.ts +163 -0
- package/src/ontology/site-families/charity-donation-trust/cultural-rules.yaml +6 -0
- package/src/ontology/site-families/charity-donation-trust/family.yaml +44 -0
- package/src/ontology/site-families/charity-donation-trust/linguistic-rules.yaml +6 -0
- package/src/ontology/site-families/check-quality-operator/cultural-rules.yaml +6 -0
- package/src/ontology/site-families/check-quality-operator/family.yaml +40 -0
- package/src/ontology/site-families/check-quality-operator/linguistic-rules.yaml +6 -0
- package/src/ontology/site-families/handwerk-trust-engineering/cultural-rules.yaml +6 -0
- package/src/ontology/site-families/handwerk-trust-engineering/family.yaml +53 -0
- package/src/ontology/site-families/handwerk-trust-engineering/linguistic-rules.yaml +6 -0
- package/src/ontology/tests/catalogs.pbt.test.ts +89 -0
- package/src/ontology/tests/enums.test.ts +203 -0
- package/src/ontology/tests/sternsystem-owner.test.ts +63 -0
- package/src/ontology/vitest.config.ts +8 -0
- package/src/passport/dht-sign.test.ts +99 -0
- package/src/passport/dht-sign.ts +73 -0
- package/src/passport/identity-sign.test.ts +134 -0
- package/src/passport/identity-sign.ts +85 -0
- package/src/passport/index.ts +53 -0
- package/src/passport/key-rotate.ts +133 -0
- package/src/passport/schema.ts +198 -0
- package/src/passport/sign.ts +225 -0
- package/src/passport/tests/schema.pbt.test.ts +93 -0
- package/src/passport/tests/schema.test.ts +222 -0
- package/src/passport/vitest.config.ts +8 -0
- package/src/share/agent/api-catalog.ts +77 -0
- package/src/share/agent/capability.ts +68 -0
- package/src/share/agent/dns-aid.test.ts +74 -0
- package/src/share/agent/dns-aid.ts +53 -0
- package/src/share/agent/fleet-catalog.ts +149 -0
- package/src/share/agent/index.ts +29 -0
- package/src/share/agent/knowledge.ts +96 -0
- package/src/share/agent/manifest.ts +126 -0
- package/src/share/agent/mcp-card.ts +63 -0
- package/src/share/agent/omit-empty.ts +77 -0
- package/src/share/agent/openapi.ts +157 -0
- package/src/share/agent/proof.ts +61 -0
- package/src/share/attribution-display.ts +86 -0
- package/src/share/check-hints.ts +38 -0
- package/src/share/content/entity-id.ts +65 -0
- package/src/share/content/index.ts +16 -0
- package/src/share/content/merge.ts +86 -0
- package/src/share/content/resolve-field-path.ts +39 -0
- package/src/share/content/substitute-deep.ts +47 -0
- package/src/share/content-discipline/index.ts +14 -0
- package/src/share/content-discipline/parsers.ts +66 -0
- package/src/share/content-discipline/types.ts +118 -0
- package/src/share/content-reference.ts +333 -0
- package/src/share/counter-utils.ts +75 -0
- package/src/share/css-value-normalize.ts +48 -0
- package/src/share/dev-props-validator.ts +131 -0
- package/src/share/entitlement.ts +172 -0
- package/src/share/env.d.ts +73 -0
- package/src/share/feature-policy.ts +367 -0
- package/src/share/formula-eval.ts +364 -0
- package/src/share/fs/index.ts +96 -0
- package/src/share/i18n/localization.ts +57 -0
- package/src/share/image-provider.ts +314 -0
- package/src/share/index.ts +86 -0
- package/src/share/knowledge/claim.ts +129 -0
- package/src/share/knowledge/derivation.ts +55 -0
- package/src/share/knowledge/freshness.ts +127 -0
- package/src/share/knowledge/index.ts +23 -0
- package/src/share/knowledge/ledger.ts +222 -0
- package/src/share/knowledge/plan.ts +122 -0
- package/src/share/knowledge/source.ts +170 -0
- package/src/share/legal/translation-policy.ts +133 -0
- package/src/share/material-credits.ts +181 -0
- package/src/share/middleware/language-redirect.ts +49 -0
- package/src/share/offer-capacity.ts +149 -0
- package/src/share/onboarding-yaml/index.ts +162 -0
- package/src/share/page.ts +351 -0
- package/src/share/redirects.test.ts +62 -0
- package/src/share/redirects.ts +54 -0
- package/src/share/rfc0042-utils.ts +95 -0
- package/src/share/runtime-context.ts +70 -0
- package/src/share/schemas/claim-records.ts +69 -0
- package/src/share/schemas/claims.ts +150 -0
- package/src/share/schemas/effects.ts +212 -0
- package/src/share/schemas/features.ts +147 -0
- package/src/share/schemas/horizontal-align.ts +22 -0
- package/src/share/schemas/icon-color.ts +27 -0
- package/src/share/schemas/index.ts +43 -0
- package/src/share/schemas/live-photo.ts +53 -0
- package/src/share/schemas/material-credit.ts +292 -0
- package/src/share/schemas/media.ts +220 -0
- package/src/share/schemas/navigation.ts +74 -0
- package/src/share/schemas/page-base.ts +33 -0
- package/src/share/schemas/participant.ts +247 -0
- package/src/share/schemas/person.ts +24 -0
- package/src/share/schemas/print.ts +93 -0
- package/src/share/schemas/section-background.ts +106 -0
- package/src/share/schemas/section-body.ts +138 -0
- package/src/share/schemas/section-cards.ts +37 -0
- package/src/share/schemas/section-cta.ts +74 -0
- package/src/share/schemas/section-header.ts +77 -0
- package/src/share/schemas/section-image.ts +77 -0
- package/src/share/schemas/section-motion.ts +52 -0
- package/src/share/schemas/section-shell.ts +63 -0
- package/src/share/schemas/section-stats.ts +37 -0
- package/src/share/schemas/site-background.ts +78 -0
- package/src/share/schemas/standard-list-item.ts +38 -0
- package/src/share/scripts/external-links.ts +45 -0
- package/src/share/scripts/gsap-counter.ts +168 -0
- package/src/share/scripts/gsap-mountain-journey.ts +236 -0
- package/src/share/scripts/gsap-parallax.ts +50 -0
- package/src/share/scripts/gsap-reveal.ts +65 -0
- package/src/share/scripts/gsap-stagger.ts +54 -0
- package/src/share/scripts/index.ts +25 -0
- package/src/share/scripts/inline-number-animation.ts +120 -0
- package/src/share/scripts/lenis.ts +109 -0
- package/src/share/scripts/live-photos.ts +250 -0
- package/src/share/scripts/lordicon.ts +94 -0
- package/src/share/scripts/orchestrator.ts +138 -0
- package/src/share/scripts/scheduler.ts +53 -0
- package/src/share/scripts/video-player.ts +116 -0
- package/src/share/semantic/ai.ts +140 -0
- package/src/share/semantic/block-extraction.ts +52 -0
- package/src/share/semantic/block-extractors/index.ts +502 -0
- package/src/share/semantic/breadcrumbs.ts +120 -0
- package/src/share/semantic/build-page.ts +309 -0
- package/src/share/semantic/business-projection.ts +278 -0
- package/src/share/semantic/derived-prices-loader.ts +36 -0
- package/src/share/semantic/extract.ts +118 -0
- package/src/share/semantic/feed.ts +124 -0
- package/src/share/semantic/ids.ts +76 -0
- package/src/share/semantic/image-sitemap.ts +153 -0
- package/src/share/semantic/index.ts +36 -0
- package/src/share/semantic/jsonld/article.ts +47 -0
- package/src/share/semantic/jsonld/breadcrumb.ts +47 -0
- package/src/share/semantic/jsonld/collection-list.ts +30 -0
- package/src/share/semantic/jsonld/context.ts +46 -0
- package/src/share/semantic/jsonld/faq.ts +49 -0
- package/src/share/semantic/jsonld/initiative.ts +53 -0
- package/src/share/semantic/jsonld/organization.ts +101 -0
- package/src/share/semantic/jsonld/person.ts +71 -0
- package/src/share/semantic/jsonld/service.ts +80 -0
- package/src/share/semantic/jsonld/shared.ts +31 -0
- package/src/share/semantic/jsonld/types.ts +18 -0
- package/src/share/semantic/jsonld/webpage.ts +98 -0
- package/src/share/semantic/jsonld/website.ts +27 -0
- package/src/share/semantic/jsonld.ts +75 -0
- package/src/share/semantic/llms-policy.ts +74 -0
- package/src/share/semantic/llms.ts +394 -0
- package/src/share/semantic/markdown-hygiene.ts +68 -0
- package/src/share/semantic/markdown-twin-provenance.ts +242 -0
- package/src/share/semantic/models.ts +402 -0
- package/src/share/semantic/organization-profile.ts +160 -0
- package/src/share/semantic/output-projection.ts +131 -0
- package/src/share/semantic/page-builders/markdown-page.ts +84 -0
- package/src/share/semantic/page-markdown.ts +234 -0
- package/src/share/semantic/page-utils.ts +125 -0
- package/src/share/semantic/price-marker-resolver.ts +92 -0
- package/src/share/semantic/robots.ts +127 -0
- package/src/share/semantic/update-stamp.ts +136 -0
- package/src/share/shared-context.ts +177 -0
- package/src/share/string-utils.ts +19 -0
- package/src/share/tests/api-catalog.test.ts +97 -0
- package/src/share/tests/breadcrumbs.test.ts +126 -0
- package/src/share/tests/build-page-price-markers.test.ts +160 -0
- package/src/share/tests/capability.test.ts +107 -0
- package/src/share/tests/claim.test.ts +90 -0
- package/src/share/tests/content-ref-index.test.ts +328 -0
- package/src/share/tests/create-dev-props-validator.test.ts +38 -0
- package/src/share/tests/derivation.test.ts +39 -0
- package/src/share/tests/dev-props-validator.test.ts +88 -0
- package/src/share/tests/fleet-catalog.test.ts +134 -0
- package/src/share/tests/formula-eval.test.ts +619 -0
- package/src/share/tests/freshness.test.ts +60 -0
- package/src/share/tests/hero-section-numbering-parity.test.ts +51 -0
- package/src/share/tests/image-sitemap.test.ts +101 -0
- package/src/share/tests/jsonld-service.test.ts +282 -0
- package/src/share/tests/knowledge.test.ts +86 -0
- package/src/share/tests/ledger.test.ts +125 -0
- package/src/share/tests/llms-0789.test.ts +63 -0
- package/src/share/tests/manifest.test.ts +100 -0
- package/src/share/tests/markdown-twin-provenance.test.ts +108 -0
- package/src/share/tests/mcp-card.test.ts +57 -0
- package/src/share/tests/onboarding-yaml.test.ts +111 -0
- package/src/share/tests/ontology-role-by-cosmic-name.test.ts +28 -0
- package/src/share/tests/openapi.test.ts +116 -0
- package/src/share/tests/organization-jsonld.test.ts +74 -0
- package/src/share/tests/output-projection.test.ts +61 -0
- package/src/share/tests/plan.test.ts +97 -0
- package/src/share/tests/price-marker-resolver.test.ts +141 -0
- package/src/share/tests/proof.test.ts +72 -0
- package/src/share/tests/resolve-field-path.test.ts +52 -0
- package/src/share/tests/source.test.ts +81 -0
- package/src/share/tests/substitute-deep.test.ts +65 -0
- package/src/share/tests/text-normalize.pbt.test.ts +143 -0
- package/src/share/tests/text-normalize.test.ts +285 -0
- package/src/share/tests/twin-path.test.ts +43 -0
- package/src/share/text-normalize.ts +548 -0
- package/src/share/text-position.ts +19 -0
- package/src/share/types/hls-js-light.d.ts +16 -0
- package/src/share/visibility.ts +167 -0
- package/src/share/vitest.config.ts +8 -0
- package/src/share/wrap-inline-numbers.ts +139 -0
- package/src/surface/blueprint-schema.ts +314 -0
- package/src/surface/blueprint-types.ts +256 -0
- package/src/surface/blueprint.ts +300 -0
- package/src/surface/breaker.ts +57 -0
- package/src/surface/decision-composer.ts +156 -0
- package/src/surface/eligibility.ts +372 -0
- package/src/surface/evidence-records.ts +97 -0
- package/src/surface/fleet.ts +60 -0
- package/src/surface/geo.ts +170 -0
- package/src/surface/governance.ts +146 -0
- package/src/surface/index.ts +216 -0
- package/src/surface/io/index.ts +18 -0
- package/src/surface/io/surface-module-context-io.ts +60 -0
- package/src/surface/io/visibility-outcomes-io.ts +46 -0
- package/src/surface/module-context.ts +120 -0
- package/src/surface/substance.ts +161 -0
- package/src/surface/tests/eligibility.pbt.test.ts +137 -0
- package/src/surface/tests/eligibility.test.ts +302 -0
- package/src/surface/types.ts +289 -0
- package/src/surface/visibility.ts +57 -0
- package/src/surface/vitest.config.ts +8 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>RFC-0176: verify the inbound/queue runtime — authenticateInbound, IntegrationEventSchema,
|
|
4
|
+
routeEventToReady (self-enabling Pipedrive route), and consumeIntegrationBatch dedup via a KV-backed
|
|
5
|
+
seen-set. fetch + KV are stubbed so the full producer→consumer flow is exercised without Cloudflare.</purpose>
|
|
6
|
+
<responsibilities>
|
|
7
|
+
<item>Assert a valid event routes once to the pipedrive gogol-adapter destination.</item>
|
|
8
|
+
<item>Assert a queue redelivery is deduped (no double-write) via the KV seen-set.</item>
|
|
9
|
+
<item>Assert inbound auth + event-shape validation are fail-closed.</item>
|
|
10
|
+
</responsibilities>
|
|
11
|
+
<non-goals>
|
|
12
|
+
<item>Do not hit the network — fetch is stubbed.</item>
|
|
13
|
+
</non-goals>
|
|
14
|
+
</MODULE_CONTRACT>
|
|
15
|
+
<CHANGE_SUMMARY>
|
|
16
|
+
<item>RFC-0176: initial queue/inbound runtime test.</item>
|
|
17
|
+
</CHANGE_SUMMARY>
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { test, expect, afterEach, beforeEach } from "vitest";
|
|
21
|
+
import {
|
|
22
|
+
IntegrationEventSchema,
|
|
23
|
+
authenticateInbound,
|
|
24
|
+
consumeIntegrationBatch,
|
|
25
|
+
kvDedup,
|
|
26
|
+
routeEventToReady,
|
|
27
|
+
type IntegrationEvent,
|
|
28
|
+
type IntegrationSecrets,
|
|
29
|
+
type KvDedupStore,
|
|
30
|
+
} from "../index.ts";
|
|
31
|
+
|
|
32
|
+
const SECRETS: IntegrationSecrets = {
|
|
33
|
+
INTEGRATION_PIPEDRIVE_API_TOKEN: "tok",
|
|
34
|
+
INTEGRATION_PIPEDRIVE_DOMAIN: "acme",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const EVENT: IntegrationEvent = {
|
|
38
|
+
eventId: "evt-1",
|
|
39
|
+
kind: "lead",
|
|
40
|
+
source: "uchat",
|
|
41
|
+
locale: "de",
|
|
42
|
+
occurredAt: "2026-06-08T00:00:00.000Z",
|
|
43
|
+
contact: { name: "Max", email: "max@example.org" },
|
|
44
|
+
payload: { note: "Hello from the chat" },
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/** In-memory KV implementing the dedup store contract. */
|
|
48
|
+
function memoryKv(): KvDedupStore & { size(): number } {
|
|
49
|
+
const map = new Map<string, string>();
|
|
50
|
+
return {
|
|
51
|
+
async get(key) {
|
|
52
|
+
return map.has(key) ? (map.get(key) ?? null) : null;
|
|
53
|
+
},
|
|
54
|
+
async put(key, value) {
|
|
55
|
+
map.set(key, value);
|
|
56
|
+
},
|
|
57
|
+
size: () => map.size,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let fetchCalls: string[] = [];
|
|
62
|
+
const realFetch = globalThis.fetch;
|
|
63
|
+
|
|
64
|
+
beforeEach(() => {
|
|
65
|
+
fetchCalls = [];
|
|
66
|
+
// Stub Pipedrive persons + leads endpoints — both return a usable id.
|
|
67
|
+
globalThis.fetch = (async (url: string | URL | Request) => {
|
|
68
|
+
fetchCalls.push(String(url));
|
|
69
|
+
return {
|
|
70
|
+
ok: true,
|
|
71
|
+
status: 200,
|
|
72
|
+
json: async () => ({ data: { id: 1 } }),
|
|
73
|
+
} as unknown as Response;
|
|
74
|
+
}) as typeof fetch;
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
afterEach(() => {
|
|
78
|
+
globalThis.fetch = realFetch;
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("routeEventToReady routes a lead to the pipedrive gogol-adapter destination", async () => {
|
|
82
|
+
const result = await routeEventToReady(EVENT, SECRETS);
|
|
83
|
+
expect(result.routed).toEqual(["crm:pipedrive"]);
|
|
84
|
+
expect(result.failed.length).toBe(0);
|
|
85
|
+
// pipedrive adapter performs persons + leads calls.
|
|
86
|
+
expect(fetchCalls.length).toBe(2);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("routeEventToReady skips when destination secrets are absent", async () => {
|
|
90
|
+
const result = await routeEventToReady(EVENT, {});
|
|
91
|
+
expect(result.skipped).toEqual(["crm:pipedrive"]);
|
|
92
|
+
expect(result.routed.length).toBe(0);
|
|
93
|
+
expect(fetchCalls.length).toBe(0);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("consumeIntegrationBatch dedups a queue redelivery via KV (no double-write)", async () => {
|
|
97
|
+
const kv = memoryKv();
|
|
98
|
+
const dedup = kvDedup(kv);
|
|
99
|
+
|
|
100
|
+
const first = await consumeIntegrationBatch([EVENT], SECRETS, dedup);
|
|
101
|
+
expect(first[0].routed).toEqual(["crm:pipedrive"]);
|
|
102
|
+
const afterFirst = fetchCalls.length;
|
|
103
|
+
expect(afterFirst).toBe(2);
|
|
104
|
+
|
|
105
|
+
// Redeliver the SAME eventId — must be skipped by dedup, no new fetches.
|
|
106
|
+
const second = await consumeIntegrationBatch([EVENT], SECRETS, dedup);
|
|
107
|
+
expect(second[0].skipped).toEqual(["crm:pipedrive"]);
|
|
108
|
+
expect(fetchCalls.length).toBe(afterFirst);
|
|
109
|
+
expect(kv.size()).toBe(1);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("authenticateInbound is fail-closed (bearer + header, unset secret rejects)", () => {
|
|
113
|
+
const ok = new Headers({ authorization: "Bearer s3cret" });
|
|
114
|
+
const okHeader = new Headers({ "x-integration-secret": "s3cret" });
|
|
115
|
+
const wrong = new Headers({ authorization: "Bearer nope" });
|
|
116
|
+
expect(authenticateInbound(ok, "s3cret")).toBe(true);
|
|
117
|
+
expect(authenticateInbound(okHeader, "s3cret")).toBe(true);
|
|
118
|
+
expect(authenticateInbound(wrong, "s3cret")).toBe(false);
|
|
119
|
+
expect(authenticateInbound(ok, undefined)).toBe(false);
|
|
120
|
+
expect(authenticateInbound(new Headers(), "s3cret")).toBe(false);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("IntegrationEventSchema rejects malformed payloads", () => {
|
|
124
|
+
expect(IntegrationEventSchema.safeParse(EVENT).success).toBe(true);
|
|
125
|
+
expect(IntegrationEventSchema.safeParse({ ...EVENT, kind: "bogus" }).success).toBe(false);
|
|
126
|
+
expect(IntegrationEventSchema.safeParse({ ...EVENT, eventId: "" }).success).toBe(false);
|
|
127
|
+
expect(IntegrationEventSchema.safeParse({}).success).toBe(false);
|
|
128
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>RFC-0191: prove the lifecycle event contracts — the closed kind catalog, the typed
|
|
4
|
+
payload schema the Stripe adapter validates against, and the guard. Pure — no I/O, no Stripe.</purpose>
|
|
5
|
+
<responsibilities>
|
|
6
|
+
<item>LifecycleEventPayloadSchema accepts a valid Stripe-mapped payload and rejects bad input.</item>
|
|
7
|
+
<item>isLifecycleEventKind guards the closed catalog.</item>
|
|
8
|
+
</responsibilities>
|
|
9
|
+
<non-goals><item>No network, no Stripe SDK — the schema is pure.</item></non-goals>
|
|
10
|
+
</MODULE_CONTRACT>
|
|
11
|
+
<CHANGE_SUMMARY><item>RFC-0191: initial lifecycle contract test.</item></CHANGE_SUMMARY>
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { test, expect } from "vitest";
|
|
15
|
+
import {
|
|
16
|
+
LIFECYCLE_EVENT_KINDS,
|
|
17
|
+
LifecycleEventPayloadSchema,
|
|
18
|
+
isLifecycleEventKind,
|
|
19
|
+
} from "../lifecycle.ts";
|
|
20
|
+
|
|
21
|
+
test("the lifecycle catalog covers invoice, subscription, and refund events", () => {
|
|
22
|
+
for (const k of [
|
|
23
|
+
"invoice.paid",
|
|
24
|
+
"invoice.payment_failed",
|
|
25
|
+
"subscription.created",
|
|
26
|
+
"subscription.updated",
|
|
27
|
+
"subscription.canceled",
|
|
28
|
+
"payment.refunded",
|
|
29
|
+
]) {
|
|
30
|
+
expect((LIFECYCLE_EVENT_KINDS as readonly string[]).includes(k)).toBeTruthy();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("the payload schema accepts a Stripe-mapped invoice.paid event", () => {
|
|
35
|
+
const r = LifecycleEventPayloadSchema.safeParse({
|
|
36
|
+
eventKind: "invoice.paid",
|
|
37
|
+
stripeEventId: "evt_123",
|
|
38
|
+
stripeCustomerId: "cus_123",
|
|
39
|
+
stripeInvoiceId: "in_123",
|
|
40
|
+
invoiceKind: "cycle",
|
|
41
|
+
invoiceStatus: "paid",
|
|
42
|
+
amountCents: 7000,
|
|
43
|
+
currency: "EUR",
|
|
44
|
+
});
|
|
45
|
+
expect(r.success).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("the payload schema rejects an unknown event kind and a negative amount", () => {
|
|
49
|
+
expect(
|
|
50
|
+
LifecycleEventPayloadSchema.safeParse({
|
|
51
|
+
eventKind: "invoice.exploded",
|
|
52
|
+
stripeEventId: "evt_1",
|
|
53
|
+
stripeCustomerId: "cus_1",
|
|
54
|
+
}).success,
|
|
55
|
+
).toBe(false);
|
|
56
|
+
expect(
|
|
57
|
+
LifecycleEventPayloadSchema.safeParse({
|
|
58
|
+
eventKind: "invoice.paid",
|
|
59
|
+
stripeEventId: "evt_1",
|
|
60
|
+
stripeCustomerId: "cus_1",
|
|
61
|
+
amountCents: -5,
|
|
62
|
+
}).success,
|
|
63
|
+
).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("isLifecycleEventKind guards the closed catalog", () => {
|
|
67
|
+
expect(isLifecycleEventKind("subscription.updated")).toBe(true);
|
|
68
|
+
expect(isLifecycleEventKind("offer.selected")).toBe(false); // a funnel kind, not lifecycle
|
|
69
|
+
});
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>RFC-0181: verify the EU delivery substrate. buildQstashPublish targets the EU region, pins
|
|
4
|
+
dedup to the eventId, and never leaks the token into the body; restRedisLedger gives first-seen-once
|
|
5
|
+
semantics and fails closed on transport error. fetch is stubbed — no network.</purpose>
|
|
6
|
+
<responsibilities>
|
|
7
|
+
<item>publish Request hits the EU base, carries dedup id + retries, body is the event (no token).</item>
|
|
8
|
+
<item>ledger.firstSeen is true on OK, false on null (redelivery), throws on non-2xx (fail-closed).</item>
|
|
9
|
+
</responsibilities>
|
|
10
|
+
<non-goals><item>No network — fetch stubbed.</item></non-goals>
|
|
11
|
+
</MODULE_CONTRACT>
|
|
12
|
+
<CHANGE_SUMMARY><item>RFC-0181: initial EU delivery substrate test.</item></CHANGE_SUMMARY>
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { test, expect } from "vitest";
|
|
16
|
+
import { QSTASH_EU_BASE, buildQstashPublish, restRedisLedger } from "../qstash.ts";
|
|
17
|
+
import type { IntegrationEvent } from "../port.ts";
|
|
18
|
+
|
|
19
|
+
const EVENT: IntegrationEvent = {
|
|
20
|
+
eventId: "evt-42",
|
|
21
|
+
kind: "lead",
|
|
22
|
+
source: "send-message",
|
|
23
|
+
locale: "de",
|
|
24
|
+
occurredAt: new Date().toISOString(),
|
|
25
|
+
contact: { name: "A", email: "a@example.de" },
|
|
26
|
+
payload: { message: "hallo" },
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
test("buildQstashPublish targets the EU region and pins dedup to the eventId", async () => {
|
|
30
|
+
const req = buildQstashPublish(EVENT, {
|
|
31
|
+
token: "qstash-secret",
|
|
32
|
+
callbackUrl: "https://warpgogol.com/internal/integration-route",
|
|
33
|
+
});
|
|
34
|
+
expect(req.url.startsWith(`${QSTASH_EU_BASE}/v2/publish/`)).toBeTruthy();
|
|
35
|
+
expect(req.url.includes("https://warpgogol.com/internal/integration-route")).toBeTruthy();
|
|
36
|
+
expect(req.headers.get("upstash-deduplication-id")).toBe("evt-42");
|
|
37
|
+
expect(req.headers.get("upstash-retries")).toBe("3");
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("buildQstashPublish puts the event (not the token) in the body", async () => {
|
|
41
|
+
const req = buildQstashPublish(EVENT, {
|
|
42
|
+
token: "qstash-secret",
|
|
43
|
+
callbackUrl: "https://warpgogol.com/internal/integration-route",
|
|
44
|
+
});
|
|
45
|
+
const body = await req.text();
|
|
46
|
+
expect(!body.includes("qstash-secret")).toBeTruthy();
|
|
47
|
+
expect(JSON.parse(body).eventId).toBe("evt-42");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("buildQstashPublish honours an explicit retry count", () => {
|
|
51
|
+
const req = buildQstashPublish(EVENT, {
|
|
52
|
+
token: "t",
|
|
53
|
+
callbackUrl: "https://x/cb",
|
|
54
|
+
retries: 5,
|
|
55
|
+
});
|
|
56
|
+
expect(req.headers.get("upstash-retries")).toBe("5");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
function stubFetch(status: number, result: string | null) {
|
|
60
|
+
return async () => new Response(JSON.stringify({ result }), { status });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
test("restRedisLedger.firstSeen is true on OK (first) and false on null (redelivery)", async () => {
|
|
64
|
+
const first = restRedisLedger(
|
|
65
|
+
{ url: "https://eu-redis.upstash.io", token: "redis-secret" },
|
|
66
|
+
stubFetch(200, "OK") as unknown as typeof fetch,
|
|
67
|
+
);
|
|
68
|
+
expect(await first.firstSeen("evt-42")).toBe(true);
|
|
69
|
+
|
|
70
|
+
const repeat = restRedisLedger(
|
|
71
|
+
{ url: "https://eu-redis.upstash.io", token: "redis-secret" },
|
|
72
|
+
stubFetch(200, null) as unknown as typeof fetch,
|
|
73
|
+
);
|
|
74
|
+
expect(await repeat.firstSeen("evt-42")).toBe(false);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("restRedisLedger fails closed (throws) on a transport error", async () => {
|
|
78
|
+
const ledger = restRedisLedger(
|
|
79
|
+
{ url: "https://eu-redis.upstash.io", token: "redis-secret" },
|
|
80
|
+
stubFetch(500, null) as unknown as typeof fetch,
|
|
81
|
+
);
|
|
82
|
+
await expect(() => ledger.firstSeen("evt-42")).rejects.toThrow();
|
|
83
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>RFC-0179: verify resolveShard is deterministic, distributes across the shared pool, names
|
|
4
|
+
resources by the documented scheme, and isolates a dedicated-tier site onto its own queue. These
|
|
5
|
+
properties are what registry-free placement and re-sharding safety depend on.</purpose>
|
|
6
|
+
<responsibilities>
|
|
7
|
+
<item>Same siteId+region+shardCount ⇒ identical assignment (stable hash).</item>
|
|
8
|
+
<item>shared tier names gogol-int-{region}-shared-{NN}; dedicated names a per-site queue.</item>
|
|
9
|
+
<item>dedup namespace is region-scoped; DLQ/consumer derive from the queue.</item>
|
|
10
|
+
</responsibilities>
|
|
11
|
+
<non-goals><item>No I/O — resolveShard is pure.</item></non-goals>
|
|
12
|
+
</MODULE_CONTRACT>
|
|
13
|
+
<CHANGE_SUMMARY><item>RFC-0179: initial sharding test.</item></CHANGE_SUMMARY>
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { test, expect } from "vitest";
|
|
17
|
+
import { fnv1a, resolveShard } from "../sharding.ts";
|
|
18
|
+
|
|
19
|
+
test("resolveShard is deterministic for the same inputs", () => {
|
|
20
|
+
const a = resolveShard("warpgogol-com", "eu", { shardCount: 4 });
|
|
21
|
+
const b = resolveShard("warpgogol-com", "eu", { shardCount: 4 });
|
|
22
|
+
expect(a).toEqual(b);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("shared tier names the queue/dlq/consumer by the documented scheme", () => {
|
|
26
|
+
const s = resolveShard("warpgogol-com", "eu", { tier: "shared", shardCount: 4 });
|
|
27
|
+
expect(s.tier).toBe("shared");
|
|
28
|
+
expect(s.queue).toMatch(/^gogol-int-eu-shared-\d{2}$/);
|
|
29
|
+
expect(s.dlq).toBe(`${s.queue}-dlq`);
|
|
30
|
+
expect(s.consumer).toBe(`${s.queue}-consumer`);
|
|
31
|
+
expect(s.dedupNamespace).toBe("gogol-int-dedup-eu");
|
|
32
|
+
expect(s.shardIndex >= 0 && s.shardIndex < 4).toBeTruthy();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("shard index is hash(siteId) mod shardCount", () => {
|
|
36
|
+
const s = resolveShard("acme-gmbh", "eu", { shardCount: 8 });
|
|
37
|
+
expect(s.shardIndex).toBe(fnv1a("acme-gmbh") % 8);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("region pins the dedup namespace and queue prefix", () => {
|
|
41
|
+
const us = resolveShard("acme-gmbh", "us", { shardCount: 4 });
|
|
42
|
+
expect(us.dedupNamespace).toBe("gogol-int-dedup-us");
|
|
43
|
+
expect(us.queue).toMatch(/^gogol-int-us-shared-/);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("dedicated tier isolates a site onto its own queue", () => {
|
|
47
|
+
const d = resolveShard("Busy Client!", "eu", { tier: "dedicated" });
|
|
48
|
+
expect(d.tier).toBe("dedicated");
|
|
49
|
+
expect(d.shardIndex).toBe(-1);
|
|
50
|
+
expect(d.queue).toBe("gogol-int-eu-ded-busy-client");
|
|
51
|
+
expect(d.dlq).toBe("gogol-int-eu-ded-busy-client-dlq");
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("the shared pool actually fans out across shards", () => {
|
|
55
|
+
const seen = new Set<number>();
|
|
56
|
+
for (let i = 0; i < 200; i += 1) {
|
|
57
|
+
seen.add(resolveShard(`site-${i}`, "eu", { shardCount: 4 }).shardIndex);
|
|
58
|
+
}
|
|
59
|
+
expect(seen.size).toBe(4);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("resolveShard rejects an empty siteId", () => {
|
|
63
|
+
expect(() => resolveShard("", "eu")).toThrow();
|
|
64
|
+
});
|